internal static ConstraintNetwork GenerateQualitativeConstraintNetwork(GKOStructuringContext strContext, RelationFamily calculus, Log log)
        {
            ConstraintNetwork resultNetwork = new ConstraintNetwork(calculus, strContext.Id + "_" + calculus.Name, log);
            List <ConfigurationConstraintTree> constraintTrees = strContext.StructuralConstraints.Where(x => x.RelationFamily == calculus).ToList();

            // Creating the constraints restricting that self edges should be labeled with the Equals relation from the calculus
            DomainConstraint            equalsDomainConstraint = DomainConstraint.SelfEqualsConstraint(calculus);
            ConfigurationConstraintTree equalsConstraint       = new ConfigurationConstraintTree(null, equalsDomainConstraint, strContext.Components.Where(x => x.Active).ToList(), log);

            // Adding the constraints restricting that self edges should be labeled with the Equals relation from the calculus
            constraintTrees.Add(equalsConstraint);

            resultNetwork.Context = strContext;
            // Adding all components as nodes in the constraint network
            strContext.Components.Where(x => x.Active).ToList().ForEach(x => resultNetwork.Nodes.Add(new Node(x)));

            // Creating all edges in the constraint network, so it is a complete graph
            foreach (var startNode in resultNetwork.Nodes)
            {
                foreach (var endNode in resultNetwork.Nodes)
                {
                    QualitativeEdge edge = new QualitativeEdge(resultNetwork, startNode, endNode);
                    resultNetwork.Edges.Add(new Tuple <Node, Node>(startNode, endNode), edge);
                }
            }

            // Each constraint tree has a number of configuration constraints
            foreach (var constraintTree in constraintTrees)
            {
                List <ConfigurationConstraint> constraints = constraintTree.GetAllConfigurationConstraints();

                // ToDo: Add check for equal constraints to avoid redundancy

                // Adding all constraints as edges in the networks
                constraints.ForEach(x =>
                {
                    // Hack: this uses the fact that each constraint has at least one allowed relation and all have the same signature and logic (i.e. start and end node)
                    Node startNode             = x.AllowedRelations[0].GetStartNode(x);
                    Node endNode               = x.AllowedRelations[0].GetEndNode(x);
                    Tuple <Node, Node> edgeKey = new Tuple <Node, Node>(startNode, endNode);
                    QualitativeEdge edge       = resultNetwork.Edges[edgeKey] as QualitativeEdge;

                    // Adding the constraint to the edge
                    edge.Constraints.Add(x);
                });
            }

            return(resultNetwork);
        }
        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);
        }