/* X = Y * Z */ // XXX: assuming non-negative values static int fd_var_eq_times_filter(fd_constraint this) { fd_int x, y, z; int min_x, max_x, min_y, max_y, min_z, max_z; int changed_x, changed_y, changed_z; x = VAR(this, 0); y = VAR(this, 1); z = VAR(this, 2); // XXX: just do (a kind of) bounds consistency, for now min_x = _fd_var_min(x); max_x = _fd_var_max(x); min_z = _fd_var_min(z); max_z = _fd_var_max(z); if (max_z > 0) changed_y = _fd_var_del_lt(min_x / max_z, y); if (min_z > 0) changed_y |= _fd_var_del_gt(max_x / min_z, y); if (changed_y && fd_domain_empty(y)) { return FD_NOSOLUTION; _fd_revise_connected(NULL, y); } min_y = _fd_var_min(y); max_y = _fd_var_max(y); if (max_y > 0) changed_z = _fd_var_del_lt(min_x / max_y, z); if (min_y > 0) changed_z |= _fd_var_del_gt(max_x / min_y, z); if (changed_z && fd_domain_empty(z)) { return FD_NOSOLUTION; _fd_revise_connected(NULL, z); min_z = _fd_var_min(z); max_z = _fd_var_max(z); } changed_x = _fd_var_del_lt(min_y * min_z, x); changed_x |= _fd_var_del_gt(max_y * max_z, x); if (changed_x && 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_times_propagate2(fd_constraint this, fd_int culprit) { fd_int x, y, z; int min_x, max_x, min_y, max_y, min_z, max_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) { min_x = _fd_var_min(x); max_x = _fd_var_max(x); min_z = _fd_var_min(z); max_z = _fd_var_max(z); if (max_z > 0) changed_y = _fd_var_del_lt(min_x / max_z, y); if (min_z > 0) changed_y |= _fd_var_del_gt(max_x / min_z, y); if (changed_y && fd_domain_empty(y)) return FD_NOSOLUTION; min_y = _fd_var_min(y); max_y = _fd_var_max(y); if (max_y > 0) changed_z = _fd_var_del_lt(min_x / max_y, z); if (min_y > 0) changed_z |= _fd_var_del_gt(max_x / min_y, z); if (changed_z && fd_domain_empty(z)) return FD_NOSOLUTION; } else if (culprit == y) // culprit == y || culprit == z { min_y = _fd_var_min(y); max_y = _fd_var_max(y); min_z = _fd_var_min(z); max_z = _fd_var_max(z); changed_x = _fd_var_del_lt(min_y * min_z, x); changed_x |= _fd_var_del_gt(max_y * max_z, x); if (changed_x && fd_domain_empty(x)) return FD_NOSOLUTION; min_x = _fd_var_min(x); max_x = _fd_var_max(x); if (max_y > 0) changed_z = _fd_var_del_lt(min_x / max_y, z); if (min_y > 0) changed_z |= _fd_var_del_gt(max_x / min_y, z); if (changed_z && fd_domain_empty(z)) return FD_NOSOLUTION; } else // culprit == z { min_y = _fd_var_min(y); max_y = _fd_var_max(y); min_z = _fd_var_min(z); max_z = _fd_var_max(z); changed_x = _fd_var_del_lt(min_y * min_z, x); changed_x |= _fd_var_del_gt(max_y * max_z, x); if (changed_x && fd_domain_empty(x)) return FD_NOSOLUTION; min_x = _fd_var_min(x); max_x = _fd_var_max(x); if (max_z > 0) changed_y = _fd_var_del_lt(min_x / max_z, y); if (min_z > 0) changed_y |= _fd_var_del_gt(max_x / min_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; } fd_constraint fd_var_eq_times(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_TIMES; #else /* CONSTRAINT_CLASS */ c->propagator2 = fd_var_eq_times_propagate2; #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; }