/* X = Y - Z */ static int fd_var_eq_minus_filter(fd_constraint this) { fd_int x, y, z; int xmin, xmax, ymin, ymax, zmin, zmax; int changed_x, changed_y, changed_z; x = VAR(this, 0); y = VAR(this, 1); z = VAR(this, 2); // XXX: just do bounds consistency, for now xmin = _fd_var_min(x); xmax = _fd_var_max(x); zmin = _fd_var_min(z); zmax = _fd_var_max(z); changed_y = _fd_var_del_lt(xmin + zmin, y) | _fd_var_del_gt(xmax + zmax, y); if (changed_y) { if (fd_domain_empty(y)) return FD_NOSOLUTION; _fd_revise_connected(NULL, y); } ymin = _fd_var_min(y); ymax = _fd_var_max(y); changed_z = _fd_var_del_lt(ymin - xmax, z) | _fd_var_del_gt(ymax - xmin, z); if (changed_z) { if (fd_domain_empty(z)) return FD_NOSOLUTION; _fd_revise_connected(NULL, z); zmin = _fd_var_min(z); zmax = _fd_var_max(z); } changed_x = _fd_var_del_lt(ymin - zmax, x) | _fd_var_del_gt(ymax - zmin, x); if (changed_x) { if (fd_domain_empty(x)) return FD_NOSOLUTION; _fd_revise_connected(NULL, x); } #if CONSTRAINT_TEMPS > 3 if (fd_var_single(x, 0) && fd_var_single(y, 0) && fd_var_single(z, 0)) fd__constraint_set_entailed(this); #endif return FD_OK; } int fd_var_eq_minus_propagate2(fd_constraint this, fd_int culprit) { fd_int x, y, z; int changed_x = 0, changed_y = 0, changed_z = 0; x = VAR(this, 0); y = VAR(this, 1); z = VAR(this, 2); // XXX: just do bounds consistency, for now if (culprit == x) { changed_y = _fd_var_del_lt(_fd_var_min(x) + _fd_var_min(z), y); changed_y |= _fd_var_del_gt(_fd_var_max(x) + _fd_var_max(z), y); if (changed_y && fd_domain_empty(y)) return FD_NOSOLUTION; changed_z = _fd_var_del_lt(_fd_var_min(y) - _fd_var_max(x), z); changed_z |= _fd_var_del_gt(_fd_var_max(y) - _fd_var_min(x), z); if (changed_z && fd_domain_empty(z)) return FD_NOSOLUTION; } else if (culprit == y) { changed_x = _fd_var_del_lt(_fd_var_min(y) - _fd_var_max(z), x); changed_x |= _fd_var_del_gt(_fd_var_max(y) - _fd_var_min(z), x); if (changed_x && fd_domain_empty(x)) return FD_NOSOLUTION; changed_z = _fd_var_del_lt(_fd_var_min(y) - _fd_var_max(x), z); changed_z |= _fd_var_del_gt(_fd_var_max(y) - _fd_var_min(x), z); if (changed_z && fd_domain_empty(z)) return FD_NOSOLUTION; } else // culprit == z { changed_x = _fd_var_del_lt(_fd_var_min(y) - _fd_var_max(z), x); changed_x |= _fd_var_del_gt(_fd_var_max(y) - _fd_var_min(z), x); if (changed_x && fd_domain_empty(x)) return FD_NOSOLUTION; changed_y = _fd_var_del_lt(_fd_var_min(x) + _fd_var_min(z), y); changed_y |= _fd_var_del_gt(_fd_var_max(x) + _fd_var_max(z), y); if (changed_y && fd_domain_empty(y)) return FD_NOSOLUTION; } if (changed_x) _fd_revise_connected(NULL, x); // XXX: NULL or this? if (changed_y) _fd_revise_connected(NULL, y); // XXX: NULL or this? if (changed_z) _fd_revise_connected(NULL, z); // XXX: NULL or this? #if CONSTRAINT_TEMPS > 3 if (fd_var_single(x, 0) && fd_var_single(y, 0) && fd_var_single(z, 0)) fd__constraint_set_entailed(this); #endif return FD_OK; } int fd_var_eq_minus_propagate(fd_constraint this, fd_int revise) { fd_int x, y, z; int changed; x = VAR(this, 0); y = VAR(this, 1); z = VAR(this, 2); // XXX: just do bounds consistency, for now if (revise == x) { changed = _fd_var_del_lt(_fd_var_min(y) - _fd_var_max(z), revise); changed |= _fd_var_del_gt(_fd_var_max(y) - _fd_var_min(z), revise); } else if (revise == y) { changed = _fd_var_del_lt(_fd_var_min(x) + _fd_var_min(z), revise); changed |= _fd_var_del_gt(_fd_var_max(x) + _fd_var_max(z), revise); } else // revise == z { changed = _fd_var_del_lt(_fd_var_min(y) - _fd_var_max(x), revise); changed |= _fd_var_del_gt(_fd_var_max(y) - _fd_var_min(x), revise); } if (changed && fd_domain_empty(revise)) return FD_NOSOLUTION; // XXX: enqueue further updates here? if (changed) _fd_revise_connected(this, revise); return FD_OK; } fd_constraint fd_var_eq_minus(fd_int x, fd_int y, fd_int z) { fd_constraint c = _fd_constraint_new(3, 0); if (c) { c->variables[0] = FD_INT2C_VAR(x); c->variables[1] = FD_INT2C_VAR(y); c->variables[2] = FD_INT2C_VAR(z); #ifdef CONSTRAINT_CLASS c->kind = FD_CONSTR_VAR_EQ_MINUS; #else /* CONSTRAINT_CLASS */ c->propagator2 = fd_var_eq_minus_propagate2; c->propagator = fd_var_eq_minus_propagate; #endif /* CONSTRAINT_CLASS */ _fd_var_add_constraint(x, c); _fd_var_add_constraint(y, c); _fd_var_add_constraint(z, c); _fd_add_constraint(c); } return c; }