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]); } }
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(); }
/// <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(); } }
// // Summary: // Check if this Domain and the other Domain have identical contents. public bool SetEqual(CspDomain otherDomain);
/// <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); }
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."); } }
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); }
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); }
/// <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); }