Commit 6289a377c3824f7e73136cd8661c39d3a6a0f69a

Authored by Salvador Abreu
2 parents 2721cfea 0ef5e9d6
Exists in master

Merge remote-tracking branch 'origin/master'

1 -PaCCS version 0.90 1 +PaCCS version 0.90c
2 2
3 -All files Copyright (C) 2009-2014 Vasco Pedro <vp@di.uevora.pt> 3 +All files Copyright (C) 2009-2015 Vasco Pedro <vp@di.uevora.pt>
4 All rights reserved. 4 All rights reserved.
5 5
6 * Compiling 6 * Compiling
@@ -173,6 +173,9 @@ Global constraints @@ -173,6 +173,9 @@ Global constraints
173 fd_sum_prod(fd_int X[], fd_int Y[], int n, int k) X . Y = k 173 fd_sum_prod(fd_int X[], fd_int Y[], int n, int k) X . Y = k
174 174
175 fd_poly_eq(int C[], fd_int Y[], int n, fd_int z) z <= C . Y <= z 175 fd_poly_eq(int C[], fd_int Y[], int n, fd_int z) z <= C . Y <= z
  176 + fd_poly_eq_k(int C[], fd_int Y[], int n, int k) C . Y = k
  177 + fd_poly_ne(int C[], fd_int Y[], int n, fd_int z) C . Y != z
  178 + fd_poly_ne_k(int C[], fd_int Y[], int n, int k) C . Y != k
176 fd_knapsack2(fd_int X[], fd_int Y[], int n, fd_int z) z <= X . Y <= z 179 fd_knapsack2(fd_int X[], fd_int Y[], int n, fd_int z) z <= X . Y <= z
177 180
178 fd_exactly(fd_int X[], int n, int c, int k) #{ i | X[i] = k } = c 181 fd_exactly(fd_int X[], int n, int c, int k) #{ i | X[i] = k } = c
1 -0.90b 1 +0.90c
src/constraints.c
@@ -149,6 +149,9 @@ void fd__constraint_free_memory() @@ -149,6 +149,9 @@ void fd__constraint_free_memory()
149 #include <constraints/poly-eq.c> 149 #include <constraints/poly-eq.c>
150 #include <constraints/element-var.c> 150 #include <constraints/element-var.c>
151 #include <constraints/exactly-vars.c> 151 #include <constraints/exactly-vars.c>
  152 +#include <constraints/poly-eq-k.c>
  153 +#include <constraints/poly-ne.c>
  154 +#include <constraints/poly-ne-k.c>
152 155
153 #ifdef CONSTRAINT_CLASS 156 #ifdef CONSTRAINT_CLASS
154 157
@@ -178,6 +181,9 @@ _FD_CONSTRAINT_INITIALISATION(max, FD_CONSTR_MAX) @@ -178,6 +181,9 @@ _FD_CONSTRAINT_INITIALISATION(max, FD_CONSTR_MAX)
178 _FD_CONSTRAINT_INITIALISATION(poly_eq, FD_CONSTR_POLY_EQ) 181 _FD_CONSTRAINT_INITIALISATION(poly_eq, FD_CONSTR_POLY_EQ)
179 _FD_CONSTRAINT_INITIALISATION(element_var, FD_CONSTR_ELEMENT_VAR) 182 _FD_CONSTRAINT_INITIALISATION(element_var, FD_CONSTR_ELEMENT_VAR)
180 _FD_CONSTRAINT_INITIALISATION(exactly_vars, FD_CONSTR_EXACTLY_VARS) 183 _FD_CONSTRAINT_INITIALISATION(exactly_vars, FD_CONSTR_EXACTLY_VARS)
  184 +_FD_CONSTRAINT_INITIALISATION(poly_eq_k, FD_CONSTR_POLY_EQ_K)
  185 +_FD_CONSTRAINT_INITIALISATION(poly_ne, FD_CONSTR_POLY_NE)
  186 +_FD_CONSTRAINT_INITIALISATION(poly_ne_k, FD_CONSTR_POLY_NE_K)
181 187
182 void _fd_init_constraints() 188 void _fd_init_constraints()
183 { 189 {
@@ -212,6 +218,9 @@ void _fd_init_constraints() @@ -212,6 +218,9 @@ void _fd_init_constraints()
212 _fd_init_constraint(poly_eq); 218 _fd_init_constraint(poly_eq);
213 _fd_init_constraint(element_var); 219 _fd_init_constraint(element_var);
214 _fd_init_constraint(exactly_vars); 220 _fd_init_constraint(exactly_vars);
  221 + _fd_init_constraint(poly_eq_k);
  222 + _fd_init_constraint(poly_ne);
  223 + _fd_init_constraint(poly_ne_k);
215 224
216 done = 1; 225 done = 1;
217 } 226 }
src/constraints.h
@@ -33,6 +33,9 @@ typedef enum { @@ -33,6 +33,9 @@ typedef enum {
33 FD_CONSTR_POLY_EQ, 33 FD_CONSTR_POLY_EQ,
34 FD_CONSTR_ELEMENT_VAR, 34 FD_CONSTR_ELEMENT_VAR,
35 FD_CONSTR_EXACTLY_VARS, 35 FD_CONSTR_EXACTLY_VARS,
  36 + FD_CONSTR_POLY_EQ_K,
  37 + FD_CONSTR_POLY_NE,
  38 + FD_CONSTR_POLY_NE_K,
36 FD_CONSTR_KINDS // number of kinds of constraints 39 FD_CONSTR_KINDS // number of kinds of constraints
37 } _fd_constraint_kind; 40 } _fd_constraint_kind;
38 41
src/constraints/poly-eq-k.c 0 → 100644
@@ -0,0 +1,469 @@ @@ -0,0 +1,469 @@
  1 +/* poly-eq-k(C, X, k) == sum(C . X) = k */
  2 +
  3 +static int fd_poly_eq_k_filter(fd_constraint this)
  4 +{
  5 + int k;
  6 + int min, max;
  7 + int terms = this->nvariables;
  8 + int *mins, *maxs;
  9 + int i;
  10 +#ifdef CONSTRAINT_TEMPS
  11 + int *base;
  12 +
  13 + assert(!fd__constraint_data_valid(this));
  14 +
  15 + if (!constraint_memory[this->index])
  16 + constraint_memory[this->index] = malloc((2 * terms + 2) * sizeof(int));
  17 +
  18 + base = constraint_memory[this->index];
  19 +
  20 + mins = base + 2;
  21 + maxs = mins + terms;
  22 +#else
  23 + mins = alloca(terms * sizeof(*mins));
  24 + maxs = alloca(terms * sizeof(*maxs));
  25 +#endif
  26 +
  27 + k = this->constants[terms];
  28 +
  29 + // sum the minima and the maxima of the terms
  30 + min = max = 0;
  31 +
  32 + for (i = 0; i < terms; ++i)
  33 + {
  34 + int vl, vh;
  35 +
  36 + if (this->constants[i] > 0)
  37 + {
  38 + vl = mins[i] = _fd_var_min(VAR(this, i));
  39 + vh = maxs[i] = _fd_var_max(VAR(this, i));
  40 + }
  41 + else
  42 + {
  43 + vl = maxs[i] = _fd_var_max(VAR(this, i));
  44 + vh = mins[i] = _fd_var_min(VAR(this, i));
  45 + }
  46 +
  47 + min += this->constants[i] * vl;
  48 + max += this->constants[i] * vh;
  49 + }
  50 +
  51 + if (min > k || max < k)
  52 + return FD_NOSOLUTION;
  53 +
  54 + if (min == max)
  55 + return FD_OK;
  56 +
  57 + // XXX: poor man's propagation
  58 + if (min == k)
  59 + {
  60 + for (i = 0; i < terms; ++i)
  61 + {
  62 + int c = this->constants[i];
  63 +
  64 + if (c && mins[i] != maxs[i])
  65 + {
  66 + if (c > 0)
  67 + _fd_var_del_gt(mins[i], VAR(this, i));
  68 + else
  69 + _fd_var_del_lt(maxs[i], VAR(this, i));
  70 +
  71 + // check needed for when variables occur more than once
  72 + // and with opposite signs
  73 + if (fd_domain_empty(VAR(this, i)))
  74 + return FD_NOSOLUTION;
  75 +
  76 + _fd_revise_connected(this, VAR(this, i));
  77 + }
  78 + }
  79 +
  80 + fd__constraint_set_entailed(this);
  81 + }
  82 + else if (max == k)
  83 + {
  84 + for (i = 0; i < terms; ++i)
  85 + {
  86 + int c = this->constants[i];
  87 +
  88 + if (c && mins[i] != maxs[i])
  89 + {
  90 + if (c > 0)
  91 + _fd_var_del_lt(maxs[i], VAR(this, i));
  92 + else
  93 + _fd_var_del_gt(mins[i], VAR(this, i));
  94 +
  95 + if (fd_domain_empty(VAR(this, i)))
  96 + return FD_NOSOLUTION;
  97 +
  98 + _fd_revise_connected(this, VAR(this, i));
  99 + }
  100 + }
  101 +
  102 + fd__constraint_set_entailed(this);
  103 + }
  104 + else
  105 + {
  106 + if (max > k)
  107 + for (i = 0; i < terms; ++i)
  108 + {
  109 + int c = this->constants[i];
  110 + int xmin = mins[i];
  111 + int xmax = maxs[i];
  112 +
  113 + if (c > 0)
  114 + {
  115 + // enforce sum{j!=i}(c[j] * min[j]) + c[i] * max[i] <= k
  116 +
  117 + if ((xmax - xmin) * c > k - min)
  118 + {
  119 + // xmax = floor((k - min) / c) + xmin
  120 + xmax = (k - min) / c + xmin;
  121 +
  122 + _fd_var_del_gt(xmax, VAR(this, i));
  123 +
  124 + if (fd_domain_empty(VAR(this, i)))
  125 + return FD_NOSOLUTION;
  126 +
  127 + _fd_revise_connected(this, VAR(this, i));
  128 + }
  129 + }
  130 + else if (c < 0)
  131 + {
  132 + // enforce sum{j!=i}(c[j] * min[j]) + c[i] * min[i] <= k
  133 +
  134 + if ((xmin - xmax) * c > k - min)
  135 + {
  136 + // xmin = ceil((k - min) / c) + xmax
  137 + xmin = (k - min) / c + xmax;
  138 +
  139 + _fd_var_del_lt(xmin, VAR(this, i));
  140 +
  141 + if (fd_domain_empty(VAR(this, i)))
  142 + return FD_NOSOLUTION;
  143 +
  144 + _fd_revise_connected(this, VAR(this, i));
  145 + }
  146 + }
  147 + }
  148 +
  149 + if (min < k)
  150 + for (i = 0; i < terms; ++i)
  151 + {
  152 + int c = this->constants[i];
  153 + int xmin = mins[i];
  154 + int xmax = maxs[i];
  155 +
  156 + if (c > 0)
  157 + {
  158 + // enforce sum{j!=i}(c[j] * max[j]) + c[i] * min[i] >= k
  159 +
  160 + if ((xmax - xmin) * c > max - k)
  161 + {
  162 + // xmin = ceil((k - max) / c) + xmax
  163 + xmin = (k - max) / c + xmax;
  164 +
  165 + _fd_var_del_lt(xmin, VAR(this, i));
  166 +
  167 + if (fd_domain_empty(VAR(this, i))) // domains may have holes
  168 + return FD_NOSOLUTION;
  169 +
  170 + _fd_revise_connected(this, VAR(this, i));
  171 + }
  172 + }
  173 + else if (c < 0)
  174 + {
  175 + // enforce sum{j!=i}(c[j] * max[j]) + c[i] * max[i] >= k
  176 +
  177 + if ((xmax - xmin) * c < k - max)
  178 + {
  179 + // xmax = floor((k - max) / c) + xmin
  180 + xmax = (k - max) / c + xmin;
  181 +
  182 + _fd_var_del_gt(xmax, VAR(this, i));
  183 +
  184 + if (fd_domain_empty(VAR(this, i))) // domains may have holes
  185 + return FD_NOSOLUTION;
  186 +
  187 + _fd_revise_connected(this, VAR(this, i));
  188 + }
  189 + }
  190 + }
  191 + }
  192 +
  193 +#ifdef CONSTRAINT_TEMPS
  194 + // save values
  195 + *base = min;
  196 + *(base + 1) = max;
  197 +
  198 + fd__constraint_remember(this);
  199 +#endif
  200 +
  201 + return FD_OK;
  202 +}
  203 +
  204 +static int fd_poly_eq_k_propagate2(fd_constraint this, fd_int culprit)
  205 +{
  206 +#ifdef CONSTRAINT_TEMPS
  207 + int k;
  208 + int min, max;
  209 + int terms = this->nvariables;
  210 + int *mins, *maxs;
  211 + int i;
  212 + int *base;
  213 + int x, c;
  214 + int nmin, nmin_x, nmax, nmax_x;
  215 +
  216 + if (!fd__constraint_data_valid(this))
  217 + return fd_poly_eq_k_filter(this); // ignores culprit
  218 +
  219 + // bounds filtering
  220 +
  221 + base = constraint_memory[this->index];
  222 +
  223 + mins = base + 2;
  224 + maxs = mins + terms;
  225 +
  226 + min = *base;
  227 + max = *(base + 1);
  228 +
  229 + k = this->constants[terms];
  230 +
  231 + // the culprit appears in one of the terms, find out which one(s)
  232 + for (x = 0; culprit != VAR(this, x); ++x)
  233 + ;
  234 +
  235 + nmin_x = _fd_var_min(VAR(this, x));
  236 + nmax_x = _fd_var_max(VAR(this, x));
  237 +
  238 + if (nmin_x == mins[x] && nmax_x == maxs[x])
  239 + return FD_OK;
  240 +
  241 + nmin = min;
  242 + nmax = max;
  243 +
  244 + do
  245 + {
  246 + c = this->constants[x];
  247 +
  248 + if (c > 0)
  249 + {
  250 + nmin = nmin + (nmin_x - mins[x]) * c;
  251 + nmax = nmax - (maxs[x] - nmax_x) * c;
  252 + }
  253 + else if (c < 0)
  254 + {
  255 + nmin = nmin - (maxs[x] - nmax_x) * c;
  256 + nmax = nmax + (nmin_x - mins[x]) * c;
  257 + }
  258 +
  259 + if (nmin > k || nmax < k)
  260 + return FD_NOSOLUTION;
  261 +
  262 + mins[x] = nmin_x;
  263 + maxs[x] = nmax_x;
  264 +
  265 + while (++x < terms && culprit != VAR(this, x))
  266 + ;
  267 + }
  268 + while (x < terms);
  269 +
  270 + // XXX: poor man's propagation
  271 + if (nmin == k)
  272 + {
  273 + for (i = 0; i < terms; ++i)
  274 + {
  275 + int c = this->constants[i];
  276 +
  277 + if (c && mins[i] != maxs[i])
  278 + {
  279 + if (c > 0)
  280 + {
  281 + _fd_var_del_gt(mins[i], VAR(this, i));
  282 +
  283 + maxs[i] = mins[i];
  284 + }
  285 + else
  286 + {
  287 + _fd_var_del_lt(maxs[i], VAR(this, i));
  288 +
  289 + mins[i] = maxs[i];
  290 + }
  291 +
  292 + if (fd_domain_empty(VAR(this, i)))
  293 + return FD_NOSOLUTION;
  294 +
  295 + _fd_revise_connected(this, VAR(this, i));
  296 + }
  297 + }
  298 +
  299 + fd__constraint_set_entailed(this);
  300 + }
  301 + else if (nmax == k)
  302 + {
  303 + for (i = 0; i < terms; ++i)
  304 + {
  305 + int c = this->constants[i];
  306 +
  307 + if (c && mins[i] != maxs[i])
  308 + {
  309 + if (c > 0)
  310 + {
  311 + _fd_var_del_lt(maxs[i], VAR(this, i));
  312 +
  313 + mins[i] = maxs[i];
  314 + }
  315 + else
  316 + {
  317 + _fd_var_del_gt(mins[i], VAR(this, i));
  318 +
  319 + maxs[i] = mins[i];
  320 + }
  321 +
  322 + if (fd_domain_empty(VAR(this, i)))
  323 + return FD_NOSOLUTION;
  324 +
  325 + _fd_revise_connected(this, VAR(this, i));
  326 + }
  327 + }
  328 +
  329 + fd__constraint_set_entailed(this);
  330 + }
  331 +
  332 +#if 0 // this is too expensive
  333 + {
  334 + if (nmax < max && nmax > k)
  335 + for (i = 0; i < terms; ++i)
  336 + {
  337 + int c = this->constants[i];
  338 + int xmin = mins[i];
  339 + int xmax = maxs[i];
  340 +
  341 + if (c > 0)
  342 + {
  343 + // enforce sum{j!=i}(c[j] * min[j]) + c[i] * max[i] <= k
  344 +
  345 + if ((xmax - xmin) * c > k - nmin)
  346 + {
  347 + // xmax = floor((k - nmin) / c) + xmin
  348 + xmax = (k - nmin) / c + xmin;
  349 +
  350 + if (_fd_var_del_gt(xmax, VAR(this, i)))
  351 + {
  352 + if (fd_domain_empty(VAR(this, i)))
  353 + return FD_NOSOLUTION;
  354 +
  355 + _fd_revise_connected(this, VAR(this, i));
  356 + }
  357 +
  358 + maxs[i] = xmax;
  359 + }
  360 + }
  361 + else if (c < 0)
  362 + {
  363 + // enforce sum{j!=i}(c[j] * min[j]) + c[i] * min[i] <= k
  364 +
  365 + if ((xmin - xmax) * c > k - nmin)
  366 + {
  367 + // xmin = ceil((k - nmin) / c) + xmax
  368 + xmin = (k - nmin) / c + xmax;
  369 +
  370 + if (_fd_var_del_lt(xmin, VAR(this, i)))
  371 + {
  372 + if (fd_domain_empty(VAR(this, i)))
  373 + return FD_NOSOLUTION;
  374 +
  375 + _fd_revise_connected(this, VAR(this, i));
  376 + }
  377 +
  378 + mins[i] = xmin;
  379 + }
  380 + }
  381 + }
  382 +
  383 + if (nmin > min && nmin < k)
  384 + for (i = 0; i < terms; ++i)
  385 + {
  386 + int c = this->constants[i];
  387 + int xmin = mins[i];
  388 + int xmax = maxs[i];
  389 +
  390 + if (c > 0)
  391 + {
  392 + // enforce sum{j!=i}(c[j] * max[j]) + c[i] * min[i] >= k
  393 +
  394 + if ((xmax - xmin) * c > nmax - k)
  395 + {
  396 + // xmin = ceil((k - nmax) / c) + xmax
  397 + xmin = (k - nmax) / c + xmax;
  398 +
  399 + if (_fd_var_del_lt(xmin, VAR(this, i)))
  400 + {
  401 +
  402 + if (fd_domain_empty(VAR(this, i))) // domains may have holes
  403 + return FD_NOSOLUTION;
  404 +
  405 + _fd_revise_connected(this, VAR(this, i));
  406 + }
  407 +
  408 + mins[i] = xmin;
  409 + }
  410 + }
  411 + else if (c < 0)
  412 + {
  413 + // enforce sum{j!=i}(c[j] * max[j]) + c[i] * max[i] >= k
  414 +
  415 + if ((xmax - xmin) * c < k - nmax)
  416 + {
  417 + // xmax = floor((k - nmax) / c) + xmin
  418 + xmax = (k - nmax) / c + xmin;
  419 +
  420 + if (_fd_var_del_gt(xmax, VAR(this, i)))
  421 + {
  422 + if (fd_domain_empty(VAR(this, i))) // domains may have holes
  423 + return FD_NOSOLUTION;
  424 +
  425 + _fd_revise_connected(this, VAR(this, i));
  426 + }
  427 +
  428 + maxs[i] = xmax;
  429 + }
  430 + }
  431 + }
  432 + }
  433 +#endif
  434 +
  435 + *base = nmin;
  436 + *(base + 1) = nmax;
  437 +
  438 + return FD_OK;
  439 +#else /* CONSTRAINT_TEMPS */
  440 + return fd_poly_eq_k_filter(this); // ignores culprit
  441 +#endif /* CONSTRAINT_TEMPS */
  442 +}
  443 +
  444 +fd_constraint fd_poly_eq_k(int cs[], fd_int xs[], int nterms, int k)
  445 +{
  446 + fd_constraint c = _fd_constraint_new(nterms, nterms + 1);
  447 + int i;
  448 +
  449 + if (c)
  450 + {
  451 + for (i = 0; i < nterms; ++i)
  452 + c->variables[i] = FD_INT2C_VAR(xs[i]);
  453 + for (i = 0; i < nterms; ++i)
  454 + c->constants[i] = cs[i];
  455 + c->constants[nterms] = k;
  456 +#ifdef CONSTRAINT_CLASS
  457 + c->kind = FD_CONSTR_POLY_EQ_K;
  458 +#else /* CONSTRAINT_CLASS */
  459 + c->propagator2 = fd_poly_eq_k_propagate2;
  460 +#endif /* CONSTRAINT_CLASS */
  461 +
  462 + for (i = 0; i < c->nvariables; ++i)
  463 + _fd_var_add_constraint(VAR(c, i), c);
  464 +
  465 + _fd_add_constraint(c);
  466 + }
  467 +
  468 + return c;
  469 +}
src/constraints/poly-ne-k.c 0 → 100644
@@ -0,0 +1,250 @@ @@ -0,0 +1,250 @@
  1 +/* poly-ne-k(C, X, k) == sum(C . X) != k */
  2 +
  3 +static int fd_poly_ne_k_filter(fd_constraint this)
  4 +{
  5 + int k;
  6 + int min, max;
  7 + int terms = this->nvariables;
  8 + int *mins, *maxs;
  9 + int unset = 0; // non-singleton variables
  10 + int i;
  11 +#ifdef CONSTRAINT_TEMPS
  12 + int *base;
  13 +
  14 + assert(!fd__constraint_data_valid(this));
  15 +
  16 + if (!constraint_memory[this->index])
  17 + constraint_memory[this->index] = malloc((2 * terms + 3) * sizeof(int));
  18 +
  19 + base = constraint_memory[this->index];
  20 +
  21 + mins = base + 3;
  22 + maxs = mins + terms;
  23 +#else
  24 + mins = alloca(terms * sizeof(*mins));
  25 + maxs = alloca(terms * sizeof(*maxs));
  26 +#endif
  27 +
  28 + k = this->constants[terms];
  29 +
  30 + // sum the minima and the maxima of the terms
  31 + min = max = 0;
  32 +
  33 + for (i = 0; i < terms; ++i)
  34 + {
  35 + int vl, vh;
  36 + int c = this->constants[i];
  37 +
  38 + if (c > 0)
  39 + {
  40 + vl = mins[i] = _fd_var_min(VAR(this, i));
  41 + vh = maxs[i] = _fd_var_max(VAR(this, i));
  42 + }
  43 + else
  44 + {
  45 + vl = maxs[i] = _fd_var_max(VAR(this, i));
  46 + vh = mins[i] = _fd_var_min(VAR(this, i));
  47 + }
  48 +
  49 + if (c && vl != vh)
  50 + unset++;
  51 +
  52 + min += c * vl;
  53 + max += c * vh;
  54 + }
  55 +
  56 + if (min > k || max < k)
  57 + {
  58 + fd__constraint_set_entailed(this);
  59 +
  60 + return FD_OK;
  61 + }
  62 +
  63 + if (min == max)
  64 + {
  65 + if (min == k)
  66 + return FD_NOSOLUTION;
  67 +
  68 + fd__constraint_set_entailed(this);
  69 +
  70 + return FD_OK;
  71 + }
  72 +
  73 + if (unset == 1)
  74 + {
  75 + int m, v;
  76 +
  77 + // find out which is the non-singleton variable
  78 + for (i = terms - 1; i >= 0; --i)
  79 + if (this->constants[i] && mins[i] != maxs[i])
  80 + break;
  81 +
  82 + if (this->constants[i] > 0)
  83 + m = min - this->constants[i] * mins[i];
  84 + else
  85 + m = min - this->constants[i] * maxs[i];
  86 +
  87 + v = (k - m) / this->constants[i];
  88 +
  89 + if (v * this->constants[i] + m == k)
  90 + fd_update_domain_and_check(del_val, v, VAR(this, i));
  91 +
  92 + fd__constraint_set_entailed(this);
  93 + }
  94 +
  95 +#ifdef CONSTRAINT_TEMPS
  96 + // save values
  97 + *base = min;
  98 + *(base + 1) = max;
  99 + *(base + 2) = unset;
  100 +
  101 + fd__constraint_remember(this);
  102 +#endif
  103 +
  104 + return FD_OK;
  105 +}
  106 +
  107 +static int fd_poly_ne_k_propagate2(fd_constraint this, fd_int culprit)
  108 +{
  109 +#ifdef CONSTRAINT_TEMPS
  110 + int k;
  111 + int min, max;
  112 + int terms = this->nvariables;
  113 + int *mins, *maxs;
  114 + int unset;
  115 + int i;
  116 + int *base;
  117 + int x, c;
  118 + int nmin, nmin_x, nmax, nmax_x;
  119 +
  120 + if (!fd__constraint_data_valid(this))
  121 + return fd_poly_ne_k_filter(this); // ignores culprit
  122 +
  123 + // bounds filtering
  124 +
  125 + base = constraint_memory[this->index];
  126 +
  127 + mins = base + 3;
  128 + maxs = mins + terms;
  129 +
  130 + k = this->constants[terms];
  131 +
  132 + min = *base;
  133 + max = *(base + 1);
  134 +
  135 + unset = *(base + 2);
  136 +
  137 + // the culprit appears in one of the terms, find out which one(s)
  138 + for (x = 0; culprit != VAR(this, x); ++x)
  139 + ;
  140 +
  141 + nmin_x = _fd_var_min(VAR(this, x));
  142 + nmax_x = _fd_var_max(VAR(this, x));
  143 +
  144 + if (nmin_x == mins[x] && nmax_x == maxs[x])
  145 + return FD_OK;
  146 +
  147 + nmin = min;
  148 + nmax = max;
  149 +
  150 + do
  151 + {
  152 + c = this->constants[x];
  153 +
  154 + if (c && nmin_x == nmax_x)
  155 + unset--;
  156 +
  157 + if (c > 0)
  158 + {
  159 + nmin = nmin + (nmin_x - mins[x]) * c;
  160 + nmax = nmax - (maxs[x] - nmax_x) * c;
  161 + }
  162 + else if (c < 0)
  163 + {
  164 + nmin = nmin - (maxs[x] - nmax_x) * c;
  165 + nmax = nmax + (nmin_x - mins[x]) * c;
  166 + }
  167 +
  168 + mins[x] = nmin_x;
  169 + maxs[x] = nmax_x;
  170 +
  171 + while (++x < terms && culprit != VAR(this, x))
  172 + ;
  173 + }
  174 + while (x < terms);
  175 +
  176 + if (nmin > k || nmax < k)
  177 + {
  178 + fd__constraint_set_entailed(this);
  179 +
  180 + return FD_OK;
  181 + }
  182 +
  183 + if (nmin == nmax)
  184 + {
  185 + if (nmin == k)
  186 + return FD_NOSOLUTION;
  187 +
  188 + fd__constraint_set_entailed(this);
  189 +
  190 + return FD_OK;
  191 + }
  192 +
  193 + if (unset == 1)
  194 + {
  195 + int m, v;
  196 +
  197 + // find out which is the non-singleton variable
  198 + for (i = terms - 1; i >= 0; --i)
  199 + if (this->constants[i] && mins[i] != maxs[i])
  200 + break;
  201 +
  202 + if (this->constants[i] > 0)
  203 + m = min - this->constants[i] * mins[i];
  204 + else
  205 + m = min - this->constants[i] * maxs[i];
  206 +
  207 + v = (k - m) / this->constants[i];
  208 +
  209 + if (v * this->constants[i] + m == k)
  210 + fd_update_domain_and_check(del_val, v, VAR(this, i));
  211 +
  212 + fd__constraint_set_entailed(this);
  213 + }
  214 +
  215 + *base = nmin;
  216 + *(base + 1) = nmax;
  217 + *(base + 2) = unset;
  218 +
  219 + return FD_OK;
  220 +#else /* CONSTRAINT_TEMPS */
  221 + return fd_poly_ne_k_filter(this); // ignores culprit
  222 +#endif /* CONSTRAINT_TEMPS */
  223 +}
  224 +
  225 +fd_constraint fd_poly_ne_k(int cs[], fd_int xs[], int nterms, int k)
  226 +{
  227 + fd_constraint c = _fd_constraint_new(nterms, nterms + 1);
  228 + int i;
  229 +
  230 + if (c)
  231 + {
  232 + for (i = 0; i < nterms; ++i)
  233 + c->variables[i] = FD_INT2C_VAR(xs[i]);
  234 + for (i = 0; i < nterms; ++i)
  235 + c->constants[i] = cs[i];
  236 + c->constants[nterms] = k;
  237 +#ifdef CONSTRAINT_CLASS
  238 + c->kind = FD_CONSTR_POLY_NE_K;
  239 +#else /* CONSTRAINT_CLASS */
  240 + c->propagator2 = fd_poly_ne_k_propagate2;
  241 +#endif /* CONSTRAINT_CLASS */
  242 +
  243 + for (i = 0; i < c->nvariables; ++i)
  244 + _fd_var_add_constraint(VAR(c, i), c);
  245 +
  246 + _fd_add_constraint(c);
  247 + }
  248 +
  249 + return c;
  250 +}
src/constraints/poly-ne.c 0 → 100644
@@ -0,0 +1,288 @@ @@ -0,0 +1,288 @@
  1 +/* poly-ne(C, X, y) == sum(C . X) != y */
  2 +
  3 +static int fd_poly_ne_filter(fd_constraint this)
  4 +{
  5 + int ub, lb;
  6 + int min, max;
  7 + int terms = this->nconstants;
  8 + int *mins, *maxs;
  9 + int unset = 0; // non-singleton variables
  10 + int i;
  11 +#ifdef CONSTRAINT_TEMPS
  12 + int *base;
  13 +
  14 + assert(!fd__constraint_data_valid(this));
  15 +
  16 + if (!constraint_memory[this->index])
  17 + constraint_memory[this->index] = malloc((2 * terms + 5) * sizeof(int));
  18 +
  19 + base = constraint_memory[this->index];
  20 +
  21 + mins = base + 5;
  22 + maxs = mins + terms;
  23 +#else
  24 + mins = alloca(terms * sizeof(*mins));
  25 + maxs = alloca(terms * sizeof(*maxs));
  26 +#endif
  27 +
  28 + lb = _fd_var_min(VAR(this, this->nvariables - 1)); // lower bound
  29 + ub = _fd_var_max(VAR(this, this->nvariables - 1)); // upper bound
  30 +
  31 + // sum the minima and the maxima of the terms
  32 + min = max = 0;
  33 +
  34 + for (i = 0; i < terms; ++i)
  35 + {
  36 + int vl, vh;
  37 + int c = this->constants[i];
  38 +
  39 + if (c > 0)
  40 + {
  41 + vl = mins[i] = _fd_var_min(VAR(this, i));
  42 + vh = maxs[i] = _fd_var_max(VAR(this, i));
  43 + }
  44 + else
  45 + {
  46 + vl = maxs[i] = _fd_var_max(VAR(this, i));
  47 + vh = mins[i] = _fd_var_min(VAR(this, i));
  48 + }
  49 +
  50 + if (c && vl != vh)
  51 + unset++;
  52 +
  53 + min += c * vl;
  54 + max += c * vh;
  55 + }
  56 +
  57 + if (min > ub || max < lb)
  58 + {
  59 + fd__constraint_set_entailed(this);
  60 +
  61 + return FD_OK;
  62 + }
  63 +
  64 + if (min == max)
  65 + {
  66 + fd_update_domain_and_check(del_val, min, VAR(this, this->nvariables - 1));
  67 +
  68 + fd__constraint_set_entailed(this);
  69 + }
  70 + else if (unset == 1 && lb == ub)
  71 + {
  72 + int m, v;
  73 +
  74 + // find out which is the non-singleton variable
  75 + for (i = terms - 1; i >= 0; --i)
  76 + if (this->constants[i] && mins[i] != maxs[i])
  77 + break;
  78 +
  79 + if (this->constants[i] > 0)
  80 + m = min - this->constants[i] * mins[i];
  81 + else
  82 + m = min - this->constants[i] * maxs[i];
  83 +
  84 + v = (lb - m) / this->constants[i];
  85 +
  86 + if (v * this->constants[i] + m == lb)
  87 + fd_update_domain_and_check(del_val, v, VAR(this, i));
  88 +
  89 + fd__constraint_set_entailed(this);
  90 + }
  91 +
  92 +#ifdef CONSTRAINT_TEMPS
  93 + // save values
  94 + *base = lb;
  95 + *(base + 1) = ub;
  96 + *(base + 2) = min;
  97 + *(base + 3) = max;
  98 + *(base + 4) = unset;
  99 +
  100 + fd__constraint_remember(this);
  101 +#endif
  102 +
  103 + return FD_OK;
  104 +}
  105 +
  106 +static int fd_poly_ne_propagate2(fd_constraint this, fd_int culprit)
  107 +{
  108 +#ifdef CONSTRAINT_TEMPS
  109 + int ub, lb;
  110 + int min, max;
  111 + int terms = this->nconstants;
  112 + int *mins, *maxs;
  113 + int unset;
  114 + int i;
  115 + int *base;
  116 + int x, c;
  117 + int nmin, nmin_x, nmax, nmax_x;
  118 +
  119 + if (!fd__constraint_data_valid(this))
  120 + return fd_poly_ne_filter(this); // ignores culprit
  121 +
  122 + // bounds filtering
  123 +
  124 + base = constraint_memory[this->index];
  125 +
  126 + mins = base + 5;
  127 + maxs = mins + terms;
  128 +
  129 + lb = *base;
  130 + ub = *(base + 1);
  131 +
  132 + min = *(base + 2);
  133 + max = *(base + 3);
  134 +
  135 + unset = *(base + 4);
  136 +
  137 + if (culprit == VAR(this, this->nvariables - 1))
  138 + {
  139 + // the culprit is the sum variable
  140 + int nlb, nub;
  141 +
  142 + nlb = _fd_var_min(culprit);
  143 + nub = _fd_var_max(culprit);
  144 +
  145 + if (nlb == lb && nub == ub)
  146 + return FD_OK;
  147 +
  148 + if (min > nub || max < nlb)
  149 + fd__constraint_set_entailed(this);
  150 +
  151 + if (unset == 1 && nlb == nub)
  152 + {
  153 + int m, v;
  154 +
  155 + // find out which is the non-singleton variable
  156 + for (i = this->nvariables - 2; i >= 0; --i)
  157 + if (this->constants[i] && mins[i] != maxs[i])
  158 + break;
  159 +
  160 + if (this->constants[i] > 0)
  161 + m = min - this->constants[i] * mins[i];
  162 + else
  163 + m = min - this->constants[i] * maxs[i];
  164 +
  165 + v = (nlb - m) / this->constants[i];
  166 +
  167 + if (v * this->constants[i] + m == nlb)
  168 + fd_update_domain_and_check(del_val, v, VAR(this, i));
  169 +
  170 + fd__constraint_set_entailed(this);
  171 + }
  172 +
  173 + *base = nlb;
  174 + *(base + 1) = nub;
  175 +
  176 + return FD_OK;
  177 + }
  178 +
  179 + // the culprit appears in one of the terms, find out which one(s)
  180 + for (x = 0; culprit != VAR(this, x); ++x)
  181 + ;
  182 +
  183 + nmin_x = _fd_var_min(VAR(this, x));
  184 + nmax_x = _fd_var_max(VAR(this, x));
  185 +
  186 + if (nmin_x == mins[x] && nmax_x == maxs[x])
  187 + return FD_OK;
  188 +
  189 + nmin = min;
  190 + nmax = max;
  191 +
  192 + do
  193 + {
  194 + c = this->constants[x];
  195 +
  196 + if (c && nmin_x == nmax_x)
  197 + unset--;
  198 +
  199 + if (c > 0)
  200 + {
  201 + nmin = nmin + (nmin_x - mins[x]) * c;
  202 + nmax = nmax - (maxs[x] - nmax_x) * c;
  203 + }
  204 + else if (c < 0)
  205 + {
  206 + nmin = nmin - (maxs[x] - nmax_x) * c;
  207 + nmax = nmax + (nmin_x - mins[x]) * c;
  208 + }
  209 +
  210 + mins[x] = nmin_x;
  211 + maxs[x] = nmax_x;
  212 +
  213 + while (++x < terms && culprit != VAR(this, x))
  214 + ;
  215 + }
  216 + while (x < terms);
  217 +
  218 + if (nmin > ub || nmax < lb)
  219 + {
  220 + fd__constraint_set_entailed(this);
  221 +
  222 + return FD_OK;
  223 + }
  224 +
  225 + if (nmin == nmax)
  226 + {
  227 + fd_update_domain_and_check(del_val, nmin, VAR(this, this->nvariables - 1));
  228 +
  229 + fd__constraint_set_entailed(this);
  230 + }
  231 + else if (unset == 1 && lb == ub)
  232 + {
  233 + int m, v;
  234 +
  235 + // find out which is the non-singleton variable
  236 + for (i = terms - 1; i >= 0; --i)
  237 + if (this->constants[i] && mins[i] != maxs[i])
  238 + break;
  239 +
  240 + if (this->constants[i] > 0)
  241 + m = min - this->constants[i] * mins[i];
  242 + else
  243 + m = min - this->constants[i] * maxs[i];
  244 +
  245 + v = (lb - m) / this->constants[i];
  246 +
  247 + if (v * this->constants[i] + m == lb)
  248 + fd_update_domain_and_check(del_val, v, VAR(this, i));
  249 +
  250 + fd__constraint_set_entailed(this);
  251 + }
  252 +
  253 + *(base + 2) = nmin;
  254 + *(base + 3) = nmax;
  255 + *(base + 4) = unset;
  256 +
  257 + return FD_OK;
  258 +#else /* CONSTRAINT_TEMPS */
  259 + return fd_poly_ne_filter(this); // ignores culprit
  260 +#endif /* CONSTRAINT_TEMPS */
  261 +}
  262 +
  263 +fd_constraint fd_poly_ne(int cs[], fd_int xs[], int nterms, fd_int y)
  264 +{
  265 + fd_constraint c = _fd_constraint_new(nterms + 1, nterms);
  266 + int i;
  267 +
  268 + if (c)
  269 + {
  270 + for (i = 0; i < nterms; ++i)
  271 + c->variables[i] = FD_INT2C_VAR(xs[i]);
  272 + c->variables[nterms] = FD_INT2C_VAR(y);
  273 + for (i = 0; i < nterms; ++i)
  274 + c->constants[i] = cs[i];
  275 +#ifdef CONSTRAINT_CLASS
  276 + c->kind = FD_CONSTR_POLY_NE;
  277 +#else /* CONSTRAINT_CLASS */
  278 + c->propagator2 = fd_poly_ne_propagate2;
  279 +#endif /* CONSTRAINT_CLASS */
  280 +
  281 + for (i = 0; i < c->nvariables; ++i)
  282 + _fd_var_add_constraint(VAR(c, i), c);
  283 +
  284 + _fd_add_constraint(c);
  285 + }
  286 +
  287 + return c;
  288 +}
@@ -50,6 +50,9 @@ fd_constraint fd_sum2(fd_int X[], int n, fd_int y); @@ -50,6 +50,9 @@ fd_constraint fd_sum2(fd_int X[], int n, fd_int y);
50 fd_constraint fd_sum_prod(fd_int X[], fd_int Y[], int n, int k); 50 fd_constraint fd_sum_prod(fd_int X[], fd_int Y[], int n, int k);
51 51
52 fd_constraint fd_poly_eq(int C[], fd_int Y[], int n, fd_int z); 52 fd_constraint fd_poly_eq(int C[], fd_int Y[], int n, fd_int z);
  53 +fd_constraint fd_poly_eq_k(int C[], fd_int Y[], int n, int k);
  54 +fd_constraint fd_poly_ne(int C[], fd_int Y[], int n, fd_int y);
  55 +fd_constraint fd_poly_ne_k(int C[], fd_int Y[], int n, int k);
53 fd_constraint fd_knapsack2(fd_int X[], fd_int Y[], int n, fd_int z); 56 fd_constraint fd_knapsack2(fd_int X[], fd_int Y[], int n, fd_int z);
54 57
55 fd_constraint fd_exactly(fd_int X[], int n, int c, int k); 58 fd_constraint fd_exactly(fd_int X[], int n, int c, int k);
src/variables.h
@@ -36,6 +36,24 @@ int _fd_var_intersect(fd_int variable1, fd_int variable2); @@ -36,6 +36,24 @@ int _fd_var_intersect(fd_int variable1, fd_int variable2);
36 int _fd_var_contains_val(fd_int variable, int value); 36 int _fd_var_contains_val(fd_int variable, int value);
37 void _fd_var_set_value(fd_int variable, int value); 37 void _fd_var_set_value(fd_int variable, int value);
38 38
  39 +#define fd_update_domain(op,var,value) \
  40 + { \
  41 + _fd_var_ ## op(var, value); \
  42 + \
  43 + _fd_revise_connected(var); \
  44 + }
  45 +
  46 +#define fd_update_domain_and_check(op, val, var) \
  47 + { \
  48 + if (_fd_var_ ## op(val, var)) \
  49 + { \
  50 + if (fd_domain_empty(var)) \
  51 + return FD_NOSOLUTION; \
  52 + \
  53 + _fd_revise_connected(this, var); \
  54 + } \
  55 + }
  56 +
39 // SEARCH 57 // SEARCH
40 extern int (*fd__cmp_variables)(fd_int, fd_int); 58 extern int (*fd__cmp_variables)(fd_int, fd_int);
41 int fd__cmp_var_size(fd_int, fd_int); 59 int fd__cmp_var_size(fd_int, fd_int);