/// <summary> /// Finds the TMS decision variables needed for the current constraint tree (including branches) which are not part of the utility function. /// Note: It DOES generate variables for the included configuration constraints /// </summary> /// <returns></returns> internal List <TmsDecisionVariable> GetNonUtilityDecisionVariables() { List <TmsDecisionVariable> variables = new List <TmsDecisionVariable>(); // When the current tree is not the root then add its decision variables as non-utility ones if (this.Parent != null) { List <string> currentDVarNames = this.GetSatDVarNames(); GKODomainAbstract boolDomain = TmsManager.GenerateBoolDomain(); foreach (var var in currentDVarNames) { variables.Add(new TmsDecisionVariable(boolDomain, var)); } } // Adding the variables from the branches if (this.IsCombination) { foreach (var branch in this.ConstraintBranches) { variables.AddRange(branch.GetNonUtilityDecisionVariables()); } } return(TmsDecisionVariable.GetDistinctVariables(variables, false)); }
/// <summary> /// Generates TmsConstraints for the current constraint tree (including branches). /// Note: It does not generate constraints for the included configuration constraints, rather it only deals with branch combination logic /// </summary> /// <returns></returns> public List <TmsConstraint> GenerateTmsConstraints() { List <TmsConstraint> constraints = new List <TmsConstraint>(); // Only trees with branches generate constraints. The configuration constraints are not processed in this function if (this.IsCombination) { GKODomainAbstract boolDomain = TmsManager.GenerateBoolDomain(); IEnumerable <IEnumerable <string> > constraintDescriptions = this.GetSatDVarParts(); // Adding the constraints from each branch foreach (var branch in this.ConstraintBranches) { constraints.AddRange(branch.GenerateTmsConstraints()); } // Generating the TMS constraints for the current level foreach (var constraintDescription in constraintDescriptions) { TmsConstraint constraint = new TmsConstraint(); string currentDvarName = this.GetSatDVarName(constraintDescription); // The first elements of the constraint are the decision variables of the branches constraint.VariableTuple = constraintDescription.ToList(); // The last element is the decision variable of the constraint represented by the current tree constraint.VariableTuple.Add(currentDvarName); switch (this.CombinationType) { case DomainConstraintCombinationType.And: constraint.ConstraintType = constraintDescription.Count().GetAndCTName(); break; case DomainConstraintCombinationType.Or: constraint.ConstraintType = constraintDescription.Count().GetOrCTName(); break; case DomainConstraintCombinationType.ExactlyOne: constraint.ConstraintType = constraintDescription.Count().GetExactlyOneCTName(); break; default: throw new Exception("The chosen constraint combination type is not recognized!"); } constraints.Add(constraint); // This prohibits the constraint to be violated if it is hard constraint if (!this.DerivedFrom.CanBeViolated) { constraints.Add(TmsConstraint.GenerateSingleValueConstraint(boolDomain, currentDvarName, TmsManager.TrueValue)); } } } return(constraints); }
/// <summary> /// Solves the constraint network /// </summary> internal SolutionData Solve(StructuralReasonerOptions options, TmsManager tms) { if (this.Type == ConstraintNetworkType.QualitativeNetwork) { return(this.SolveQualitative(options, tms)); } else if (this.Type == ConstraintNetworkType.MetricNetwork) { return(this.SolveMetric(options, tms)); } return(null); }
/// <summary> /// Configures the internal TMS used to solve the structuring problems. /// <para> /// It is required to call this method once after the relevant options have been set /// </para> /// <para>Once this operation is complete some of the process options cannot be changed anymore, e.g. /// metric domain max value, soft constraints inclusion /// </para> /// </summary> public void ConfigureTms() { Stopwatch stopwatch = new Stopwatch(); ProcessLog.AddItem(LogType.Info, String.Format("Starting TMS configuration")); stopwatch.Start(); this.tms = new TmsManager(this.Options, this.ProcessLog); this.Options.TmsConfigured = true; stopwatch.Stop(); ProcessLog.AddItem(LogType.Info, String.Format("TMS configuration finished ({0} ms)", stopwatch.ElapsedMilliseconds)); }
/// <summary> /// Finds the TMS decision variables needed for the current constraint tree (branches are not relevant) which are not part of the utility function. /// Note: It DOES generate the satisfaction decision variables for the included configuration constraints /// </summary> /// <returns></returns> internal List <TmsDecisionVariable> GetUtilityDecisionVariables() { List <TmsDecisionVariable> variables = new List <TmsDecisionVariable>(); // Only when the current tree is the root its variables are considered utility ones if (this.Parent == null) { List <string> currentDVarNames = this.GetSatDVarNames(); GKODomainAbstract boolDomain = TmsManager.GenerateBoolDomain(); foreach (var var in currentDVarNames) { variables.Add(new TmsDecisionVariable(boolDomain, var) { UtilityFactor = 1 }); } } return(TmsDecisionVariable.GetDistinctVariables(variables, true)); }
/// <summary> /// ! Use this only once (not for every relation) per edge constraint ! /// </summary> /// <param name="constraint"></param> /// <param name="edge"></param> /// <returns></returns> public override List <TmsConstraint> GetTmsConstraints(ConfigurationConstraint constraint, Edge edge) { ////OLD: Rem: Qualitative relations use composition constraints and constraint limiting the allowed relations between components, hence there are no constraints implied by a single relation //throw new NotSupportedException("A single qualitative relation do not imply a constraint!"); List <TmsConstraint> result = new List <TmsConstraint>(); RelationFamily relFamily = constraint.AllowedRelations[0].RelationFamily; if (!(edge is QualitativeEdge)) { edge.Network.SturcturalReasonerLog.AddItem(LogType.Warning, string.Format("Edge {0} is not a qualitative edge. The requested TMS constraints will not be added.", edge.GetUId())); } else if (!edge.Constraints.Contains(constraint)) { edge.Network.SturcturalReasonerLog.AddItem(LogType.Warning, string.Format("The constraint {0} is not found in the edge {1}. The requested TMS constraints will not be added.", constraint.DomainConstraint.Name, edge.GetUId())); } else if (relFamily == StructuralRelationsManager.GetRelationFamily(RelationFamilyNames.MetricRelationsName)) { edge.Network.SturcturalReasonerLog.AddItem(LogType.Warning, string.Format("The constraint {0} is metric while the needed relation for edge {1} is qualitative. The requested TMS constraints will not be added.", constraint.DomainConstraint.Name, edge.GetUId())); } else { QualitativeEdge qualEdge = (QualitativeEdge)edge; GKODomain calculusDomain = StructuralRelationsManager.GetDomain(constraint.AllowedRelations[0].RelationFamily.GetTmsRelationsDomainName()); TmsConstraint exactlyOneHoldsConstraint = new TmsConstraint(); List <string> relDvars = new List <string>(); // holds all relation variables GKODomain boolDomain = TmsManager.GenerateBoolDomain(); string dVarSat = constraint.GetSatDVarName(); // This will create a constraint saying that the edge dvar is matching the chosen relation and the relation's dvar is TRUE, or if they are not matching and the relation's dvar is FALSE foreach (var relation in constraint.AllowedRelations) { TmsConstraint tmsConstraint = new TmsConstraint(); string edgeDVar = qualEdge.GetDVarName(); string edgeRelDVar = qualEdge.GetDVarName((QualitativeRelation)relation); string constraintTypeName = calculusDomain.GetIndividualValueCTName(relation.Name); relDvars.Add(edgeRelDVar); tmsConstraint.ConstraintType = constraintTypeName; tmsConstraint.VariableTuple = new List <string>() { edgeDVar, edgeRelDVar }; result.Add(tmsConstraint); } // This will create the constraint saying that one of the relation dvars has to be set // This works because the calculi are JEPD exactlyOneHoldsConstraint.ConstraintType = relDvars.Count.GetExactlyOneCTName(); exactlyOneHoldsConstraint.VariableTuple = new List <string>(relDvars); exactlyOneHoldsConstraint.VariableTuple.Add(dVarSat); // This prohibits the constraint to be violated if (!constraint.CanBeViolated) { result.Add(TmsConstraint.GenerateSingleValueConstraint(boolDomain, dVarSat, TmsManager.TrueValue)); } result.Add(exactlyOneHoldsConstraint); } return(result); }
/// <summary> /// Generates the metric constraint network for the structured components /// </summary> /// <param name="structuringContexts">The list of structured components to generate the networks for. /// They must include the metric relation family in the list of included ones</param> /// <returns></returns> internal static List <ConstraintNetwork> GenerateMetricConstraintNetworks(List <GKOStructuringContext> structuringContexts, TmsManager tms, StructuralReasonerOptions options, Log log) { List <ConstraintNetwork> constraintNetworks = new List <ConstraintNetwork>(); List <List <Node> > clusters = new List <List <Node> >(); List <ConfigurationConstraintTree> constraintTrees = new List <ConfigurationConstraintTree>(); Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); // Adding all constraint trees to the list foreach (var context in structuringContexts) { context.StructuralConstraints.ForEach(x => { // Additionally assign the special metric values based on the context of the constraints x.AssignSpecialMetricValues(context); constraintTrees.Add(x); }); } stopwatch.Stop(); log.AddItem(LogType.Info, String.Format("Assigning special metric values finished ({0} ms).", stopwatch.ElapsedMilliseconds)); stopwatch.Restart(); // Combine the nodes in the constraint trees in linked clusters, // this serve as base for generating the constraint networks foreach (var constraintTree in constraintTrees) { clusters.AddRange(constraintTree.GetNodeClusters()); ConstraintNetwork.NormalizeClusters(clusters); } stopwatch.Stop(); log.AddItem(LogType.Info, String.Format("Finding node clusters finished ({0} ms).", stopwatch.ElapsedMilliseconds)); #region TCSP specific // These constraints limit the domain of the decision variables for TCSP if (options.MetricReasoningAlgorithm == MetricReasoningAlgorithm.Tcsp) { stopwatch.Restart(); List <Node> nodes = clusters.SelectMany(x => x).Where(x => x != null).Distinct().ToList(); // Add min and max constraint for the constrained attributes foreach (var constrAttribute in nodes) { List <GKOComponent> compList = new List <GKOComponent>() { constrAttribute.Component }; DomainConstraint minConstraint = DomainConstraint.MinValueConstraint(constrAttribute.Attribute, tms.MetricDomain); DomainConstraint maxConstraint = DomainConstraint.MaxValueConstraint(constrAttribute.Attribute, tms.MetricDomain); ConfigurationConstraintTree minTree = new ConfigurationConstraintTree(null, minConstraint, compList, log); ConfigurationConstraintTree maxTree = new ConfigurationConstraintTree(null, maxConstraint, compList, log); constraintTrees.Add(minTree); constraintTrees.Add(maxTree); } stopwatch.Stop(); log.AddItem(LogType.Info, String.Format("Creating Min/Max constraints for TCSP finished ({0} ms).", stopwatch.ElapsedMilliseconds)); } #endregion stopwatch.Restart(); // Generating a new constraint network for each found node cluster foreach (var nodeCluster in clusters) { ConstraintNetwork network = new ConstraintNetwork(StructuralRelationsManager.MetricRelationsFamily, log); network.Nodes = nodeCluster; constraintNetworks.Add(network); } // Adding all configuration constraints in the constraint networks foreach (var constraintTree in constraintTrees) { ConfigurationConstraint[] treeConstraints = constraintTree.GetAllConfigurationConstraints().ToArray(); for (int i = 0; i < treeConstraints.Length; i++) { ConstraintNetwork.ApplyMetricConstraint(treeConstraints[i], constraintNetworks, log); } } // UId has to be assigned to the networks for (int i = 0; i < constraintNetworks.Count; i++) { constraintNetworks[i].UId = "MetricConstraintNetwork_" + (i + 1).ToString(); } stopwatch.Stop(); log.AddItem(LogType.Info, String.Format("Generating the constraint networks finished ({0} ms).", stopwatch.ElapsedMilliseconds)); return(constraintNetworks); }
/// <summary> /// Solves the configuration problem using TMS /// </summary> /// <param name="solutionInformation">The solution information to be updated</param> /// <param name="tmsVariables">The normal decision variables</param> /// <param name="tmsSoftVariables">The decision variables used for soft constraints</param> /// <param name="tmsConstraints">The constraints to e satisfied</param> private void SolveWithTms(SolutionData solutionInformation, TmsManager tms, List <TmsDecisionVariable> tmsVariables, List <TmsDecisionVariable> tmsSoftVariables, List <TmsConstraint> tmsConstraints) { // ToDo: tms.Solve(tmsVariables, tmsSoftVariables, tmsConstraints, solutionInformation); }
internal SolutionDataMetric SolveMetric(StructuralReasonerOptions options, TmsManager tms) { SolutionDataMetric solutionInformation = new SolutionDataMetric(this); solutionInformation.StartTime = DateTime.Now; //try //{ if (options.MetricReasoningAlgorithm == MetricReasoningAlgorithm.Tcsp) { Tcsp tcsp = new Tcsp(this); Stp solution = null; if (this.Edges.Values.Any(x => x.AllConstraints.Any(y => !y.OwningTreeRoot.IsValidForTcsp))) { solutionInformation.Log.AddItem(LogType.Error, string.Format("Disjunctive domain constraints are not allowed in TCSP!", this.UId)); } else { solutionInformation.Log.AddItem(LogType.Info, string.Format("Solving metric network {0} with TCSP", this.UId)); solution = tcsp.Solve(); solutionInformation.Log.AddItem(LogType.Info, string.Format("TCSP solving process complete ({0} ms)", (DateTime.Now - solutionInformation.StartTime).TotalMilliseconds)); } if (solution != null && solution.IsConsistent) { solutionInformation.SolutionFound = true; solutionInformation.Solution = solution.GetSolution(); } else { solutionInformation.SolutionFound = false; } } else { List <TmsDecisionVariable> tmsVariables = new List <TmsDecisionVariable>(); // Normal TMS variables List <TmsDecisionVariable> tmsUtilityVariables = new List <TmsDecisionVariable>(); // Utility TMS variables List <TmsConstraint> tmsConstraints = new List <TmsConstraint>(); HashSet <ConfigurationConstraintTree> relevantConstraintTrees = new HashSet <ConfigurationConstraintTree>(); GKODomainAbstract satisfiedDomain = tms.BoolDomain; GKODomainAbstract metricDomain = tms.MetricDomain; solutionInformation.Log.AddItem(LogType.Info, string.Format("Solving metric network {0} with CDA* started", this.UId)); solutionInformation.Stopwatch.Start(); // Adding all node decision variables foreach (var node in this.Nodes) { // The biginning of time is not relevant for the CDA* if (node != null) { tmsVariables.Add(new TmsDecisionVariable(metricDomain, node.GetDVarName())); } } // Processing configuration constraints in edges foreach (var edge in this.Edges.Values) { foreach (var constraint in edge.Constraints) { List <MetricRelationPart> metricParts = constraint.RelationParts.Where(x => x is MetricRelationPart).Select(x => (MetricRelationPart)x).ToList(); TmsConstraint tmsConstraint = new TmsConstraint(); // Creating the TMS constraint implied by the configuration constraint tmsConstraints.AddRange(constraint.AllowedRelations[0].GetTmsConstraints(constraint, edge)); // Each metric part in the constraint has its own decision variable which has to be created // Additionally, there is a hard constraint restricting the value of the variable to the single selected values foreach (var metricPart in metricParts) { // If the value of the metric part is already used it will have the same decision variable name if (!tmsVariables.Any(x => x.Name == metricPart.GetDVarName())) { tmsVariables.Add(new TmsDecisionVariable(metricDomain, metricPart.GetDVarName())); tmsConstraints.Add(TmsConstraint.GenerateSingleValueConstraint(StructuralRelationsManager.MetricDomain, metricPart.GetDVarName(), metricPart.GetValue())); } } } // Adding all configuration trees, from which the configuration constraints in edge are derived, in a set. This set is used later to generate the constraints combination and utility TMS variables and TMS constraints foreach (var constraint in edge.AllConstraints) { relevantConstraintTrees.Add(constraint.OwningTreeRoot); } } // Generating the constraints and variables for each constraint tree foreach (var constraintTree in relevantConstraintTrees) { tmsConstraints.AddRange(constraintTree.GenerateTmsConstraints()); tmsVariables.AddRange(constraintTree.GetNonUtilityDecisionVariables()); tmsUtilityVariables.AddRange(constraintTree.GetUtilityDecisionVariables()); } // Since some decision variables can be duplicated, we have to find the distinct ones // Additionally, for utility variables their utility factor has to be recalculated as needed tmsVariables = TmsDecisionVariable.GetDistinctVariables(tmsVariables, false); tmsUtilityVariables = TmsDecisionVariable.GetDistinctVariables(tmsUtilityVariables, true); // It is possible that a variable is defined in both lists so it has to be removed from this one tmsVariables = tmsVariables.Where(x => !tmsUtilityVariables.Any(y => x.Name == y.Name)).ToList(); solutionInformation.Stopwatch.Stop(); solutionInformation.Log.AddItem(LogType.Info, string.Format("TMS variables and constraints generated ({0} ms)", solutionInformation.Stopwatch.ElapsedMilliseconds)); solutionInformation.Log.AddItem(LogType.Info, string.Format("TMS solution process started", solutionInformation.Stopwatch.ElapsedMilliseconds)); solutionInformation.Log.AddItem(LogType.Info, string.Format("Variables (excl. soft): {0}", tmsVariables.Count)); solutionInformation.Log.AddItem(LogType.Info, string.Format("Variables for soft constraints: {0}", tmsUtilityVariables.Count)); solutionInformation.Log.AddItem(LogType.Info, string.Format("Constraints: {0}", tmsConstraints.Count)); solutionInformation.Stopwatch.Restart(); this.SolveWithTms(solutionInformation, tms, tmsVariables, tmsUtilityVariables, tmsConstraints); solutionInformation.Stopwatch.Stop(); solutionInformation.Log.AddItem(LogType.Info, string.Format("TMS solution process complete ({0} ms)", solutionInformation.Stopwatch.ElapsedMilliseconds)); } //} //catch (Exception e) //{ // solutionInformation.Log.AddItem(LogType.Error, e.ToString()); //} solutionInformation.SolutionFinished(); return(solutionInformation); }
internal SolutionDataQualitative SolveQualitative(StructuralReasonerOptions options, TmsManager tms) { SolutionDataQualitative solutionInformation = new SolutionDataQualitative(this); List <TmsDecisionVariable> tmsVariables = new List <TmsDecisionVariable>(); // Normal TMS variables List <TmsDecisionVariable> tmsUtilityVariables = new List <TmsDecisionVariable>(); // Utility TMS variables List <TmsConstraint> tmsConstraints = new List <TmsConstraint>(); HashSet <ConfigurationConstraintTree> relevantConstraintTrees = new HashSet <ConfigurationConstraintTree>(); GKODomainAbstract satisfiedDomain = tms.BoolDomain; GKODomainAbstract calculusDomain = tms.CalculiDomains.Single(x => x.Name == this.RelationFamily.GetTmsRelationsDomainName()); solutionInformation.StartTime = DateTime.Now; //try //{ solutionInformation.Stopwatch.Start(); // For each edge adds the decion variables of the edge and generates the TMS constraints for each configuration constraint foreach (var edge in this.Edges.Values) { QualitativeEdge qualEdge = (edge as QualitativeEdge); string edgeDVar = qualEdge.GetDVarName(); // Adding the edge decision variable tmsVariables.Add(new TmsDecisionVariable(calculusDomain, edgeDVar)); // Adding the bool dvar for each relation used in a constraint of the edge // They are mapped to the edge dvar later with a constraint foreach (var relation in edge.Constraints.SelectMany(x => x.AllowedRelations).Distinct()) { tmsVariables.Add(new TmsDecisionVariable(satisfiedDomain, qualEdge.GetDVarName((QualitativeRelation)relation))); } foreach (var constraint in edge.Constraints) { // ToDo: Make the GetTmsConstraints more consistent - now it is actually working on a constraint lvl for qualitative relations // Adding the TMS constraints derivde by the relation tmsConstraints.AddRange(constraint.AllowedRelations[0].GetTmsConstraints(constraint, edge)); } // Adding all configuration trees, from which the configuration constraints in edge are derived, in a set. This set is used later to generate the constraints combination and utility TMS variables and TMS constraints foreach (var constraint in edge.AllConstraints) { relevantConstraintTrees.Add(constraint.OwningTreeRoot); } } // Generating the constraints and variables for each constraint tree foreach (var constraintTree in relevantConstraintTrees) { tmsConstraints.AddRange(constraintTree.GenerateTmsConstraints()); tmsVariables.AddRange(constraintTree.GetNonUtilityDecisionVariables()); tmsUtilityVariables.AddRange(constraintTree.GetUtilityDecisionVariables()); } // Since some decision variables can be duplicated, we have to find the distinct ones // Additionally, for utility variables their utility factor has to be recalculated as needed tmsVariables = TmsDecisionVariable.GetDistinctVariables(tmsVariables, false); tmsUtilityVariables = TmsDecisionVariable.GetDistinctVariables(tmsUtilityVariables, true); // Generating the composition constraints foreach (var nodeA in this.Nodes) { foreach (var nodeB in this.Nodes) { foreach (var nodeC in this.Nodes) { QualitativeEdge edgeAB = (QualitativeEdge)this.Edges[new Tuple <Node, Node>(nodeA, nodeB)]; QualitativeEdge edgeBC = (QualitativeEdge)this.Edges[new Tuple <Node, Node>(nodeB, nodeC)]; QualitativeEdge edgeAC = (QualitativeEdge)this.Edges[new Tuple <Node, Node>(nodeA, nodeC)]; string edgeABDVar = edgeAB.GetDVarName(); string edgeBCDVar = edgeBC.GetDVarName(); string edgeACDVar = edgeAC.GetDVarName(); TmsConstraint compositionConstraint = new TmsConstraint(); // Creating the constraint restricting the allowed relations by the edge compositionConstraint.ConstraintType = this.RelationFamily.GetTmsCompositionConstraintName(); compositionConstraint.VariableTuple = new List <string>() { edgeABDVar, edgeBCDVar, edgeACDVar }; tmsConstraints.Add(compositionConstraint); } } } solutionInformation.Stopwatch.Stop(); solutionInformation.Log.AddItem(LogType.Info, string.Format("TMS variables and constraints generated ({0} ms)", solutionInformation.Stopwatch.ElapsedMilliseconds)); solutionInformation.Log.AddItem(LogType.Info, string.Format("TMS solution process started", solutionInformation.Stopwatch.ElapsedMilliseconds)); solutionInformation.Log.AddItem(LogType.Info, string.Format("Variables (excl. soft): {0}", tmsVariables.Count)); solutionInformation.Log.AddItem(LogType.Info, string.Format("Variables for soft constraints: {0}", tmsUtilityVariables.Count)); solutionInformation.Log.AddItem(LogType.Info, string.Format("Constraints: {0}", tmsConstraints.Count)); solutionInformation.Stopwatch.Restart(); this.SolveWithTms(solutionInformation, tms, tmsVariables, tmsUtilityVariables, tmsConstraints); solutionInformation.Stopwatch.Stop(); solutionInformation.Log.AddItem(LogType.Info, string.Format("TMS solution process complete ({0} ms)", solutionInformation.Stopwatch.ElapsedMilliseconds)); //} //catch (Exception e) //{ // solutionInformation.Log.AddItem(LogType.Error, e.ToString()); //} solutionInformation.SolutionFinished(); return(solutionInformation); }