/* element-var */ /* element-var(X, y, z) == X[y] = z (0 <= y < |X|) */ static int fd_element_var_filter(fd_constraint this) { int length = this->nvariables - 2; fd_int index, value; int imax, min, max; int v; int i; // do some filtering... index = VAR(this, this->nvariables - 2); // check the index variable if (_fd_var_del_ge(length, index)) { if (fd_domain_empty(index)) return FD_NOSOLUTION; _fd_revise_connected(this, index); } value = VAR(this, this->nvariables - 1); // see if the index is already fixed if (fd_var_single(index, &v)) { if (_fd_var_intersect(VAR(this, v), value)) { if (fd_domain_empty(VAR(this, v))) return FD_NOSOLUTION; _fd_revise_connected(this, VAR(this, v)); } if (_fd_var_intersect(value, VAR(this, v))) { if (fd_domain_empty(value)) return FD_NOSOLUTION; _fd_revise_connected(this, value); } return FD_OK; } // do some bounds filtering on the value variable imax = _fd_var_max(index); min = _fd_var_min(VAR(this, imax)); max = _fd_var_max(VAR(this, imax)); for (i = _fd_var_min(index); i < imax; ++i) { int m; if ((m = _fd_var_min(VAR(this, i))) < min) min = m; else if ((m = _fd_var_max(VAR(this, i))) > max) max = m; } if (_fd_var_del_lt(min, value) | _fd_var_del_gt(max, value)) { if (fd_domain_empty(value)) return FD_NOSOLUTION; _fd_revise_connected(this, value); } // XXX: more... return FD_OK; } static int fd_element_var_propagate2(fd_constraint this, fd_int culprit) { int length = this->nvariables - 2; fd_int index, value; int i; // do some filtering... index = VAR(this, this->nvariables - 2); value = VAR(this, this->nvariables - 1); // see if the culprit is the index variable if (culprit == index) { if (fd_var_single(index, &i)) { if (_fd_var_intersect(VAR(this, i), value)) { if (fd_domain_empty(VAR(this, i))) return FD_NOSOLUTION; _fd_revise_connected(this, VAR(this, i)); } if (_fd_var_intersect(value, VAR(this, i))) { if (fd_domain_empty(value)) return FD_NOSOLUTION; _fd_revise_connected(this, value); } } return FD_OK; } // see if the culprit is the value variable if (culprit == value) { int k; if (fd_var_single(value, &k)) { // check which variables have k in their domain int imax = _fd_var_max(index); for (i = _fd_var_min(index); i <= imax; ++i) if (!_fd_var_contains_val(VAR(this, i), k) && _fd_var_del_val(i, index)) { if (fd_domain_empty(index)) return FD_NOSOLUTION; _fd_revise_connected(NULL, index); } } return FD_OK; } // XXX: filter for non-index and non-value variables return FD_OK; } fd_constraint fd_element_var(fd_int *variables, int nvariables, fd_int index, fd_int value) { fd_constraint c = _fd_constraint_new(nvariables + 2, 0); int i; // XXX: add a constraint 0 <= INDEX < nvariables if (c) { for (i = 0; i < nvariables; ++i) c->variables[i] = FD_INT2C_VAR(variables[i]); c->variables[nvariables] = FD_INT2C_VAR(index); c->variables[nvariables + 1] = FD_INT2C_VAR(value); #ifdef CONSTRAINT_CLASS c->kind = FD_CONSTR_ELEMENT_VAR; #else /* CONSTRAINT_CLASS */ c->propagator2 = fd_element_var_propagate2; #endif /* CONSTRAINT_CLASS */ for (i = 0; i < c->nvariables; ++i) _fd_var_add_constraint(VAR(c, i), c); _fd_add_constraint(c); } return c; }