all-different.c 3.54 KB
/* all-different */

#ifdef USE_MATCHING

#include "matching.h"

static int fd_all_different_filter(fd_constraint this)
{
#ifdef CONSTRAINT_TEMPS
  int **memory;
  int ok;

  assert(!fd__constraint_data_valid(this));

  // memory is allocated in _fd_find_matching()
  memory = (int **) &constraint_memory[this->index];

  ok = _fd_find_matching(this, memory);

  if (ok)
    fd__constraint_remember(this);

  return ok ? FD_OK : FD_NOSOLUTION;
#else
  return _fd_find_matching(this) ? FD_OK : FD_NOSOLUTION;
#endif /* CONSTRAINT_TEMPS */
}

static int fd_all_different_propagate2(fd_constraint this, fd_int culprit)
{
#ifdef CONSTRAINT_TEMPS
  int *memory;

  if (!fd__constraint_data_valid(this))
    return fd_all_different_filter(this);

  // memory is allocated in _fd_find_matching()
  memory = constraint_memory[this->index];

  return _fd_update_matching(this, culprit, memory) ? FD_OK : FD_NOSOLUTION;
#else
  return fd_all_different_filter(this);
#endif /* CONSTRAINT_TEMPS */
}

#else /* USE_MATCHING */

static int fd_all_different_filter(fd_constraint this)
{
  int value;
  int i, j;

  // only filter wrt variables whose domain is a singleton
  for (i = 0; i < this->nvariables; ++i)
    if (fd_var_single(VAR(this, i), &value))
      for (j = 0; j < this->nvariables; ++j)
	if (j != i)
	  {
	    fd_int revise = VAR(this, j);

	    if (_fd_var_del_val(value, revise))
	      {
		if (fd_domain_empty(revise))
		  return FD_NOSOLUTION;

		if (i < j)
		  _fd_revise_connected(this, revise);
		else
		  _fd_revise_connected(NULL, revise);
	      }
	  }

  return FD_OK;
}

static int fd_all_different_propagate2(fd_constraint this, fd_int culprit)
{
  int value;
  int i;

  // only revise if culprit's domain is a singleton
  if (!fd_var_single(culprit, &value))
    return FD_OK;

  for (i = 0; i < this->nvariables; ++i)
    if (VAR(this, i) != culprit)
      {
	fd_int revise = VAR(this, i);

	if (_fd_var_del_val(value, revise))
	  {
	    if (fd_domain_empty(revise))
	      return FD_NOSOLUTION;

	    _fd_revise_connected(NULL, revise);
	  }
      }

  return FD_OK;
}

#endif /* USE_MATCHING */

static int fd_all_different_propagate(fd_constraint this, fd_int revise)
{
  int value;
  int changed = 0;
#ifdef USE_ENTAILED
  int set = 0;
#endif
  int i;

  // only revise wrt variables whose domain is a singleton
  for (i = 0; i < this->nvariables; ++i)
    if (VAR(this, i) != revise &&
	fd_var_single(VAR(this, i), &value))
      {
	changed |= _fd_var_del_val(value, revise);
#if defined(USE_ENTAILED) && 0
	set++;
#endif
      }

  if (changed && fd_domain_empty(revise))
    return FD_NOSOLUTION;


#if defined(USE_ENTAILED) && 0
  // XXX: hampers performance when not optimised
  if (set == this->nvariables - 1)
    _fd_constraint_set_entailed(this);
#endif

  if (changed)
    if (fd_var_single(revise, NULL))
      _fd_revise_connected(NULL, revise); // XXX?
    else
      _fd_revise_connected(this, revise);

  return FD_OK;
}

fd_constraint fd_all_different(fd_int *variables, int nvariables)
{
  fd_constraint c;
  int i;

  if (nvariables == 2)
    return fd_ne(variables[0], variables[1]);

  c = _fd_constraint_new(nvariables, 0);

  if (c)
    {
      for (i = 0; i < nvariables; ++i)
	c->variables[i] = FD_INT2C_VAR(variables[i]);
#ifdef CONSTRAINT_CLASS
      c->kind = FD_CONSTR_ALL_DIFFERENT;
#else /* CONSTRAINT_CLASS */
      c->propagator2 = fd_all_different_propagate2;
      c->propagator = fd_all_different_propagate;
#endif /* CONSTRAINT_CLASS */

      for (i = 0; i < nvariables; ++i)
	_fd_var_add_constraint(VAR(c, i), c);

      _fd_add_constraint(c);
    }

  return c;
}