コード例 #1
0
        public void Solve(int?[,] field)
        {
            ConstraintSystem S = ConstraintSystem.CreateSolver();
            CspDomain        Z = S.CreateIntegerInterval(1, 9);

            CspTerm[][] sudoku = S.CreateVariableArray(Z, "cell", 9, 9);
            for (int row = 0; row < 9; row++)
            {
                for (int col = 0; col < 9; col++)
                {
                    if (field[row, col] > 0)
                    {
                        S.AddConstraints(S.Equal(field[row, col] ?? 0, sudoku[row][col]));
                    }
                }
                S.AddConstraints(S.Unequal(GetSlice(sudoku, row, row, 0, 8)));
            }
            for (int col = 0; col < 9; col++)
            {
                S.AddConstraints(S.Unequal(GetSlice(sudoku, 0, 8, col, col)));
            }
            for (int a = 0; a < 3; a++)
            {
                for (int b = 0; b < 3; b++)
                {
                    S.AddConstraints(S.Unequal(GetSlice(sudoku, a * 3, a * 3 + 2, b * 3, b * 3 + 2)));
                }
            }
            ConstraintSolverSolution soln = S.Solve();

            if (!soln.HasFoundSolution)
            {
                throw new NoSolutionException("Для поставленной цифры нет решение!");
            }


            object[] h = new object[9];
            for (int row = 0; row < 9; row++)
            {
                if ((row % 3) == 0)
                {
                    System.Console.WriteLine();
                }
                for (int col = 0; col < 9; col++)
                {
                    soln.TryGetValue(sudoku[row][col], out h[col]);
                }
                System.Console.WriteLine("{0}{1}{2} {3}{4}{5} {6}{7}{8}", h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7], h[8]);
            }
        }
コード例 #2
0
        static void Main(string[] args)
        {
            ConstraintSystem s1 = ConstraintSystem.CreateSolver();

            // () and ()
            CspTerm p1 = s1.CreateBoolean("p1");
            CspTerm p2 = s1.CreateBoolean("p2");
            CspTerm p3 = s1.CreateBoolean("p3");
            CspTerm p4 = s1.CreateBoolean("p4");

            var x = new CspDomain();

            CspTerm test = s1.And(s1.Or(p1, s1.And(s1.Neg(p3)), s1.Neg(p1)), s1.And(p2, s1.Neg(s1.Difference(p1, p2))));

            CspTerm tOr12 = s1.Or(s1.Neg(t1), s1.Neg(t2));
            CspTerm tOr13 = s1.Or(s1.Neg(t1), s1.Neg(t3));
            CspTerm tOr14 = s1.Or(s1.Neg(t1), s1.Neg(t4));

            CspTerm tOr23 = s1.Or(s1.Neg(t2), s1.Neg(t3));
            CspTerm tOr24 = s1.Or(s1.Neg(t2), s1.Neg(t4));

            CspTerm tOr34 = s1.Or(s1.Neg(t3), s1.Neg(t4));

            CspTerm tOr = s1.Or(t1, t2, t3, t4);

            s1.AddConstraints(tOr12);
            s1.AddConstraints(tOr13);
            s1.AddConstraints(tOr14);
            s1.AddConstraints(tOr23);
            s1.AddConstraints(tOr24);
            s1.AddConstraints(tOr34);
            s1.AddConstraints(tOr);

            ConstraintSolverSolution solution1 = s1.Solve();

            if (solution1.HasFoundSolution)
            {
                Console.WriteLine("Is Satisfiable");
            }
            else
            {
                Console.WriteLine("Not satisfiable");
            }

            Console.ReadKey();
        }
コード例 #3
0
        /// <summary>
        /// Knapsack enumerator -- enumerate up to "numAnswers" combinations of "weights" such that the sum of the weights is less than the weight limit.
        /// It places the patterns of items inside the list of patterns.  The efficiency parameter ensures that we don't output any which use less than "efficiency" percent
        /// off the weightlimit.
        /// </summary>
        /// <param name="maxAnswers">maximum number of combinations to get out.  Limits runtime.  If zero return all.</param>
        /// <param name="weights">weight of each item to go into the knapsack</param>
        /// <param name="weightLimit">knapsack weight limit</param>
        /// <param name="efficiency">limit patterns to use at least this % of the weight limit (between 0.0 and 1.0) </param>
        /// <param name="patterns">output list of patterns of inclusion of the weights.</param>
        public static void SolveKnapsack(int maxAnswers, int[] weights, int weightLimit, double efficiency, out List <int[]> patterns)
        {
            // convenience value.
            int NumItems            = weights.Length;
            ConstraintSystem solver = ConstraintSystem.CreateSolver();
            CspDomain        dom    = solver.CreateIntegerInterval(0, weightLimit);

            CspTerm knapsackSize = solver.Constant(weightLimit);

            // these represent the quantity of each item.
            CspTerm[] itemQty     = solver.CreateVariableVector(dom, "Quantity", NumItems);
            CspTerm[] itemWeights = new CspTerm[NumItems];

            for (int cnt = 0; cnt < NumItems; cnt++)
            {
                itemWeights[cnt] = solver.Constant(weights[cnt]);
            }

            // contributors to the weight (weight * variable value)
            CspTerm[] contributors = new CspTerm[NumItems];
            for (int cnt = 0; cnt < NumItems; cnt++)
            {
                contributors[cnt] = itemWeights[cnt] * itemQty[cnt];
            }

            // single constraint
            CspTerm knapSackCapacity = solver.GreaterEqual(knapsackSize, solver.Sum(contributors));

            solver.AddConstraints(knapSackCapacity);

            // must be efficient
            CspTerm knapSackAtLeast = solver.LessEqual(knapsackSize * efficiency, solver.Sum(contributors));

            solver.AddConstraints(knapSackAtLeast);

            // start counter and allocate a list for the results.
            int nanswers = 0;

            patterns = new List <int[]>();

            ConstraintSolverSolution sol = solver.Solve();

            while (sol.HasFoundSolution)
            {
                int[] pattern = new int[NumItems];
                // extract this pattern from the enumeration.
                for (int cnt = 0; cnt < NumItems; cnt++)
                {
                    object val;
                    sol.TryGetValue(itemQty[cnt], out val);
                    pattern[cnt] = (int)val;
                }
                // add it to the output.
                patterns.Add(pattern);
                nanswers++;
                // stop if we reach the limit of results.
                if (maxAnswers > 0 && nanswers >= maxAnswers)
                {
                    break;
                }
                sol.GetNext();
            }
        }
コード例 #4
0
 //
 // Summary:
 //     Check if this Domain and the other Domain have identical contents.
 public bool SetEqual(CspDomain otherDomain);
コード例 #5
0
ファイル: CSPsolver.cs プロジェクト: mcguenther/SPLConqueror
        /// <summary>
        /// Generates a constraint system based on a variability model. The constraint system can be used to check for satisfiability of configurations as well as optimization.
        /// </summary>
        /// <param name="variables">Empty input, outputs a list of CSP terms that correspond to the configuration options of the variability model</param>
        /// <param name="optionToTerm">A map to get for a given configuration option the corresponding CSP term of the constraint system</param>
        /// <param name="termToOption">A map that gives for a given CSP term the corresponding configuration option of the variability model</param>
        /// <param name="vm">The variability model for which we generate a constraint system</param>
        /// <returns>The generated constraint system consisting of logical terms representing configuration options as well as their boolean constraints.</returns>
        internal static ConstraintSystem getConstraintSystem(out List <CspTerm> variables, out Dictionary <BinaryOption, CspTerm> optionToTerm, out Dictionary <CspTerm, BinaryOption> termToOption, VariabilityModel vm)
        {
            //Reusing seems to not work correctely. The problem: configurations are realized as additional constraints for the system.
            //however, when checking for the next config, the old config's constraints remain in the solver such that we have a wrong result.

            /*
             * if (csystem != null && variables_global != null && optionToTerm_global != null && termToOption_global != null && vm != null)
             * {//For optimization purpose
             *  if (vm.BinaryOptions.Count == vm_global.BinaryOptions.Count && vm.Name.Equals(vm_global.Name))
             *  {
             *      variables = variables_global;
             *      optionToTerm = optionToTerm_global;
             *      termToOption = termToOption_global;
             *      return csystem;
             *  }
             * }*/

            ConstraintSystem S = ConstraintSystem.CreateSolver();

            optionToTerm = new Dictionary <BinaryOption, CspTerm>();
            termToOption = new Dictionary <CspTerm, BinaryOption>();
            variables    = new List <CspTerm>();
            foreach (BinaryOption binOpt in vm.BinaryOptions)
            {
                CspDomain domain = S.DefaultBoolean;
                CspTerm   temp   = S.CreateVariable(domain, binOpt);
                optionToTerm.Add(binOpt, temp);
                termToOption.Add(temp, binOpt);
                variables.Add(temp);
            }

            List <List <ConfigurationOption> > alreadyHandledAlternativeOptions = new List <List <ConfigurationOption> >();

            //Constraints of a single configuration option
            foreach (BinaryOption current in vm.BinaryOptions)
            {
                CspTerm cT = optionToTerm[current];
                if (current.Parent == null || current.Parent == vm.Root)
                {
                    if (current.Optional == false && current.Excluded_Options.Count == 0)
                    {
                        S.AddConstraints(S.Implies(S.True, cT));
                    }
                    else
                    {
                        S.AddConstraints(S.Implies(cT, optionToTerm[vm.Root]));
                    }
                }

                if (current.Parent != null && current.Parent != vm.Root)
                {
                    CspTerm parent = optionToTerm[(BinaryOption)current.Parent];
                    S.AddConstraints(S.Implies(cT, parent));
                    if (current.Optional == false && current.Excluded_Options.Count == 0)
                    {
                        S.AddConstraints(S.Implies(parent, cT));//mandatory child relationship
                    }
                }

                //Alternative or other exclusion constraints
                if (current.Excluded_Options.Count > 0)
                {
                    List <ConfigurationOption> alternativeOptions = current.collectAlternativeOptions();
                    if (alternativeOptions.Count > 0)
                    {
                        //Check whether we handled this group of alternatives already
                        foreach (var alternativeGroup in alreadyHandledAlternativeOptions)
                        {
                            foreach (var alternative in alternativeGroup)
                            {
                                if (current == alternative)
                                {
                                    goto handledAlternative;
                                }
                            }
                        }

                        //It is not allowed that an alternative group has no parent element
                        CspTerm parent = null;
                        if (current.Parent == null)
                        {
                            parent = S.True;
                        }
                        else
                        {
                            parent = optionToTerm[(BinaryOption)current.Parent];
                        }

                        CspTerm[] terms = new CspTerm[alternativeOptions.Count + 1];
                        terms[0] = cT;
                        int i = 1;
                        foreach (BinaryOption altEle in alternativeOptions)
                        {
                            CspTerm temp = optionToTerm[altEle];
                            terms[i] = temp;
                            i++;
                        }
                        S.AddConstraints(S.Implies(parent, S.ExactlyMofN(1, terms)));
                        alreadyHandledAlternativeOptions.Add(alternativeOptions);
                        handledAlternative : { }
                    }

                    //Excluded option(s) as cross-tree constraint(s)
                    List <List <ConfigurationOption> > nonAlternative = current.getNonAlternativeExlcudedOptions();
                    if (nonAlternative.Count > 0)
                    {
                        foreach (var excludedOption in nonAlternative)
                        {
                            CspTerm[] orTerm = new CspTerm[excludedOption.Count];
                            int       i      = 0;
                            foreach (var opt in excludedOption)
                            {
                                CspTerm target = optionToTerm[(BinaryOption)opt];
                                orTerm[i] = target;
                                i++;
                            }
                            S.AddConstraints(S.Implies(cT, S.Not(S.Or(orTerm))));
                        }
                    }
                }
                //Handle implies
                if (current.Implied_Options.Count > 0)
                {
                    foreach (List <ConfigurationOption> impliedOr in current.Implied_Options)
                    {
                        CspTerm[] orTerms = new CspTerm[impliedOr.Count];
                        //Possible error: if a binary option impies a numeric option
                        for (int i = 0; i < impliedOr.Count; i++)
                        {
                            orTerms[i] = optionToTerm[(BinaryOption)impliedOr.ElementAt(i)];
                        }
                        S.AddConstraints(S.Implies(optionToTerm[current], S.Or(orTerms)));
                    }
                }
            }

            //Handle global cross-tree constraints involving multiple options at a time
            // the constraints should be in conjunctive normal form
            foreach (string constraint in vm.BinaryConstraints)
            {
                bool     and = false;
                string[] terms;
                if (constraint.Contains("&"))
                {
                    and   = true;
                    terms = constraint.Split('&');
                }
                else
                {
                    terms = constraint.Split('|');
                }

                CspTerm[] cspTerms = new CspTerm[terms.Count()];
                int       i        = 0;
                foreach (string t in terms)
                {
                    string optName = t.Trim();
                    if (optName.StartsWith("-") || optName.StartsWith("!"))
                    {
                        optName = optName.Substring(1);
                        BinaryOption binOpt     = vm.getBinaryOption(optName);
                        CspTerm      cspElem    = optionToTerm[binOpt];
                        CspTerm      notCspElem = S.Not(cspElem);
                        cspTerms[i] = notCspElem;
                    }
                    else
                    {
                        BinaryOption binOpt  = vm.getBinaryOption(optName);
                        CspTerm      cspElem = optionToTerm[binOpt];
                        cspTerms[i] = cspElem;
                    }
                    i++;
                }
                if (and)
                {
                    S.AddConstraints(S.And(cspTerms));
                }
                else
                {
                    S.AddConstraints(S.Or(cspTerms));
                }
            }
            csystem             = S;
            optionToTerm_global = optionToTerm;
            vm_global           = vm;
            termToOption_global = termToOption;
            variables_global    = variables;
            return(S);
        }
コード例 #6
0
        public static void Run(int teamsNo)
        {
            // schedule N teams to play N-1 matches (one against every other team) with a difference
            //   of no more than 1 extra game away or home.  Note that N must be even (since every team
            //   must be paired every week).

            ConstraintSystem S = ConstraintSystem.CreateSolver();

            // The teams are numbered 0 to N-1 for simplicity in index lookups,
            //    since our arrays are zero-based.
            CspDomain Teams = S.CreateIntegerInterval(0, teamsNo - 1);


            CspTerm[][] matches = S.CreateVariableArray(Teams, "opponents", teamsNo, teamsNo - 1);

            CspTerm[][] atHome = S.CreateBooleanArray("atHome", teamsNo, teamsNo - 1);

            // each row represents the N-1 games the teams play.  The 0th week has an even-odd
            //  assignment since by symmetry that is equivalent to any other assignment and
            //  we thereby eliminate redundant solutions being enumerated.

            for (int t = 0; t < teamsNo; t++)
            {
                CspTerm atHomeSum = S.Sum(atHome[t]);
                S.AddConstraints(
                    S.Unequal(t, matches[t]),                                         // don't play self, and play every other team
                    S.LessEqual(teamsNo / 2 - 1, atHomeSum, S.Constant(teamsNo / 2)), // a balance of atHomes
                    S.Equal(t ^ 1, matches[t][0])                                     // even-odd pairing in the initial round
                    );
            }

            for (int w = 0; w < teamsNo - 1; w++)
            {
                S.AddConstraints(
                    S.Unequal(GetColumn(matches, w))              // every team appears once each week
                    );
                for (int t = 0; t < teamsNo; t++)
                {
                    S.AddConstraints(
                        S.Equal(t, S.Index(matches, matches[t][w], w)),           // Each team's pair's pair must be itself.
                        S.Equal(atHome[t][w], !S.Index(atHome, matches[t][w], w)) // Each pair is Home-Away or Away-Home.
                        );
                }
            }

            // That's it!  The problem is delivered to the solver.
            // Now to get an answer...

            //bool unsolved = true;
            ConstraintSolverSolution soln = S.Solve();

            if (soln.HasFoundSolution)
            {
                //unsolved = false;

                Console.Write("       | ");
                for (int w = 0; w < teamsNo - 1; w++)
                {
                    Console.Write("{1}Wk{0,2}", w + 1, w == 0 ? "" : " | ");
                }
                Console.WriteLine();
                Console.Write("       | ");
                for (int w = 0; w < teamsNo - 1; w++)
                {
                    Console.Write("{1}OP H", w + 1, w == 0 ? "" : " | ");
                }
                Console.WriteLine();
                Console.WriteLine("       {0}", "|" + new String('-', teamsNo * 6));
                for (int t = 0; t < teamsNo; t++)
                {
                    StringBuilder line = new StringBuilder();
                    line.AppendFormat("Team {0,2}| ", t + 1);
                    for (int w = 0; w < teamsNo - 1; w++)
                    {
                        object opponent, home;
                        if (!soln.TryGetValue(matches[t][w], out opponent))
                        {
                            throw new InvalidProgramException(matches[t][w].Key.ToString());
                        }
                        if (!soln.TryGetValue(atHome[t][w], out home))
                        {
                            throw new InvalidProgramException(atHome[t][w].Key.ToString());
                        }
                        line.AppendFormat("{2}{0,2} {1}",
                                          ((int)opponent) + 1,
                                          (int)home == 1 ? "*" : " ",
                                          w == 0 ? "" : " | "
                                          );
                        //line.Append(opponent.ToString());
                        //line.Append(((int)home == 1) ? " H," : " A,");
                    }
                    System.Console.WriteLine(line.ToString());
                }
                System.Console.WriteLine();
            }
            else
            {
                System.Console.WriteLine("No solution found.");
            }
        }
コード例 #7
0
        public ConstraintSolverSolution SolveB(int maxSolutions = 100)
        {
            ConstraintSystem S = ConstraintSystem.CreateSolver();

            //Define how many agents may work per shift
            CspDomain cspShiftsForceDomain = S.CreateIntegerInterval(first: 0, last: MaxAgents);

            //Decision variables, one per shift, that will hold the result of how may agents must work per shift to fullfil requirements
            CspTerm[] cspShiftsForce = S.CreateVariableVector(domain: cspShiftsForceDomain, key: "force", length: Shifts.Count);

            //index shifts, their variable CspTerm by the shift's relative no (0=first, 1=second, etc)
            ShiftsX = new Dictionary <Models.Shift, CspTerm>();
            int i = 0;

            Shifts.ForEach(x => { ShiftsX.Add(x, cspShiftsForce[i]); i++; });

            //Constraint - Agents on every half hour must be >= requirement for that half hour
            List <CspTerm> cspHalfHourExcess = new List <CspTerm>();

            foreach (var halfHourRq in HalfHourRequirements)
            {
                //find shifts including that halftime, and calculate their sum of force
                List <CspTerm> cspActive = new List <CspTerm>();
                foreach (var entry in ShiftsX)
                {
                    if (entry.Key.IncludesHalfHour(halfHourRq.Start))
                    {
                        cspActive.Add(entry.Value);
                    }
                }

                //add constraint for sum of force of active shifts on that halfhour
                //if we need agents but no shifts exists for a halfhour, do not add a constraint
                if (cspActive.Count > 0)
                {
                    var s = S.Sum(cspActive.ToArray()) - S.Constant(halfHourRq.RequiredForce);
                    S.AddConstraints(
                        S.LessEqual(constant: 0, inputs: s)
                        );
                    cspHalfHourExcess.Add(s);
                }
            }

            //var goal = S.Sum(shiftsX.Values.ToArray());
            //bool ok = S.TryAddMinimizationGoals(goal);

            var  goalMinExcess = S.Sum(cspHalfHourExcess.ToArray());
            bool ok            = S.TryAddMinimizationGoals(goalMinExcess);

            ConstraintSolverSolution solution = S.Solve();

            Console.WriteLine();
            GetSolutionsAll(solution: solution, maxSolutions: maxSolutions);
            if (ShiftsForce == null || ShiftsForce.Count == 0)
            {
                Console.WriteLine("No solution found");
            }

            if (ShiftsForce != null)
            {
                foreach (var shiftForceEntry in ShiftsForce)
                {
                    ShowSolution(no: shiftForceEntry.Key, shiftsForce: shiftForceEntry.Value, showAgents: true, showSlots: false);
                }
            }

            return(solution);
        }
コード例 #8
0
        public ConstraintSystem PrepareCspSolver()
        {
            ConstraintSystem S = ConstraintSystem.CreateSolver();

            //Define how many agents may work per shift
            var       maxRq = HalfHourRequirements.Max(x => x.RequiredForce);
            CspDomain cspShiftsForceDomain = S.CreateIntegerInterval(first: 0, last: maxRq);

            //var cspShiftsForceDomain = S.CreateIntegerSet(new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 });

            //Decision variables, one per shift, that will hold the result of how may agents must work per shift to fullfil requirements
            CspTerm[] cspShiftsForce = S.CreateVariableVector(domain: cspShiftsForceDomain, key: "force", length: Shifts.Count);

            //index shifts, their variable CspTerm by the shift's relative no (0=first, 1=second, etc)
            ShiftsX = new Dictionary <Models.Shift, CspTerm>();
            int i = 0;

            Shifts.ForEach(x => { ShiftsX.Add(x, cspShiftsForce[i]); i++; });

            //Constraint - Agents from every active shift on every half hour must be >= requirement for that half hour
            List <CspTerm> cspHalfHourExcess = new List <CspTerm>();

            foreach (var halfHourRq in HalfHourRequirements)
            {
                //find shifts including that halftime, and calculate their sum of force
                List <CspTerm> cspActive = new List <CspTerm>();
                foreach (var entry in ShiftsX)
                {
                    if (entry.Key.IncludesHalfHour(halfHourRq.Start))
                    {
                        cspActive.Add(entry.Value);
                    }
                }

                //add constraint for sum of force of active shifts on that halfhour
                //if we need agents but no shifts exists for a halfhour, do not add a constraint
                if (cspActive.Count > 0)
                {
                    //var s = S.Sum(cspActive.ToArray()) - S.Constant(halfHourRq.RequiredForce);
                    S.AddConstraints(
                        S.LessEqual(constant: halfHourRq.RequiredForce, inputs: S.Sum(cspActive.ToArray()))
                        );
                    //cspHalfHourExcess.Add(s);
                }
            }

            //if (false && cspHalfHourExcess.Count > 0)
            //    S.AddConstraints(
            //      S.LessEqual(constant: 0, inputs: S.Sum(cspHalfHourExcess.ToArray()))
            //    );

            bool xx = true;

            if (xx)
            {
                var  goal = S.Sum(ShiftsX.Values.ToArray());
                bool ok   = S.TryAddMinimizationGoals(goal);
            }
            else
            {
                //S.RemoveAllMinimizationGoals();
                var  goalMinExcess = S.Sum(cspHalfHourExcess.ToArray());
                bool ok            = S.TryAddMinimizationGoals(goalMinExcess);
            }
            return(S);
        }
コード例 #9
0
        /// <summary>
        /// Generates a constraint system based on a variability model. The constraint system can be used to check for satisfiability of configurations as well as optimization.
        /// </summary>
        /// <param name="variables">Empty input, outputs a list of CSP terms that correspond to the configuration options of the variability model</param>
        /// <param name="optionToTerm">A map to get for a given configuration option the corresponding CSP term of the constraint system</param>
        /// <param name="termToOption">A map that gives for a given CSP term the corresponding configuration option of the variability model</param>
        /// <param name="vm">The variability model for which we generate a constraint system</param>
        /// <returns>The generated constraint system consisting of logical terms representing configuration options as well as their boolean constraints.</returns>
        internal static ConstraintSystem GetGeneralConstraintSystem(out Dictionary <CspTerm, bool> variables, out Dictionary <ConfigurationOption, CspTerm> optionToTerm, out Dictionary <CspTerm, ConfigurationOption> termToOption, VariabilityModel vm)
        {
            ConstraintSystem S = ConstraintSystem.CreateSolver();

            optionToTerm = new Dictionary <ConfigurationOption, CspTerm>();
            termToOption = new Dictionary <CspTerm, ConfigurationOption>();
            variables    = new Dictionary <CspTerm, bool>();

            foreach (ConfigurationOption o in vm.getOptions())
            {
                CspDomain binDomain = S.DefaultBoolean;
                CspTerm   temp;
                if (o is BinaryOption)
                {
                    temp = S.CreateVariable(binDomain, o);
                }
                else
                {
                    NumericOption numOpt = (NumericOption)o;
                    temp = S.CreateVariable(S.CreateIntegerInterval((int)numOpt.Min_value, (int)numOpt.Max_value), o);
                }

                optionToTerm.Add(o, temp);
                termToOption.Add(temp, o);
                if (o is NumericOption)
                {
                    variables.Add(temp, false);
                }
                else
                {
                    variables.Add(temp, true);
                }
            }

            List <List <ConfigurationOption> > alreadyHandledAlternativeOptions = new List <List <ConfigurationOption> >();

            //Constraints of a single configuration option
            foreach (ConfigurationOption current in vm.getOptions())
            {
                CspTerm cT = optionToTerm[current];
                if (current.Parent == null || current.Parent == vm.Root)
                {
                    if ((current is BinaryOption && ((BinaryOption)current).Optional == false && current.Excluded_Options.Count == 0))
                    {
                        S.AddConstraints(S.Implies(S.True, cT));
                    }
                    else
                    {
                        S.AddConstraints(S.Implies(cT, optionToTerm[vm.Root]));
                    }
                }

                if (current.Parent != null && current.Parent != vm.Root)
                {
                    CspTerm parent = optionToTerm[(BinaryOption)current.Parent];
                    S.AddConstraints(S.Implies(cT, parent));
                    if (current is BinaryOption && ((BinaryOption)current).Optional == false && current.Excluded_Options.Count == 0)
                    {
                        S.AddConstraints(S.Implies(parent, cT));//mandatory child relationship
                    }
                }

                // Add numeric integer values
                if (current is NumericOption)
                {
                    NumericOption  numOpt = (NumericOption)current;
                    List <double>  values = numOpt.getAllValues();
                    List <CspTerm> equals = new List <CspTerm>();
                    foreach (double d in values)
                    {
                        equals.Add(S.Equal((int)d, cT));
                    }
                    S.AddConstraints(S.Or(equals.ToArray()));
                }

                //Alternative or other exclusion constraints
                if (current.Excluded_Options.Count > 0 && current is BinaryOption)
                {
                    BinaryOption binOpt = (BinaryOption)current;
                    List <ConfigurationOption> alternativeOptions = binOpt.collectAlternativeOptions();
                    if (alternativeOptions.Count > 0)
                    {
                        //Check whether we handled this group of alternatives already
                        foreach (var alternativeGroup in alreadyHandledAlternativeOptions)
                        {
                            foreach (var alternative in alternativeGroup)
                            {
                                if (current == alternative)
                                {
                                    goto handledAlternative;
                                }
                            }
                        }

                        //It is not allowed that an alternative group has no parent element
                        CspTerm parent = null;
                        if (current.Parent == null)
                        {
                            parent = S.True;
                        }
                        else
                        {
                            parent = optionToTerm[(BinaryOption)current.Parent];
                        }

                        CspTerm[] terms = new CspTerm[alternativeOptions.Count + 1];
                        terms[0] = cT;
                        int i = 1;
                        foreach (BinaryOption altEle in alternativeOptions)
                        {
                            CspTerm temp = optionToTerm[altEle];
                            terms[i] = temp;
                            i++;
                        }
                        S.AddConstraints(S.Implies(parent, S.ExactlyMofN(1, terms)));
                        alreadyHandledAlternativeOptions.Add(alternativeOptions);
                        handledAlternative : { }
                    }

                    //Excluded option(s) as cross-tree constraint(s)
                    List <List <ConfigurationOption> > nonAlternative = binOpt.getNonAlternativeExlcudedOptions();
                    if (nonAlternative.Count > 0)
                    {
                        foreach (var excludedOption in nonAlternative)
                        {
                            CspTerm[] orTerm = new CspTerm[excludedOption.Count];
                            int       i      = 0;
                            foreach (var opt in excludedOption)
                            {
                                CspTerm target = optionToTerm[(BinaryOption)opt];
                                orTerm[i] = target;
                                i++;
                            }
                            S.AddConstraints(S.Implies(cT, S.Not(S.Or(orTerm))));
                        }
                    }
                }
                //Handle implies
                if (current.Implied_Options.Count > 0)
                {
                    foreach (List <ConfigurationOption> impliedOr in current.Implied_Options)
                    {
                        CspTerm[] orTerms = new CspTerm[impliedOr.Count];
                        //Possible error: if a binary option impies a numeric option
                        for (int i = 0; i < impliedOr.Count; i++)
                        {
                            orTerms[i] = optionToTerm[(BinaryOption)impliedOr.ElementAt(i)];
                        }
                        S.AddConstraints(S.Implies(optionToTerm[current], S.Or(orTerms)));
                    }
                }
            }

            //Handle global cross-tree constraints involving multiple options at a time
            // the constraints should be in conjunctive normal form
            foreach (string constraint in vm.BinaryConstraints)
            {
                bool     and = false;
                string[] terms;
                if (constraint.Contains("&"))
                {
                    and   = true;
                    terms = constraint.Split('&');
                }
                else
                {
                    terms = constraint.Split('|');
                }

                CspTerm[] cspTerms = new CspTerm[terms.Count()];
                int       i        = 0;
                foreach (string t in terms)
                {
                    string optName = t.Trim();
                    if (optName.StartsWith("-") || optName.StartsWith("!"))
                    {
                        optName = optName.Substring(1);
                        BinaryOption binOpt     = vm.getBinaryOption(optName);
                        CspTerm      cspElem    = optionToTerm[binOpt];
                        CspTerm      notCspElem = S.Not(cspElem);
                        cspTerms[i] = notCspElem;
                    }
                    else
                    {
                        BinaryOption binOpt  = vm.getBinaryOption(optName);
                        CspTerm      cspElem = optionToTerm[binOpt];
                        cspTerms[i] = cspElem;
                    }
                    i++;
                }
                if (and)
                {
                    S.AddConstraints(S.And(cspTerms));
                }
                else
                {
                    S.AddConstraints(S.Or(cspTerms));
                }
            }
            return(S);
        }