/// <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);
        }