Esempio n. 1
0
        public EdgeList matchingStringsToEdgeList(BipartiteGraph G, List <string> M_String)
        {
            var       M_to_EdgeListM = new EdgeList();
            GraphNode nd1, nd2;

            foreach (string edg in M_String)
            {
                nd1 = G.GetNode(edg.Split('-')[0]);
                nd2 = G.GetNode(edg.Split('-')[1]);
                if (G.Contains(nd1, nd2))
                {
                    M_to_EdgeListM.Add(G.Edges.FindByNodes(nd1, nd2));
                }
                else if (G.Contains(nd2, nd1))
                {
                    M_to_EdgeListM.Add(G.Edges.FindByNodes(nd2, nd1));
                }
                //else
                //{
                //    M_to_EdgeListM.Add(new Edge(nd1,nd2,0));
                //}
            }

            return(M_to_EdgeListM);
        }
        private Node GetNode(string from)
        {
            if (G.duplicateModToModel.ContainsKey(from))
            {
                from = G.duplicateModToModel[from];
            }

            return(G.GetNode(from));
        }
        private bool IsFeasiblePath(BipartiteGraph G, MatchingList path, NodeList unmatchedNodes)
        {
            if (unmatchedNodes.Contains(G.GetNode(path[0])) || unmatchedNodes.Contains(G.GetNode(path[2])))
            {
                return(true);
            }

            return(false);
        }
        //YHB: this method find the graph G_minus by deleting given edge-e from the G i.e. given graph
        private static BipartiteGraph BuildGminus(BipartiteGraph G, Edge e)
        {
            BipartiteGraph Gminus = G.Clone();
            GraphNode      from   = G.GetNode(e.FromNode.Value);
            GraphNode      to     = G.GetNode(e.ToNode.Value);

            if (G.Contains(from, to))
            {
                Gminus.RemoveDirectedEdge(from, to);
            }
            else
            {
                Gminus.RemoveDirectedEdge(to, from);
            }


            return(Gminus);
        }
        private Edge GetEdgeInPathNotInM(BipartiteGraph G, MatchingList M, MatchingList path)
        {
            Edge   e    = null;
            string edge = path.Except(M).ToList()[0];

            string[]  nodes = edge.Split('-');
            GraphNode node1 = G.GetNode(nodes[0]);
            GraphNode node2 = G.GetNode(nodes[1]);

            if (G.Contains(node1, node2))
            {
                e = G.Edges.FindByNodes(node1, node2);
            }
            else if (G.Contains(node2, node1))
            {
                e = G.Edges.FindByNodes(node2, node1);
            }
            return(e);
        }
        private Edge getEdgeInPathNotInM(BipartiteGraph G, List <String> M, List <String> path)
        {
            Edge   e       = null;
            String eString = path.Except(M).ToList()[0];

            String[]  eNodes = eString.Split('-');
            GraphNode nd1    = G.GetNode(eNodes[0]);
            GraphNode nd2    = G.GetNode(eNodes[1]);

            if (G.Contains(nd1, nd2))
            {
                e = G.Edges.FindByNodes(nd1, nd2);
            }
            else if (G.Contains(nd2, nd1))
            {
                e = G.Edges.FindByNodes(nd2, nd1);
            }
            return(e);
        }
        private bool isFeasiblePath(BipartiteGraph G, List <String> path, NodeList unmatchedNodes)
        {
            bool isFeasiblePath = false;

            if (unmatchedNodes.Contains(G.GetNode(path[0])) || unmatchedNodes.Contains(G.GetNode(path[2])))
            {
                isFeasiblePath = true;
            }

            return(isFeasiblePath);
        }
        public static EdgeList Get(BipartiteGraph bipartiteGraph)
        {
            NodeList models = bipartiteGraph.ModelsSet;

            if (models is null)
            {
                throw new ArgumentException("Graph has no models", nameof(bipartiteGraph));
            }

            NodeList variables = bipartiteGraph.VariablesSet;

            if (variables is null)
            {
                throw new ArgumentException("Graph has no variables", nameof(bipartiteGraph));
            }

            //Assigning int values to each node in the graph starting from 0.
            var modNodeIntMap = models.Select((m, i) => new KeyValuePair <string, int>(m.Value, i)).ToDictionary(kvp => kvp.Key, kvp => kvp.Value);

            //Creating Adjacency List
            var adjacencyList = new List <int[]>(variables.Count);

            foreach (GraphNode variable in variables)
            {
                adjacencyList.Add(variable.Neighbors.Select(n => modNodeIntMap[n.Value]).ToArray());
            }

            // Get Match
            IList <int> match = new HopcroftKarpClass(adjacencyList, models.Count).GetMatching();

            // Format the match
            var MatchingEdgeList = new EdgeList();
            int idx = 0;

            foreach (Node variable in variables)
            {
                int matchedModelIndex = match[idx];
                if (matchedModelIndex != -1)
                {
                    string modelValue = modNodeIntMap.FirstOrDefault(x => x.Value == matchedModelIndex).Key;
                    //matching edge list contains edges having direction from
                    MatchingEdgeList.Add(bipartiteGraph.Edges.FindByNodes(variable, bipartiteGraph.GetNode(modelValue)));
                    // 'variables set' to 'model set'
                    idx++;
                }
                else
                {
                    idx++; /*variable associated at that location is unmatched*/                   //Implement to store unmatched variable information if required
                }
            }

            return(MatchingEdgeList);
        }
        //This method find the corresponding edges of matching M(which contains edges from other Graph) for the given Graph G
        private static EdgeList CorrespondingEdgeList(BipartiteGraph G, EdgeList M)
        {
            var corresponding = new EdgeList();

            foreach (Edge edge in M)
            {
                GraphNode from = G.GetNode(edge.FromNode.Value);
                GraphNode to   = G.GetNode(edge.ToNode.Value);
                if (from == null && to == null)
                {
                    continue;
                }

                if (G.Edges.FindByNodes(from, to) != null)
                {
                    corresponding.Add(G.Edges.FindByNodes(from, to));
                }
                else
                {
                    corresponding.Add(G.Edges.FindByNodes(to, from));
                }
            }
            return(corresponding);
        }
        private EdgeList MatchingToEdgeList(BipartiteGraph G, MatchingList M_String)
        {
            var edgeList = new EdgeList();

            foreach (string edg in M_String)
            {
                GraphNode node1 = G.GetNode(edg.Split('-')[0]);
                GraphNode node2 = G.GetNode(edg.Split('-')[1]);
                if (G.Contains(node1, node2))
                {
                    edgeList.Add(G.Edges.FindByNodes(node1, node2));
                }
                else if (G.Contains(node2, node1))
                {
                    edgeList.Add(G.Edges.FindByNodes(node2, node1));
                }
                //else
                //{
                //    M_to_EdgeListM.Add(new Edge(nd1,nd2,0));
                //}
            }

            return(edgeList);
        }
Esempio n. 11
0
        private static EdgeList CorrespondingListForTheGraph(BipartiteGraph G, EdgeList M) //This method find the corresponding edges of matching M(which contains edges from other Graph) for the given Graph G
        {
            var M_corresp = new EdgeList();

            foreach (Edge edg in M)
            {
                GraphNode frm = G.GetNode(edg.FromNode.Value);
                GraphNode to  = G.GetNode(edg.ToNode.Value);
                if (frm == null && to == null)
                {
                    goto xyz;
                }
                if (G.Edges.FindByNodes(frm, to) != null)
                {
                    M_corresp.Add(G.Edges.FindByNodes(frm, to));
                }
                else
                {
                    M_corresp.Add(G.Edges.FindByNodes(to, frm));
                }
                xyz :;
            }
            return(M_corresp);
        }
        private MatchingList PathToMatching(BipartiteGraph G, MatchingList path)
        {
            var    matching = new MatchingList();
            string edge;

            for (int i = 0; i < path.Count() - 1; i++)
            {
                if (G.GetNode(path[i]).NodeType == GraphNode.Type.Type2)
                {
                    edge = EdgeString(path[i], path[i + 1]);
                }
                else
                {
                    edge = EdgeString(path[i + 1], path[i]);
                }

                matching.Add(edge);
            }
            return(matching);
        }
        private List <String> pathToEdgesAsStrings(BipartiteGraph G, List <String> path) //04-01-2017 Added for MaximumMatchings
        {
            var    pathAsStrings = new List <String>();
            String str;

            for (int i = 0; i < path.Count() - 1; i++)
            {
                if (G.GetNode(path[i]).NodeType == GraphNode.Type.Type2)
                {
                    str = path[i] + '-' + path[i + 1];
                }
                else
                {
                    str = path[i + 1] + '-' + path[i];
                }

                pathAsStrings.Add(str);
            }
            return(pathAsStrings);
        }
Esempio n. 14
0
        private static BipartiteGraph G_minus_e(BipartiteGraph G, Edge e)
        {//YHB: this method find the graph G_minus by deleting given edge-e from the G i.e. given graph
            BipartiteGraph G_minus = G;

            if (G.Contains(G.GetNode(e.FromNode.Value), G.GetNode(e.ToNode.Value)))
            {
                G_minus.RemoveDirectedEdge(G.GetNode(e.FromNode.Value), G.GetNode(e.ToNode.Value));
            }
            else
            {
                G_minus.RemoveDirectedEdge(G.GetNode(e.ToNode.Value), G.GetNode(e.FromNode.Value));
            }


            return(G_minus);
        }
Esempio n. 15
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);
            }
        }
        // A recursive function to find which vertices are connected.
        private void DFS(BipartiteGraph G, GraphNode v)
        {
            length2Path.Add(v.Value);
            if (_path2Count++ == 2)
            {
                return;
            }
            _count++;
            //mark this vertex as being visited
            _marked.Add(v.Value.ToString(), true);

            /*
             * for each vertex w in the linked list for vertex v
             * there exists an edge between v and w
             * if it is not in _marked it hasn't been visited
             * yet so mark it then check all the vertices
             * in it's linked list (it has edges to).
             * */
            foreach (GraphNode w in v.Neighbors)
            {
                if (!_marked.ContainsKey(w.Value.ToString()))
                {
                    if (_path2Count < 2)
                    {
                        DFS(G, w);
                    }
                    else if (_path2Count == 2)
                    {
                        if (unmatchedVertices.Contains(w) || unmatchedVertices.Contains(G.GetNode(length2Path[0])))
                        {
                            DFS(G, w);
                        }
                        else
                        {
                            goto nextNeighbour;
                        }
                    }
                }
                else
                {
                    goto nextNeighbour;
                }

                nextNeighbour :;
            }
            return;
        }
Esempio n. 17
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);
        }
        public void findOverconstrainedModelsReversalCost(List <String> M, out List <string> overConstrainedModelsList, out List <string> unmappedVariablesList, out int revCost)
        {
            revCost = 0;//04102017
            overConstrainedModelsList = new List <string>();
            unmappedVariablesList     = new List <string>();

            if (M != null) //after filtering the matchings from list_AllMaximumMatchings
            {
                //foreach (GraphNode gn in web1.getUnmatchedVerticesOfGraph(maxT.list_AllMaximumMatchings[n])) //original code
                foreach (GraphNode gn in G.GetUnmatchedVertices(M)) //after filtering the matchings
                {
                    if (gn.NodeType == GraphNode.Type.Type2)
                    {
                        if (G.duplicateModToModel.ContainsKey(gn.Value))
                        {
                            overConstrainedModelsList.Add(G.duplicateModToModel[gn.Value]);
                        }
                        else
                        {
                            overConstrainedModelsList.Add(gn.Value);
                        }
                    }
                    else
                    {
                        unmappedVariablesList.Add(gn.Value);
                    }
                }



                //for finding revCost of this matching //04102017
                foreach (string match in M) //04102017
                {                           //04102017 Entire added on //04102017
                    Node     fromNode;
                    Node     toNode;
                    string[] split = match.Split('-');
                    string   from  = split[0];
                    string   to    = split[1];

                    if (G.duplicateModToModel.ContainsKey(from))
                    {
                        fromNode = G.GetNode(G.duplicateModToModel[from]);
                    }
                    else
                    {
                        fromNode = G.GetNode(from);
                    }

                    if (G.duplicateModToModel.ContainsKey(to))
                    {
                        toNode = G.GetNode(G.duplicateModToModel[to]);
                    }
                    else
                    {
                        toNode = G.GetNode(to);
                    }

                    //Node from = this.G.GetNode();
                    Edge e = G.Edges.FindByNodes(fromNode, toNode);
                    if (e == null)
                    {
                        e = G.Edges.FindByNodes(toNode, fromNode); //04102017
                    }
                    revCost += e.Cost2;                            //04102017
                }//04102017
            }
        }