golfers.c 3.29 KB
/* Social golfers */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "fdc_int.h"

#define MAX_P MAX_VARIABLES
#define MAX_G MAX_VARIABLES

int main(int argc, char *argv[])
{
  int P = 12;	  // no. of players
  int G = 4;	  // no. of groups per week
  int K = 3;	  // players per group
  int W = 2;	  // no. of weeks
  int GW;	  // total groups

  fd_int *vs;
#define vs(r, c) vs[(r) * GW + (c)]
  fd_int *ts, *us;
  int p, g, p0, p1, g0, g1, w;
  int solutions = 0, one_solution = 1;
  int use_label = 0;
  int i;

  fd_init(&argc, &argv);

  for (i = 1; i < argc; ++i)
    if (!strcmp(argv[i], "--all"))
      one_solution = 0;
    else if (!strcmp(argv[i], "--label"))
      use_label = 1;
    else if (argc - i < 3)
      {	       
	fd__error("must give G, K, and W (or nothing)\n");
	return 1;
      }
    else
      {
	G = atoi(argv[i++]);
	K = atoi(argv[i++]);
	W = atoi(argv[i]);
      }

  P = G * K;
  GW = G * W;

  vs = calloc(P * GW, sizeof(fd_int));
  ts = calloc(P > GW ? P : GW, sizeof(fd_int));
  us = calloc(P > GW ? P : GW, sizeof(fd_int));

  for (p = 0; p < P; ++p)
    for (g = 0; g < GW; ++g)
      vs(p, g) = fd_new(0, 1);

  if (use_label)
    fd_label(vs, P * GW);

  // a player appears in W groups
  for (p = 0; p < P; ++p)
    fd_sum(vs + GW * p, GW, W);

  // K players per group
  for (g = 0; g < GW; ++g)
    {
      for (p = 0; p < P; ++p)
	ts[p] = vs(p, g);

      fd_sum(ts, P, K);
    }

  // no player should be in another group with another player more
  // than once: the scalar (or dot) product between any two rows must
  // not exceed 1
  for (p0 = 0; p0 < P; ++p0)
    for (p1 = p0 + 1; p1 < P; ++p1)
      {
	for (g = 0; g < GW; ++g)
	  {
	    ts[g] = vs(p0, g);
	    us[g] = vs(p1, g);
	  }

	fd_knapsack2(ts, us, GW, fd_new(0,1));
      }

  // every G groups correspond to one week and no player can be in
  // more than one: the scalar product between any two columns within
  // every G groups must be 0
  for (w = 0; w < W; ++w)
    for (g0 = 0; g0 < G; ++g0)
      for (g1 = g0 + 1; g1 < G; ++g1)
	{
	  for (p = 0; p < P; ++p)
	    {
	      ts[p] = vs(p, w * G + g0);
	      us[p] = vs(p, w * G + g1);
	    }

	  fd_sum_prod(ts, us, P, 0);
	}

  // try to eliminate solutions which result from exchanging rows
  // and/or columns
  // XXX: quite incomplete

#if 0
  // constrain the first row to be of the form 1 0...0 1 0...0 ... 1 0...0
  {
    fd_int zero = fd_new(0, 0);

    for (g = 0; g < W; ++g)
      fd_gt(vs(0, g * G), zero);
  }
#endif

  // constrain the first column to be of the form 1 ... 1 0 ... 0
  for (p = 1; p < P; ++p)
    fd_ge(vs(p - 1, 0), vs(p, 0));

  while (fd_solve() == FD_OK)
    {
      printf("solution %d:\n", ++solutions);

      for (p = 0; p < P; ++p)
	{
	  for (g = 0; g < GW; ++g)
	    {
	      fd_print(vs(p, g));
	      putchar(' ');
	    }
	  putchar('\n');
	}

      for (w = 0; w < W; ++w)
	{
	  for (g = 0; g < G; ++g)
	    {
	      printf(" (");
	      for (p = 0, p0 = 0; p0 < K; ++p)
		if (fd_var_value(vs(p, w * G + g)) == 1)
		  printf("%d%c", p, ++p0 == K ? ')' : ' ');
	    }
	  putchar('\n');
	}

#if !(defined(LOCAL_SEARCH) || defined(DISTRIBUTED_SOLVER))
      if (one_solution)
#endif
	break;
    }

  if (solutions)
    printf("%d solutions found\n", solutions);
  else
    printf("inconsistent CSP\n");

  fd_end();

  return !solutions;
}