Пример #1
0
 /// The actual problem
 Queens(const SizeOptions& opt)
   : q(*this,opt.size(),0,opt.size()-1) {
   const int n = q.size();
   switch (opt.propagation()) {
   case PROP_BINARY:
     for (int i = 0; i<n; i++)
       for (int j = i+1; j<n; j++) {
         rel(*this, q[i] != q[j]);
         rel(*this, q[i]+i != q[j]+j);
         rel(*this, q[i]-i != q[j]-j);
       }
     break;
   case PROP_MIXED:
     for (int i = 0; i<n; i++)
       for (int j = i+1; j<n; j++) {
         rel(*this, q[i]+i != q[j]+j);
         rel(*this, q[i]-i != q[j]-j);
       }
     distinct(*this, q, opt.icl());
     break;
   case PROP_DISTINCT:
     distinct(*this, IntArgs::create(n,0,1), q, opt.icl());
     distinct(*this, IntArgs::create(n,0,-1), q, opt.icl());
     distinct(*this, q, opt.icl());
     break;
   }
   switch(opt.branching()) {
   case BRANCH_MIN:
       branch(*this, q, INT_VAR_SIZE_MIN(), INT_VAL_MIN());
       break;
   case BRANCH_MID:
     branch(*this, q, INT_VAR_SIZE_MIN(), INT_VAL_MIN());
     break;
   case BRANCH_MAX_MAX:
     branch(*this, q, INT_VAR_SIZE_MAX(), INT_VAL_MIN());
     break;
   case BRANCH_KNIGHT_MOVE:
     branch(*this, q, INT_VAR_MIN_MIN(), INT_VAL_MED());
     break;
   }
 }
Пример #2
0
	SUSHI_EQUATION(const SizeOptions& opt)
	: n_x(*this, 1, wordlength),
    n_y(*this, 1, wordlength),
    n_z(*this, 1, wordlength),
    n_t(*this, opt.size()+1, opt.size()+1),
	  X(*this, wordlength , val_dom_min, val_dom_max),
    Y(*this, wordlength , val_dom_min, val_dom_max),
    Z(*this, wordlength , val_dom_min, val_dom_max),
    T(*this, opt.size()+1 , val_dom_min, val_dom_max){

      int n = opt.size();
		gecode_find_solution = false;

		REG r_a(1);
    REG r_b(2);
		REG dum(dummy_sym);
		REG reg_z = r_b(n,n) + r_a + r_b(n,n);
    if (opt.propagation() == PROP_PAD) {
      reg_z += (*dum);
    }
    

	  DFA myDFA_z(reg_z);

    // T = "a" . Y[0,n]
    rel(*this, T[0]==1);
    for (int i = 0; (i < n) && (i+1 < T.size()); i++){
      T[i+1] = Y[i];
    }
    rel(*this, n_y >= n);
    
    switch(opt.propagation()){
      case PROP_OPEN:
        extensional(*this, Z, myDFA_z, n_z);
  	    //concat(*this, X, n_x, T, n_t, Z, n_z, ICL_BND);
        rel(*this, n_z == (n_x+n_t));
        
        for(int i=0; i<wordlength; i++)
        {
          rel(*this, (i<n_x) >> (X[i]==Z[i]));
        
          BoolVar b = expr(*this, i==n_x);
        
          for(int j=0; (i+j)<wordlength; j++)
          {
            rel(*this, (b&&(j<n_t)) >> (T[j]==Z[i+j]));
          }
        }
        break;
      case PROP_CLOSED:
        extensional(*this, Z, myDFA_z);
        rel(*this, n_z == (n_x+n_t));
        rel(*this, n_y == wordlength);
  	    for(int i=0; i<wordlength; i++)
  	    {
  	    	rel(*this, (i<n_x) >> (X[i]==Z[i]));

  	    	BoolVar b = expr(*this, i==n_x);

  	    	for(int j=0; (j < T.size()) && ((i+j)<wordlength); j++)
  	    	{
  	    		rel(*this, (b&&(j<n_t)) >> (T[j]==Z[i+j]));
  	    	}
  	    }
        break;
      case PROP_PAD:
        extensional(*this, Z, myDFA_z);
  	    for(int i=0; i<wordlength; i++)
  	    {
  	    	rel(*this, (Z[i]==dummy_sym) == (n_z<=i));
  	    	rel(*this, (Y[i]==dummy_sym) == (n_y<=i));
  	    	rel(*this, (X[i]==dummy_sym) == (n_x<=i));
  	    }

  	    rel(*this, n_z == (n_x+n_t));

  	    for(int i=0; i<wordlength; i++)
  	    {
  	    	rel(*this, (i<n_x) >> (X[i]==Z[i]));

  	    	BoolVar b = expr(*this, i==n_x);

  	    	for(int j=0; (j < T.size()) && ((i+j)<wordlength); j++)
  	    	{
  	    		rel(*this, (b&&(j<n_t)) >> (T[j]==Z[i+j]));
  	    	}
  	    }
        break;
    }
	  
    IntVarArgs lengths;
		lengths << n_z << n_x << n_y;
		
    switch(opt.branching()){
    case BRANCH_N_A:
      branch(*this, lengths, INT_VAR_SIZE_MIN(), INT_VAL_MIN());
      branch(*this, Z, INT_VAR_SIZE_MIN(), INT_VAL_MIN());
		  branch(*this, X, INT_VAR_SIZE_MIN(), INT_VAL_MIN());
      branch(*this, Y, INT_VAR_SIZE_MIN(), INT_VAL_MIN());
      break;
    case BRANCH_A_N:
      branch(*this, Z, INT_VAR_SIZE_MIN(), INT_VAL_MIN());
	    branch(*this, X, INT_VAR_SIZE_MIN(), INT_VAL_MIN());
      branch(*this, Y, INT_VAR_SIZE_MIN(), INT_VAL_MIN());
      branch(*this, lengths, INT_VAR_SIZE_MIN(), INT_VAL_MIN());
      break;
    case BRANCH_BOUND:
      boundednone(*this, Z, n_z);
      boundednone(*this, X, n_x);
      boundednone(*this, Y, n_y);
      break;
    }
	}
Пример #3
0
  /// Actual model
  PerfectSquare(const SizeOptions& opt)
    : x(*this,specs[opt.size()][0],0,specs[opt.size()][1]-1),
      y(*this,specs[opt.size()][0],0,specs[opt.size()][1]-1) {

    const int* s = specs[opt.size()];
    int n = *s++;
    int w = *s++;

    // Restrict position according to square size
    for (int i=n; i--; ) {
      rel(*this, x[i], IRT_LQ, w-s[i]);
      rel(*this, y[i], IRT_LQ, w-s[i]);
    }

    IntArgs sa(n,s);

    // Squares do not overlap
    nooverlap(*this, x, sa, y, sa);

    /*
     * Capacity constraints
     *
     */
    switch (opt.propagation()) {
    case PROP_REIFIED:
      {
        for (int cx=0; cx<w; cx++) {
          BoolVarArgs bx(*this,n,0,1);
          for (int i=0; i<n; i++)
            dom(*this, x[i], cx-s[i]+1, cx, bx[i]);
          linear(*this, sa, bx, IRT_EQ, w);
        }
        for (int cy=0; cy<w; cy++) {
          BoolVarArgs by(*this,n,0,1);
          for (int i=0; i<n; i++)
            dom(*this, y[i], cy-s[i]+1, cy, by[i]);
          linear(*this, sa, by, IRT_EQ, w);
        }
      }
      break;
    case PROP_CUMULATIVES:
      {
        IntArgs m(n), dh(n);
        for (int i = n; i--; ) {
          m[i]=0; dh[i]=s[i];
        }
        IntArgs limit(1, w);
        {
          // x-direction
          IntVarArgs e(n);
          for (int i=n; i--;)
            e[i]=expr(*this, x[i]+dh[i]);
          cumulatives(*this, m, x, dh, e, dh, limit, true);
          cumulatives(*this, m, x, dh, e, dh, limit, false);
        }
        {
          // y-direction
          IntVarArgs e(n);
          for (int i=n; i--;)
            e[i]=expr(*this, y[i]+dh[i]);
          cumulatives(*this, m, y, dh, e, dh, limit, true);
          cumulatives(*this, m, y, dh, e, dh, limit, false);
        }
      }
      break;
    default:
      GECODE_NEVER;
    }

    branch(*this, x, INT_VAR_MIN_MIN(), INT_VAL_MIN());
    branch(*this, y, INT_VAR_MIN_MIN(), INT_VAL_MIN());
  }
Пример #4
0
	KaluzaExample(const SizeOptions& opt)
		: var_0xINPUT_9_n(*this,1,wordlength),
			T0_2_n(*this,1,wordlength),
			T1_2_n(*this,1,wordlength),
			PCTEMP_LHS_1_idx_0_n(*this,1,wordlength),
			T2_2_n(*this,1,wordlength),
			PCTEMP_LHS_1_group_1_n(*this,1,wordlength),
			PCTEMP_LHS_1_len_0(*this,1,wordlength),
			var_0xINPUT_9(*this,wordlength,val_dom_min,val_dom_max),
			T0_2(*this,wordlength,val_dom_min,val_dom_max),
			T1_2(*this,wordlength,val_dom_min,val_dom_max),
			PCTEMP_LHS_1_idx_0(*this,wordlength,val_dom_min,val_dom_max),
			T2_2(*this,wordlength,val_dom_min,val_dom_max),
			PCTEMP_LHS_1_group_1(*this,wordlength,val_dom_min,val_dom_max){
				
		// PCTEMP_LHS_1_len_0 == Len(PCTEMP_LHS_1_idx_0);
		rel(*this, PCTEMP_LHS_1_len_0==PCTEMP_LHS_1_idx_0_n);
		// PCTEMP_LHS_1_len_0 < 15;
		rel(*this, PCTEMP_LHS_1_len_0 < 15);
		
		switch(opt.propagation()){
			case PROP_PAD:
			{
				PAD_INVARIANT(*this,var_0xINPUT_9, var_0xINPUT_9_n);
				PAD_INVARIANT(*this,T0_2, T0_2_n);
				PAD_INVARIANT(*this,T1_2, T1_2_n);
				PAD_INVARIANT(*this,PCTEMP_LHS_1_idx_0, PCTEMP_LHS_1_idx_0_n);
				PAD_INVARIANT(*this,T2_2, T2_2_n);
				PAD_INVARIANT(*this,PCTEMP_LHS_1_group_1, PCTEMP_LHS_1_group_1_n);
			
				//var_0xINPUT_9 := T0_2 . T1_2;
				rel(*this, var_0xINPUT_9_n == (T0_2_n+T1_2_n)); // Zn=Xn+Yn
				for(int i=0; i<wordlength; i++) 
				{
					rel(*this, (i<T0_2_n) >> (T0_2[i]==var_0xINPUT_9[i]));	// i<Xn --> X[i]=Z[i]
					BoolVar b = expr(*this, i==T0_2_n);						// b    <-> i=Xn
					for(int j=0; (i+j)<wordlength; j++)	//(i+j)<|Z|&j<|Y|
						rel(*this, (b&&(j<T1_2_n)) >> (T1_2[j]==var_0xINPUT_9[i+j]));	// b&(j<Yn) --> Y[i]=Z[i]
				}
				//T1_2 := PCTEMP_LHS_1_idx_0 . T2_2;
				rel(*this, T1_2_n == (PCTEMP_LHS_1_idx_0_n+T2_2_n)); // Zn=Xn+Yn
				for(int i=0; i<wordlength; i++) 
				{
					rel(*this, (i<PCTEMP_LHS_1_idx_0_n) >> (PCTEMP_LHS_1_idx_0[i]==T1_2[i]));	// i<Xn --> X[i]=Z[i]
					BoolVar b = expr(*this, i==PCTEMP_LHS_1_idx_0_n);						// b    <-> i=Xn
					for(int j=0; (i+j)<wordlength; j++)	//(i+j)<|Z|&j<|Y|
						rel(*this, (b&&(j<T2_2_n)) >> (T2_2[j]==T1_2[i+j]));	// b&(j<Yn) --> Y[i]=Z[i]
				}
				//PCTEMP_LHS_1_group_1 == PCTEMP_LHS_1_idx_0;
				PAD_EQUAL(*this, PCTEMP_LHS_1_group_1, PCTEMP_LHS_1_group_1_n, PCTEMP_LHS_1_idx_0, PCTEMP_LHS_1_idx_0_n);
			
				// PCTEMP_LHS_1_idx_0 \in CapturedBrack(/john/,0);
				Gecode::DFA::Transition tp[] = {{0,75,1},{1,80,2},{2,73,3},{3,79,4},{4,dummy_sym,4},{-1,0,0}};
				int fp1[] = {4,-1};
				john = DFA(0,tp,fp1);
				extensional(*this, PCTEMP_LHS_1_idx_0, john);
			
				// T0_2 \notin CapturedBrack(/john/, 0);
				int fp2[] = {0,1,2,3,5,-1};
				notjohn = DFA(0,bigp,fp2);
				extensional(*this, T0_2, notjohn);
				break;
			}
			case PROP_OPEN:
			{
				open_invariant(*this,var_0xINPUT_9, var_0xINPUT_9_n);
				open_invariant(*this,T0_2, T0_2_n);
				open_invariant(*this,T1_2, T1_2_n);
				open_invariant(*this,PCTEMP_LHS_1_idx_0, PCTEMP_LHS_1_idx_0_n);
				open_invariant(*this,T2_2, T2_2_n);
				open_invariant(*this,PCTEMP_LHS_1_group_1, PCTEMP_LHS_1_group_1_n);


				//var_0xINPUT_9 := T0_2 . T1_2;
				open_concat(*this, T0_2, T0_2_n, T1_2, T1_2_n, var_0xINPUT_9, var_0xINPUT_9_n);
				//T1_2 := PCTEMP_LHS_1_idx_0 . T2_2;
				open_concat(*this, PCTEMP_LHS_1_idx_0, PCTEMP_LHS_1_idx_0_n, T2_2, T2_2_n, T1_2, T1_2_n);
				//PCTEMP_LHS_1_group_1 == PCTEMP_LHS_1_idx_0;
				open_equal(*this, PCTEMP_LHS_1_group_1, PCTEMP_LHS_1_group_1_n, PCTEMP_LHS_1_idx_0, PCTEMP_LHS_1_idx_0_n);
				// PCTEMP_LHS_1_idx_0 \in CapturedBrack(/john/,0);
				Gecode::DFA::Transition tp[] = {{0,75,1},{1,80,2},{2,73,3},{3,79,4},{4,dummy_sym,4},{-1,0,0}};
				int fp1[] = {4,-1};
				john = DFA(0,tp,fp1);
				extensional(*this, PCTEMP_LHS_1_idx_0, john);
			
				// T0_2 \notin CapturedBrack(/john/, 0);
				int fp2[] = {0,1,2,3,5,-1};
				notjohn = DFA(0,bigp,fp2);
				extensional(*this, T0_2, notjohn);
				// // PCTEMP_LHS_1_idx_0 \in CapturedBrack(/john/,0);
// 				Gecode::DFA::Transition t[] = {{0,75,1},{1,80,2},{2,73,3},{3,79,4},{-1,0,0}};
// 				int f1[] = {4,-1};
// 				john = DFA(0,t,f1);
// 				extensional(*this, PCTEMP_LHS_1_idx_0, john, PCTEMP_LHS_1_idx_0_n);
// 				// T0_2 \notin CapturedBrack(/john/, 0);
// 				int f2[] = {0,1,2,3,5,-1};
// 				notjohn = DFA(0,big,f2);
// 				extensional(*this, T0_2, notjohn, T0_2_n);
				break;
			}
		}
		branch(*this, var_0xINPUT_9, INT_VAR_SIZE_MIN(), INT_VAL_MIN());
		branch(*this, T0_2, INT_VAR_SIZE_MIN(), INT_VAL_MIN());
		branch(*this, T1_2, INT_VAR_SIZE_MIN(), INT_VAL_MIN());
		branch(*this, PCTEMP_LHS_1_idx_0, INT_VAR_SIZE_MIN(), INT_VAL_MIN());
		branch(*this, T2_2, INT_VAR_SIZE_MIN(), INT_VAL_MIN());
		branch(*this, PCTEMP_LHS_1_group_1, INT_VAR_SIZE_MIN(), INT_VAL_MIN());

	}
Пример #5
0
  /// Actual model
  Domino(const SizeOptions& opt)
    : spec(specs[opt.size()]),
      width(spec[0]), height(spec[1]),
      x(*this, (width+1)*height, 0, 28) {
    spec+=2; // skip board size information

    // Copy spec information to the board
    IntArgs board((width+1)*height);
    for (int i=0; i<width; i++)
      for (int j=0; j<height; j++)
        board[j*(width+1)+i] = spec[j*width+i];

    // Initialize the separator column in the board
    for (int i=0; i<height; i++) {
      board[i*(width+1)+8] = -1;
      rel(*this, x[i*(width+1)+8]==28);
    }

    // Variables representing the coordinates of the first
    // and second half of a domino piece
    IntVarArgs p1(*this, 28, 0, (width+1)*height-1);
    IntVarArgs p2(*this, 28, 0, (width+1)*height-1);


    if (opt.propagation() == PROP_ELEMENT) {
      int dominoCount = 0;

      int possibleDiffsA[] = {1, width+1};
      IntSet possibleDiffs(possibleDiffsA, 2);

      for (int i=0; i<=6; i++)
        for (int j=i; j<=6; j++) {

          // The two coordinates must be adjacent.
          // I.e., they may differ by 1 or by the width.
          // The separator column makes sure that a field
          // at the right border is not adjacent to the first field
          // in the next row.
          IntVar diff(*this, possibleDiffs);
          abs(*this, expr(*this, p1[dominoCount]-p2[dominoCount]),
              diff, ICL_DOM);

          // If the piece is symmetrical, order the locations
          if (i == j)
            rel(*this, p1[dominoCount], IRT_LE, p2[dominoCount]);

          // Link the current piece to the board
          element(*this, board, p1[dominoCount], i);
          element(*this, board, p2[dominoCount], j);

          // Link the current piece to the array where its
          // number is stored.
          element(*this, x, p1[dominoCount], dominoCount);
          element(*this, x, p2[dominoCount], dominoCount);
          dominoCount++;
        }
    } else {
      int dominoCount = 0;

      for (int i=0; i<=6; i++)
        for (int j=i; j<=6; j++) {
          // Find valid placements for piece i-j
          // Extensional is used as a table-constraint listing all valid
          // tuples.
          // Note that when i == j, only one of the orientations are used.
          REG valids;
          for (int pos = 0; pos < (width+1)*height; ++pos) {
            if ((pos+1) % (width+1) != 0) { // not end-col
              if (board[pos] == i && board[pos+1] == j)
                valids |= REG(pos) + REG(pos+1);
              if (board[pos] == j && board[pos+1] == i && i != j)
                valids |= REG(pos+1) + REG(pos);
            }
            if (pos/(width+1) < height-1) { // not end-row
              if (board[pos] == i && board[pos+width+1] == j)
                valids |= REG(pos) + REG(pos+width+1);
              if (board[pos] == j && board[pos+width+1] == i && i != j)
                valids |= REG(pos+width+1) + REG(pos);
            }
          }
          IntVarArgs piece(2);
          piece[0] = p1[dominoCount];
          piece[1] = p2[dominoCount];
          extensional(*this, piece, valids);


          // Link the current piece to the array where its
          // number is stored.
          element(*this, x, p1[dominoCount], dominoCount);
          element(*this, x, p2[dominoCount], dominoCount);
          dominoCount++;
        }
    }

    // Branch by piece
    IntVarArgs ps(28*2);
    for (int i=0; i<28; i++) {
      ps[2*i]   = p1[i];
      ps[2*i+1] = p2[i];
    }

    branch(*this, ps, INT_VAR_NONE, INT_VAL_MIN);
  }
Пример #6
0
  /// Construction of the model.
  Pentominoes(const SizeOptions& opt)
    : spec(examples[opt.size()]),
      width(spec[0].width+1), // Add one for extra row at end.
      height(spec[0].height),
      filled(spec[0].amount),
      nspecs(examples_size[opt.size()]-1),
      ntiles(compute_number_of_tiles(spec+1, nspecs)),
      board(*this, width*height, filled,ntiles+1) {
    spec += 1; // No need for the specification-part any longer

    // Set end-of-line markers
    for (int h = 0; h < height; ++h) {
      for (int w = 0; w < width-1; ++w)
	rel(*this, board[h*width + w], IRT_NQ, ntiles+1);
      rel(*this, board[h*width + width - 1], IRT_EQ, ntiles+1);
    }

    // Post constraints
    if (opt.propagation() == PROPAGATION_INT) {
      int tile = 0;
      for (int i = 0; i < nspecs; ++i) {
        for (int j = 0; j < spec[i].amount; ++j) {
          // Color
          int col = tile+1;
          // Expression for color col
          REG mark(col);
          // Build expression for complement to color col
          REG other;
          bool first = true;
          for (int j = filled; j <= ntiles; ++j) {
            if (j == col) continue;
            if (first) {
              other = REG(j);
              first = false;
            } else {
              other |= REG(j);
            }
          }
          // End of line marker
          REG eol(ntiles+1);
          extensional(*this, board, get_constraint(i, mark, other, eol));
          ++tile;
        }
      }
    } else { // opt.propagation() == PROPAGATION_BOOLEAN
      int ncolors = ntiles + 2;
      // Boolean variables for channeling
      BoolVarArgs p(*this,ncolors * board.size(),0,1);

      // Post channel constraints
      for (int i=board.size(); i--; ) {
        BoolVarArgs c(ncolors);
        for (int j=ncolors; j--; )
          c[j]=p[i*ncolors+j];
        channel(*this, c, board[i]);
      }

      // For placing tile i, we construct the expression over
      // 0/1-variables and apply it to the projection of
      // the board on the color for the tile.
      REG other(0), mark(1);
      int tile = 0;
      for (int i = 0; i < nspecs; ++i) {
        for (int j = 0; j < spec[i].amount; ++j) {
          int col = tile+1;
          // Projection for color col
          BoolVarArgs c(board.size());

          for (int k = board.size(); k--; ) {
            c[k] = p[k*ncolors+col];
          }

          extensional(*this, c, get_constraint(i, mark, other, other));
          ++tile;
        }
      }
    }

    if (opt.symmetry() == SYMMETRY_FULL) {
      // Remove symmetrical boards
      IntVarArgs orig(board.size()-height), symm(board.size()-height);
      int pos = 0;
      for (int i = 0; i < board.size(); ++i) {
        if ((i+1)%width==0) continue;
        orig[pos++] = board[i];
      }

      int w2, h2;
      bsymmfunc syms[] = {flipx, flipy, flipd1, flipd2, rot90, rot180, rot270};
      int symscnt = sizeof(syms)/sizeof(bsymmfunc);
      for (int i = 0; i < symscnt; ++i) {
        syms[i](orig, width-1, height, symm, w2, h2);
        if (width-1 == w2 && height == h2)
          rel(*this, orig, IRT_LQ, symm);
      }
    }

    // Install branching
    branch(*this, board, INT_VAR_NONE, INT_VAL_MIN);
  }
Пример #7
0
  /// The model of the problem
  CrowdedChess(const SizeOptions& opt)
    : n(opt.size()),
      s(*this, n*n, 0, PMAX-1),
      queens(*this, n, 0, n-1),
      rooks(*this, n, 0, n-1),
      knights(*this, n*n, 0, 1) {
    const int nkval = sizeof(kval)/sizeof(int);
    const int nn = n*n, q = n, r = n, b = (2*n)-2,
      k = n <= nkval ? kval[n-1] : kval[nkval-1];
    const int e = nn - (q + r + b + k);

    assert(nn == (e + q + r + b + k));

    Matrix<IntVarArray> m(s, n);

    // ***********************
    // Basic model
    // ***********************

    count(*this, s, E, IRT_EQ, e, opt.icl());
    count(*this, s, Q, IRT_EQ, q, opt.icl());
    count(*this, s, R, IRT_EQ, r, opt.icl());
    count(*this, s, B, IRT_EQ, b, opt.icl());
    count(*this, s, K, IRT_EQ, k, opt.icl());

    // Collect rows and columns for handling rooks and queens
    for (int i = 0; i < n; ++i) {
      IntVarArgs aa = m.row(i), bb = m.col(i);

      count(*this, aa, Q, IRT_EQ, 1, opt.icl());
      count(*this, bb, Q, IRT_EQ, 1, opt.icl());
      count(*this, aa, R, IRT_EQ, 1, opt.icl());
      count(*this, bb, R, IRT_EQ, 1, opt.icl());

      // Connect (queens|rooks)[i] to the row it is in
      element(*this, aa, queens[i], Q, ICL_DOM);
      element(*this, aa,  rooks[i], R, ICL_DOM);
    }

    // N-queens constraints
    distinct(*this, queens, ICL_DOM);
    distinct(*this, IntArgs::create(n,0,1), queens, ICL_DOM);
    distinct(*this, IntArgs::create(n,0,-1), queens, ICL_DOM);

    // N-rooks constraints
    distinct(*this,  rooks, ICL_DOM);

    // Collect diagonals for handling queens and bishops
    for (int l = n; l--; ) {
      const int il = (n-1) - l;
      IntVarArgs d1(l+1), d2(l+1), d3(l+1), d4(l+1);
      for (int i = 0; i <= l; ++i) {
        d1[i] = m(i+il, i);
        d2[i] = m(i, i+il);
        d3[i] = m((n-1)-i-il, i);
        d4[i] = m((n-1)-i, i+il);
      }

      count(*this, d1, Q, IRT_LQ, 1, opt.icl());
      count(*this, d2, Q, IRT_LQ, 1, opt.icl());
      count(*this, d3, Q, IRT_LQ, 1, opt.icl());
      count(*this, d4, Q, IRT_LQ, 1, opt.icl());
      if (opt.propagation() == PROP_DECOMPOSE) {
        count(*this, d1, B, IRT_LQ, 1, opt.icl());
        count(*this, d2, B, IRT_LQ, 1, opt.icl());
        count(*this, d3, B, IRT_LQ, 1, opt.icl());
        count(*this, d4, B, IRT_LQ, 1, opt.icl());
      }
    }
    if (opt.propagation() == PROP_TUPLE_SET) {
      IntVarArgs b(s.size());
      for (int i = s.size(); i--; )
        b[i] = channel(*this, expr(*this, (s[i] == B)));
      extensional(*this, b, bishops, EPK_DEF, opt.icl());
    }

    // Handle knigths
    // Connect knigths to board
    for(int i = n*n; i--; )
      knights[i] = expr(*this, (s[i] == K));
    knight_constraints();


    // ***********************
    // Redundant constraints
    // ***********************

    // Queens and rooks not in the same place
    // Faster than going through the channelled board-connection
    for (int i = n; i--; )
      rel(*this, queens[i], IRT_NQ, rooks[i]);

    // Place bishops in two corners (from Schimpf and Hansens solution)
    // Avoids some symmetries of the problem
    rel(*this, m(n-1,   0), IRT_EQ, B);
    rel(*this, m(n-1, n-1), IRT_EQ, B);


    // ***********************
    // Branching
    // ***********************
    // Place each piece in turn
    branch(*this, s, INT_VAR_MIN_MIN(), INT_VAL_MIN());
  }