/// <summary> /// Recursively solves a TCSP /// </summary> /// <param name="unprocessedEdges">The TCSP unprocessed edges</param> /// <param name="selectedLabels">The current active edge intervals</param> /// <returns>The first consistent solution</returns> private Stp SolveTcsp(Dictionary <Tuple <Node, Node>, MetricEdge> unprocessedEdges, Dictionary <Tuple <Node, Node>, Interval> selectedLabels) { if (selectedLabels.Count == this.edgesCounts) { Stp completeStp; stopwatch1.Start(); completeStp = new Stp(selectedLabels); completeStp.ApplyDPC(completeStp.Nodes); stopwatch1.Stop(); this.ExaminedStps++; if (completeStp.IsConsistent) { completeStp.ApplyAPSP(); return(completeStp); } else { return(null); } } else { // Ordering the edges has a huge impact on the performance // Here the Beginning of time edges are processed first Tuple <Node, Node> currEdgeKey = unprocessedEdges.Keys.OrderBy(x => x.Item1).First(); MetricEdge currEdge = unprocessedEdges[currEdgeKey]; // Removing the explored edge unprocessedEdges.Remove(currEdgeKey); // Explore all possible intervals in the selected edge foreach (var interval in currEdge.AllowedIntervals) { Stp partialStp; // inserting the interval data in the selected labels selectedLabels.Add(currEdgeKey, interval); stopwatch55.Start(); partialStp = new Stp(selectedLabels); partialStp.ApplyDPC(partialStp.Nodes); stopwatch55.Stop(); // If the partial assignment is consistent continue with the assignment if (partialStp.IsConsistent) { Stp solution = SolveTcsp(unprocessedEdges, selectedLabels); // If a solution is available return it if (solution != null) { return(solution); } else { // The current labeling has to be removed before continuing selectedLabels.Remove(currEdgeKey); } } else { // The current labeling has to be removed before continuing selectedLabels.Remove(currEdgeKey); } } // If no solution is found the edge is returned to the list of unprocessed ones unprocessedEdges.Add(currEdgeKey, currEdge); return(null); } }
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); }