all_different.c 9.69 KB
/*
 * all_different.c
 *
 *  Created on: 27/08/2014
 *      Author: pedro
 */

#ifndef __OPENCL_VERSION__

#include <stddef.h>
#include <stdio.h>

#include "all_different.h"

#include "../bitmaps.h"
#include "../config.h"
#include "../variables.h"

#endif

#include "../kernels/cl_aux_functions.h"
#if CL_D_TYPE == CL_BITMAP
#include "../kernels/cl_bitmaps.h"
#elif CL_D_TYPE == CL_INTERVAL
#include  "../kernels/cl_intervals.h"
#endif
#include "../kernels/cl_constraints.h"
#include "../kernels/cl_variables.h"
#include "../kernels/cl_ttl.h"

#ifndef __OPENCL_VERSION__

/*
 * Creates a new constraint of the all_different type and return the constraint ID
 * ∀ 0 ≤ i, j < n; i != j → X[i] != X[j]
 * X_ids - array with the IDs of the variables that are constrained by this constraint
 * n_vs - number of ID variables in vs_id
 */
unsigned int c_all_different(unsigned int* X_ids, unsigned int n_vs) {

	// set to include in kernel compilation
	USE_CS[ALL_DIFFERENT] = 1;
	USE_NON_CS_REIFI[ALL_DIFFERENT] = 1;

	// creates a new generic constraint
	unsigned int c_id = c_new(X_ids, n_vs, NULL, 0, -1);

	// pointers to this type of constraint functions
	CS[c_id].kind = ALL_DIFFERENT;
	CS[c_id].check_sol_f = &all_different_check;
	CS[c_id].constant_val = 0;

	return c_id;
}

/*
 * Creates a new reified constraint of the all_different type and return the constraint ID
 * ∀ 0 ≤ i, j < n; i != j → X[i] != X[j]
 * X_id - array with the IDs of the variables that are constrained by this constraint
 * n_vs - number of ID variables in vs_id
 * reif_v_id - ID of the reification variable
 */
unsigned int c_all_different_reif(unsigned int* X_ids, unsigned int n_vs, int reif_v_id) {

	if (VS[reif_v_id].max > 1) {
		v_del_gt(&VS[reif_v_id], 1);

		if (VS[reif_v_id].n_vals == 0) {
			fprintf(stderr, "\nError: Constraint ALL_DIFFERENT_REIF makes model inconsistent at creation:\n");
			exit(-1);
		}
	}

	// set to include in kernel compilation
	USE_CS[ALL_DIFFERENT] = 1;
	USE_CS_REIFI[ALL_DIFFERENT] = 1;

	// creates a new generic constraint
	unsigned int c_id = c_new(X_ids, n_vs, NULL, 0, reif_v_id);

	// pointers to this type of constraint functions
	CS[c_id].kind = ALL_DIFFERENT;
	CS[c_id].check_sol_f = &all_different_check;
	CS[c_id].constant_val = 0;

	return c_id;
}

/*
 * Return true if the all_different constraint is respected or false if not
 * ∀ 0 ≤ i, j < n; i != j → X[i] != X[j]
 * c - constraint to check if is respected
 * explored - if the CSP was already explored, which mean that all the variables must already be singletons
 * */
bool all_different_check(constr* c, bool explored) {
	unsigned int i, j;
	// check if any variable inside the all_diff constraint has the same value, has domain 0 or more than
	// one value in the domain. If so, return false. Else return true.
	for (i = 0; i < c->n_c_vs; i++) {
		for (j = i + 1; j < c->n_c_vs; j++) {
			if (
#if CHECK_SOL_N_VALS
				(c->c_vs[i]->to_label && c->c_vs[i]->n_vals != 1) || (c->c_vs[j]->to_label && c->c_vs[j]->n_vals != 1) ||
#endif
				c->c_vs[i]->min == c->c_vs[j]->min) {

				if (explored) {
					fprintf(stderr, "\nError: Constraint ALL_DIFFERENT (%d) not respected:\n", c->c_id);

					fprintf(stderr, "Variable ID=%u -> minimum=%u, maximum=%u, number of values=%u\n\n", c->c_vs[i]->v_id, b_get_min_val(&c->c_vs[i]->domain_b),
							b_get_max_val(&c->c_vs[i]->domain_b), b_cnt_vals(&c->c_vs[i]->domain_b));
					fprintf(stderr, "Variable ID=%u -> minimum=%u, maximum=%u, number of values=%u\n\n", c->c_vs[j]->v_id, b_get_min_val(&c->c_vs[j]->domain_b),
							b_get_max_val(&c->c_vs[j]->domain_b), b_cnt_vals(&c->c_vs[j]->domain_b));
				}
				return false;
			}
		}
	}
	return true;
}

#endif

#if CS_ALL_DIFFERENT == 1
/*
 * Propagate the domain of the variable with the ID prop_v_id through all the other variables on the same c_numb ID all_diff constraint
 * ∀ 0 ≤ i, j < n; i != j → X[i] != X[j]
  * prop_ok will be set to 1 if success or to 0 if any domain became empty
 * vs_per_c_idx - vector with all constrained variables ID per constraint, per constraint ID order
 * vs_prop_ - all CSP variables
 * prop_v_id - variable ID to propagate
 * current_cs - constraint that should be propagated for the variable with prop_v_id ID
 * vs_id_to_prop_ - circular vector with the ids of the variables to propagate
 */
CUDA_FUNC void all_different_prop(CL_INTS_MEM int* vs_per_c_idx, CL_MEMORY VARS_PROP* vs_prop_, unsigned int prop_v_id, CL_CS_MEM cl_constr* current_cs, CL_MEMORY unsigned short* vs_id_to_prop_,
		bool* prop_ok TTL_CTR) {

	if (V_N_VALS(vs_prop_[prop_v_id]) == 1) {
		int x_id;	// index of the variable which domain may be pruned with this propagation
		bool changed = 0;
		int i;

		// search for variables in constraint c_numb to reduce domain

		for (i = 0; i < current_cs->n_c_vs; i++) {
			CHECK_TTL(ttl_ctr, 22)

			x_id = vs_per_c_idx[i];

			// If variables are not the same
			if (x_id != convert_int(prop_v_id)) {

				// remove singleton domain value from the other domain
				cl_v_del_val_m(&changed, &vs_prop_[x_id], V_MIN(vs_prop_[prop_v_id]) TTL_CTR_V);
				if (changed) {

					// if the removal of the value resulted in an empty domain return 0
					if (V_IS_EMPTY(vs_prop_[x_id])) {
						*prop_ok = 0;
						i = current_cs->n_c_vs;
					} else {
						// Add variable to the vector that contains the variables that must be propagated
						v_add_to_prop(vs_id_to_prop_, vs_prop_, x_id);
					}
				}
			}
		}
	}
}

#if CS_R_ALL_DIFFERENT == 1
/*
 * Validate all_different constraint to be normally propagated, when reified
 * ∀ 0 ≤ i, j < n; i != j → X[i] != X[j]
 * vs_per_c_idx - vector with all constrained variables ID per constraint, per constraint ID order
 * vs_prop_ - all CSP variables with current step values
 * current_cs - constraint that should be propagated for the variable with prop_v_id ID
 * vs_id_to_prop_ - circular vector with the ids of the variables to propagate
 */
CUDA_FUNC void all_different_reif( CL_INTS_MEM int* vs_per_c_idx, CL_MEMORY VARS_PROP* vs_prop_, unsigned int prop_v_id, CL_CS_MEM cl_constr* current_cs, CL_MEMORY unsigned short* vs_id_to_prop_
		TTL_CTR) {

	if (V_N_VALS(vs_prop_[prop_v_id]) == 1) {
		VARS_PROP x;
		int x_id;	// index of the variable which domain may be pruned with this propagation
		bool changed = 0;
		bool all_singl = true;
		int i;

		// search for variables in constraint c_numb to reduce domain
		for (i = 0; i < current_cs->n_c_vs; i++) {
			CHECK_TTL(ttl_ctr, 36)

			x_id = vs_per_c_idx[i];

			// If variables are not the same
			if (x_id != convert_int(prop_v_id)) {

				if (V_N_VALS(vs_prop_[x_id]) != 1) {
					all_singl = false;
				}

				cl_v_copy_pm(&x, &vs_prop_[x_id] TTL_CTR_V);

				// remove singleton domain value from the other domain
				cl_v_del_val_n(&changed, &x, V_MIN(vs_prop_[prop_v_id]) TTL_CTR_V);
				// if the removal of the value resulted in an empty domain return 0
				if (V_IS_EMPTY(x)) {
					cl_v_bool_del_val_m(&vs_prop_[current_cs->reif_var_id], 1 TTL_CTR_V);
					v_add_to_prop(vs_id_to_prop_, vs_prop_, convert_int(current_cs->reif_var_id));
					return;
				}
			}
		}

		// constraint already fixed
		if (all_singl) {
			cl_v_bool_del_val_m(&vs_prop_[current_cs->reif_var_id], 0 TTL_CTR_V);
			v_add_to_prop(vs_id_to_prop_, vs_prop_, convert_int(current_cs->reif_var_id));
			return;
		}
	}
}

/*
 * Propagate the domain of the variable with the ID prop_v_id through all the other variables on the same c_numb ID all_diff opposit constraint
 * ∃ 0 ≤ i, j < n; i != j → X[i] == X[j]
 * vs_per_c_idx - vector with all constrained variables ID per constraint, per constraint ID order
 * vs_prop_ - all CSP variables
 * prop_v_id - variable ID to propagate
 * current_cs - constraint that should be propagated for the variable with prop_v_id ID
 * vs_id_to_prop_ - circular vector with the ids of the variables to propagate
 */
CUDA_FUNC void all_different_prop_opposite(CL_INTS_MEM int* vs_per_c_idx, CL_MEMORY VARS_PROP* vs_prop_, unsigned int prop_v_id, CL_CS_MEM cl_constr* current_cs,
		bool* prop_ok TTL_CTR) {

	if (V_N_VALS(vs_prop_[prop_v_id]) == 1) {
		int x_id;	// index of the variable which domain may be pruned with this propagation
		bool contains;
		int i;

		// search for variables in constraint c_numb to reduce domain

		for (i = 0; i < current_cs->n_c_vs; i++) {
			CHECK_TTL(ttl_ctr, 22)

			x_id = vs_per_c_idx[i];
			cl_v_contains_val_m(&contains, &vs_prop_[x_id], V_MIN(vs_prop_[prop_v_id]) TTL_CTR_V);

			// If a variable contains the prop_v_id value
			if (x_id != convert_int(prop_v_id) && contains) {
				return;
			}
		}
		*prop_ok = 0;
	}
}
#endif

CUDA_FUNC void all_different_propagate(CL_INTS_MEM int* vs_per_c_idx, CL_MEMORY VARS_PROP* vs_prop_, unsigned int prop_v_id, CL_CS_MEM cl_constr* current_cs, CL_MEMORY unsigned short* vs_id_to_prop_,
		bool* prop_ok PROPAGATED_FUNC TTL_CTR) {

#if CS_R_ALL_DIFFERENT == 0
	all_different_prop(vs_per_c_idx, vs_prop_, prop_v_id, current_cs, vs_id_to_prop_, prop_ok TTL_CTR_V);
#if CL_STATS == 1
	*propagated = true;
#endif
#elif CS_R_ALL_DIFFERENT == 1
	if (current_cs->reified == 1) {
		if (prop_v_id != current_cs->reif_var_id) {
			if (V_N_VALS(vs_prop_[current_cs->reif_var_id]) > 1) {
				all_different_reif(vs_per_c_idx, vs_prop_, prop_v_id, current_cs, vs_id_to_prop_ TTL_CTR_V);
			}
			if (V_N_VALS(vs_prop_[current_cs->reif_var_id]) == 1) {
				if (V_MIN(vs_prop_[current_cs->reif_var_id]) == 1) {
					all_different_prop(vs_per_c_idx, vs_prop_, prop_v_id, current_cs, vs_id_to_prop_, prop_ok TTL_CTR_V);
				} else {
					all_different_prop_opposite(vs_per_c_idx, vs_prop_, prop_v_id, current_cs, prop_ok TTL_CTR_V);
				}
#if CL_STATS == 1
				*propagated = true;
#endif
			}
		}
	} else {
		all_different_prop(vs_per_c_idx, vs_prop_, prop_v_id, current_cs, vs_id_to_prop_, prop_ok TTL_CTR_V);
#if CL_STATS == 1
		*propagated = true;
#endif
	}
#endif
}
#endif