/// <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); }
private void ReAssertDecisionAssumptions() { _solver.Pop(); _solver.Push(); foreach (Assumption assumption in _decisionAssumptions.Values) { AssertValueAssumption(assumption); } }
/// <summary> /// Generates all valid combinations of all configuration options in the given model. /// </summary> /// <param name="vm">the variability model containing the binary options and their constraints</param> /// <param name="optionsToConsider">the options that should be considered. All other options are ignored</param> /// <returns>Returns a list of <see cref="Configuration"/></returns> public List <Configuration> GenerateAllVariants(VariabilityModel vm, List <ConfigurationOption> optionsToConsider) { List <Configuration> allConfigurations = new List <Configuration>(); List <BoolExpr> variables; Dictionary <BoolExpr, BinaryOption> termToOption; Dictionary <BinaryOption, BoolExpr> optionToTerm; Tuple <Context, BoolExpr> z3Tuple = Z3Solver.GetInitializedBooleanSolverSystem(out variables, out optionToTerm, out termToOption, vm, this.henard); Context z3Context = z3Tuple.Item1; BoolExpr z3Constraints = z3Tuple.Item2; Microsoft.Z3.Solver 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); while (solver.Check() == Status.SATISFIABLE) { Model model = solver.Model; List <BinaryOption> binOpts = RetrieveConfiguration(variables, model, termToOption, optionsToConsider); Configuration c = new Configuration(binOpts); // Check if the non-boolean constraints are satisfied if (vm.configurationIsValid(c) && !VariantGenerator.IsInConfigurationFile(c, allConfigurations) && VariantGenerator.FulfillsMixedConstraints(c, vm)) { allConfigurations.Add(c); } solver.Push(); solver.Assert(Z3Solver.NegateExpr(z3Context, Z3Solver.ConvertConfiguration(z3Context, binOpts, optionToTerm, vm))); } solver.Push(); solver.Pop(Convert.ToUInt32(allConfigurations.Count() + 1)); return(allConfigurations); }
/// <summary> /// Generates all valid combinations of all configuration options in the given model. /// </summary> /// <param name="vm">the variability model containing the binary options and their constraints</param> /// <param name="optionsToConsider">the options that should be considered. All other options are ignored</param> /// <returns>Returns a list of <see cref="Configuration"/></returns> public List <Configuration> GenerateAllVariants(VariabilityModel vm, List <ConfigurationOption> optionsToConsider) { List <Configuration> allConfigurations = new List <Configuration>(); List <Expr> variables; Dictionary <Expr, ConfigurationOption> termToOption; Dictionary <ConfigurationOption, Expr> optionToTerm; Tuple <Context, BoolExpr> z3Tuple = Z3Solver.GetInitializedSolverSystem(out variables, out optionToTerm, out termToOption, vm); Context z3Context = z3Tuple.Item1; BoolExpr z3Constraints = z3Tuple.Item2; Microsoft.Z3.Solver solver = z3Context.MkSolver(); solver.Set(RANDOM_SEED, z3RandomSeed); solver.Assert(z3Constraints); while (solver.Check() == Status.SATISFIABLE) { Model model = solver.Model; Tuple <List <BinaryOption>, Dictionary <NumericOption, double> > confOpts = RetrieveConfiguration(variables, model, termToOption, optionsToConsider); Configuration c = new Configuration(confOpts.Item1, confOpts.Item2); // Check if the non-boolean constraints are satisfied bool configIsValid = vm.configurationIsValid(c); bool isInConfigurationFile = !VariantGenerator.IsInConfigurationFile(c, allConfigurations); bool fulfillsMixedConstraintrs = VariantGenerator.FulfillsMixedConstraints(c, vm); if (configIsValid && isInConfigurationFile && fulfillsMixedConstraintrs) { allConfigurations.Add(c); } solver.Push(); solver.Assert(Z3Solver.NegateExpr(z3Context, Z3Solver.ConvertConfiguration(z3Context, confOpts.Item1, optionToTerm, vm, numericValues: confOpts.Item2))); } solver.Push(); solver.Pop(Convert.ToUInt32(allConfigurations.Count() + 1)); return(allConfigurations); }
// Constructor public SolverContext(Modelling.BLOs.Model model) { // Create an empty z3 context Dictionary <string, string> configSettings = new Dictionary <string, string>(); configSettings["MODEL"] = "true"; configSettings["MACRO_FINDER"] = "true"; _context = new Context(configSettings); _context.PrintMode = Z3_ast_print_mode.Z3_PRINT_SMTLIB2_COMPLIANT; // Setup the z3 context and solver _solver = _context.MkSolver(); // Setup custom conversion method BoolToInt (boolean -> integer) FuncDecl boolToInt = _context.MkFuncDecl("BoolToInt", _context.MkBoolSort(), _context.MkIntSort()); Expr i = _context.MkConst("i", _context.MkBoolSort()); Expr fDef = _context.MkITE(_context.MkEq(i, _context.MkTrue()), _context.MkInt(1), _context.MkInt(0)); // x == true => 1, x == false => 0 Expr fStatement = _context.MkForall(new Expr[] { i }, _context.MkEq(_context.MkApp(boolToInt, i), fDef)); _solver.Assert(fStatement as BoolExpr); _functions.Add("BoolToInt", new Function(boolToInt)); // Create the static part (constants and constraints) model.Features.ForEach(feature => { string featureSID = GenerateFeatureSID(feature.Identifier); AddFeature_Constant(feature.Identifier); feature.Attributes.ForEach(attribute => AddAttribute_Constant(attribute.Identifier, feature.Identifier, attribute.AttributeDataType)); }); model.Relations.ForEach(relation => { AddRelation_Constraint(relation.RelationType, relation.ParentFeature.Identifier, relation.ChildFeature.Identifier); }); model.GroupRelations.ForEach(groupRelation => { string[] childFeatureIDs = groupRelation.ChildFeatures.Select(feature => feature.Identifier).ToArray(); AddGroupRelation_Constraint(groupRelation.GroupRelationType, groupRelation.ParentFeature.Identifier, childFeatureIDs, groupRelation.UpperBound ?? default(int), groupRelation.LowerBound ?? default(int)); }); model.CompositionRules.ForEach(compRule => { AddCompositionRule_Constraint(compRule.CompositionRuleType, compRule.FirstFeature.Identifier, compRule.SecondFeature.Identifier); }); // Create initial point _solver.Push(); }
/// <summary> /// Demonstrate how to use <code>Push</code>and <code>Pop</code>to /// control the size of models. /// </summary> /// <remarks>Note: this test is specialized to 32-bit bitvectors.</remarks> public static void CheckSmall(Context ctx, Solver solver, BitVecExpr[] to_minimize) { Sort bv32 = ctx.MkBitVecSort(32); int num_Exprs = to_minimize.Length; UInt32[] upper = new UInt32[num_Exprs]; UInt32[] lower = new UInt32[num_Exprs]; BitVecExpr[] values = new BitVecExpr[num_Exprs]; for (int i = 0; i < upper.Length; ++i) { upper[i] = UInt32.MaxValue; lower[i] = 0; } bool some_work = true; int last_index = -1; UInt32 last_upper = 0; while (some_work) { solver.Push(); bool check_is_sat = true; while (check_is_sat && some_work) { // Assert all feasible bounds. for (int i = 0; i < num_Exprs; ++i) { solver.Assert(ctx.MkBVULE(to_minimize[i], ctx.MkBV(upper[i], 32))); } check_is_sat = Status.SATISFIABLE == solver.Check(); if (!check_is_sat) { if (last_index != -1) { lower[last_index] = last_upper + 1; } break; } Console.WriteLine("{0}", solver.Model); // narrow the bounds based on the current model. for (int i = 0; i < num_Exprs; ++i) { Expr v = solver.Model.Evaluate(to_minimize[i]); UInt64 ui = ((BitVecNum)v).UInt64; if (ui < upper[i]) { upper[i] = (UInt32)ui; } Console.WriteLine("{0} {1} {2}", i, lower[i], upper[i]); } // find a new bound to add some_work = false; last_index = 0; for (int i = 0; i < num_Exprs; ++i) { if (lower[i] < upper[i]) { last_upper = (upper[i] + lower[i]) / 2; last_index = i; solver.Assert(ctx.MkBVULE(to_minimize[i], ctx.MkBV(last_upper, 32))); some_work = true; break; } } } solver.Pop(); } }
/// <summary> /// Generates up to n solutions of the given variability model. /// Note that this method could also generate less than n solutions if the variability model does not contain sufficient solutions. /// Moreover, in the case that <code>n < 0</code>, all solutions are generated. /// </summary> /// <param name="vm">The <see cref="VariabilityModel"/> to obtain solutions for.</param> /// <param name="n">The number of solutions to obtain.</param> /// <returns>A list of configurations, in which a configuration is a list of SELECTED binary options.</returns> public List <List <BinaryOption> > GenerateUpToNFast(VariabilityModel vm, int n) { // Use the random seed to produce new random seeds Random random = new Random(Convert.ToInt32(z3RandomSeed)); List <BoolExpr> variables; Dictionary <BoolExpr, BinaryOption> termToOption; Dictionary <BinaryOption, BoolExpr> optionToTerm; Tuple <Context, BoolExpr> z3Tuple = Z3Solver.GetInitializedBooleanSolverSystem(out variables, out optionToTerm, out termToOption, vm, this.henard, random.Next()); Context z3Context = z3Tuple.Item1; BoolExpr z3Constraints = z3Tuple.Item2; List <BoolExpr> excludedConfigurations = new List <BoolExpr>(); List <BoolExpr> constraints = Z3Solver.lastConstraints; List <List <BinaryOption> > configurations = new List <List <BinaryOption> >(); Microsoft.Z3.Solver s = z3Context.MkSolver(); // TODO: The following line works for z3Solver version >= 4.6.0 //solver.Set (RANDOM_SEED, z3RandomSeed); Params solverParameter = z3Context.MkParams(); if (henard) { solverParameter.Add(RANDOM_SEED, NextUInt(random)); } else { solverParameter.Add(RANDOM_SEED, z3RandomSeed); } s.Parameters = solverParameter; s.Assert(z3Constraints); s.Push(); Model model = null; while (s.Check() == Status.SATISFIABLE && (configurations.Count < n || n < 0)) { model = s.Model; List <BinaryOption> config = RetrieveConfiguration(variables, model, termToOption); configurations.Add(config); if (henard) { BoolExpr newConstraint = Z3Solver.NegateExpr(z3Context, Z3Solver.ConvertConfiguration(z3Context, config, optionToTerm, vm)); excludedConfigurations.Add(newConstraint); Dictionary <BoolExpr, BinaryOption> oldTermToOption = termToOption; // Now, initialize a new one for the next configuration z3Tuple = Z3Solver.GetInitializedBooleanSolverSystem(out variables, out optionToTerm, out termToOption, vm, this.henard, random.Next()); z3Context = z3Tuple.Item1; z3Constraints = z3Tuple.Item2; s = z3Context.MkSolver(); //s.Set (RANDOM_SEED, NextUInt (random)); solverParameter = z3Context.MkParams(); solverParameter.Add(RANDOM_SEED, NextUInt(random)); s.Parameters = solverParameter; constraints = Z3Solver.lastConstraints; excludedConfigurations = Z3Solver.ConvertConstraintsToNewContext(oldTermToOption, optionToTerm, excludedConfigurations, z3Context); constraints.AddRange(excludedConfigurations); s.Assert(z3Context.MkAnd(Z3Solver.Shuffle(constraints, new Random(random.Next())))); s.Push(); } else { s.Add(Z3Solver.NegateExpr(z3Context, Z3Solver.ConvertConfiguration(z3Context, config, optionToTerm, vm))); } } return(configurations); }