Ejemplo n.º 1
0
        public void ParseAttributeLine(string line)
        {
            var tokens = line.Split('.');
            var value  = line.Split(',');

            if (!value[0].Contains("Integer"))
            {
                return;
            }
            var nfpVal    = Convert.ToInt32(value[1]);
            var influence = new InfluenceFunction(tokens[0] + " * " + nfpVal);



            //BETTY:
            //F1.Atribute1: Integer[0 to 100],57,0;
            //F1.Atribute0: Integer[0 to 100],4,0;
            //Betty can have multiple Attributes on one Feature
            //Need new InfluenceModel for second Attribute???
            //TODO
            if (!_inflModel.BinaryOptionsInfluence.ContainsKey(_varModel.getBinaryOption(tokens[0])))
            {
                _inflModel.BinaryOptionsInfluence.Add(_varModel.getBinaryOption(tokens[0]), influence);
            }
            //Console.WriteLine(influence.ToString());
        }
Ejemplo n.º 2
0
        public void testTransformVMtoAllBinary()
        {
            VariabilityModel transformed = ConvertUtil.transformVarModelAllbinary(vm);

            Assert.AreEqual(0, transformed.NumericOptions.Count);
            Assert.AreEqual(9, transformed.BinaryOptions.Count);
            Assert.That(transformed.getBinaryOption("testNum_5") != null);
            Assert.That(transformed.BinaryConstraints.Contains("!testNum_0"));
            Assert.That(transformed.getBinaryOption("testNum_5")
                        .Parent.Equals(transformed.getBinaryOption("testNum")));
        }
Ejemplo n.º 3
0
        private void initializeArbitraryBooleanConstraints(Cplex cplex, VariabilityModel vm,
                                                           Dictionary <BinaryOption, INumVar> optsToCplex)
        {
            foreach (string booleanConstraint in vm.BinaryConstraints)
            {
                string[] cnfParts = booleanConstraint.Split('&');

                foreach (string cnfPart in cnfParts)
                {
                    string[]   variables     = cnfPart.Split('|');
                    INumExpr[] logicOrConstr = new INumExpr[variables.Length];

                    for (int i = 0; i < variables.Length; i++)
                    {
                        string var = variables[i].Trim();
                        // In binary domain (1 - x) equals the negation of x
                        if (var.StartsWith("!") || var.StartsWith("-"))
                        {
                            logicOrConstr[i] = cplex.Sum(1, cplex.Negative((optsToCplex[vm.getBinaryOption(var.Substring(1))])));
                        }
                        else
                        {
                            logicOrConstr[i] = optsToCplex[vm.getBinaryOption(var)];
                        }
                    }

                    // Since we use cnf notation, it is enough to check if the sum of a single clause is
                    // greater or equal 1
                    cplex.AddGe(cplex.Sum(logicOrConstr), one);
                }
            }
        }
Ejemplo n.º 4
0
        private static List <List <BinaryOption> > changeModel(VariabilityModel vm, List <List <BinaryOption> > variants)
        {
            List <List <BinaryOption> > toReturn = new List <List <BinaryOption> >();

            foreach (List <BinaryOption> variant in variants)
            {
                List <BinaryOption> variantInRightModel = new List <BinaryOption>();

                foreach (BinaryOption opt in variant)
                {
                    variantInRightModel.Add(vm.getBinaryOption(opt.Name));
                }

                toReturn.Add(variantInRightModel);
            }

            return(toReturn);
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Generates a solver system (in z3: context) based on a variability model. The solver 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>
        /// <param name="randomSeed">The z3 random seed</param>
        /// <returns>The generated constraint system consisting of logical terms representing configuration options as well as their boolean constraints.</returns>
        internal static Tuple <Context, BoolExpr> GetInitializedBooleanSolverSystem(out List <BoolExpr> variables, out Dictionary <BinaryOption, BoolExpr> optionToTerm, out Dictionary <BoolExpr, BinaryOption> termToOption, VariabilityModel vm, bool henard, int randomSeed = 0)
        {
            // Create a context and turn on model generation
            Context context = new Context(new Dictionary <string, string>()
            {
                { "model", "true" }
            });

            // Assign the out-parameters
            variables    = new List <BoolExpr>();
            optionToTerm = new Dictionary <BinaryOption, BoolExpr>();
            termToOption = new Dictionary <BoolExpr, BinaryOption>();

            if (henard)
            {
                // Select different (shuffled) literals for the features
                Random random = new Random(randomSeed);
                List <BinaryOption> randomizedOptions = (from item in vm.BinaryOptions
                                                         orderby random.Next()
                                                         select item).ToList();

                char name = 'A';

                // Read in the binary variables
                foreach (BinaryOption binOpt in randomizedOptions)
                {
                    BoolExpr booleanVariable = GenerateBooleanVariable(context, name.ToString());
                    variables.Add(booleanVariable);
                    optionToTerm.Add(binOpt, booleanVariable);
                    termToOption.Add(booleanVariable, binOpt);

                    if (name == 90)
                    {
                        name = 'a';
                    }
                    else
                    {
                        name++;
                    }
                }
            }
            else
            {
                // Read in the binary variables
                foreach (BinaryOption binOpt in vm.BinaryOptions)
                {
                    BoolExpr booleanVariable = GenerateBooleanVariable(context, binOpt.Name);
                    variables.Add(booleanVariable);
                    optionToTerm.Add(binOpt, booleanVariable);
                    termToOption.Add(booleanVariable, binOpt);
                }
            }

            List <List <ConfigurationOption> > alreadyHandledAlternativeOptions = new List <List <ConfigurationOption> >();

            List <BoolExpr> andGroup = new List <BoolExpr>();

            //Constraints of a single configuration option
            foreach (BinaryOption current in vm.BinaryOptions)
            {
                BoolExpr expr = (BoolExpr)optionToTerm[current];
                if (current.Parent == null || current.Parent == vm.Root)
                {
                    if (current.Optional == false && current.Excluded_Options.Count == 0)
                    {
                        andGroup.Add(expr);
                    }
                }

                if (current.Parent != null && current.Parent != vm.Root)
                {
                    BoolExpr parent = (BoolExpr)optionToTerm[(BinaryOption)current.Parent];
                    andGroup.Add(context.MkImplies(expr, parent));
                    if (current.Optional == false && current.Excluded_Options.Count == 0)
                    {
                        andGroup.Add(context.MkImplies(parent, expr));
                    }
                }

                //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
                        BoolExpr parent = null;
                        if (current.Parent == null)
                        {
                            parent = context.MkTrue();
                        }
                        else
                        {
                            parent = (BoolExpr)optionToTerm[(BinaryOption)current.Parent];
                        }

                        BoolExpr[] terms = new BoolExpr[alternativeOptions.Count + 1];
                        terms[0] = expr;
                        int i = 1;
                        foreach (BinaryOption altEle in alternativeOptions)
                        {
                            BoolExpr temp = (BoolExpr)optionToTerm[altEle];
                            terms[i] = temp;
                            i++;
                        }

                        BoolExpr[] exactlyOneOfN = new BoolExpr[] { context.MkAtMost(terms, 1), context.MkOr(terms) };
                        andGroup.Add(context.MkImplies(parent, context.MkAnd(exactlyOneOfN)));
                        alreadyHandledAlternativeOptions.Add(alternativeOptions);

                        // Go-To label
                        handledAlternative : { }
                    }

                    //Excluded option(s) as cross-tree constraint(s)
                    List <List <ConfigurationOption> > nonAlternative = current.getNonAlternativeExlcudedOptions();
                    if (nonAlternative.Count > 0)
                    {
                        foreach (var excludedOption in nonAlternative)
                        {
                            BoolExpr[] orTerm = new BoolExpr[excludedOption.Count];
                            int        i      = 0;
                            foreach (var opt in excludedOption)
                            {
                                BoolExpr target = (BoolExpr)optionToTerm[(BinaryOption)opt];
                                orTerm[i] = target;
                                i++;
                            }
                            andGroup.Add(context.MkImplies(expr, context.MkNot(context.MkOr(orTerm))));
                        }
                    }
                }
                //Handle implies
                if (current.Implied_Options.Count > 0)
                {
                    foreach (List <ConfigurationOption> impliedOr in current.Implied_Options)
                    {
                        BoolExpr[] orTerms = new BoolExpr[impliedOr.Count];
                        //Possible error: if a binary option implies a numeric option
                        for (int i = 0; i < impliedOr.Count; i++)
                        {
                            orTerms[i] = (BoolExpr)optionToTerm[(BinaryOption)impliedOr.ElementAt(i)];
                        }
                        andGroup.Add(context.MkImplies((BoolExpr)optionToTerm[current], context.MkOr(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('|');
                }

                BoolExpr[] smtTerms = new BoolExpr[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);
                        BoolExpr     boolVar = (BoolExpr)optionToTerm[binOpt];
                        boolVar     = context.MkNot(boolVar);
                        smtTerms[i] = boolVar;
                    }
                    else
                    {
                        BinaryOption binOpt  = vm.getBinaryOption(optName);
                        BoolExpr     boolVar = (BoolExpr)optionToTerm[binOpt];
                        smtTerms[i] = boolVar;
                    }


                    i++;
                }
                if (and)
                {
                    andGroup.Add(context.MkAnd(smtTerms));
                }
                else
                {
                    andGroup.Add(context.MkOr(smtTerms));
                }
            }

            if (henard)
            {
                lastConstraints = andGroup;
            }

            BoolExpr generalConstraint = context.MkAnd(andGroup.ToArray());

            return(new Tuple <Context, BoolExpr>(context, generalConstraint));
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Generates a solver system (in z3: context) based on a variability model. The solver system can be used to check for satisfiability of configurations as well as optimization.
        /// Additionally to <see cref="Z3Solver.GetInitializedBooleanSolverSystem(out List{BoolExpr}, out Dictionary{BinaryOption, BoolExpr}, out Dictionary{BoolExpr, BinaryOption}, VariabilityModel, bool, int)"/>, this method supports numeric features.
        /// Note that we do not support Henard's randomized approach here, because it is defined only on boolean constraints.
        /// </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>
        /// <param name="randomSeed">The z3 random seed</param>
        /// <returns>The generated constraint system consisting of logical terms representing configuration options as well as their constraints.</returns>
        internal static Tuple <Context, BoolExpr> GetInitializedSolverSystem(out List <Expr> variables, out Dictionary <ConfigurationOption, Expr> optionToTerm, out Dictionary <Expr, ConfigurationOption> termToOption, VariabilityModel vm, int randomSeed = 0)
        {
            // Create a context and turn on model generation
            Context context = new Context(new Dictionary <string, string>()
            {
                { "model", "true" }
            });

            // Assign the out-parameters
            variables    = new List <Expr>();
            optionToTerm = new Dictionary <ConfigurationOption, Expr>();
            termToOption = new Dictionary <Expr, ConfigurationOption>();

            // Create the binary configuration options
            foreach (BinaryOption binOpt in vm.BinaryOptions)
            {
                BoolExpr booleanVariable = GenerateBooleanVariable(context, binOpt.Name);
                variables.Add(booleanVariable);
                optionToTerm.Add(binOpt, booleanVariable);
                termToOption.Add(booleanVariable, binOpt);
            }

            // Create the numeric configuration options
            foreach (NumericOption numOpt in vm.NumericOptions)
            {
                Expr numericVariable = GenerateDoubleVariable(context, numOpt.Name);
                variables.Add(numericVariable);
                optionToTerm.Add(numOpt, numericVariable);
                termToOption.Add(numericVariable, numOpt);
            }

            // Initialize variables for constraint parsing
            List <List <ConfigurationOption> > alreadyHandledAlternativeOptions = new List <List <ConfigurationOption> >();

            List <BoolExpr> andGroup = new List <BoolExpr>();

            // Parse the constraints of the binary (boolean) configuration options
            foreach (BinaryOption current in vm.BinaryOptions)
            {
                BoolExpr expr = (BoolExpr)optionToTerm[current];
                if (current.Parent == null || current.Parent == vm.Root)
                {
                    if (current.Optional == false && current.Excluded_Options.Count == 0)
                    {
                        andGroup.Add(expr);
                    }
                }

                if (current.Parent != null && current.Parent != vm.Root)
                {
                    BoolExpr parent = (BoolExpr)optionToTerm[(BinaryOption)current.Parent];
                    andGroup.Add(context.MkImplies(expr, parent));
                    if (current.Optional == false && current.Excluded_Options.Count == 0)
                    {
                        andGroup.Add(context.MkImplies(parent, expr));
                    }
                }

                // 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 (List <ConfigurationOption> alternativeGroup in alreadyHandledAlternativeOptions)
                        {
                            foreach (ConfigurationOption alternative in alternativeGroup)
                            {
                                if (current == alternative)
                                {
                                    goto handledAlternative;
                                }
                            }
                        }

                        // It is not allowed that an alternative group has no parent element
                        BoolExpr parent = null;
                        if (current.Parent == null)
                        {
                            parent = context.MkTrue();
                        }
                        else
                        {
                            parent = (BoolExpr)optionToTerm[(BinaryOption)current.Parent];
                        }

                        BoolExpr[] terms = new BoolExpr[alternativeOptions.Count + 1];
                        terms[0] = expr;
                        int i = 1;
                        foreach (BinaryOption altEle in alternativeOptions)
                        {
                            BoolExpr temp = (BoolExpr)optionToTerm[altEle];
                            terms[i] = temp;
                            i++;
                        }

                        BoolExpr[] exactlyOneOfN = new BoolExpr[] { context.MkAtMost(terms, 1), context.MkOr(terms) };
                        andGroup.Add(context.MkImplies(parent, context.MkAnd(exactlyOneOfN)));
                        alreadyHandledAlternativeOptions.Add(alternativeOptions);

                        // Go-To label
                        handledAlternative : { }
                    }

                    // Excluded option(s) as cross-tree constraint(s)
                    List <List <ConfigurationOption> > nonAlternative = current.getNonAlternativeExlcudedOptions();
                    if (nonAlternative.Count > 0)
                    {
                        foreach (var excludedOption in nonAlternative)
                        {
                            BoolExpr[] orTerm = new BoolExpr[excludedOption.Count];
                            int        i      = 0;
                            foreach (var opt in excludedOption)
                            {
                                BoolExpr target = (BoolExpr)optionToTerm[(BinaryOption)opt];
                                orTerm[i] = target;
                                i++;
                            }
                            andGroup.Add(context.MkImplies(expr, context.MkNot(context.MkOr(orTerm))));
                        }
                    }
                }
                // Handle implies
                if (current.Implied_Options.Count > 0)
                {
                    foreach (List <ConfigurationOption> impliedOr in current.Implied_Options)
                    {
                        BoolExpr[] orTerms = new BoolExpr[impliedOr.Count];
                        // Possible error: if a binary option implies a numeric option
                        for (int i = 0; i < impliedOr.Count; i++)
                        {
                            orTerms[i] = (BoolExpr)optionToTerm[(BinaryOption)impliedOr.ElementAt(i)];
                        }
                        andGroup.Add(context.MkImplies((BoolExpr)optionToTerm[current], context.MkOr(orTerms)));
                    }
                }
            }

            // Parse the constraints (ranges, step) of the numeric features
            foreach (NumericOption numOpt in vm.NumericOptions)
            {
                Expr            numExpression    = optionToTerm[numOpt];
                List <double>   allValues        = numOpt.getAllValues();
                List <BoolExpr> valueExpressions = new List <BoolExpr>();
                foreach (double value in allValues)
                {
                    FPNum fpNum = context.MkFPNumeral(value, context.MkFPSortDouble());
                    if (!numericLookUpTable.ContainsKey(fpNum.ToString()))
                    {
                        numericLookUpTable.Add(fpNum.ToString(), value);
                    }
                    valueExpressions.Add(context.MkEq(numExpression, fpNum));
                }
                andGroup.Add(context.MkOr(valueExpressions.ToArray()));
            }


            // Parse the boolean cross-tree constraints
            foreach (string constraint in vm.BinaryConstraints)
            {
                bool     and = false;
                string[] terms;
                if (constraint.Contains("&"))
                {
                    and   = true;
                    terms = constraint.Split('&');
                }
                else
                {
                    terms = constraint.Split('|');
                }

                BoolExpr[] smtTerms = new BoolExpr[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);
                        BoolExpr     boolVar = (BoolExpr)optionToTerm[binOpt];
                        boolVar     = context.MkNot(boolVar);
                        smtTerms[i] = boolVar;
                    }
                    else
                    {
                        BinaryOption binOpt  = vm.getBinaryOption(optName);
                        BoolExpr     boolVar = (BoolExpr)optionToTerm[binOpt];
                        smtTerms[i] = boolVar;
                    }


                    i++;
                }
                if (and)
                {
                    andGroup.Add(context.MkAnd(smtTerms));
                }
                else
                {
                    andGroup.Add(context.MkOr(smtTerms));
                }
            }

            // Parse the non-boolean constraints
            Dictionary <BinaryOption, Expr> optionMapping = new Dictionary <BinaryOption, Expr>();

            if (vm.NonBooleanConstraints.Count > 0)
            {
                foreach (NonBooleanConstraint nonBooleanConstraint in vm.NonBooleanConstraints)
                {
                    andGroup.Add(ProcessMixedConstraint(nonBooleanConstraint, optionMapping, context, optionToTerm));
                }
            }

            // Parse the mixed constraints
            // Note that this step is currently omitted due to critical performance issues.
            // Therefore, we check whether the mixed constraints are satisfied after finding the configuration.
            //if (vm.MixedConstraints.Count > 0)
            //{

            //foreach (MixedConstraint constr in vm.MixedConstraints)
            //{
            //    andGroup.Add(ProcessMixedConstraint(constr, optionMapping, context, optionToTerm));
            //}
            //}



            // Return the initialized system
            BoolExpr generalConstraint = context.MkAnd(andGroup.ToArray());

            return(new Tuple <Context, BoolExpr>(context, generalConstraint));
        }
Ejemplo n.º 7
0
        /// <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);
        }
Ejemplo n.º 8
0
        /// <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);
        }