/// <summary> /// Generates a TMS constraint restricting the value of a decision variable to a predefined one /// </summary> /// <param name="domain">The domain of the decision variable</param> /// <param name="dVarName">The decision variable</param> /// <param name="value">The value that the decision value is restricted to have</param> /// <returns>The TMS constraint</returns> internal static TmsConstraint GenerateSingleValueConstraint(GKODomainAbstract domain, string dVarName, string value) { TmsConstraint tmsConstraint = new TmsConstraint(); tmsConstraint.ConstraintType = domain.GetIndividualValueCTName(value); tmsConstraint.VariableTuple = new List <string>() { dVarName }; return(tmsConstraint); }
///// <summary> ///// Create all constraint types corresponding to the subsets of the relations in a relation family ///// </summary> ///// <param name="calculus">The relation family</param> //private void CreateCTForPowerset(RelationFamily calculus) //{ // //GKOConstraintType constraintType; // //GKODomainAbstract relationsDomain; // //GKODomainAbstract powerSetIxDomain; // //bool enableSoftConstraints = this.structuralReasonerOptions.SoftConstraintsEnabled; // //if (calculus.Name == RelationFamilyNames.MetricRelationsName) // //{ // // throw new NotSupportedException("The metric relations do not support this operation."); // //} // //relationsDomain = StructuralRelationsManager.GetDomain(calculus.GetTmsRelationsDomainName()); // //powerSetIxDomain = this.CalculiPwSetIxDomain; // //constraintType = new GKOConstraintType(); // //constraintType.Id = calculus.GetPwSetCTName(); // //constraintType.Name = calculus.GetPwSetCTName(); // //constraintType.Signature = new List<GKODomainAbstract>() { powerSetIxDomain, relationsDomain }; // //constraintType.Tuples = new List<List<string>>(); // //if (enableSoftConstraints) // //{ // // constraintType.Signature.Add(this.BoolDomain); // //} // //// The name of the constraint is labeled by the integer representation of the included relations // //// e.g. set 17 = 10001, i.e. relations 0 and 3 are included in the constraint with label 17 // //for (int setIx = 1; setIx < Math.Pow(2, calculus.Relations.Count); setIx++) // //{ // // List<BinaryRelation> includedRelations = new List<BinaryRelation>(); // // for (int i = 0; i < calculus.Relations.Count; i++) // // { // // if ((setIx & (1 << i)) != 0) // // { // // //n-th bit is set, so we include the n-th relation // // includedRelations.Add(calculus.Relations[i]); // // } // // } // // // When soft constraints are enabled the constraint types should be adjusted accordingly // // if (enableSoftConstraints) // // { // // List<BinaryRelation> excludedReltions = calculus.Relations.Except(includedRelations).ToList(); // // foreach (var rel in includedRelations) // // { // // constraintType.Tuples.Add(new List<string>() { setIx.ToString(), rel.Name, TmsManager.TrueValue }); // // } // // // Adding the non-satisfied tuples: *, 0 // // // ct.Tuples.Add(new List<string>() { TmsManager.WildcardValue, TmsManager.FalseValue }); // // foreach (var rel in excludedReltions) // // { // // constraintType.Tuples.Add(new List<string>() { setIx.ToString(), rel.Name, TmsManager.FalseValue }); // // } // // } // // else // // { // // foreach (var rel in includedRelations) // // { // // constraintType.Tuples.Add(new List<string>() { setIx.ToString(), rel.Name }); // // } // // } // //} // //this.ConstraintTypes.Add(constraintType.Name, constraintType.CreateIConstraintType(cdaStarTms, this.Domains)); //} /// <summary> /// Creates the metric constraint types /// </summary> /// <returns></returns> private void CreateMetricRelConstrTypes() { GKOIntDomain metricDomain = this.MetricDomain; GKODomainAbstract satisfiedDomain = this.BoolDomain; GKOConstraintType constraintType; List <List <string> > tuples; // Legacy variable. Now it should be always true bool enableSoftConstraints = true; // Creating the "Greater than" (a>b) constraint type constraintType = new GKOConstraintType() { Id = CTNameGreaterThan, Name = CTNameGreaterThan }; constraintType.Signature = new List <GKODomainAbstract>() { metricDomain, metricDomain }; if (enableSoftConstraints) { constraintType.Signature.Add(satisfiedDomain); } tuples = new List <List <string> >(); for (int a = metricDomain.MinValue; a < metricDomain.MaxValue + 1; a += metricDomain.StepWidth) { if (enableSoftConstraints) { for (int b = metricDomain.MinValue; b < metricDomain.MaxValue + 1; b += metricDomain.StepWidth) { // in some cases the non-satisfied tuples are added: *, *, 0 // tuples.Add(new List<string>() { TmsManager.WildcardValue, TmsManager.WildcardValue, TmsManager.FalseValue }); tuples.Add(new List <string>() { a.ToString(), b.ToString(), a > b ? TrueValue : FalseValue }); } } else { for (int b = metricDomain.MinValue; b < a; b += metricDomain.StepWidth) { tuples.Add(new List <string>() { a.ToString(), b.ToString() }); } } } constraintType.Tuples = tuples; // Adds the constraint type to the CS3 this.ConstraintTypes.Add(constraintType.Name, constraintType.CreateIConstraintType(cdaStarTms, this.Domains)); // Creating the "Greater or equals" (a>=b) constraint type constraintType = new GKOConstraintType() { Id = CTNameGreaterOrEquals, Name = CTNameGreaterOrEquals }; constraintType.Signature = new List <GKODomainAbstract>() { metricDomain, metricDomain }; if (enableSoftConstraints) { constraintType.Signature.Add(satisfiedDomain); } tuples = new List <List <string> >(); for (int a = metricDomain.MinValue; a < metricDomain.MaxValue + 1; a += metricDomain.StepWidth) { if (enableSoftConstraints) { for (int b = metricDomain.MinValue; b < metricDomain.MaxValue + 1; b += metricDomain.StepWidth) { // in some cases the non-satisfied tuples are added: *, *, 0 // tuples.Add(new List<string>() { TmsManager.WildcardValue, TmsManager.WildcardValue, TmsManager.FalseValue }); tuples.Add(new List <string>() { a.ToString(), b.ToString(), a >= b ? TrueValue : FalseValue }); } } else { for (int b = metricDomain.MinValue; b <= a; b += metricDomain.StepWidth) { tuples.Add(new List <string>() { a.ToString(), b.ToString() }); } } } constraintType.Tuples = tuples; // Adds the constraint type to the CS3 this.ConstraintTypes.Add(constraintType.Name, constraintType.CreateIConstraintType(cdaStarTms, this.Domains)); // Creating the "Equals" (a=b) constraint type constraintType = new GKOConstraintType() { Id = CTNameEquals, Name = CTNameEquals }; constraintType.Signature = new List <GKODomainAbstract>() { metricDomain, metricDomain }; if (enableSoftConstraints) { constraintType.Signature.Add(satisfiedDomain); } tuples = new List <List <string> >(); for (int a = metricDomain.MinValue; a < metricDomain.MaxValue + 1; a += metricDomain.StepWidth) { if (enableSoftConstraints) { for (int b = metricDomain.MinValue; b < metricDomain.MaxValue + 1; b += metricDomain.StepWidth) { // in some cases the non-satisfied tuples are added: *, *, 0 // tuples.Add(new List<string>() { TmsManager.WildcardValue, TmsManager.WildcardValue, TmsManager.FalseValue }); tuples.Add(new List <string>() { a.ToString(), b.ToString(), a == b ? TmsManager.TrueValue : TmsManager.FalseValue }); } } else { tuples.Add(new List <string>() { a.ToString(), a.ToString() }); } } constraintType.Tuples = tuples; // Adds the constraint type to the CS3 this.ConstraintTypes.Add(constraintType.Name, constraintType.CreateIConstraintType(cdaStarTms, this.Domains)); // Creating the "Not equals" (a!=b) constraint type constraintType = new GKOConstraintType() { Id = CTNameNotEquals, Name = CTNameNotEquals }; constraintType.Signature = new List <GKODomainAbstract>() { metricDomain, metricDomain }; if (enableSoftConstraints) { constraintType.Signature.Add(satisfiedDomain); } tuples = new List <List <string> >(); for (int a = metricDomain.MinValue; a < metricDomain.MaxValue + 1; a += metricDomain.StepWidth) { if (enableSoftConstraints) { for (int b = metricDomain.MinValue; b < metricDomain.MaxValue + 1; b += metricDomain.StepWidth) { // in some cases the non-satisfied tuples are added: *, *, 0 // tuples.Add(new List<string>() { TmsManager.WildcardValue, TmsManager.WildcardValue, TmsManager.FalseValue }); tuples.Add(new List <string>() { a.ToString(), b.ToString(), a != b ? TrueValue : FalseValue }); } } else { for (int b = metricDomain.MinValue; b < metricDomain.MaxValue + 1; b += metricDomain.StepWidth) { if (a != b) { tuples.Add(new List <string>() { a.ToString(), b.ToString() }); } } } } constraintType.Tuples = tuples; // Adds the constraint type to the CS3 this.ConstraintTypes.Add(constraintType.Name, constraintType.CreateIConstraintType(cdaStarTms, this.Domains)); // Creating the "Plus" (a + b = c) constraint type constraintType = new GKOConstraintType() { Id = CTNamePlus, Name = CTNamePlus }; constraintType.Signature = new List <GKODomainAbstract>() { metricDomain, metricDomain, metricDomain }; if (enableSoftConstraints) { constraintType.Signature.Add(satisfiedDomain); } tuples = new List <List <string> >(); for (int a = metricDomain.MinValue; a < metricDomain.MaxValue + 1; a += metricDomain.StepWidth) { if (enableSoftConstraints) { for (int b = metricDomain.MinValue; b < metricDomain.MaxValue + 1; b += metricDomain.StepWidth) { for (int c = metricDomain.MinValue; c < metricDomain.MaxValue + 1; c += metricDomain.StepWidth) { // in some cases the non-satisfied tuples are added: *, *, *, 0 // tuples.Add(new List<string>() { TmsManager.WildcardValue, TmsManager.WildcardValue, TmsManager.WildcardValue, TmsManager.FalseValue }); tuples.Add(new List <string>() { a.ToString(), b.ToString(), c.ToString(), (a + b) == c ? TrueValue : FalseValue }); } } } else { for (int b = metricDomain.MinValue; a + b < metricDomain.MaxValue + 1; b += metricDomain.StepWidth) { tuples.Add(new List <string>() { a.ToString(), b.ToString(), (a + b).ToString() }); } } } constraintType.Tuples = tuples; // Adds the constraint type to the CS3 this.ConstraintTypes.Add(constraintType.Name, constraintType.CreateIConstraintType(cdaStarTms, this.Domains)); }
///// <summary> ///// Generates the domain used as index for the powerset of the enabled calculi ///// </summary> ///// <returns></returns> //private GKOIntDomain GenerateCalculiPwSetIxDomain() //{ // GKOIntDomain domain = new GKOIntDomain() // { // Id = DomainNameCalculiPwSetIx, // Name = DomainNameCalculiPwSetIx, // StepWidth = 1, // MinValue = 0, // MaxValue = (int)Math.Pow(2, StructuralRelationsManager.RelationFamilies.Max(x => x.Relations.Count)) // }; // return domain; //} #region Constraint Types /// <summary> /// Creates constraint types in the CS3, each new CT contains only one value from a domain. /// NOTE: These constraint types are used to allow only one value to be selected for a variable. /// </summary> /// <param name="domain">The domain to create constraint types for</param> /// <param name="addSoft">Specifies whether to add a softness variable at the end</param> private void CreateIndividualCTForDomain(GKODomainAbstract domain, bool addSoft) { List <GKOConstraintType> constraintTypes = new List <GKOConstraintType>(); List <string> domainValues = new List <string>(); if (domain is GKOIntDomain) { GKOIntDomain domainTemp = domain as GKOIntDomain; for (int i = domainTemp.MinValue; i < domainTemp.MaxValue + 1; i += domainTemp.StepWidth) { domainValues.Add(i.ToString()); } } else if (domain is GKODomain) { GKODomain domainTemp = domain as GKODomain; foreach (var value in domainTemp.Values) { domainValues.Add(value); } } foreach (var value in domainValues) { GKOConstraintType ct = new GKOConstraintType() { Id = domain.GetIndividualValueCTName(value), Name = domain.GetIndividualValueCTName(value), Signature = new List <GKODomainAbstract>() { domain }, Tuples = new List <List <string> >() { new List <string>() { value } } }; if (addSoft) { ct.Signature.Add(this.BoolDomain); ct.Tuples[0].Add(TrueValue); foreach (var excludedValue in domainValues) { ct.Tuples.Add(new List <string>() { excludedValue, FalseValue }); } } constraintTypes.Add(ct); } constraintTypes.ForEach(x => this.ConstraintTypes.Add(x.Name, x.CreateIConstraintType(cdaStarTms, this.Domains))); }
internal TmsDecisionVariable(GKODomainAbstract domain, string name) { this.Domain = domain; this.Name = name; this.UtilityFactor = 0; }
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); }