/// <summary>
        /// Finds the TMS decision variables needed for the current constraint tree (including branches) which are not part of the utility function.
        /// Note: It DOES generate variables for the included configuration constraints
        /// </summary>
        /// <returns></returns>
        internal List <TmsDecisionVariable> GetNonUtilityDecisionVariables()
        {
            List <TmsDecisionVariable> variables = new List <TmsDecisionVariable>();

            // When the current tree is not the root then add its decision variables as non-utility ones
            if (this.Parent != null)
            {
                List <string>     currentDVarNames = this.GetSatDVarNames();
                GKODomainAbstract boolDomain       = TmsManager.GenerateBoolDomain();

                foreach (var var in currentDVarNames)
                {
                    variables.Add(new TmsDecisionVariable(boolDomain, var));
                }
            }

            // Adding the variables from the branches
            if (this.IsCombination)
            {
                foreach (var branch in this.ConstraintBranches)
                {
                    variables.AddRange(branch.GetNonUtilityDecisionVariables());
                }
            }

            return(TmsDecisionVariable.GetDistinctVariables(variables, false));
        }
        /// <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>
        /// Solves the constraint network
        /// </summary>
        internal SolutionData Solve(StructuralReasonerOptions options, TmsManager tms)
        {
            if (this.Type == ConstraintNetworkType.QualitativeNetwork)
            {
                return(this.SolveQualitative(options, tms));
            }
            else if (this.Type == ConstraintNetworkType.MetricNetwork)
            {
                return(this.SolveMetric(options, tms));
            }

            return(null);
        }
Example #4
0
        /// <summary>
        /// Configures the internal TMS used to solve the structuring problems.
        /// <para>
        /// It is required to call this method once after the relevant options have been set
        /// </para>
        /// <para>Once this operation is complete some of the process options cannot be changed anymore, e.g.
        /// metric domain max value, soft constraints inclusion
        /// </para>
        /// </summary>
        public void ConfigureTms()
        {
            Stopwatch stopwatch = new Stopwatch();

            ProcessLog.AddItem(LogType.Info, String.Format("Starting TMS configuration"));

            stopwatch.Start();
            this.tms = new TmsManager(this.Options, this.ProcessLog);
            this.Options.TmsConfigured = true;
            stopwatch.Stop();

            ProcessLog.AddItem(LogType.Info, String.Format("TMS configuration finished ({0} ms)", stopwatch.ElapsedMilliseconds));
        }
        /// <summary>
        /// Finds the TMS decision variables needed for the current constraint tree (branches are not relevant) which are not part of the utility function.
        /// Note: It DOES generate the satisfaction decision variables for the included configuration constraints
        /// </summary>
        /// <returns></returns>
        internal List <TmsDecisionVariable> GetUtilityDecisionVariables()
        {
            List <TmsDecisionVariable> variables = new List <TmsDecisionVariable>();

            // Only when the current tree is the root its variables are considered utility ones
            if (this.Parent == null)
            {
                List <string>     currentDVarNames = this.GetSatDVarNames();
                GKODomainAbstract boolDomain       = TmsManager.GenerateBoolDomain();

                foreach (var var in currentDVarNames)
                {
                    variables.Add(new TmsDecisionVariable(boolDomain, var)
                    {
                        UtilityFactor = 1
                    });
                }
            }

            return(TmsDecisionVariable.GetDistinctVariables(variables, true));
        }
        /// <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);
        }
        /// <summary>
        /// Generates the metric constraint network for the structured components
        /// </summary>
        /// <param name="structuringContexts">The list of structured components to generate the networks for.
        /// They must include the metric relation family in the list of included ones</param>
        /// <returns></returns>
        internal static List <ConstraintNetwork> GenerateMetricConstraintNetworks(List <GKOStructuringContext> structuringContexts, TmsManager tms, StructuralReasonerOptions options, Log log)
        {
            List <ConstraintNetwork>           constraintNetworks = new List <ConstraintNetwork>();
            List <List <Node> >                clusters           = new List <List <Node> >();
            List <ConfigurationConstraintTree> constraintTrees    = new List <ConfigurationConstraintTree>();
            Stopwatch stopwatch = new Stopwatch();

            stopwatch.Start();
            // Adding all constraint trees to the list
            foreach (var context in structuringContexts)
            {
                context.StructuralConstraints.ForEach(x =>
                {
                    // Additionally assign the special metric values based on the context of the constraints
                    x.AssignSpecialMetricValues(context);
                    constraintTrees.Add(x);
                });
            }
            stopwatch.Stop();
            log.AddItem(LogType.Info, String.Format("Assigning special metric values finished ({0} ms).", stopwatch.ElapsedMilliseconds));

            stopwatch.Restart();
            // Combine the nodes in the constraint trees in linked clusters,
            // this serve as base for generating the constraint networks
            foreach (var constraintTree in constraintTrees)
            {
                clusters.AddRange(constraintTree.GetNodeClusters());
                ConstraintNetwork.NormalizeClusters(clusters);
            }
            stopwatch.Stop();
            log.AddItem(LogType.Info, String.Format("Finding node clusters finished ({0} ms).", stopwatch.ElapsedMilliseconds));

            #region TCSP specific
            // These constraints limit the domain of the decision variables for TCSP
            if (options.MetricReasoningAlgorithm == MetricReasoningAlgorithm.Tcsp)
            {
                stopwatch.Restart();
                List <Node> nodes = clusters.SelectMany(x => x).Where(x => x != null).Distinct().ToList();

                // Add min and max constraint for the constrained attributes
                foreach (var constrAttribute in nodes)
                {
                    List <GKOComponent> compList = new List <GKOComponent>()
                    {
                        constrAttribute.Component
                    };
                    DomainConstraint            minConstraint = DomainConstraint.MinValueConstraint(constrAttribute.Attribute, tms.MetricDomain);
                    DomainConstraint            maxConstraint = DomainConstraint.MaxValueConstraint(constrAttribute.Attribute, tms.MetricDomain);
                    ConfigurationConstraintTree minTree       = new ConfigurationConstraintTree(null, minConstraint, compList, log);
                    ConfigurationConstraintTree maxTree       = new ConfigurationConstraintTree(null, maxConstraint, compList, log);

                    constraintTrees.Add(minTree);
                    constraintTrees.Add(maxTree);
                }

                stopwatch.Stop();
                log.AddItem(LogType.Info, String.Format("Creating Min/Max constraints for TCSP finished ({0} ms).", stopwatch.ElapsedMilliseconds));
            }
            #endregion

            stopwatch.Restart();

            // Generating a new constraint network for each found node cluster
            foreach (var nodeCluster in clusters)
            {
                ConstraintNetwork network = new ConstraintNetwork(StructuralRelationsManager.MetricRelationsFamily, log);
                network.Nodes = nodeCluster;

                constraintNetworks.Add(network);
            }

            // Adding all configuration constraints in the constraint networks
            foreach (var constraintTree in constraintTrees)
            {
                ConfigurationConstraint[] treeConstraints = constraintTree.GetAllConfigurationConstraints().ToArray();

                for (int i = 0; i < treeConstraints.Length; i++)
                {
                    ConstraintNetwork.ApplyMetricConstraint(treeConstraints[i], constraintNetworks, log);
                }
            }

            // UId has to be assigned to the networks
            for (int i = 0; i < constraintNetworks.Count; i++)
            {
                constraintNetworks[i].UId = "MetricConstraintNetwork_" + (i + 1).ToString();
            }

            stopwatch.Stop();
            log.AddItem(LogType.Info, String.Format("Generating the constraint networks finished ({0} ms).", stopwatch.ElapsedMilliseconds));

            return(constraintNetworks);
        }
 /// <summary>
 /// Solves the configuration problem using TMS
 /// </summary>
 /// <param name="solutionInformation">The solution information to be updated</param>
 /// <param name="tmsVariables">The normal decision variables</param>
 /// <param name="tmsSoftVariables">The decision variables used for soft constraints</param>
 /// <param name="tmsConstraints">The constraints to e satisfied</param>
 private void SolveWithTms(SolutionData solutionInformation, TmsManager tms, List <TmsDecisionVariable> tmsVariables, List <TmsDecisionVariable> tmsSoftVariables, List <TmsConstraint> tmsConstraints)
 {
     // ToDo:
     tms.Solve(tmsVariables, tmsSoftVariables, tmsConstraints, solutionInformation);
 }
        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);
        }