/// <summary> /// Checks whether the boolean selection is valid w.r.t. the variability model. Does not check for numeric options' correctness. /// </summary> /// <param name="config">The list of binary options that are SELECTED (only selected options must occur in the list).</param> /// <param name="vm">The variability model that represents the context of the configuration.</param> /// <param name="partialConfiguration">Whether the given list of options represents only a partial configuration. This means that options not in config might be additionally select to obtain a valid configuration.</param> /// <returns>True if it is a valid selection w.r.t. the VM, false otherwise</returns> public bool checkConfigurationSAT(List <BinaryOption> config, VariabilityModel vm, bool partialConfiguration) { List <CspTerm> variables = new List <CspTerm>(); Dictionary <BinaryOption, CspTerm> elemToTerm = new Dictionary <BinaryOption, CspTerm>(); Dictionary <CspTerm, BinaryOption> termToElem = new Dictionary <CspTerm, BinaryOption>(); ConstraintSystem S = CSPsolver.getConstraintSystem(out variables, out elemToTerm, out termToElem, vm); //Feature Selection foreach (BinaryOption binayOpt in elemToTerm.Keys) { CspTerm term = elemToTerm[binayOpt]; if (config.Contains(binayOpt)) { S.AddConstraints(S.Implies(S.True, term)); } else if (!partialConfiguration) { S.AddConstraints(S.Implies(S.True, S.Not(term))); } } ConstraintSolverSolution sol = S.Solve(); if (sol.HasFoundSolution) { return(true); } else { return(false); } }
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]); } }
/// <summary> /// Checks whether the boolean selection is valid w.r.t. the variability model. Does not check for numeric options' correctness. /// </summary> /// <param name="config">The list of binary options that are SELECTED (only selected options must occur in the list).</param> /// <param name="vm">The variability model that represents the context of the configuration.</param> /// <param name="exact">Checks also the number of selected options such that it returns only true if exactly the given configuration is valid /// (e.g., if we need to select more features to get a valid config, it returns false if exact is set to true). /// <returns>True if it is a valid selection w.r.t. the VM, false otherwise</returns> public bool checkConfigurationSAT(List <BinaryOption> config, VariabilityModel vm, bool exact) { List <CspTerm> variables = new List <CspTerm>(); Dictionary <BinaryOption, CspTerm> elemToTerm = new Dictionary <BinaryOption, CspTerm>(); Dictionary <CspTerm, BinaryOption> termToElem = new Dictionary <CspTerm, BinaryOption>(); ConstraintSystem S = CSPsolver.getConstraintSystem(out variables, out elemToTerm, out termToElem, vm); //Feature Selection foreach (BinaryOption binayOpt in elemToTerm.Keys) { CspTerm term = elemToTerm[binayOpt]; if (config.Contains(binayOpt)) { S.AddConstraints(S.Implies(S.True, term)); } else { if (exact) { S.AddConstraints(S.Implies(S.True, S.Not(term))); } } } ConstraintSolverSolution sol = S.Solve(); if (sol.HasFoundSolution) { int count = 0; foreach (CspTerm cT in variables) { if (sol.GetIntegerValue(cT) == 1) { count++; } } //Needs testing TODO if (count != config.Count && exact == true) { return(false); } return(true); } else { return(false); } }
private void AddBinaryConfigurationsToConstraintSystem(VariabilityModel vm, ConstraintSystem s, Configuration configurationToExclude, Dictionary <BinaryOption, CspTerm> elemToTerm) { List <BinaryOption> allBinaryOptions = vm.BinaryOptions; List <CspTerm> positiveTerms = new List <CspTerm>(); List <CspTerm> negativeTerms = new List <CspTerm>(); foreach (BinaryOption binOpt in allBinaryOptions) { if (configurationToExclude.BinaryOptions.ContainsKey(binOpt) && configurationToExclude.BinaryOptions[binOpt] == BinaryOption.BinaryValue.Selected) { positiveTerms.Add(elemToTerm[binOpt]); } else { negativeTerms.Add(elemToTerm[binOpt]); } } if (negativeTerms.Count > 0) { positiveTerms.Add(s.Not(s.And(negativeTerms.ToArray()))); } s.AddConstraints(s.Not(s.And(positiveTerms.ToArray()))); }
/// <summary> /// The method aims at finding a configuration which is similar to the given configuration, but does not contain the optionToBeRemoved. If further options need to be removed from the given configuration, they are outputed in removedElements. /// Idea: Encode this as a CSP problem. We aim at finding a configuration that maximizes a goal. Each option of the given configuration gets a large value assigned. All other options of the variability model gets a negative value assigned. /// We will further create a boolean constraint that forbids selecting the optionToBeRemoved. Now, we find an optimal valid configuration. /// </summary> /// <param name="optionToBeRemoved">The binary configuration option that must not be part of the new configuration.</param> /// <param name="originalConfig">The configuration for which we want to find a similar one.</param> /// <param name="removedElements">If further options need to be removed from the given configuration to build a valid configuration, they are outputed in this list.</param> /// <param name="vm">The variability model containing all options and their constraints.</param> /// <returns>A configuration that is valid, similar to the original configuration and does not contain the optionToBeRemoved.</returns> public List <BinaryOption> GenerateConfigWithoutOption(BinaryOption optionToBeRemoved, List <BinaryOption> originalConfig, out List <BinaryOption> removedElements, VariabilityModel vm) { List <CspTerm> variables = new List <CspTerm>(); Dictionary <BinaryOption, CspTerm> elemToTerm = new Dictionary <BinaryOption, CspTerm>(); Dictionary <CspTerm, BinaryOption> termToElem = new Dictionary <CspTerm, BinaryOption>(); ConstraintSystem S = CSPsolver.getConstraintSystem(out variables, out elemToTerm, out termToElem, vm); removedElements = new List <BinaryOption>(); //Forbid the selection of this configuration option CspTerm optionToRemove = elemToTerm[optionToBeRemoved]; S.AddConstraints(S.Implies(S.True, S.Not(optionToRemove))); //Defining Goals CspTerm[] finalGoals = new CspTerm[variables.Count]; int r = 0; foreach (var term in variables) { if (originalConfig.Contains(termToElem[term])) { finalGoals[r] = term * -1000; //Since we minimize, we put a large negative value of an option that is within the original configuration to increase chances that the option gets selected again } else { finalGoals[r] = variables[r] * 10000;//Positive number will lead to a small chance that an option gets selected when it is not in the original configuration } r++; } S.TryAddMinimizationGoals(S.Sum(finalGoals)); ConstraintSolverSolution soln = S.Solve(); List <BinaryOption> tempConfig = new List <BinaryOption>(); if (soln.HasFoundSolution && soln.Quality == ConstraintSolverSolution.SolutionQuality.Optimal) { tempConfig.Clear(); foreach (CspTerm cT in variables) { if (soln.GetIntegerValue(cT) == 1) { tempConfig.Add(termToElem[cT]); } } //Adding the options that have been removed from the original configuration foreach (var opt in originalConfig) { if (!tempConfig.Contains(opt)) { removedElements.Add(opt); } } return(tempConfig); } return(null); }
CspTerm[][] CreateConstrainSystemMatrix(ConstraintSystem system) { var size = HouseNumbers.Count; var matrix = system.CreateBooleanArray(new object(), size, size); Enumerable.Range(0, size).ToList().ForEach(i => { var row = system.CreateBooleanVector(new object(), size); var column = system.CreateBooleanVector(new object(), size); Enumerable.Range(0, size).ToList().ForEach(j => { row[j] = matrix[i][j]; column[j] = matrix[j][i]; }); system.AddConstraints(system.Equal(1, system.Sum(row))); system.AddConstraints(system.Equal(1, system.Sum(column))); }); return(matrix); }
public override void AddConstaint() { ConstraintSystem solver = ConstraintSystemSolver.Instance.Solver; CspTerm constraint = null; CspTerm inputTerm = Input1.CspTerm; CspTerm outputTerm = Output.CspTerm; Type consType = type; if (IsNotHealthy) { // In case the gate is Broken (Not Healthy) - we don't want to add any constraint!!! return; /* * switch (type) * { * case Type.buffer: * consType = Type.not; * break; * case Type.not: * consType = Type.buffer; * break; * } */ } lock (ConstraintSystemSolver.Instance.Locker) { //Debug.WriteLine("SAT IN!"); switch (consType) { case Type.buffer: constraint = solver.Equal(inputTerm, outputTerm); break; case Type.not: constraint = solver.Equal(inputTerm, solver.Not(outputTerm)); break; } solver.AddConstraints(constraint); //Debug.WriteLine("SAT OUT!"); } }
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(); }
private List <List <BinaryOption> > generateTilSize(int i1, int size, int timeout, VariabilityModel vm) { var foundSolutions = new List <List <BinaryOption> >(); List <CspTerm> variables = new List <CspTerm>(); Dictionary <BinaryOption, CspTerm> elemToTerm = new Dictionary <BinaryOption, CspTerm>(); Dictionary <CspTerm, BinaryOption> termToElem = new Dictionary <CspTerm, BinaryOption>(); ConstraintSystem S = CSPsolver.getConstraintSystem(out variables, out elemToTerm, out termToElem, vm); CspTerm t = S.ExactlyMofN(i1, variables.ToArray()); S.AddConstraints(new CspTerm[] { t }); var csp = new ConstraintSolverParams { TimeLimitMilliSec = timeout * 1000, }; ConstraintSolverSolution soln = S.Solve(csp); int counter = 0; while (soln.HasFoundSolution) { List <BinaryOption> tempConfig = ( from cT in variables where soln.GetIntegerValue(cT) == 1 select termToElem[cT]).ToList(); if (tempConfig.Contains(null)) { tempConfig.Remove(null); } foundSolutions.Add(tempConfig); counter++; if (counter == size) { break; } soln.GetNext(); } //Console.WriteLine(i1 + "\t" + foundSolutions.Count); return(foundSolutions); }
/// <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(); } }
public override void AddConstaint() { ConstraintSystem solver = ConstraintSystemSolver.Instance.Solver; CspTerm constraint = null; CspTerm[] inputTerms = new CspTerm[Input.Count]; for (int i = 0; i < Input.Count; i++) { inputTerms[i] = Input[i].CspTerm; } CspTerm outputTerm = Output.CspTerm; Type consType = type; if (IsNotHealthy) { // In case the gate is Broken (Not Healthy) - we don't want to add any constraint!!! return; /* * switch (type) * { * case Type.and: * consType = Type.nand; * break; * case Type.nand: * consType = Type.and; * break; * case Type.or: * consType = Type.nor; * break; * case Type.nor: * consType = Type.or; * break; * case Type.xor: * consType = Type.nxor; * break; * case Type.nxor: * consType = Type.xor; * break; * } */ } lock (ConstraintSystemSolver.Instance.Locker) { //Debug.WriteLine("SAT IN!"); switch (consType) { case Type.and: CspTerm allAndInputs = solver.And(inputTerms); constraint = solver.Equal(allAndInputs, outputTerm); break; case Type.nand: CspTerm allNandInputs = solver.And(inputTerms); constraint = solver.Equal(allNandInputs, solver.Not(outputTerm)); break; case Type.nor: CspTerm allNorInputs = solver.Or(inputTerms); constraint = solver.Equal(allNorInputs, solver.Not(outputTerm)); break; case Type.or: CspTerm allOrInputs = solver.Or(inputTerms); constraint = solver.Equal(allOrInputs, outputTerm); break; case Type.xor: //XOR is also: //http://en.wikipedia.org/wiki/XOR_gate#/media/File:254px_3gate_XOR.jpg CspTerm firstNand = solver.Not(solver.And(inputTerms)); CspTerm firstOr = solver.Or(inputTerms); CspTerm secendAnd = solver.And(firstNand, firstOr); constraint = solver.Equal(secendAnd, outputTerm); break; case Type.nxor: //XOR is also: //http://en.wikipedia.org/wiki/XOR_gate#/media/File:254px_3gate_XOR.jpg CspTerm firstNand2 = solver.Not(solver.And(inputTerms)); CspTerm firstOr2 = solver.Or(inputTerms); CspTerm secendAnd2 = solver.And(firstNand2, firstOr2); constraint = solver.Equal(secendAnd2, solver.Not(outputTerm)); break; } solver.AddConstraints(constraint); //Debug.WriteLine("SAT OUT!"); } }
/// <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); }
/// <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); }
static void Main(string[] args) { try { Console.WriteLine("Seleccione el método por el que desea resolver el problema:\n1 Programación por restricciones\n2 Programación Lineal"); switch (int.Parse(Console.ReadLine())) { case 1: SolverContext context = new SolverContext(); Model model = context.CreateModel(); // Creación de variables Decision x1 = new Decision(Domain.Integer, "x1"); model.AddDecision(x1); Decision x2 = new Decision(Domain.Integer, "x2"); model.AddDecision(x2); Decision x3 = new Decision(Domain.Integer, "x3"); model.AddDecision(x3); // Creación de limites model.AddConstraint("limitX1", 50 <= x1 <= 300); model.AddConstraint("limitX2", 100 <= x2 <= 200); model.AddConstraint("limitX3", 20 <= x3 <= 1000); // Creación de restricciones model.AddConstraint("restriccion1", 200 <= (x1 + x2 + x3) <= 280); model.AddConstraint("restriccion2", 100 <= (x1 + (3 * x3)) <= 2000); model.AddConstraint("restriccion3", 50 <= ((2 + x1) + (4 * x3)) <= 1000); // Función objetivo model.AddGoal("maximo", GoalKind.Maximize, -(4 * x1) - (2 * x2) + x3); // Solucion Solution solucion = context.Solve(new SimplexDirective()); Report reporte = solucion.GetReport(); // Imprimir Console.WriteLine(reporte); Console.ReadLine(); break; case 2: //Solucionador específico ConstraintSystem csp = ConstraintSystem.CreateSolver(); // Creacíón de variables CspTerm sx1 = csp.CreateVariable(csp.CreateIntegerInterval(50, 300), "x1"); CspTerm sx2 = csp.CreateVariable(csp.CreateIntegerInterval(100, 200), "x2"); CspTerm sx3 = csp.CreateVariable(csp.CreateIntegerInterval(20, 1000), "x3"); // Creación de restricciones csp.AddConstraints(200 <= (sx1 + sx2 + sx3) <= 280, 100 <= sx1 + (3 * sx2) <= 2000, 50 <= (2 * sx1) + (4 * sx3) <= 1000); // Solución ConstraintSolverSolution cspSolucion = csp.Solve(); int numero = 1; while (cspSolucion.HasFoundSolution) { object rx1, rx2, rx3; if (!cspSolucion.TryGetValue(sx1, out rx1) || !cspSolucion.TryGetValue(sx2, out rx2) || !cspSolucion.TryGetValue(sx3, out rx3)) { throw new InvalidProgramException("No se encontro solución"); } Console.WriteLine(String.Format("Solución {0} :\nx1={1}\nx2={2}\nx3={3}", numero, rx1, rx2, rx3)); numero += 1; cspSolucion.GetNext(); } /* * //Solucionador específico * SimplexSolver sSolver = new SimplexSolver(); * //Creación de variables * int sx1, sx2, sx3; * sSolver.AddVariable("x1", out sx1); * sSolver.SetBounds(sx1, 50, 300); * sSolver.AddVariable("x2", out sx2); * sSolver.SetBounds(sx2, 100, 200); * sSolver.AddVariable("x3", out sx3); * sSolver.SetBounds(sx3,20,1000); * //Creación de restricciones * int r1, r2, r3, goal; * sSolver.AddRow("restriccion1", out r1); * sSolver.SetCoefficient(r1, sx1, 1); * sSolver.SetCoefficient(r1, sx2, 1); * sSolver.SetCoefficient(r1, sx3, 1); * sSolver.SetBounds(r1, 200, 280); * sSolver.AddRow("restriccion2", out r2); * sSolver.SetCoefficient(r2, sx1, 1); * sSolver.SetCoefficient(r2, sx2, 3); * sSolver.SetBounds(r2, 100, 2000); * sSolver.AddRow("restriccion3", out r3); * sSolver.SetCoefficient(r3, sx1, 2); * sSolver.SetCoefficient(r3, sx3, 4); * sSolver.SetBounds(r3, 50, 1000); * //Función objetivo * sSolver.AddRow("objetivo", out goal); * sSolver.SetCoefficient(goal, sx1, -4); * sSolver.SetCoefficient(goal, sx2, -2); * sSolver.SetCoefficient(goal, sx3, 1); * sSolver.SetBounds(goal, Rational.NegativeInfinity,Rational.PositiveInfinity); * sSolver.AddGoal(goal, 1, false); * //Solución * sSolver.Solve(new SimplexSolverParams()); * sSolver.GetReport(); */ break; } } catch (Exception ex) { Console.WriteLine(ex.Message); Console.WriteLine(ex.StackTrace); Console.ReadLine(); } }
///// <summary> Helper function for reading the Bus Driver data file ///// </summary> //static List<string> Numerals(string line) //{ // List<string> result = new List<string>(); // int left = 0; // while (left < line.Length) // { // char c = line[left]; // if (('0' <= c) && (c <= '9')) // { // int right = left + 1; // while ((right < line.Length) && ('0' <= line[right]) && (line[right] <= '9')) // right++; // result.Add(line.Substring(left, right - left)); // left = right + 1; // } // else // left++; // } // return result; //} /// <summary> Bus Drivers. Data taken from data files of London bus companies, with the /// problem being to find the cheapest, complete, non-overlapping set of task /// assignments that will give a feasible schedule. /// </summary> public static void BusDrivers(string sourceFilePath) { // http://www-old.cs.st-andrews.ac.uk/~ianm/CSPLib/prob/prob022/index.html ConstraintSystem S = ConstraintSystem.CreateSolver(); List <CspTerm> driverCosts = new List <CspTerm>(); List <int[]> driversTasks = new List <int[]>(); int nTasks = 0; // Read the data file. Each row specifies a driver cost, a count of tasks, and the task numbers try { using (StreamReader sr = new StreamReader(sourceFilePath)) { String line; while ((line = sr.ReadLine()) != null) { int[] tasks; driverCosts.Add(S.Constant(ReadDriver(line, out tasks))); nTasks += tasks.Length; Array.Sort <int>(tasks); driversTasks.Add(tasks); } } int nDrivers = driversTasks.Count; // create a master list of tasks by sorting the raw union and then compressing out duplicates. int[] allTasks = new int[nTasks]; nTasks = 0; foreach (int[] tasks in driversTasks) { foreach (int x in tasks) { allTasks[nTasks++] = x; } } Array.Sort <int>(allTasks); nTasks = 0; for (int i = 1; i < allTasks.Length; i++) { if (allTasks[nTasks] < allTasks[i]) { allTasks[++nTasks] = allTasks[i]; } } nTasks++; Array.Resize <int>(ref allTasks, nTasks); // We now have an array of all the tasks, and a list of all the drivers. // The problem statement comes down to: // - each task must be assigned exactly once // - minimize the cost of drivers // We add a boolean vector representing the drivers, true if the driver is to be used. CspTerm[] driversUsed = S.CreateBooleanVector("drivers", nDrivers); // these are the Decision Variables // We now create an array which maps which tasks are in which drivers. // In addition to this static map, we create a dynamic map of the usage and the costs. CspTerm[][] taskActualUse = new CspTerm[nTasks][]; CspTerm[] driverActualCost = new CspTerm[nDrivers]; for (int t = 0; t < nTasks; t++) { taskActualUse[t] = new CspTerm[nDrivers]; for (int r = 0; r < nDrivers; r++) { taskActualUse[t][r] = (0 <= Array.BinarySearch <int>(driversTasks[r], allTasks[t])) ? driversUsed[r] : S.False; } S.AddConstraints( S.ExactlyMofN(1, taskActualUse[t]) // this task appears exactly once ); } // set the goal for (int r = 0; r < nDrivers; r++) { driverActualCost[r] = driversUsed[r] * driverCosts[r]; // dynamic cost map } S.TryAddMinimizationGoals(S.Sum(driverActualCost)); // now run the Solver and print the solutions int solnId = 0; ConstraintSolverSolution soln = S.Solve(); if (soln.HasFoundSolution) { System.Console.WriteLine("Solution #" + solnId++); for (int d = 0; d < driversUsed.Length; d++) { object isUsed; if (!soln.TryGetValue(driversUsed[d], out isUsed)) { throw new InvalidProgramException("can't find drive in the solution: " + d.ToString()); } // Take only the decision variables which turn out true. // For each true row, print the row number and the list of tasks. if (1 == (int)isUsed) { StringBuilder line = new StringBuilder(d.ToString()); line.Append(": "); foreach (int x in driversTasks[d]) { line.Append(x.ToString()).Append(", "); } System.Console.WriteLine(line.ToString()); } } } if (solnId == 0) { System.Console.WriteLine("No solution found."); } } catch (Exception e) { // Let the user know what went wrong. Console.WriteLine("The file could not be read:"); Console.WriteLine(e.Message); } }
/// <summary> /// Based on a given (partial) configuration and a variability, we aim at finding all optimally maximal or minimal (in terms of selected binary options) configurations. /// </summary> /// <param name="config">The (partial) configuration which needs to be expaned to be valid.</param> /// <param name="vm">Variability model containing all options and their constraints.</param> /// <param name="minimize">If true, we search for the smallest (in terms of selected options) valid configuration. If false, we search for the largest one.</param> /// <param name="unwantedOptions">Binary options that we do not want to become part of the configuration. Might be part if there is no other valid configuration without them</param> /// <returns>A list of configurations that satisfies the VM and the goal (or null if there is none).</returns> public List <List <BinaryOption> > MaximizeConfig(List <BinaryOption> config, VariabilityModel vm, bool minimize, List <BinaryOption> unwantedOptions) { List <CspTerm> variables = new List <CspTerm>(); Dictionary <BinaryOption, CspTerm> elemToTerm = new Dictionary <BinaryOption, CspTerm>(); Dictionary <CspTerm, BinaryOption> termToElem = new Dictionary <CspTerm, BinaryOption>(); ConstraintSystem S = CSPsolver.getConstraintSystem(out variables, out elemToTerm, out termToElem, vm); //Feature Selection if (config != null) { foreach (BinaryOption binOpt in config) { CspTerm term = elemToTerm[binOpt]; S.AddConstraints(S.Implies(S.True, term)); } } //Defining Goals CspTerm[] finalGoals = new CspTerm[variables.Count]; for (int r = 0; r < variables.Count; r++) { if (minimize == true) { BinaryOption binOpt = termToElem[variables[r]]; if (unwantedOptions != null && (unwantedOptions.Contains(binOpt) && !config.Contains(binOpt))) { finalGoals[r] = variables[r] * 10000; } else { // Element is part of an altnerative Group ... we want to select always the same option of the group, so we give different weights to the member of the group //Functionality deactivated... todo needs further handling /*if (binOpt.getAlternatives().Count != 0) * { * finalGoals[r] = variables[r] * (binOpt.getID() * 10); * } * else * {*/ finalGoals[r] = variables[r] * 1; //} // wenn in einer alternative, dann bekommt es einen wert nach seiner reihenfolge // id mal 10 } } else { finalGoals[r] = variables[r] * -1; // dynamic cost map } } S.TryAddMinimizationGoals(S.Sum(finalGoals)); ConstraintSolverSolution soln = S.Solve(); List <string> erg2 = new List <string>(); List <BinaryOption> tempConfig = new List <BinaryOption>(); List <List <BinaryOption> > resultConfigs = new List <List <BinaryOption> >(); while (soln.HasFoundSolution && soln.Quality == ConstraintSolverSolution.SolutionQuality.Optimal) { tempConfig.Clear(); foreach (CspTerm cT in variables) { if (soln.GetIntegerValue(cT) == 1) { tempConfig.Add(termToElem[cT]); } } if (minimize && tempConfig != null) { resultConfigs.Add(tempConfig); break; } if (!Configuration.containsBinaryConfiguration(resultConfigs, tempConfig)) { resultConfigs.Add(tempConfig); } soln.GetNext(); } return(resultConfigs); }
private static ConstraintSystem AddConstraintsToSolver( ConstraintSystem solver, ZebraPuzzleConstraints constraints) { solver.AddConstraints( constraints.TheEnglishManLivesInTheRedHouse()); solver.AddConstraints( constraints.TheSwedeHasADog()); solver.AddConstraints( constraints.TheDaneDrinksTea()); solver.AddConstraints( constraints.TheGreenHouseIsImmediatelyLeftOfTheWhiteHouse()); solver.AddConstraints( constraints.TheyDrinkCoffeeInTheGreenHouse()); solver.AddConstraints( constraints.TheManWhoSmokesPallMallHasBirds()); solver.AddConstraints( constraints.InTheYellowHouseTheySmokeDunhill()); solver.AddConstraints( constraints.InTheMiddleHouseTheyDrinkMilk()); solver.AddConstraints( constraints.TheNorwegianLivesInTheFirstHouse()); solver.AddConstraints( constraints.TheManWhoSmokesBlendInHouseNextToHouseWithCats()); solver.AddConstraints( constraints.InHouseNextToHouseWhereHaveAHorseSmokeDunhill()); solver.AddConstraints( constraints.TheManWhoSmokesBlueMasterDrinksBeer()); solver.AddConstraints( constraints.TheGermanSmokesPrince()); solver.AddConstraints( constraints.TheNorwegianLivesNextToTheBlueHouse()); solver.AddConstraints( constraints.TheyDrinkWaterInHouseNextToHouseWhereSmokeBlend()); return(solver); }
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> /// This method searches for a corresponding methods in the dynamically loaded assemblies and calls it if found. It prefers due to performance reasons the Microsoft Solver Foundation implementation. /// </summary> /// <param name="config">The (partial) configuration which needs to be expaned to be valid.</param> /// <param name="vm">Variability model containing all options and their constraints.</param> /// <param name="minimize">If true, we search for the smallest (in terms of selected options) valid configuration. If false, we search for the largest one.</param> /// <param name="unWantedOptions">Binary options that we do not want to become part of the configuration. Might be part if there is no other valid configuration without them.</param> /// <returns>The valid configuration (or null if there is none) that satisfies the VM and the goal.</returns> public List <BinaryOption> MinimizeConfig(List <BinaryOption> config, VariabilityModel vm, bool minimize, List <BinaryOption> unWantedOptions) { List <CspTerm> variables = new List <CspTerm>(); Dictionary <BinaryOption, CspTerm> elemToTerm = new Dictionary <BinaryOption, CspTerm>(); Dictionary <CspTerm, BinaryOption> termToElem = new Dictionary <CspTerm, BinaryOption>(); ConstraintSystem S = CSPsolver.getConstraintSystem(out variables, out elemToTerm, out termToElem, vm); //Feature Selection foreach (BinaryOption binOpt in config) { CspTerm term = elemToTerm[binOpt]; S.AddConstraints(S.Implies(S.True, term)); } //Defining Goals CspTerm[] finalGoals = new CspTerm[variables.Count]; for (int r = 0; r < variables.Count; r++) { if (minimize == true) { if (unWantedOptions != null && (unWantedOptions.Contains(termToElem[variables[r]]) && !config.Contains(termToElem[variables[r]]))) { finalGoals[r] = variables[r] * 100; } else { finalGoals[r] = variables[r] * 1; } } else { finalGoals[r] = variables[r] * -1; // dynamic cost map } } S.TryAddMinimizationGoals(S.Sum(finalGoals)); ConstraintSolverSolution soln = S.Solve(); List <string> erg2 = new List <string>(); List <BinaryOption> tempConfig = new List <BinaryOption>(); while (soln.HasFoundSolution) { tempConfig.Clear(); foreach (CspTerm cT in variables) { if (soln.GetIntegerValue(cT) == 1) { tempConfig.Add(termToElem[cT]); } } if (minimize && tempConfig != null) { break; } soln.GetNext(); } return(tempConfig); }
public static void Run() { ConstraintSystem S = ConstraintSystem.CreateSolver(); List <KeyValuePair <CspTerm, string> > termList = new List <KeyValuePair <CspTerm, string> >(); // create a Term between [1..5], associate it with a name for later ease of display NamedTerm namedTerm = delegate(string name) { CspTerm x = S.CreateVariable(S.CreateIntegerInterval(1, 5), name); termList.Add(new KeyValuePair <CspTerm, string>(x, name)); return(x); }; // the people and attributes will all be matched via the house they reside in. CspTerm English = namedTerm("English"), Spanish = namedTerm("Spanish"), Japanese = namedTerm("Japanese"), Italian = namedTerm("Italian"), Norwegian = namedTerm("Norwegian"); CspTerm red = namedTerm("red"), green = namedTerm("green"), white = namedTerm("white"), blue = namedTerm("blue"), yellow = namedTerm("yellow"); CspTerm dog = namedTerm("dog"), snails = namedTerm("snails"), fox = namedTerm("fox"), horse = namedTerm("horse"), zebra = namedTerm("zebra"); CspTerm painter = namedTerm("painter"), sculptor = namedTerm("sculptor"), diplomat = namedTerm("diplomat"), violinist = namedTerm("violinist"), doctor = namedTerm("doctor"); CspTerm tea = namedTerm("tea"), coffee = namedTerm("coffee"), milk = namedTerm("milk"), juice = namedTerm("juice"), water = namedTerm("water"); S.AddConstraints( S.Unequal(English, Spanish, Japanese, Italian, Norwegian), S.Unequal(red, green, white, blue, yellow), S.Unequal(dog, snails, fox, horse, zebra), S.Unequal(painter, sculptor, diplomat, violinist, doctor), S.Unequal(tea, coffee, milk, juice, water), S.Equal(English, red), S.Equal(Spanish, dog), S.Equal(Japanese, painter), S.Equal(Italian, tea), S.Equal(1, Norwegian), S.Equal(green, coffee), S.Equal(1, green - white), S.Equal(sculptor, snails), S.Equal(diplomat, yellow), S.Equal(3, milk), S.Equal(1, S.Abs(Norwegian - blue)), S.Equal(violinist, juice), S.Equal(1, S.Abs(fox - doctor)), S.Equal(1, S.Abs(horse - diplomat)) ); bool unsolved = true; ConstraintSolverSolution soln = S.Solve(); while (soln.HasFoundSolution) { unsolved = false; System.Console.WriteLine("solved."); StringBuilder[] houses = new StringBuilder[5]; for (int i = 0; i < 5; i++) { houses[i] = new StringBuilder(i.ToString()); } foreach (KeyValuePair <CspTerm, string> kvp in termList) { string item = kvp.Value; object house; if (!soln.TryGetValue(kvp.Key, out house)) { throw new InvalidProgramException("can't find a Term in the solution: " + item); } houses[(int)house - 1].Append(", "); houses[(int)house - 1].Append(item); } foreach (StringBuilder house in houses) { System.Console.WriteLine(house); } soln.GetNext(); } if (unsolved) { System.Console.WriteLine("No solution found."); } else { System.Console.WriteLine("Solution should have the Norwegian drinking water and the Japanese with the zebra."); } }
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 static void Run(string parameters) { // http://www-old.cs.st-andrews.ac.uk/~ianm/CSPLib/prob/prob022/index.html ConstraintSystem S = ConstraintSystem.CreateSolver(); List <CspTerm> driverCosts = new List <CspTerm>(); List <int[]> driversTasks = new List <int[]>(); int nTasks = 0; // Read the data file. Each row specifies a driver cost, a count of tasks, and the task numbers try { //parse parameters to extract data //<line no> = bus driver no-1 (eg line 1 = driver0) //1 4 3 4 16 17 //1 = cost of driver // 4 = number of bus routes (tasks) // 3, 4, 16, 17 = the bus routes (tasks) for the driver var lines = Regex.Split(parameters, "\r\n|\r|\n"); foreach (var line in lines) { if (string.IsNullOrWhiteSpace(line)) { continue; } int[] tasks; driverCosts.Add(S.Constant(ReadDriver(line, out tasks))); nTasks += tasks.Length; Array.Sort <int>(tasks); driversTasks.Add(tasks); } int nDrivers = driversTasks.Count; // create a master list of unique tasks (bus routes) that be assigned to drivers List <int> tasksU = new List <int>(); driversTasks.ForEach(x => tasksU.AddRange(x)); int[] allTasks = tasksU.OrderBy(x => x).Distinct().ToArray(); nTasks = allTasks.Length; // We now have an array of all the tasks, and a list of all the drivers. // The problem statement comes down to: // - each task must be assigned exactly once // - minimize the cost of drivers // We add a boolean vector representing the drivers, true if the driver is to be used. CspTerm[] driversUsed = S.CreateBooleanVector("drivers", nDrivers); // these are the Decision Variables // We now create an array which maps which tasks are in which drivers. // In addition to this static map, we create a dynamic map of the usage and the costs. CspTerm[][] taskActualUse = new CspTerm[nTasks][]; CspTerm[] driverActualCost = new CspTerm[nDrivers]; for (int t = 0; t < nTasks; t++) //for each task / bus route { taskActualUse[t] = new CspTerm[nDrivers]; //for each route, array of all bus drivers (used to flag who may drive the route) for (int r = 0; r < nDrivers; r++) //for each driver { taskActualUse[t][r] = (0 <= Array.BinarySearch <int>(driversTasks[r], allTasks[t])) ? driversUsed[r] : S.False; } S.AddConstraints( S.ExactlyMofN(1, taskActualUse[t]) // this task appears exactly once ); } // set the goal: minimize total driver's cost for (int r = 0; r < nDrivers; r++) { driverActualCost[r] = driversUsed[r] * driverCosts[r]; // dynamic cost map } S.TryAddMinimizationGoals(S.Sum(driverActualCost)); // now run the Solver and print the solutions int solnId = 0; ConstraintSolverSolution soln = S.Solve(); if (soln.HasFoundSolution) { System.Console.WriteLine("Solution #" + solnId++); for (int d = 0; d < driversUsed.Length; d++) { object isUsed; if (!soln.TryGetValue(driversUsed[d], out isUsed)) { throw new InvalidProgramException("can't find drive in the solution: " + d.ToString()); } // Take only the decision variables which turn out true. // For each true row, print the row number and the list of tasks. if (1 == (int)isUsed) { StringBuilder line = new StringBuilder(d.ToString()); line.Append(": "); foreach (int x in driversTasks[d]) { line.Append(x.ToString()).Append(", "); } System.Console.WriteLine(line.ToString()); } } } if (solnId == 0) { System.Console.WriteLine("No solution found."); } } catch (Exception e) { // Let the user know what went wrong. Console.WriteLine("The file could not be read:"); Console.WriteLine(e.Message); } }