/// <summary> /// Returns all possible buckets using the <see cref="HybridStrategy.optionsToConsider"/>. /// </summary> /// <returns>a <see cref="List"/> containing the sum of all value combinations of the features</returns> private List <double> ComputeBuckets() { List <List <double> > allValueSets = new List <List <double> >(); foreach (ConfigurationOption o in this.optionsToConsider) { if (o is NumericOption) { NumericOption numOpt = (NumericOption)o; List <double> distances = new List <double>(); List <double> valuesOfNumericOption = numOpt.getAllValues(); foreach (double numOptValue in valuesOfNumericOption) { distances.Add(this.metric.ComputeDistanceOfNumericFeature(numOptValue, numOpt.Min_value, numOpt.Max_value)); } allValueSets.Add(distances); } else { BinaryOption binOpt = (BinaryOption)o; if (!binOpt.Optional && CountChildren(binOpt, GlobalState.varModel) > 0) { allValueSets.Add(new List <double> { this.metric.ComputeDistanceOfBinaryFeature(1) }); } else { allValueSets.Add(new List <double> { this.metric.ComputeDistanceOfBinaryFeature(0), this.metric.ComputeDistanceOfBinaryFeature(1) }); } } } List <double> result = ComputeSumOfCartesianProduct(allValueSets); // Sort the list result.Sort(delegate(double x, double y) { return(x.CompareTo(y)); }); return(result); }
/// <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); }