Пример #1
0
        private static (MatchingDictionary completeMatching, MaximumMatchings2 matches) FindAllMatches(List <Data> inputs, List <Data> allData, List <WorkflowComponent> workflowComponents)
        {
            var inputsHash  = new HashSet <string>(inputs.Select(d => d.Id));
            var outputsHash = new HashSet <string>();

            // 1.0. Check for non-reversible variables that are either only input or output
            var nonReversibleData = allData.Where(d => !(d is DoubleData)).ToList();
            Dictionary <string, IOStatus> nonReversibleStatus = workflowComponents.GetDataStatus(nonReversibleData);

            //var collisionDictionary = new Dictionary<string, char>();
            //foreach (var component in workflowComponents)
            //{
            //	foreach (var input in component.ModelDataInputs)
            //	{
            //		if (!(input is DoubleData))
            //		{
            //			string inName = input.Id;
            //			if (collisionDictionary.ContainsKey(inName))
            //				collisionDictionary[inName] = 'b';
            //			else
            //				collisionDictionary[inName] = 'i';
            //		}
            //	}

            //	foreach (var output in component.ModelDataOutputs)
            //	{
            //		if (!(output is DoubleData))
            //		{
            //			string outName = output.Id;
            //			if (collisionDictionary.ContainsKey(outName))
            //				collisionDictionary[outName] = 'b';
            //			else
            //				collisionDictionary[outName] = 'o';
            //		}
            //	}
            //}

            foreach (string data in nonReversibleStatus.Keys)
            {
                if (nonReversibleStatus[data] == IOStatus.Input)
                {
                    inputsHash.Add(data);
                }
                else if (nonReversibleStatus[data] == IOStatus.Output)
                {
                    outputsHash.Add(data);
                }
            }


            var bipartite = new BipartiteGraph();

            Primes.Reset();
            var outputsDict = new MatchingDictionary(workflowComponents.Select(c => c.Id));

            // 1.1 Add Nodes for the Variables
            // Filter-out the selected inputs and outputs, as they don't belong to the bipartite graph
            foreach (Data data in allData.Where(d => !inputsHash.Contains(d.Id) && !outputsHash.Contains(d.Id)))
            {
                bipartite.AddNode(data.Id, GraphNode.Type.Type1);
            }

            // 1.2 Add Nodes for the Models, and edges between Variables and Nodes
            foreach (WorkflowComponent component in workflowComponents)
            {
                int uniqueNonReversibleOutputs = 0;

                outputsDict.Add(component.Id, new HashSet <string>());

                bipartite.AddNode(CS(component.Id), GraphNode.Type.Type2);
                GraphNode modelNode = bipartite.GetNode(CS(component.Id));

                // Filter-out the selected inputs, as they don't belong to the bipartite graph
                foreach (Data data in component.ModelDataInputs.Where(d => !inputsHash.Contains(d.Id)))
                {
                    if (outputsHash.Contains(data.Id))
                    {
                        // Shouldn't arrive here
                        uniqueNonReversibleOutputs++;
                        outputsDict[component.Id].Add(data.Id);
                    }
                    else
                    {
                        bipartite.AddDirectedEdge(data.Id, modelNode, Primes.Next(), 1);
                    }
                }

                // Filter-out the selected inputs, as they don't belong to the bipartite graph
                foreach (Data data in component.ModelDataOutputs.Where(d => !inputsHash.Contains(d.Id)))
                {
                    if (outputsHash.Contains(data.Id))
                    {
                        uniqueNonReversibleOutputs++;
                        outputsDict[component.Id].Add(data.Id);
                    }
                    else
                    {
                        bipartite.AddDirectedEdge(data.Id, modelNode, Primes.Next(), 0);
                    }
                }
                // How many output the model need
                if (component.ModelDataOutputs.Count - uniqueNonReversibleOutputs > 1)
                {
                    bipartite.modelAndItsOutputs.Add(CS(component.Id), component.ModelDataOutputs.Count - uniqueNonReversibleOutputs);                     //signle output models are not stored
                }
                else if (component.ModelDataOutputs.Count - uniqueNonReversibleOutputs == 0)
                {
                    bipartite.Remove(CS(component.Id));
                }
            }

            // 1.3 Associate matchings to each model, maping models to set of outputs
            var matches = new MaximumMatchings2(bipartite, getAllMatchings: true);

            return(outputsDict, matches);
        }
Пример #2
0
        private static MatchingDictionary MatchModelsWithVariablesGlobal(List <Data> allData, List <WorkflowComponent> components, GlobalReversalMode mode)
        {
            if (mode == GlobalReversalMode.NoReversedModels || mode == GlobalReversalMode.Global)
            {
                List <WorkflowComponent>      originalComponents = components.GetAllComponents();
                Dictionary <string, IOStatus> status             = originalComponents.GetInputsOutputsStatus(allData, out List <Data> inputs, out List <Data> outputs);
                foreach (string key in status.Keys)
                {
                    if (status[key] == IOStatus.Conflict)
                    {
                        throw new ArgumentException($"The following varibale \"{key}\" is of non-reversible type and output of more than one model. Therefore the workflow cannot be created");
                    }
                }

                var inputsHash = new HashSet <string>(inputs.Select(d => d.Id));

                var bipartite = new BipartiteGraph();
                Primes.Reset();
                var completeMatching = new MatchingDictionary(originalComponents.Select(c => c.Id));

                // 1.1 Add Nodes for the Variables
                // Filter-out the selected inputs and outputs, as they don't belong to the bipartite graph
                foreach (Data data in allData.Where(d => !inputsHash.Contains(d.Id)))
                {
                    bipartite.AddNode(data.Id, GraphNode.Type.Type1);
                }

                // 1.2 Add Nodes for the Models, and edges between Variables and Nodes
                foreach (WorkflowComponent component in originalComponents)
                {
                    completeMatching.Add(component.Id, new HashSet <string>());

                    bipartite.AddNode(CS(component.Id), GraphNode.Type.Type2);
                    GraphNode modelNode = bipartite.GetNode(CS(component.Id));

                    // Filter-out the selected inputs, as they don't belong to the bipartite graph
                    foreach (Data data in component.ModelDataInputs.Where(d => !inputsHash.Contains(d.Id)))
                    {
                        bipartite.AddDirectedEdge(data.Id, modelNode, Primes.Next(), 1);
                    }

                    // Filter-out the selected inputs, as they don't belong to the bipartite graph
                    foreach (Data data in component.ModelDataOutputs.Where(d => !inputsHash.Contains(d.Id)))
                    {
                        bipartite.AddDirectedEdge(data.Id, modelNode, Primes.Next(), 0);
                    }

                    // How many output the model need
                    if (component.ModelDataOutputs.Count > 1)
                    {
                        bipartite.modelAndItsOutputs.Add(CS(component.Id), component.ModelDataOutputs.Count);                         //signle output models are not stored
                    }
                }

                // 1.3 Associate matchings to each model, maping models to set of outputs
                var matches = new MaximumMatchings2(bipartite, true);

                if (matches.OverConstrainedModels.Count > 0)
                {
                    throw new ArgumentException($"The inputs conbination is not valid as the following models are overconstraint:\r\n\t" +
                                                matches.OverConstrainedModels.Aggregate((total, last) => total += "\r\n\t" + last) + "\r\n");
                }

                Matching matching = matches.OrderedFilteredMaximumMatchings.FirstOrDefault()
                                    ?? throw new NullReferenceException("NO suitable matchings were found");

                completeMatching.CompleteWithMatching(matching);

                return(completeMatching);
            }
            else
            {
                Dictionary <string, IOStatus> status = components.GetInputsOutputsStatus(allData, out List <Data> inputs, out List <Data> outputs);


                var inputsHash  = new HashSet <string>(inputs.Select(d => d.Id));
                var outputsHash = new HashSet <string>();

                List <WorkflowComponent>      originalComponents = components.GetAllComponents();
                Dictionary <string, IOStatus> originalStatus     = originalComponents.GetDataStatus(allData);

                var nonReversibleData = allData.Where(d => !(d is DoubleData)).ToList();
                Dictionary <string, IOStatus> nonReversibleStatus = components.GetDataStatus(nonReversibleData);
                foreach (string data in nonReversibleStatus.Keys)
                {
                    if (nonReversibleStatus[data] == IOStatus.Input)
                    {
                        inputsHash.Add(data);                         // Should be already there
                    }
                    else if (nonReversibleStatus[data] == IOStatus.Output || nonReversibleStatus[data] == IOStatus.Both)
                    {
                        outputsHash.Add(data);
                    }
                }

                var reversedInputsHash  = new HashSet <string>();
                var reversedOutputsHash = new HashSet <string>();
                foreach (WorkflowComponent component in components)
                {
                    if (component is IReversableWorkflow rw)
                    {
                        foreach (Data data in rw.ReversedInputs)
                        {
                            reversedInputsHash.Add(data.Id);
                        }

                        foreach (Data data in rw.ReversedOutputs)
                        {
                            reversedOutputsHash.Add(data.Id);
                        }

                        IEnumerable <Data> NonReversableReversedInputs  = rw.ReversedInputs.Where(d => !(d is DoubleData));
                        IEnumerable <Data> NonReversableReversedOutputs = rw.ReversedOutputs.Where(d => !(d is DoubleData));

                        // If the model id the upper end of a reversal throug non-reversible variables.
                        int difference = NonReversableReversedOutputs.Count() - NonReversableReversedInputs.Count();
                        while (difference > 0)
                        {
                            // Assign as many reversible variable to the inputs as reversals end in the component
                            IEnumerable <Data> reversableReversedInputs = rw.ReversedInputs.Where(d => d is DoubleData);
                            foreach (Data data in reversableReversedInputs.Take(difference))
                            {
                                inputsHash.Add(data.Id);
                            }
                        }
                    }
                }

                // Relax one input per reversal -> lowerEndOfReversal might have more elements than non-reversible reversal, but those should be already not in inputHash
                IEnumerable <string> lowerEndOfReversals = reversedOutputsHash.Except(reversedInputsHash);
                inputsHash.ExceptWith(lowerEndOfReversals);

                var bipartite = new BipartiteGraph();
                Primes.Reset();
                var completeMatching = new MatchingDictionary(originalComponents.Select(c => c.Id));

                // 1.1 Add Nodes for the Variables
                // Filter-out the selected inputs and outputs, as they don't belong to the bipartite graph
                foreach (Data data in allData.Where(d => !inputsHash.Contains(d.Id) && !outputsHash.Contains(d.Id)))
                {
                    bipartite.AddNode(data.Id, GraphNode.Type.Type1);
                }

                // 1.2 Add Nodes for the Models, and edges between Variables and Nodes
                foreach (WorkflowComponent component in originalComponents)
                {
                    completeMatching.Add(component.Id, new HashSet <string>());

                    // if the component has all its inputs and outputs determined do not add to the graph
                    bool addModel = component.ModelDataOutputs.Count > component.ModelDataOutputs.Where(d => inputsHash.Count > -1 && outputsHash.Contains(d.Id)).Count();
                    if (addModel)
                    {
                        bipartite.AddNode(component.Id, GraphNode.Type.Type2);
                    }

                    GraphNode modelNode = bipartite.GetNode(component.Id);

                    int uniqueNonReversibleOutputs = 0;

                    // Filter-out the selected inputs, as they don't belong to the bipartite graph
                    foreach (Data data in component.ModelDataInputs.Where(d => !inputsHash.Contains(d.Id) && !outputsHash.Contains(d.Id)))
                    {
                        bipartite.AddDirectedEdge(data.Id, modelNode, Primes.Next(), 1);
                    }

                    // Filter-out the selected inputs, as they don't belong to the bipartite graph
                    foreach (Data data in component.ModelDataOutputs.Where(d => !inputsHash.Contains(d.Id)))
                    {
                        if (outputsHash.Contains(data.Id))
                        {
                            uniqueNonReversibleOutputs++;
                            completeMatching[component.Id].Add(data.Id);
                        }
                        else
                        {
                            bipartite.AddDirectedEdge(data.Id, modelNode, Primes.Next(), 0);
                        }
                    }

                    // How many output the model need
                    if (component.ModelDataOutputs.Count - uniqueNonReversibleOutputs > 1 && addModel)
                    {
                        bipartite.modelAndItsOutputs.Add(component.Id, component.ModelDataOutputs.Count - uniqueNonReversibleOutputs);                         //signle output models are not stored
                    }
                }

                // 1.3 Associate matchings to each model, maping models to set of outputs
                var matches = new MaximumMatchings2(bipartite, true);

                if (matches.OverConstrainedModels.Count > 0)
                {
                    throw new ArgumentException($"The inputs conbination is not valid as the following models are overconstraint:\r\n\t" +
                                                matches.OverConstrainedModels.Aggregate((total, last) => total += "\r\n\t" + last) + "\r\n");
                }

                Matching matching = matches.OrderedFilteredMaximumMatchings.FirstOrDefault()
                                    ?? throw new NullReferenceException("NO suitable matchings were found");

                completeMatching.CompleteWithMatching(matching);

                return(completeMatching);
            }
        }