/**
  *
  * Global constraint alldifferent_except_0 (decomposition) in Choco.
  *
  *
  * From Global Constraint Catalog
  * http://www.emn.fr/x-info/sdemasse/gccat/Calldifferent_except_0.html
  * """
  * Enforce all variables of the collection VARIABLES to take distinct values, 
  * except those variables that are assigned to 0.
  * """
  * 
  * This Choco model was created by Hakan Kjellerstrand (hakank@bonetmail.com)
  * Also, see my Choco page: http://www.hakank.org/choco/ 
  *
  */

import static choco.Choco.*;
import choco.cp.model.CPModel;
import choco.cp.solver.CPSolver;
import choco.cp.solver.constraints.*;
import choco.cp.solver.*;
import choco.kernel.model.variables.integer.*;
import choco.kernel.*;
import choco.kernel.model.*;
import choco.kernel.model.variables.*;
import choco.kernel.model.constraints.*;


import java.io.*;
import java.util.*;
import java.text.*;

public class AllDifferentExcept0_test {

    //
    // decomposition of alldifferent except 0
    //
    public void allDifferentExcept0(CPModel m, IntegerVariable[] v) {

        allDifferentExceptC(m, v, 0);

    }

    //
    // slightly more general: alldifferent except c
    //
    public void allDifferentExceptC(CPModel m, IntegerVariable[] v, int c) {
        int len = v.length;

        for(int i = 0; i < v.length; i++) {
            for(int j = i+1; j < v.length; j++) {
                // if v[i] > 0 && v[j] > 0 -> v[i] != v[j]
                m.addConstraint(ifThenElse(
                                           and(
                                               gt(v[i], c), 
                                               gt(v[j], c)
                                               ), 
                                           neq(v[i], v[j]),
                                           TRUE
                                           )
                                );
            }
        }
        
    }


    public void increasing(CPModel m, IntegerVariable[] v) {
        for(int j = 1; j < v.length; j++) {
            m.addConstraint(geq(v[j], v[j-1]));
        }
    }

    public void model() {

        int n = 10;
        CPModel m = new CPModel();
        IntegerVariable[] x = new IntegerVariable[n];
        for (int i = 0; i < n; i++) {
            x[i] = makeIntVar("x" + i, 0, n);
        }
        
        increasing(m, x);
        // allDifferentExcept0(m, x);
        allDifferentExceptC(m, x, 0);
        
        
        CPSolver S = new CPSolver();
        S.read(m);

        S.monitorTimeLimit(true);
        S.monitorBackTrackLimit(true);
        S.monitorNodeLimit(true);
        S.monitorFailLimit(true);

        S.solve();
        S.printRuntimeStatistics();

        if(S.isFeasible()) {
            
            int num_solutions = 0;
            do {

                for(int I = 0; I < n; I++) {                    
                    System.out.print(S.getVar(x[I]).getVal() + " ");
                }

                System.out.println();                
                num_solutions++;

            } while (S.nextSolution() == Boolean.TRUE);

            System.out.println("Number of solutions: " + num_solutions);

        } else {

            System.out.println("Problem is not feasible.");

        }

    } // end model

    public static void main(String args[]) {
        AllDifferentExcept0_test t = new AllDifferentExcept0_test();
        t.model();
        
    } // end main

} // end class
 
