/// <summary> /// Try to find a configuration with low weight. /// </summary> /// <param name="sortedRanking">A list of binary options and their weight ordered by their weight.</param> /// <param name="cache">A sat solver cache instance that already contains the constraints of /// size and disallowed features.</param> /// <param name="vm">The variability model of the given system.</param> /// <returns>A configuration that has a small weight.</returns> public static List <BinaryOption> getSmallWeightConfig(List <KeyValuePair <List <BinaryOption>, int> > sortedRanking, Z3Cache cache, VariabilityModel vm) { KeyValuePair <List <BinaryOption>, int>[] ranking = sortedRanking.ToArray(); Microsoft.Z3.Solver solver = cache.GetSolver(); Context z3Context = cache.GetContext(); for (int i = 0; i < ranking.Length; i++) { List <BinaryOption> candidates = ranking[i].Key; solver.Push(); solver.Assert(forceFeatures(candidates, z3Context, cache.GetOptionToTermMapping())); if (solver.Check() == Status.SATISFIABLE) { Model model = solver.Model; solver.Pop(); return(Z3VariantGenerator.RetrieveConfiguration(cache.GetVariables(), model, cache.GetTermToOptionMapping())); } solver.Pop(); } return(null); }
/// <summary> /// Adds the given configuration as a constraint to the solver. /// </summary> /// <param name="vm">The variability model</param> /// <param name="configToExclude">The configuration to exclude</param> /// <param name="numberSelectedFeatures">The number of features to be selected</param> public void AddConstraint(VariabilityModel vm, Configuration configToExclude, int numberSelectedFeatures) { if (!constraintsCache.ContainsKey(numberSelectedFeatures)) { constraintsCache[numberSelectedFeatures] = new HashSet <Configuration>(); } if (constraintsCache[numberSelectedFeatures].Contains(configToExclude)) { return; } constraintsCache[numberSelectedFeatures].Add(configToExclude); if (_z3Cache == null) { _z3Cache = new Dictionary <int, Z3Cache>(); } Dictionary <BinaryOption, BoolExpr> optionToTerm; Context z3Context; Microsoft.Z3.Solver solver; if (!this._z3Cache.Keys.Contains(numberSelectedFeatures)) { InitializeZ3Cache(vm, numberSelectedFeatures); } Z3Cache cache = this._z3Cache[numberSelectedFeatures]; z3Context = cache.GetContext(); solver = cache.GetSolver(); optionToTerm = cache.GetOptionToTermMapping(); // Add the previous configurations as constraints solver.Assert(Z3Solver.NegateExpr(z3Context, Z3Solver.ConvertConfiguration(z3Context, configToExclude.getBinaryOptions(BinaryOption.BinaryValue.Selected), optionToTerm, vm))); // Create a new backtracking point for the next run solver.Push(); }
public List <BinaryOption> GenerateConfigurationFromBucket(VariabilityModel vm, int numberSelectedFeatures, Dictionary <List <BinaryOption>, int> featureWeight, Configuration lastSampledConfiguration) { if (_z3Cache == null) { _z3Cache = new Dictionary <int, Z3Cache>(); } List <KeyValuePair <List <BinaryOption>, int> > featureRanking; if (featureWeight != null) { featureRanking = featureWeight.ToList(); featureRanking.Sort((first, second) => first.Value.CompareTo(second.Value)); } else { featureRanking = new List <KeyValuePair <List <BinaryOption>, int> >(); } List <BoolExpr> variables = null; Dictionary <BoolExpr, BinaryOption> termToOption = null; Dictionary <BinaryOption, BoolExpr> optionToTerm = null; Tuple <Context, BoolExpr> z3Tuple; Context z3Context; Microsoft.Z3.Solver solver; // Reuse the solver if it is already in the cache if (this._z3Cache.Keys.Contains(numberSelectedFeatures)) { Z3Cache cache = this._z3Cache[numberSelectedFeatures]; z3Context = cache.GetContext(); solver = cache.GetSolver(); variables = cache.GetVariables(); termToOption = cache.GetTermToOptionMapping(); optionToTerm = cache.GetOptionToTermMapping(); if (lastSampledConfiguration != null) { // Add the previous configurations as constraints solver.Assert(Z3Solver.NegateExpr(z3Context, Z3Solver.ConvertConfiguration(z3Context, lastSampledConfiguration.getBinaryOptions(BinaryOption.BinaryValue.Selected), optionToTerm, vm))); // Create a new backtracking point for the next run solver.Push(); } } else { z3Tuple = Z3Solver.GetInitializedBooleanSolverSystem(out variables, out optionToTerm, out termToOption, vm, this.henard); z3Context = z3Tuple.Item1; BoolExpr z3Constraints = z3Tuple.Item2; solver = z3Context.MkSolver(); // TODO: The following line works for z3Solver version >= 4.6.0 //solver.Set (RANDOM_SEED, z3RandomSeed); Params solverParameter = z3Context.MkParams(); solverParameter.Add(RANDOM_SEED, z3RandomSeed); solver.Parameters = solverParameter; solver.Assert(z3Constraints); if (lastSampledConfiguration != null) { // Add the previous configurations as constraints solver.Assert(Z3Solver.NegateExpr(z3Context, Z3Solver.ConvertConfiguration(z3Context, lastSampledConfiguration.getBinaryOptions(BinaryOption.BinaryValue.Selected), optionToTerm, vm))); } // The goal of this method is, to have an exact number of features selected // Therefore, initialize an integer array with the value '1' for the pseudo-boolean equal function int[] neutralWeights = new int[variables.Count]; for (int i = 0; i < variables.Count; i++) { neutralWeights[i] = 1; } solver.Assert(z3Context.MkPBEq(neutralWeights, variables.ToArray(), numberSelectedFeatures)); // Create a backtracking point before adding the optimization goal solver.Push(); this._z3Cache[numberSelectedFeatures] = new Z3Cache(z3Context, solver, variables, optionToTerm, termToOption); } // Check if there is still a solution available by finding the first satisfiable configuration if (solver.Check() == Status.SATISFIABLE) { Model model = solver.Model; List <BinaryOption> possibleSolution = RetrieveConfiguration(variables, model, termToOption); // Disable finding a configuration where the least frequent feature/feature combinations are selected // if no featureWeight is given. List <BinaryOption> approximateOptimal = null; if (featureRanking.Count != 0) { approximateOptimal = WeightMinimizer .getSmallWeightConfig(featureRanking, this._z3Cache[numberSelectedFeatures], vm); } if (approximateOptimal == null) { return(possibleSolution); } else { return(approximateOptimal); } } else { return(null); } }
public List <BinaryOption> GenerateConfigurationFromBucket(VariabilityModel vm, int numberSelectedFeatures, Dictionary <List <BinaryOption>, int> featureWeight, List <BinaryOption> desiredOptions) { if (_z3Cache == null) { _z3Cache = new Dictionary <int, Z3Cache>(); } List <KeyValuePair <List <BinaryOption>, int> > featureRanking; if (featureWeight != null) { featureRanking = featureWeight.OrderBy(pair => pair.Value).ToList(); } else { featureRanking = new List <KeyValuePair <List <BinaryOption>, int> >(); } List <BoolExpr> variables = null; Dictionary <BoolExpr, BinaryOption> termToOption = null; Microsoft.Z3.Solver solver; if (!this._z3Cache.Keys.Contains(numberSelectedFeatures)) { InitializeZ3Cache(vm, numberSelectedFeatures); } Z3Cache cache = this._z3Cache[numberSelectedFeatures]; solver = cache.GetSolver(); variables = cache.GetVariables(); termToOption = cache.GetTermToOptionMapping(); Dictionary <BinaryOption, BoolExpr> optionToTerm = cache.GetOptionToTermMapping(); Context z3Context = cache.GetContext(); solver.Push(); if (desiredOptions != null) { foreach (BinaryOption binaryOption in desiredOptions) { solver.Add(optionToTerm[binaryOption]); } } // Check if there is still a solution available by finding the first satisfiable configuration if (solver.Check() == Status.SATISFIABLE) { Model model = solver.Model; List <BinaryOption> possibleSolution = RetrieveConfiguration(variables, model, termToOption); // Disable finding a configuration where the least frequent feature/feature combinations are selected // if no featureWeight is given. List <BinaryOption> approximateOptimal = null; if (featureRanking.Count != 0) { approximateOptimal = WeightMinimizer .getSmallWeightConfig(featureRanking, this._z3Cache[numberSelectedFeatures], vm); } solver.Pop(); if (approximateOptimal == null) { return(possibleSolution); } else { return(approximateOptimal); } } else { solver.Pop(); return(null); } }