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