/// <summary> /// This algorithm calls for each binary option in the variability model the CSP solver to generate a valid, minimal configuration containing that option. /// </summary> /// <param name="vm">The variability model for which the feature-wise configurations should be generated.</param> /// <returns>A list of configurations, in which each configuration is a list of binary options that represent the SELECTED options.</returns> public List<List<BinaryOption>> generateFeatureWiseConfigsCSP(VariabilityModel vm) { this.configurations.Clear(); Solver.VariantGenerator generator = new Solver.VariantGenerator(null); foreach (var opt in vm.BinaryOptions) { if (opt == vm.Root) continue; List<BinaryOption> temp = new List<BinaryOption>(); temp.Add(opt); temp = generator.minimizeConfig(temp, vm, true, null); if (temp != null && Configuration.containsBinaryConfiguration(this.configurations, temp) == false) this.configurations.Add(temp); //Now finding a configuration without the current option, but with all other options to be able to compute a delta List<BinaryOption> withoutOpt = new List<BinaryOption>(); BinaryOption[] tempArray = temp.ToArray(); withoutOpt = tempArray.ToList<BinaryOption>(); withoutOpt.Remove(opt); List<BinaryOption> excluded = new List<BinaryOption>(); excluded.Add(opt); withoutOpt = generator.minimizeConfig(withoutOpt, vm, true, excluded); if (withoutOpt != null && Configuration.containsBinaryConfiguration(this.configurations, withoutOpt) == false) this.configurations.Add(withoutOpt); } return this.configurations; }
/// <summary> /// This method returns a list of all configurations stored in a given file. All options of the configurations have to be defined in the variability model. /// /// The file should be structured as follows: /// /// <![CDATA[ <results> ]]> /// <![CDATA[ <row> ]]> /// <![CDATA[ <data column="Configuration"> ]]> /// <![CDATA[ binaryOption1, binaryOption3,... ]]> /// <![CDATA[ </data> ]]> /// <![CDATA[ <data column="Variable Features"> ]]> /// <![CDATA[ numOption1;64,numOption2;4 ]]> /// <![CDATA[ </data> ]]> /// <![CDATA[ <data column="Performance"> ]]> /// <![CDATA[ 21.178 ]]> /// <![CDATA[ </data> ]]> /// <![CDATA[ <data column="Footprint"> ]]> /// <![CDATA[ 1679 ]]> /// <![CDATA[ </data> ]]> /// <![CDATA[ </row> ]]> /// <![CDATA[ <row> ]]> /// <![CDATA[ <data column="Configuration"> ]]> /// <![CDATA[ .... ]]> /// <![CDATA[ <results> ]]> /// /// /// </summary> /// <param name="dat">Object representing the configuration file.</param> /// <param name="model">Variability model of the configurations.</param> /// <returns></returns> public static List <Configuration> readConfigurations(string file, VariabilityModel model) { XmlDocument dat = new System.Xml.XmlDocument(); dat.Load(file); return(readConfigurations(dat, model)); }
/// <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="vm">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; }
/// <summary> /// Creates a new mixed constraint between boolean and numeric options and literals. /// </summary> /// <param name="unparsedExpr">The expression of the constraint as string.</param> /// <param name="varMod">The variability model the constraint applies to.</param> /// <param name="requirement">String indicating if the constraints evaluates to /// to false if not all options are present.</param> /// <param name="exprKind">Value indicating if the the expression will be negated.</param> public MixedConstraint(String unparsedExpr, VariabilityModel varMod, string requirement, string exprKind = "pos") : base(unparsedExpr, varMod) { if (requirement.Trim().ToLower().Equals(REQUIRE_ALL)) { this.requirement = REQUIRE_ALL; } else if (requirement.Trim().ToLower().Equals(REQUIRE_NONE)) { this.requirement = REQUIRE_NONE; } else { throw new ArgumentException(String.Format("The tag {0} for mixed requirements is not valid.", requirement)); } if (exprKind.Trim().ToLower().Equals(NEGATIVE)) { this.negativeOrPositiveExpr = NEGATIVE; } else if (exprKind.Trim().ToLower().Equals(POSITIVE)) { this.negativeOrPositiveExpr = POSITIVE; } else { throw new ArgumentException(String.Format("The expression kind {0} is not valid. Expression can either be neg or pos.", exprKind)); } }
/// <summary> /// Creates a new mixed constraint between boolean and numeric options and literals. /// </summary> /// <param name="unparsedExpr">The expression of the constraint as string.</param> /// <param name="varMod">The variability model the constraint applies to.</param> /// <param name="requirement">String indicating if the constraints evaluates to /// to false if not all options are present.</param> /// <param name="exprKind">Value indicating if the the expression will be negated.</param> public MixedConstraint(String unparsedExpr, VariabilityModel varMod, string requirement, string exprKind = "pos") : base(unparsedExpr, varMod) { if (requirement.Trim().ToLower().Equals(REQUIRE_ALL)) { this.requirement = REQUIRE_ALL; } else if (requirement.Trim().ToLower().Equals(REQUIRE_NONE)) { this.requirement = REQUIRE_NONE; } else { throw new ArgumentException(String.Format("The tag {0} for mixed requirements is not valid.", requirement)); } if (exprKind.Trim().ToLower().Equals(NEGATIVE)) { this.negativeOrPositiveExpr = NEGATIVE; } else if (exprKind.Trim().ToLower().Equals(POSITIVE)) { this.negativeOrPositiveExpr = POSITIVE; } else { throw new ArgumentException(String.Format("The expression kind {0} is not valid. Expression can either be neg or pos.", exprKind)); } String[] parts = base.ToString().Split(new string[] { ">", "<", "=", "<=", ">=" }, StringSplitOptions.None); leftHandSide = new InfluenceFunction(parts[0], varMod); rightHandSide = new InfluenceFunction(parts[parts.Length - 1], varMod); var = varMod; }
private VariabilityModel extractFeatureModelFromExpression(String expression) { VariabilityModel varModel = new VariabilityModel("TEMP"); string[] parts = expression.Split(new char[] { '+', '*', '[', ']' }); double value = 0.0; for (int i = 0; i < parts.Length; i++) { string part = parts[i].Trim(); if (part.Length > 0) { if (!Double.TryParse(part, out value)) { if (varModel.getNumericOption(part) == null) { NumericOption option = new NumericOption(varModel, part); varModel.addConfigurationOption(option); } } } } return(varModel); }
/// <summary> /// Creates a binary option based on the information stored in the xml node. The binary option is assigned to the variability model. /// </summary> /// <param name="node">Node of the xml file holding the information of the binary option.</param> /// <param name="vm">The variabilit model the binary option is assigned to. </param> /// <returns>A binary option of the variabilit model with the information stored in the xml node.</returns> public static BinaryOption loadFromXML(XmlElement node, VariabilityModel vm) { BinaryOption option = new BinaryOption(vm, "temp"); option.loadFromXML(node); return(option); }
/// <summary> /// Creates a new NonBooleanConstraint for a expression. The expression have to consist binary and numeric options and operators such as "+,*,>=,<=,>,<, and =" only. /// Where all binary and numeric options have to be defined in the variability model. /// </summary> /// <param name="unparsedExpression"></param> /// <param name="varModel"></param> public NonBooleanConstraint(String unparsedExpression, VariabilityModel varModel) { if (unparsedExpression.Contains(">=")) { comparator = ">="; } else if (unparsedExpression.Contains("<=")) { comparator = "<="; } else if (unparsedExpression.Contains("=")) { comparator = "="; } else if (unparsedExpression.Contains(">")) { comparator = ">"; } else if (unparsedExpression.Contains("<")) { comparator = "<"; } String[] parts = unparsedExpression.Split(comparator.ToCharArray()); leftHandSide = new InfluenceFunction(parts[0], varModel); rightHandSide = new InfluenceFunction(parts[parts.Length-1], varModel); }
/// <summary> /// Creates a numeric option based on the information of the given XML Node (calls base function) /// </summary> /// <param name="numOptNode">The XML Element containing the information</param> /// <param name="variabilityModel">The variability model to which the option belongs to</param> /// <returns>The newly created option</returns> internal static ConfigurationOption loadFromXML(XmlElement numOptNode, VariabilityModel variabilityModel) { NumericOption numOpt = new NumericOption(variabilityModel, "temp"); numOpt.loadFromXML(numOptNode); return(numOpt); }
/// <summary> /// Creates a new NonBooleanConstraint for a expression. The expression have to consist binary and numeric options and operators such as +, *, <=, <, >=, >, and = only. /// Where all binary and numeric options have to be defined in the variability model. /// </summary> /// <param name="unparsedExpression"></param> /// <param name="varModel"></param> public NonBooleanConstraint(String unparsedExpression, VariabilityModel varModel) { if (unparsedExpression.Contains(">=")) { comparator = ">="; } else if (unparsedExpression.Contains("<=")) { comparator = "<="; } else if (unparsedExpression.Contains("=")) { comparator = "="; } else if (unparsedExpression.Contains(">")) { comparator = ">"; } else if (unparsedExpression.Contains("<")) { comparator = "<"; } String[] parts = unparsedExpression.Split(comparator.ToCharArray()); leftHandSide = new InfluenceFunction(parts[0], varModel); rightHandSide = new InfluenceFunction(parts[parts.Length - 1], varModel); }
/// <summary> /// This method returns a list of all configurations stored in a given file. All options of the configurations have to be defined in the variability model. /// /// If the file is a xml file, it should be structured as follows: /// /// <![CDATA[ <results> ]]> /// <![CDATA[ <row> ]]> /// <![CDATA[ <data column="Configuration"> ]]> /// <![CDATA[ binaryOption1, binaryOption3,... ]]> /// <![CDATA[ </data> ]]> /// <![CDATA[ <data column="Variable Features"> ]]> /// <![CDATA[ numOption1;64,numOption2;4 ]]> /// <![CDATA[ </data> ]]> /// <![CDATA[ <data column="Performance"> ]]> /// <![CDATA[ 21.178 ]]> /// <![CDATA[ </data> ]]> /// <![CDATA[ <data column="Footprint"> ]]> /// <![CDATA[ 1679 ]]> /// <![CDATA[ </data> ]]> /// <![CDATA[ </row> ]]> /// <![CDATA[ <row> ]]> /// <![CDATA[ <data column="Configuration"> ]]> /// <![CDATA[ .... ]]> /// <![CDATA[ <results> ]]> /// /// /// If the file is a csv file, two different formats are supported. /// /// For the first on, the file should have a header: /// /// binaryOption1;numOption1;binaryOption2;numOption2;Performance;Footprint /// true;64;false;4;21.178;1679 /// /// Note: If a binary option is selected in a configuration, the value can either be "true" or "1". /// /// In the second format, no header is needed and only binary options are supported. Additionally, the measurements have to consider only one non-functional property. /// /// </summary> /// <param name="file">Full qualified file name.</param> /// <param name="model">Variability model of the configurations.</param> /// <returns></returns> public static List <Configuration> readConfigurations(string file, VariabilityModel model) { if (file.EndsWith(".xml")) { XmlDocument dat = new System.Xml.XmlDocument(); try { dat.Load(file); } catch (FileNotFoundException) { GlobalState.logError.logLine("Configuration file \"" + file + "\" coud not be found." + " Could not read configurations."); return(null); } catch (XmlException xmlExc) { GlobalState.logError.logLine("Configuration file \"" + file + "\" has invalid xml format." + " Could not read configurations. Additional information:" + xmlExc.Message); return(null); } return(readConfigurations(dat, model)); } else { return(readCSV(file, model)); } }
/// <summary> /// Generates configurations based on the feature-wise heuristic: The method utilizes the structure of the variability model by first determining the set of options that are always selected. /// In each iteration, it starts from this set of options (partial configuration) and adds a single option to this partial configurations. /// It then checks whether configuration is valid and if not calls a CSP solver to make this configuration valid with as few selected options as possible. /// </summary> /// <param name="vm">The variability model for which the feature-wise configurations should be generated.</param> /// <returns>A list of configurations, in which each configuration is a list of binary options that represent the SELECTED options.</returns> public List<List<BinaryOption>> generateFeatureWiseConfigurations(VariabilityModel vm) { configurations.Clear(); List<BinaryOption> optionalFirstLevelElements = new List<BinaryOption>(); List<BinaryOption> binOptions = vm.BinaryOptions; //First: Add options that are present in all configurations List<BinaryOption> firstLevelMandatoryFeatures = new List<BinaryOption>(); foreach (BinaryOption binOpt in binOptions) { if (binOpt.Parent == null || binOpt.Parent == vm.Root) { if (!binOpt.Optional) { if (!binOpt.hasAlternatives()) { firstLevelMandatoryFeatures.Add(binOpt); //Todo: Recursive down search /*List<BinaryOption> tmpList = (List<BinaryOption>)vm.getMandatoryChildsRecursive(binOpt); if (tmpList != null && tmpList.Count > 0) firstLevelMandatoryFeatures.AddRange(tmpList);*/ } } else optionalFirstLevelElements.Add(binOpt); } } Solver.CheckConfigSAT checkSAT = new Solver.CheckConfigSAT(null); Solver.VariantGenerator generator = new Solver.VariantGenerator(null); //Generating new configurations: one per option if (checkSAT.checkConfigurationSAT(firstLevelMandatoryFeatures, vm, false)) this.configurations.Add(firstLevelMandatoryFeatures); foreach (BinaryOption e in binOptions) { BinaryOption[] temp = new BinaryOption[firstLevelMandatoryFeatures.Count]; firstLevelMandatoryFeatures.CopyTo(temp); List<BinaryOption> tme = temp.ToList<BinaryOption>(); if (!tme.Contains(e)) { tme.Add(e); if (checkSAT.checkConfigurationSAT(tme, vm, false)) { if (!this.configurations.Contains(tme)) this.configurations.Add(tme); } else { tme = generator.minimizeConfig(tme, vm, true, null); if (tme != null && Configuration.containsBinaryConfiguration(this.configurations, tme) == false) this.configurations.Add(tme); } } else continue; } return this.configurations; }
//Two formats are possible: with header and 0,1s for binary selection or no header and giving the names of config options per per line (this excludex numeric options) private static List <Configuration> readCSV(string file, VariabilityModel model) { StreamReader sr; try { sr = new StreamReader(file); } catch (ArgumentException) { GlobalState.logError.logLine("Loading a configuration file with empty filename \"\" is not possible." + " The \"all\" command requires an argument."); return(null); } catch (FileNotFoundException) { GlobalState.logError.logLine("Configuration file \"" + file + "\" does not exist." + " Could not read the configuration file."); return(null); } String line1, line2; if (!sr.EndOfStream) { line1 = sr.ReadLine(); } else { return(null); } if (!sr.EndOfStream) { line2 = sr.ReadLine(); } else { return(null); } sr.Close(); var l1 = line1.Split(';'); var l2 = line2.Split(';'); if (l1.Length < 2 || l2.Length < 2) { return(null); } int d = 0; if (int.TryParse(l2[0], out d)) { return(readConfigurations_Header_CSV(file, model)); } else { return(readCSVBinaryOptFormat(file, model)); } }
/// <summary> /// Clears the global state. This mehtod should be used after performing all experiments of one case study. /// </summary> public static void clear() { varModel = null; currentNFP = null; allMeasurements = new ResultDB(); evaluationSet = new ResultDB(); nfProperties = new Dictionary <string, NFProperty>(); optionOrder = new List <ConfigurationOption>(); }
/// <summary> /// Clears the global state. This mehtod should be used after performing all experiments of one case study. /// </summary> public static void clear() { varModel = null; currentNFP = null; allMeasurements = new ResultDB(); evalutionSet = new ResultDB(); infModel = null; nfProperties = new Dictionary <string, NFProperty>(); }
/// <summary> /// Generates a configuration for each pair of configuration options. Exceptions: parent-child-relationships, impliciation-relationships /// </summary> /// <param name="vm">The variability model containing the binary options for which we want to generate the pair-wise configurations.</param> /// <returns>A list of configurations in which each configuration is represented by a list of SELECTED binary options</returns> public List<List<BinaryOption>> generatePairWiseVariants(VariabilityModel vm) { //List<String> activeLearning = new List<string>(new string[] { "ls", "inl", "cf", "dcr", "saa", "ive", "wlur", "lir", "vp", "saacyc" }); this.configurations.Clear(); List<BinaryOption> measuredElements = new List<BinaryOption>(); foreach (BinaryOption current in vm.BinaryOptions) { //if (!activeLearning.Contains(current.Name)) // continue; measuredElements.Add(current); foreach (BinaryOption pair in vm.BinaryOptions) { //if (!activeLearning.Contains(pair.Name)) // continue; //Check parent-child relationship if (pair.isAncestor(current) || current.isAncestor(pair) || pair == current) continue; //Check if one option implies the presence of the other option bool impliedOption = false; foreach (var implied in pair.Implied_Options) { if (implied.Count == 1 && implied[0] == current) { impliedOption = true; break; } } if (impliedOption) continue; //vice versa foreach (var implied in current.Implied_Options) { if (implied.Count == 1 && implied[0] == pair) { impliedOption = true; break; } } if (impliedOption) continue; if (pair != current && !measuredElements.Contains(pair)) { List<BinaryOption> tempConfig = new List<BinaryOption>(); tempConfig.Add(current); tempConfig.Add(pair); tempConfig = generator.minimizeConfig(tempConfig, vm, true, null); if (tempConfig.Count > 0 && !Configuration.containsBinaryConfiguration(configurations,tempConfig)) configurations.Add(tempConfig); } } } return this.configurations; }
/// <summary> /// Sets this configuration option as parent for all binary option /// in a model, that have this option as parent. /// </summary> /// <param name="vm">The model that will be used to update the children.</param> public void updateChildren(VariabilityModel vm) { foreach (ConfigurationOption option in vm.BinaryOptions) { if (option.parentName != null && option.parentName.Equals(this.name)) { option.Parent = this; } } }
/// <summary> /// Clears the global state. This mehtod should be used after performing all experiments of one case study. /// </summary> public static void clear() { varModel = null; currentNFP = null; allMeasurements = new ResultDB(); evalutionSet = new ResultDB(); infModel = null; nfProperties = new Dictionary<string,NFProperty>(); optionOrder = new List<ConfigurationOption>(); }
/// <summary> /// Creates a new configuration option of the given name for the variability model. /// </summary> /// <param name="vm">The variability model, the option is defined for.</param> /// <param name="name">The name of the configuration option.</param> public ConfigurationOption(VariabilityModel vm, String name) { this.vm = vm; if (!name.All(Char.IsLetter)) { this.name = removeInvalidCharsFromName(name); } else { this.name = name; } }
/// <summary> /// Read a Feature model in SXFM format and create a new VaribilityModel that /// equals the Feature model. /// </summary> /// <param name="path">The path of the SXFM Feature model.</param> /// <returns>VaribilityModel object that equals the SXFM Feature model.</returns> public static VariabilityModel loadFromSXFM(string path) { VariabilityModel model = new VariabilityModel("to_change"); if (model.loadSXFM(path)) { return(model); } else { return(null); } }
/// <summary> /// Static method that reads an xml file and constructs a variability model using the stored information /// </summary> /// <param name="path">Path to the XML File</param> /// <returns>The instantiated variability model or null if there is no variability model at the path or if the model could not be parsed.</returns> public static VariabilityModel loadFromXML(String path) { VariabilityModel vm = new VariabilityModel("temp"); if (vm.loadXML(path)) { return(vm); } else { return(null); } }
/// <summary> /// This method returns a list of all configurations stored in a given file. All options of the configurations have to be defined in the variability model. /// /// If the file is a xml file, it should be structured as follows: /// /// <![CDATA[ <results> ]]> /// <![CDATA[ <row> ]]> /// <![CDATA[ <data column="Configuration"> ]]> /// <![CDATA[ binaryOption1, binaryOption3,... ]]> /// <![CDATA[ </data> ]]> /// <![CDATA[ <data column="Variable Features"> ]]> /// <![CDATA[ numOption1;64,numOption2;4 ]]> /// <![CDATA[ </data> ]]> /// <![CDATA[ <data column="Performance"> ]]> /// <![CDATA[ 21.178 ]]> /// <![CDATA[ </data> ]]> /// <![CDATA[ <data column="Footprint"> ]]> /// <![CDATA[ 1679 ]]> /// <![CDATA[ </data> ]]> /// <![CDATA[ </row> ]]> /// <![CDATA[ <row> ]]> /// <![CDATA[ <data column="Configuration"> ]]> /// <![CDATA[ .... ]]> /// <![CDATA[ <results> ]]> /// /// /// If the file is a csv file, two different formats are supported. /// /// For the first on, the file should have a header: /// /// binaryOption1;numOption1;binaryOption2;numOption2;Performance;Footprint /// true;64;false;4;21.178;1679 /// /// Note: If a binary option is selected in a configuration, the value can either be "true" or "1". /// /// In the second format, no header is needed and only binary options are supported. Additionally, the measurements have to consider only one non-functional property. /// /// </summary> /// <param name="file">Full qualified file name.</param> /// <param name="model">Variability model of the configurations.</param> /// <returns></returns> public static List <Configuration> readConfigurations(string file, VariabilityModel model) { if (file.EndsWith(".xml")) { XmlDocument dat = new System.Xml.XmlDocument(); dat.Load(file); return(readConfigurations(dat, model)); } else { return(readCSV(file, model)); } }
private bool tokenIsAFeatureOrNumber(string token, VariabilityModel varModel) { token = token.Trim(); double value = 0.0; if (Double.TryParse(token, out value)) { return(true); } if (varModel != null) { NumericOption numOption = varModel.getNumericOption(token); if (numOption != null) { if (!participatingNumOptions.Contains(numOption)) { this.participatingNumOptions.Add(numOption); } numberOfParticipatingFeatures++; return(true); } BinaryOption binOption = varModel.getBinaryOption(token); if (token.StartsWith("Enabled") || token.StartsWith("Disabled")) { binOption = getAbstractOption(token, varModel); } if (binOption != null) { if (!participatingBoolOptions.Contains(binOption)) { this.participatingBoolOptions.Add(binOption); } numberOfParticipatingFeatures++; return(true); } } else { if (token.Equals(this.numOption.Name)) { return(true); } } return(false); }
private static double getValueOfToken(Configuration config, string token, VariabilityModel fm) { token = token.Trim(); double value = 0.0; if (Double.TryParse(token, out value)) { return(value); } NumericOption numOpt = fm.getNumericOption(token); if (numOpt != null) { return(config.NumericOptions[numOpt]); } BinaryOption binOpt = fm.getBinaryOption(token); if (token.StartsWith("Enabled") || token.StartsWith("Disabled")) { binOpt = getAbstractOption(token, fm); } if (binOpt != null) { if (token.Equals("base") || token.Equals("root")) { return(1.0); } if (config.BinaryOptions.Keys.Contains(binOpt) && config.BinaryOptions[binOpt] == BinaryOption.BinaryValue.Selected) { return(1.0); } else { foreach (BinaryOption option in config.BinaryOptions.Keys) { // option has to be selected in the configuration if (option.Name == binOpt.Name && config.BinaryOptions[option] == BinaryOption.BinaryValue.Selected) { return(1.0); } } } } return(0.0); }
/// <summary> /// This method searches for a corresponding methods in the dynamically loadeda assemblies and calls it if found. It prefers due to performance reasons the Microsoft Solver Foundation implementation. /// </summary> /// <param name="vm">The variability model containing the binary options and their constraints.</param> /// <returns>Returns a list of configurations, in which a configuration is a list of SELECTED binary options (deselected options are not present)</returns> public List<List<BinaryOption>> generateAllVariantsFast(VariabilityModel vm) { foreach (Lazy<IVariantGenerator, ISolverType> solver in solvers) { if (solver.Metadata.SolverType.Equals("MSSolverFoundation")) return solver.Value.generateAllVariantsFast(vm); } //If not MS Solver, take any solver. Should be changed when supporting more than 2 solvers here foreach (Lazy<IVariantGenerator, ISolverType> solver in solvers) { return solver.Value.generateAllVariantsFast(vm); } return null; }
private static double getValueOfToken(Configuration config, string token, VariabilityModel fm) { token = token.Trim(); double value = 0.0; if (Double.TryParse(token, out value)) { return(value); } NumericOption numOpt = fm.getNumericOption(token); if (numOpt != null) { return(config.NumericOptions[numOpt]); } BinaryOption binOpt = fm.getBinaryOption(token); if (binOpt != null) { if (token.Equals("base")) { return(1.0); } if (config.BinaryOptions.Keys.Contains(binOpt) && config.BinaryOptions[binOpt] == BinaryOption.BinaryValue.Selected) { return(1.0); } else { foreach (BinaryOption option in config.BinaryOptions.Keys) { if (option.Name == binOpt.Name) { return(1.0); } } } } return(0.0); }
/// <summary> /// /// </summary> /// <param name="vm"></param> /// <returns></returns> public List<List<BinaryOption>> generateNegativeFWAllCombinations(VariabilityModel vm) { this.configurations.Clear(); List<List<BinaryOption>> maxConfigs = new List<List<BinaryOption>>(); maxConfigs = getMaxConfigurations(vm, true); configurations.AddRange(maxConfigs); //Compute negative feature-wise for all maximum configurations foreach (List<BinaryOption> config in maxConfigs) { bool abort = false; List<BinaryOption> currentConfig = new List<BinaryOption>(); foreach (BinaryOption e in config) currentConfig.Add(e); List<BinaryOption> removedElements = new List<BinaryOption>(); while (abort == false) { abort = true; BinaryOption currentElementUnderConsdiration = null; foreach (BinaryOption e in currentConfig) { currentElementUnderConsdiration = e; //Constructing new Configuration without the current element List<BinaryOption> configToMeasure = new List<BinaryOption>(); configToMeasure = generator.generateConfigWithoutOption(e, currentConfig, out removedElements, vm); if (configToMeasure == null) { abort = true; continue; } else if(!Configuration.containsBinaryConfiguration(configurations,configToMeasure)) configurations.Add(configToMeasure); } } } return this.configurations; }
//Two formats are possible: with header and 0,1s for binary selection or no header and giving the names of config options per per line (this excludex numeric options) private static List <Configuration> readCSV(string file, VariabilityModel model) { StreamReader sr = new StreamReader(file); String line1, line2; if (!sr.EndOfStream) { line1 = sr.ReadLine(); } else { return(null); } if (!sr.EndOfStream) { line2 = sr.ReadLine(); } else { return(null); } sr.Close(); var l1 = line1.Split(';'); var l2 = line2.Split(';'); if (l1.Length < 2 || l2.Length < 2) { return(null); } int d = 0; if (int.TryParse(l2[0], out d)) { return(readConfigurations_Header_CSV(file, model)); } else { return(readCSVBinaryOptFormat(file, model)); } }
/// <summary> /// Checks whether the boolean selection of a configuration is valid w.r.t. the variability model. Does not check for numeric options' correctness. /// </summary> /// <param name="c">The configuration that needs to be checked.</param> /// <param name="vm">The variability model that represents the context of the configuration.</param> /// <returns>True if it is a valid selection w.r.t. the VM, false otherwise</returns> public bool checkConfigurationSAT(Configuration c, 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); //Feature Selection foreach (BinaryOption binayOpt in elemToTerm.Keys) { CspTerm term = elemToTerm[binayOpt]; if (c.getBinaryOptions(BinaryOption.BinaryValue.Selected).Contains(binayOpt)) { S.AddConstraints(S.Implies(S.True, term)); } else { 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++; } //-1??? Needs testing TODO if (count - 1 != c.getBinaryOptions(BinaryOption.BinaryValue.Selected).Count) { return false; } return true; } else return false; }
private static BinaryOption getAbstractOption(String token, VariabilityModel vm) { NumericOption numOpt; if (token.StartsWith("Enabled")) { numOpt = vm.getNumericOption(token.Substring(7)); if (numOpt != null) { return(numOpt.abstractEnabledConfigurationOption()); } } else { numOpt = vm.getNumericOption(token.Substring(8)); if (numOpt != null) { return(numOpt.abstractDisabledConfigurationOption()); } } return(null); }
private static List <Configuration> readCSVBinaryOptFormat(string file, VariabilityModel model) { List <Configuration> result = new List <Configuration>(); StreamReader sr = new StreamReader(file); while (!sr.EndOfStream) { var line = sr.ReadLine().Split(';'); List <BinaryOption> temp = new List <BinaryOption>(); for (int i = 0; i < line.Length - 1; i++) { BinaryOption b = model.getBinaryOption(line[i]); temp.Add(b); } double value = Double.Parse(line[line.Length - 1].Replace(',', '.'), System.Globalization.CultureInfo.InvariantCulture); var c = new Configuration(temp); c.setMeasuredValue(GlobalState.currentNFP, value); result.Add(c); } sr.Close(); return(result); }
//get one variant per feature multiplied with alternative combinations; the variant tries to maximize the number of selected features, but without the feature in question /// <summary> /// /// </summary> /// <param name="vm"></param> /// <returns></returns> public List<List<BinaryOption>> generateNegativeFW(VariabilityModel vm) { this.configurations.Clear(); List<List<BinaryOption>> maxConfigs = new List<List<BinaryOption>>(); maxConfigs = getMaxConfigurations(vm, false); configurations.AddRange(maxConfigs); //Idea try to vary only the first maximum configuration by removing only a single feature //If a feature is not present in this maximum configuration, find a maximum configuration in which it is present and then remove the feature //Challenges: alternative features or mandatory features cannot be removed foreach (BinaryOption binOpt in vm.BinaryOptions) { if (binOpt.Optional == false || binOpt.hasAlternatives()) continue; foreach (List<BinaryOption> config in maxConfigs) { if (!config.Contains(binOpt)) continue; List<BinaryOption> removedElements = null; //Get a configuration without the feature based on the maximum configuration: config List<BinaryOption> configToMeasure = generator.generateConfigWithoutOption(binOpt, config, out removedElements, vm); if (configToMeasure == null) {//This didn't work, let us try to use another maximum configuration continue; } else { if (!Configuration.containsBinaryConfiguration(configurations,configToMeasure)) configurations.Add(configToMeasure); break; } } } return this.configurations; }
/// <summary> /// Creates a configuration based on a hash representation of that configuration. /// </summary> /// <param name="hashString">The String which from which we can infer the configuration</param> /// <param name="vm">The variability model that is required for identifying options in the hash string to instantiate actual configuration options.</param> /// <returns>A configuration that maps to the given hash string.</returns> internal static Configuration createFromHashString(string hashString, VariabilityModel vm) { Dictionary <NumericOption, double> numOptions = new Dictionary <NumericOption, double>(); List <BinaryOption> binaryFeatures = new List <BinaryOption>(); Configuration c; String[] optionList = hashString.Split(new String[] { "%;%" }, StringSplitOptions.RemoveEmptyEntries); foreach (String option in optionList) { if (Char.IsDigit(option[option.Length - 1]))//If last char is a digit, then it must be a numeric option { //Now remove the digit from the name int index = option.Length - 1; Char last = option[index]; while (Char.IsDigit(last) || last == ',' || last == '.' || last == '-') { index--; last = option[index]; } Double optionsValue = Math.Round(Double.Parse(option.Substring(index + 1).Replace(',', '.')), 1); NumericOption no = vm.getNumericOption(option.Substring(0, index + 1)); if (no == null) { continue; } numOptions.Add(no, optionsValue); } else { BinaryOption binOpt = vm.getBinaryOption(option); binaryFeatures.Add(binOpt); } } c = new Configuration(binaryFeatures, numOptions); return(c); }
/// <summary> /// This method reads all configurations specified in the .csv file. In this mehtod, we assume that the file has a header. /// </summary> /// <param name="file"></param> /// <param name="model">The variabiliy model for the configurations.</param> /// <returns>A list of all configurations </returns> public static List<Configuration> readConfigurations_Header_CSV(String file, VariabilityModel model) { List<Configuration> configurations = new List<Configuration>(); StreamReader sr = new StreamReader(file); String[] optionOrder = new String[model.getOptions().Count - 1]; String[] nfpOrder = null; bool isHeader = true; while(!sr.EndOfStream) { String[] tokens = sr.ReadLine().Split(';'); if (isHeader) { nfpOrder = new String[tokens.Length - optionOrder.Length]; for (int i = 0; i < tokens.Length; i++) { String token = tokens[i]; if (i < optionOrder.Length) { optionOrder[i] = token; } else { nfpOrder[i - optionOrder.Length] = token; if (!GlobalState.nfProperties.ContainsKey(token)) { GlobalState.nfProperties.Add(token, new NFProperty(token)); } } } isHeader = false; } else { Dictionary<BinaryOption, BinaryOption.BinaryValue> binOptions = new Dictionary<BinaryOption, BinaryOption.BinaryValue>(); Dictionary<NumericOption, double> numOptions = new Dictionary<NumericOption, double>(); Dictionary<NFProperty, double> properties = new Dictionary<NFProperty, double>(); for (int i = 0; i < tokens.Length; i++) { String token = tokens[i]; if (i < optionOrder.Length) { ConfigurationOption option = model.getOption(optionOrder[i]); if (option.GetType() == typeof(BinaryOption)) { if (token.Equals("true") || token.Equals("1")) binOptions.Add((BinaryOption)option, BinaryOption.BinaryValue.Selected); else binOptions.Add((BinaryOption)option, BinaryOption.BinaryValue.Deselected); } else { double value = Convert.ToDouble(token); numOptions.Add((NumericOption)option, value); } } else { NFProperty nfp = GlobalState.nfProperties[nfpOrder[i - optionOrder.Length]]; double value = Convert.ToDouble(token); properties.Add(nfp, value); double currentMaxMeasuredValue; if (GlobalState.allMeasurements.maxMeasuredValue.TryGetValue(nfp, out currentMaxMeasuredValue)) { if (Math.Abs(value) > Math.Abs(currentMaxMeasuredValue)) { GlobalState.allMeasurements.maxMeasuredValue[nfp] = value; } } else { GlobalState.allMeasurements.maxMeasuredValue.Add(nfp, value); } } } Configuration config = new Configuration(binOptions, numOptions, properties); configurations.Add(config); } } sr.Close(); return configurations; }
/// <summary> /// This method returns a list of all configurations stored in a given file. All options of the configurations have to be defined in the variability model. /// </summary> /// <param name="dat">Object representing the configuration file.</param> /// <param name="model">Variability model of the configurations.</param> /// <returns>Returns a list of configurations that were defined in the XML document. Can be an empty list.</returns> public static List<Configuration> readConfigurations(XmlDocument dat, VariabilityModel model) { XmlElement currentElemt = dat.DocumentElement; // Retrieve the decimal delimiter and the separator sign if included if (currentElemt.HasAttribute(decimalDelimiterTag) && currentElemt.HasAttribute(separatorTag)) { // I assume that the decimal delimiter as well as the separator are only one symbol ConfigurationReader.decimalDelimiter = currentElemt.GetAttribute(decimalDelimiterTag)[0]; ConfigurationReader.separator = currentElemt.GetAttribute(separatorTag)[0]; if (currentElemt.GetAttribute(decimalDelimiterTag).Length > 1 || currentElemt.GetAttribute(separatorTag).Length > 1) { GlobalState.logError.log("The decimal delimiter and the separator must consist of only one symbol."); } if (ConfigurationReader.decimalDelimiter == ConfigurationReader.separator) { GlobalState.logError.log("The decimal delimiter symbol and the separator symbol must be different."); } } else if (currentElemt.HasAttribute(decimalDelimiterTag)) { ConfigurationReader.decimalDelimiter = currentElemt.GetAttribute(decimalDelimiterTag)[0]; if (currentElemt.GetAttribute(decimalDelimiterTag).Length > 1) { GlobalState.logError.log("The decimal delimiter must consist of only one symbol."); } } else if (currentElemt.HasAttribute(separatorTag)) { ConfigurationReader.separator = currentElemt.GetAttribute(separatorTag)[0]; if (currentElemt.GetAttribute(separatorTag).Length > 1) { GlobalState.logError.log("The separator symbol must be different."); } } HashSet<Configuration> configurations = new HashSet<Configuration>(); int numberOfConfigs = currentElemt.ChildNodes.Count; int configsWithTooLargeDeviation = 0; foreach (XmlNode node in currentElemt.ChildNodes) { bool readMultipleMeasurements = false; if (node.Attributes.Count > 0 && node.Attributes[0].Value.ToLower() == "true") { readMultipleMeasurements = true; } Dictionary<NFProperty, double> propertiesForConfig = new Dictionary<NFProperty, double>(); ; bool alternativeFormat = false; string binaryString = ""; string numericString = ""; string configID = ""; Dictionary<NFProperty, double> measuredProperty = new Dictionary<NFProperty, double>(); Configuration c = null; bool hasSetConfig = false; foreach (XmlNode childNode in node.ChildNodes) { if (c == null && hasSetConfig) continue; switch (childNode.Attributes[0].Value) { // TODO we use this to support result files having the old structure case "Configuration": binaryString = childNode.InnerText; break; case "Variable Features": numericString = childNode.InnerText; break; case "BinaryOptions": binaryString = childNode.InnerText; break; case "NumericOptions": numericString = childNode.InnerText; break; case "ConfigID": if (readMultipleMeasurements) { configID = childNode.InnerText.Replace("_", "%;%"); } else configID = childNode.InnerText; if (configID.Contains("%;%seek") && configID.Contains("%;%seek0") == false) { hasSetConfig = true; c = null; break; } alternativeFormat = true; c = Configuration.createFromHashString(configID, GlobalState.varModel); hasSetConfig = true; break; case "CompilerOptions": //todo break; case "ConfigFileOptions": //todo break; case "ParameterOptions": //todo break; case "ProgramName": //todo break; case "StartupBegin": //todo break; case "StartupEnd": //todo break; default: NFProperty property = GlobalState.getOrCreateProperty(childNode.Attributes[0].Value); double measuredValue = 0; //-1 means that measurement failed... 3rd values strongly devigates in C.'s measurements, hence we use it only in case we have no other measurements if (readMultipleMeasurements) { //if (property.Name != "run-real") // continue; String[] m = childNode.InnerText.ToString().Split(separator); double val1 = 0; if (!Double.TryParse(m[0], out val1)) break; if (m.Length > 1) { List<double> values = new List<double>(); double avg = 0; foreach (var i in m) { double d = Convert.ToDouble(i.Replace(decimalDelimiter, '.')); if (d != -1) { values.Add(d); avg += d; } } if (values.Count == 0) { configsWithTooLargeDeviation++; c = null; break; } avg = avg / values.Count; /* foreach (var d in values) { if ((d / avg) * 100 > 10) { configsWithTooLargeDeviation++; c = null; break; } }*/ measuredValue = avg; /*double val2 = Convert.ToDouble(m[1]); if (val1 == -1) measuredValue = val2; else if (val1 == -1 && val2 == -1) measuredValue = Convert.ToDouble(m[2]); else if (val2 == -1) measuredValue = val1; else measuredValue = (val1 + val2) / 2;*/ } else measuredValue = val1; } else measuredValue = Convert.ToDouble(childNode.InnerText.ToString().Replace(decimalDelimiter, '.')); // Save the largest measured value. double currentMaxMeasuredValue; if (GlobalState.allMeasurements.maxMeasuredValue.TryGetValue(property, out currentMaxMeasuredValue)) { if (Math.Abs(measuredValue) > Math.Abs(currentMaxMeasuredValue)) { GlobalState.allMeasurements.maxMeasuredValue[property] = measuredValue; } } else { GlobalState.allMeasurements.maxMeasuredValue.Add(property, measuredValue); } // Add measured value to the configuration. if (alternativeFormat && c != null) { c.setMeasuredValue(property, measuredValue); } else { measuredProperty.Add(property, measuredValue); } break; } } if (alternativeFormat && c != null) { if (configurations.Contains(c)) { GlobalState.logError.logLine("Mutiple definition of one configuration in the configurations file: " + c.ToString()); } else { // if (GlobalState.currentNFP != null && c.nfpValues.Keys.Contains(GlobalState.currentNFP) && c.nfpValues[GlobalState.currentNFP] != -1) configurations.Add(c); } cont: { } continue; } Dictionary<BinaryOption, BinaryOption.BinaryValue> binaryOptions = new Dictionary<BinaryOption, BinaryOption.BinaryValue>(); string[] binaryOptionNames = binaryString.Split(','); foreach (string binaryOptionName in binaryOptionNames) { string currOption = binaryOptionName.Trim(); if (currOption.Length > 0) { BinaryOption bOpt = null; bOpt = model.getBinaryOption(currOption); if (bOpt == null) GlobalState.logError.logLine("No Binary option found with name: " + currOption); binaryOptions.Add(bOpt, BinaryOption.BinaryValue.Selected); } } // Add "root" binary option to the configuration if (!binaryOptions.ContainsKey(model.Root)) binaryOptions.Add(model.Root, BinaryOption.BinaryValue.Selected); Dictionary<NumericOption, double> numericOptions = new Dictionary<NumericOption, double>(); if (!string.IsNullOrEmpty(numericString)) { string[] numOptionArray = numericString.Trim().Split(','); foreach (string numOption in numOptionArray) { string[] numOptionsKeyValue; if (numOption.Contains(";")) numOptionsKeyValue = numOption.Split(';'); else numOptionsKeyValue = numOption.Split(' ');// added for rc-lookahead 40 numOptionsKeyValue[0] = numOptionsKeyValue[0].Trim(); if (numOptionsKeyValue[0].Length == 0) continue; NumericOption varFeat = model.getNumericOption(numOptionsKeyValue[0]); if (varFeat == null) GlobalState.logError.logLine("No numeric option found with name: " + numOptionsKeyValue[0]); double varFeatValue = Convert.ToDouble(numOptionsKeyValue[1]); numericOptions.Add(varFeat, varFeatValue); } } Configuration config = new Configuration(binaryOptions, numericOptions, measuredProperty); //if(configurations.Contains(config)) //{ // GlobalState.logError.log("Mutiple definition of one configuration in the configurations file: " + config.ToString()); //}else //{ configurations.Add(config); //} } GlobalState.logInfo.logLine("Configs with too large deviation: " + configsWithTooLargeDeviation); return configurations.ToList(); }
/// <summary> /// This method returns a list of all configurations stored in a given file. All options of the configurations have to be defined in the variability model. /// /// If the file is a xml file, it should be structured as follows: /// /// <![CDATA[ <results> ]]> /// <![CDATA[ <row> ]]> /// <![CDATA[ <data column="Configuration"> ]]> /// <![CDATA[ binaryOption1, binaryOption3,... ]]> /// <![CDATA[ </data> ]]> /// <![CDATA[ <data column="Variable Features"> ]]> /// <![CDATA[ numOption1;64,numOption2;4 ]]> /// <![CDATA[ </data> ]]> /// <![CDATA[ <data column="Performance"> ]]> /// <![CDATA[ 21.178 ]]> /// <![CDATA[ </data> ]]> /// <![CDATA[ <data column="Footprint"> ]]> /// <![CDATA[ 1679 ]]> /// <![CDATA[ </data> ]]> /// <![CDATA[ </row> ]]> /// <![CDATA[ <row> ]]> /// <![CDATA[ <data column="Configuration"> ]]> /// <![CDATA[ .... ]]> /// <![CDATA[ <results> ]]> /// /// /// If the file is a csv file, two different formats are supported. /// /// For the first on, the file should have a header: /// /// binaryOption1;numOption1;binaryOption2;numOption2;Performance;Footprint /// true;64;false;4;21.178;1679 /// /// Note: If a binary option is selected in a configuration, the value can either be "true" or "1". /// /// In the second format, no header is needed and only binary options are supported. Additionally, the measurements have to consider only one non-functional property. /// /// </summary> /// <param name="file">Full qualified file name.</param> /// <param name="model">Variability model of the configurations.</param> /// <returns></returns> public static List<Configuration> readConfigurations(string file, VariabilityModel model) { if (file.EndsWith(".xml")) { XmlDocument dat = new System.Xml.XmlDocument(); dat.Load(file); return readConfigurations(dat, model); } else { return readCSV(file, model); } }
public VariabilityModel createVarModel() { VariabilityModel varMod = new VariabilityModel("testModel_1"); // -------------------- BINARY OPTIONS ---------------- BinaryOption binOp1 = new BinaryOption(varMod, "binOpt1"); binOp1.Optional = false; binOp1.Prefix = "--"; varMod.addConfigurationOption(binOp1); BinaryOption binOp2 = new BinaryOption(varMod, "binOpt2"); binOp2.Optional = true; binOp2.Prefix = "-?"; binOp2.Postfix = "kg"; binOp2.Parent = binOp1; binOp2.OutputString = "binOpt2"; varMod.addConfigurationOption(binOp2); BinaryOption binOp3 = new BinaryOption(varMod, "binOpt3"); binOp3.Optional = true; binOp3.Prefix = ""; binOp3.Postfix = ""; binOp3.Parent = binOp1; List<List<ConfigurationOption>> exclude = new List<List<ConfigurationOption>>(); List<ConfigurationOption> subExclude = new List<ConfigurationOption>(); subExclude.Add(binOp2); exclude.Add(subExclude); binOp3.Excluded_Options = exclude; varMod.addConfigurationOption(binOp3); BinaryOption binOp4 = new BinaryOption(varMod, "binOpt4"); binOp4.Optional = true; binOp4.Prefix = "4_"; binOp4.Postfix = "_4"; binOp4.Parent = binOp1; List<List<ConfigurationOption>> implied = new List<List<ConfigurationOption>>(); List<ConfigurationOption> subimplied = new List<ConfigurationOption>(); subimplied.Add(binOp2); implied.Add(subimplied); binOp4.Implied_Options = implied; varMod.addConfigurationOption(binOp4); // -------------------- NUMERIC OPTIONS ---------------- NumericOption numOpt1 = new NumericOption(varMod, "numOpt1"); numOpt1.DefaultValue = 0.0; numOpt1.Prefix = "num1-"; numOpt1.Postfix = "--"; numOpt1.Min_value = 0; numOpt1.Max_value = 10; numOpt1.StepFunction = new InfluenceFunction("n + 2"); varMod.addConfigurationOption(numOpt1); NumericOption numOpt2 = new NumericOption(varMod, "numOpt2"); numOpt2.DefaultValue = 0.8; numOpt2.Prefix = ""; numOpt2.Postfix = ""; numOpt2.Min_value = 0.1; numOpt2.Max_value = 5; numOpt2.StepFunction = new InfluenceFunction("n * 2"); varMod.addConfigurationOption(numOpt2); return varMod; }
/// <summary> /// Checks if the specified expression is compatible with the specified model. /// </summary> /// <param name="exp">Specified expression. Must not be null.</param> /// <param name="model">Specified variability model. Must not be null.</param> /// <returns>Returns true if expression and model are compatible else false</returns> private bool checkExpressionCompatibility(string exp, VariabilityModel model) { if (exp == null) throw new ArgumentNullException("Parameter exp must not be null!"); if (model == null) throw new ArgumentNullException("Parameter model must not be null!"); foreach (string prt in exp.Split(' ')) { double d; if (!isOperator(prt) && prt != "log10(" && prt != ")" && !double.TryParse(prt, out d) && model.getOption(prt) == null) { return false; } } return true; }
private double getValueOfToken(Dictionary<NumericOption,double> config, string token, VariabilityModel varModel) { token = token.Trim(); double value = 0.0; if (Double.TryParse(token, out value)) { return value; } if (varModel == null) { if (token.Equals(this.numOption.Name)) return config[this.numOption]; } else { NumericOption numOpt = varModel.getNumericOption(token); if (numOpt != null) return (config[numOpt]); } return 0.0; }
/// <summary> /// Parses the binary options, represented as string, of a configuration. /// </summary> /// <param name="binaryString">The string representation of the selected binary configuration options.</param> /// <param name="binaryOptions">The data strcutre containing the parsed binary options and their values.</param> /// <param name="varModel">The variability model the configuration is defined for.</param> /// <returns>True if the configuration is valid.</returns> private static bool parseBinaryOptionString(string binaryString, out Dictionary <BinaryOption, BinaryOption.BinaryValue> binaryOptions, VariabilityModel varModel) { bool valid = true; Dictionary <BinaryOption, BinaryOption.BinaryValue> _binaryOptions = new Dictionary <BinaryOption, BinaryOption.BinaryValue>(); string[] binaryOptionNames = binaryString.Split(','); foreach (string binaryOptionName in binaryOptionNames) { string currOption = binaryOptionName.Trim(); if (currOption.Length > 0) { BinaryOption bOpt = null; bOpt = varModel.getBinaryOption(currOption); if (bOpt == null) { GlobalState.logError.logLine("No Binary option found with name: " + currOption); valid = false; break; } _binaryOptions.Add(bOpt, BinaryOption.BinaryValue.Selected); } } binaryOptions = _binaryOptions; return(valid); }
/// <summary> /// This method reads all configurations specified in the .csv file. In this mehtod, we assume that the file has a header. /// </summary> /// <param name="file"></param> /// <param name="model">The variabiliy model for the configurations.</param> /// <returns>A list of all configurations </returns> public static List <Configuration> readConfigurations_Header_CSV(String file, VariabilityModel model) { List <Configuration> configurations = new List <Configuration>(); StreamReader sr = new StreamReader(file); String[] optionOrder = new String[model.getOptions().Count]; String[] nfpOrder = null; bool isHeader = true; while (!sr.EndOfStream) { String[] tokens = sr.ReadLine().Split(';'); if (isHeader) { nfpOrder = new String[tokens.Length - optionOrder.Length]; for (int i = 0; i < tokens.Length; i++) { String token = tokens[i]; if (i < optionOrder.Length) { optionOrder[i] = token; } else { nfpOrder[i - optionOrder.Length] = token; if (!GlobalState.nfProperties.ContainsKey(token)) { GlobalState.nfProperties.Add(token, new NFProperty(token)); } } } isHeader = false; } else { Dictionary <BinaryOption, BinaryOption.BinaryValue> binOptions = new Dictionary <BinaryOption, BinaryOption.BinaryValue>(); Dictionary <NumericOption, double> numOptions = new Dictionary <NumericOption, double>(); Dictionary <NFProperty, double> properties = new Dictionary <NFProperty, double>(); for (int i = 0; i < tokens.Length; i++) { String token = tokens[i]; if (i < optionOrder.Length) { ConfigurationOption option = model.getOption(optionOrder[i]); if (option.GetType() == typeof(BinaryOption)) { if (token.Equals("true") || token.Equals("1")) { binOptions.Add((BinaryOption)option, BinaryOption.BinaryValue.Selected); } } else { double value = Convert.ToDouble(token); numOptions.Add((NumericOption)option, value); } } else { NFProperty nfp = GlobalState.nfProperties[nfpOrder[i - optionOrder.Length]]; double value = Convert.ToDouble(token); properties.Add(nfp, value); double currentMaxMeasuredValue; if (GlobalState.allMeasurements.maxMeasuredValue.TryGetValue(nfp, out currentMaxMeasuredValue)) { if (Math.Abs(value) > Math.Abs(currentMaxMeasuredValue)) { GlobalState.allMeasurements.maxMeasuredValue[nfp] = value; } } else { GlobalState.allMeasurements.maxMeasuredValue.Add(nfp, value); } } } Configuration config = new Configuration(binOptions, numOptions, properties); configurations.Add(config); } } sr.Close(); return(configurations); }
//Two formats are possible: with header and 0,1s for binary selection or no header and giving the names of config options per per line (this excludex numeric options) private static List<Configuration> readCSV(string file, VariabilityModel model) { StreamReader sr = new StreamReader(file); String line1, line2; if (!sr.EndOfStream) line1 = sr.ReadLine(); else return null; if (!sr.EndOfStream) line2 = sr.ReadLine(); else return null; sr.Close(); var l1 = line1.Split(';'); var l2 = line2.Split(';'); if (l1.Length < 2 || l2.Length < 2) return null; int d = 0; if (int.TryParse(l2[0], out d)) return readConfigurations_Header_CSV(file, model); else return readCSVBinaryOptFormat(file, model); }
/// <summary> /// Creates a new feature by concartinating two given features with a multiplication. /// </summary> /// <param name="original">The first feature to concatinate.</param> /// <param name="toAdd">The second feature to concatinate.</param> /// <param name="vm">The variability model, the two features are defined for.</param> public Feature(Feature original, Feature toAdd, VariabilityModel vm) : base(original.getPureString() + " * " + toAdd.getPureString(), vm) { hashCode = initHashCode(); }
/// <summary> /// Sets all necessary information and initializes all components. /// </summary> /// <param name="exp">Loaded expression of the function. Must not be null.</param> /// <param name="model">Corresponding variability model of the expression.</param> private void loadComponents(string exp, VariabilityModel model) { if (exp == null) throw new ArgumentNullException("Parameter exp may not be null!"); if (model != null && !checkExpressionCompatibility(exp, model)) { MessageBox.Show(ERROR_EXP_MODEL_INCOMPATIBLE); return; } String optExpression = Regex.Replace(exp, @"\r\n?|\n", ""); // Test if the loaded expression can be used try { new InfluenceFunction(optExpression); } catch { MessageBox.Show(ERROR_INVALID_EXP); return; } if (originalFunction == null) initializeOnce(); modelLoaded = model != null; originalFunction = modelLoaded ? new InfluenceFunction(optExpression, model) : new InfluenceFunction(optExpression); currentModel = originalFunction.getVariabilityModel(); adjustedExpressionTree = originalFunction.getExpressionTree(); calculateOccurances(); // Update readFunction-textbox getMaxAbstractConstant(originalFunction.ToString()); updateFunctionTextBox(originalFunctionTextBox, sortExpression(originalFunction.ToString())); // Activating all components and returning their original state ilFunctionPanel.Scene = new ILScene(); ilFunctionPanel.Refresh(); initializeComponents(); updateAdjustedFunction(); }
private bool tokenIsAFeatureOrNumber(string token, VariabilityModel varModel) { token = token.Trim(); double value = 0.0; if (Double.TryParse(token, out value)) { return true; } if (varModel != null) { NumericOption numOption = varModel.getNumericOption(token); if (numOption != null) { if (!participatingNumOptions.Contains(numOption)) this.participatingNumOptions.Add(numOption); numberOfParticipatingFeatures++; return true; } BinaryOption binOption = varModel.getBinaryOption(token); if (binOption != null) { if (!participatingBoolOptions.Contains(binOption)) this.participatingBoolOptions.Add(binOption); numberOfParticipatingFeatures++; return true; } } else { if(token.Equals(this.numOption.Name)) return true; } return false; }
private static double getValueOfToken(Configuration config, string token, VariabilityModel fm) { token = token.Trim(); double value = 0.0; if (Double.TryParse(token, out value)) { return value; } NumericOption numOpt = fm.getNumericOption(token); if (numOpt != null) { return config.NumericOptions[numOpt]; } BinaryOption binOpt = fm.getBinaryOption(token); if (binOpt != null) { if(token.Equals("base")) return 1.0; if (config.BinaryOptions.Keys.Contains(binOpt) && config.BinaryOptions[binOpt] == BinaryOption.BinaryValue.Selected) return 1.0; else { foreach (BinaryOption option in config.BinaryOptions.Keys) { if (option.Name == binOpt.Name ) { return 1.0; } } } } return 0.0; }
/// <summary> /// This method searches for a corresponding methods in the dynamically loadeda assemblies and calls it if found. It prefers due to performance reasons the Microsoft Solver Foundation implementation. /// </summary> /// <param name="c">The configuration that needs to be checked.</param> /// <param name="vm">The variability model that represents the context of the configuration.</param> /// <returns>True if it is a valid selection w.r.t. the VM, false otherwise</returns> public bool checkConfigurationSAT(Configuration c, VariabilityModel vm) { foreach (Lazy<ICheckConfigSAT, ISolverType> solver in solvers) { if (solver.Metadata.SolverType.Equals("MSSolverFoundation")) return solver.Value.checkConfigurationSAT(c, vm); } //If not MS Solver, take any solver. Should be changed when supporting more than 2 solvers here foreach (Lazy<ICheckConfigSAT, ISolverType> solver in solvers) { return solver.Value.checkConfigurationSAT(c, vm); } return false; }
/// <summary> /// Creates an influence function based on the expression. The variability model is used to identify binary and numeric /// configuration options. /// </summary> /// <param name="expression">A function consisting of numbers, operators and configuration-option names.</param> /// <param name="varModel">The variability model of the configuration options.</param> public InfluenceFunction(string expression, VariabilityModel varModel) { this.varModel = varModel; parseExpressionToPolnishNotation(expression); }
private static List<Configuration> readCSVBinaryOptFormat(string file, VariabilityModel model) { List<Configuration> result = new List<Configuration>(); StreamReader sr = new StreamReader(file); while (!sr.EndOfStream) { var line = sr.ReadLine().Split(';'); List<BinaryOption> temp = new List<BinaryOption>(); for (int i = 0; i < line.Length - 1; i++) { BinaryOption b = model.getBinaryOption(line[i]); temp.Add(b); } double value = Double.Parse(line[line.Length - 1].Replace(',', '.')); var c = new Configuration(temp); c.setMeasuredValue(GlobalState.currentNFP, value); result.Add(c); } sr.Close(); return result; }
/// <summary> /// This method returns a list of all configurations stored in a given file. All options of the configurations have to be defined in the variability model. /// </summary> /// <param name="dat">Object representing the configuration file.</param> /// <param name="varModel">Variability model of the configurations.</param> /// <returns>Returns a list of configurations that were defined in the XML document. Can be an empty list.</returns> public static List <Configuration> readConfigurations(XmlDocument dat, VariabilityModel varModel) { XmlElement currentElemt = dat.DocumentElement; parseHeaderOfDocument(currentElemt); HashSet <Configuration> configurations = new HashSet <Configuration>(); int configsWithTooLargeDeviation = 0; foreach (XmlNode nodeOfOneConfiguration in currentElemt.ChildNodes) { bool readMultipleMeasurements = false; if (nodeOfOneConfiguration.Attributes.Count > 0 && nodeOfOneConfiguration.Attributes[0].Value.ToLower() == "true") { readMultipleMeasurements = true; } Dictionary <NFProperty, double> propertiesForConfig = new Dictionary <NFProperty, double>();; bool alternativeFormat = false; string binaryString = ""; string numericString = ""; string configID = ""; Dictionary <NFProperty, double> measuredProperty = new Dictionary <NFProperty, double>(); Configuration c = null; bool hasSetConfig = false; foreach (XmlNode childNode in nodeOfOneConfiguration.ChildNodes) { if (c == null && hasSetConfig) { continue; } switch (childNode.Attributes[0].Value) { // TODO we use this to support result files having the old structure case "BinaryOptions": case "Configuration": binaryString = childNode.InnerText; break; case "NumericOptions": case "Variable Features": numericString = childNode.InnerText; break; case "ConfigID": if (readMultipleMeasurements) { configID = childNode.InnerText.Replace("_", "%;%"); } else { configID = childNode.InnerText; } if (configID.Contains("%;%seek") && configID.Contains("%;%seek0") == false) { hasSetConfig = true; c = null; break; } alternativeFormat = true; c = Configuration.createFromHashString(configID, GlobalState.varModel); hasSetConfig = true; break; default: NFProperty property = GlobalState.getOrCreateProperty(childNode.Attributes[0].Value); double measuredValue = 0; //-1 means that measurement failed... 3rd values strongly devigates in C.'s measurements, hence we use it only in case we have no other measurements if (readMultipleMeasurements) { //if (property.Name != "run-real") // continue; String[] m = childNode.InnerText.ToString().Split(separator); double val1 = 0; if (!Double.TryParse(m[0], out val1)) { break; } if (m.Length > 1) { List <double> values = new List <double>(); double avg = 0; foreach (var i in m) { double d = double.Parse(i.Replace(decimalDelimiter, '.'), System.Globalization.CultureInfo.InvariantCulture); if (d != -1) { values.Add(d); avg += d; } } if (values.Count == 0) { configsWithTooLargeDeviation++; c = null; break; } avg = avg / values.Count; /* foreach (var d in values) * { * if ((d / avg) * 100 > 10) * { * configsWithTooLargeDeviation++; * c = null; * break; * } * }*/ measuredValue = avg; /*double val2 = Convert.ToDouble(m[1]); * if (val1 == -1) * measuredValue = val2; * else if (val1 == -1 && val2 == -1) * measuredValue = Convert.ToDouble(m[2]); * else if (val2 == -1) * measuredValue = val1; * else * measuredValue = (val1 + val2) / 2;*/ } else { measuredValue = val1; } } else { measuredValue = double.Parse(childNode.InnerText.ToString().Replace(decimalDelimiter, '.'), System.Globalization.CultureInfo.InvariantCulture); } // TODO how to handle configurations with negative nfps? if (measuredValue < 0) { goto nextConfig; } // Save the largest measured value. double currentMaxMeasuredValue; if (GlobalState.allMeasurements.maxMeasuredValue.TryGetValue(property, out currentMaxMeasuredValue)) { if (Math.Abs(measuredValue) > Math.Abs(currentMaxMeasuredValue)) { GlobalState.allMeasurements.maxMeasuredValue[property] = measuredValue; } } else { GlobalState.allMeasurements.maxMeasuredValue.Add(property, measuredValue); } // Add measured value to the configuration. if (alternativeFormat && c != null) { c.setMeasuredValue(property, measuredValue); } else { measuredProperty.Add(property, measuredValue); } break; } } if (alternativeFormat && c != null) { if (configurations.Contains(c)) { GlobalState.logError.logLine("Mutiple definition of one configuration in the configurations file: " + c.ToString()); } else { // if (GlobalState.currentNFP != null && c.nfpValues.Keys.Contains(GlobalState.currentNFP) && c.nfpValues[GlobalState.currentNFP] != -1) configurations.Add(c); } continue; } // indicates if this configuration is valid in the current feature model bool valid = true; // parse the binary options string Dictionary <BinaryOption, BinaryOption.BinaryValue> binaryOptions = new Dictionary <BinaryOption, BinaryOption.BinaryValue>(); valid &= parseBinaryOptionString(binaryString, out binaryOptions, varModel); // parse the numeric options string Dictionary <NumericOption, double> numericOptions = new Dictionary <NumericOption, double>(); valid &= parseNumericOptionString(numericString, out numericOptions, varModel); // Add "root" binary option to the configuration if (!binaryOptions.ContainsKey(varModel.Root)) { binaryOptions.Add(varModel.Root, BinaryOption.BinaryValue.Selected); } if (valid) { Configuration config = new Configuration(binaryOptions, numericOptions, measuredProperty); configurations.Add(config); } else { GlobalState.logError.logLine("Invalid configuration:" + binaryString + numericString); } nextConfig : { } } GlobalState.logInfo.logLine("Configs with too large deviation: " + configsWithTooLargeDeviation); return(configurations.ToList()); }
/// <summary> /// Creates a new feature based on the given expression. /// </summary> /// <param name="expression">The string represenation of the feature.</param> /// <param name="vm">The variability model the expression is defined for.</param> public Feature(String expression, VariabilityModel vm) : base(expression, vm) { hashCode = initHashCode(); }
private VariabilityModel extractFeatureModelFromExpression(String expression) { VariabilityModel varModel = new VariabilityModel("TEMP"); string[] parts = expression.Split(new char[] { '+', '*', '[', ']' }); double value = 0.0; for (int i = 0; i < parts.Length;i++) { string part = parts[i].Trim(); if (part.Length > 0) { if (!Double.TryParse(part, out value)) { if (varModel.getNumericOption(part) == null) { NumericOption option = new NumericOption(varModel, part); varModel.addConfigurationOption(option); } } } } return varModel; }
/// <summary> /// Parses the numeric options, represented as string, of a configuration. /// </summary> /// <param name="numericString">The string representation of the numeric configuration options.</param> /// <param name="numericOptions">The data strcutre containing the parsed numeric options and their values.</param> /// <param name="varModel">The variability model the configuration is defined for.</param> /// <returns>True if the configuration is valid</returns> private static bool parseNumericOptionString(string numericString, out Dictionary <NumericOption, double> numericOptions, VariabilityModel varModel) { bool valid = true; Dictionary <NumericOption, double> _numericOptions = new Dictionary <NumericOption, double>(); if (!string.IsNullOrEmpty(numericString)) { string[] numOptionArray = numericString.Trim().Split(','); foreach (string numOption in numOptionArray) { if (!valid) { break; } string[] numOptionsKeyValue; if (numOption.Contains(";")) { numOptionsKeyValue = numOption.Split(';'); } else { numOptionsKeyValue = numOption.Split(' ');// added for rc-lookahead 40 } numOptionsKeyValue[0] = numOptionsKeyValue[0].Trim(); if (numOptionsKeyValue[0].Length == 0) { continue; } NumericOption varFeat = varModel.getNumericOption(numOptionsKeyValue[0]); if (varFeat == null) { GlobalState.logError.logLine("No numeric option found with name: " + numOptionsKeyValue[0]); valid = false; } else { double varFeatValue = Convert.ToDouble(numOptionsKeyValue[1]); _numericOptions.Add(varFeat, varFeatValue); } } } numericOptions = _numericOptions; return(valid); }
/// <summary> /// Creates a numeric option based on the information of the given XML Node (calls base function) /// </summary> /// <param name="numOptNode">The XML Element containing the information</param> /// <param name="variabilityModel">The variability model to which the option belongs to</param> /// <returns>The newly created option</returns> internal static ConfigurationOption loadFromXML(XmlElement numOptNode, VariabilityModel variabilityModel) { NumericOption numOpt = new NumericOption(variabilityModel, "temp"); numOpt.loadFromXML(numOptNode); return numOpt; }
/// <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.BooleanConstraints) { 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; }
public void saveVarModel(VariabilityModel varMod) { varMod.saveXML(@"D:\SPLConquerorGitHub\\SPLConqueror\ExampleFiles\foo.xml"); }
/// <summary> /// Constructor to create a new numeric option. All values are set to zero (calls basic constructor) /// </summary> /// <param name="vm">The variability model to which the option belongs to</param> /// <param name="name">Name of that option</param> public NumericOption(VariabilityModel vm, String name) : base(vm, name) { this.Optional = false; }
/// <summary> /// Constructor to create a new numeric option. All values are set to zero (calls basic constructor) /// </summary> /// <param name="vm">The variability model to which the option belongs to</param> /// <param name="name">Name of that option</param> public NumericOption(VariabilityModel vm, String name) : base(vm, name) { }
/// <summary> /// Static method that reads an xml file and constructs a variability model using the stored information /// </summary> /// <param name="path">Path to the XML File</param> /// <returns>The instantiated variability model or null if there is no variability model at the path or if the model could not be parsed.</returns> public static VariabilityModel loadFromXML(String path) { VariabilityModel vm = new VariabilityModel("temp"); if (vm.loadXML(path)) return vm; else return null; }
/// <summary> /// Creates an influence function based on the expression. All token wich are neither number nor operators are considered to be /// numeric configuration options. /// </summary> /// <param name="expression">A function consisting of numbers, operators and configuration-option names.</param> public InfluenceFunction(String expression) { this.varModel = extractFeatureModelFromExpression(createWellFormedExpression(expression)); parseExpressionToPolnishNotation(expression); }