internal Map<Node, Node> ComputeIsomorphism() { // We start with a functional pass. ControlState c = ControlState.InitialFunctionalPass; while (true) { switch (c) { # region Find all reachable functional matches of current active nodes x and y. case ControlState.InitialFunctionalPass: c = ExtendForOnlyFunctionalEdges(x, y); break; # endregion #region Find all relational matches after one or more functional pass. case ControlState.RelationalPass: if (xPartitions.Count > 0) goto case ControlState.NextPartition; if (relationalPassIndex >= index) { if (relationalPassIndex == numberOfNodes) c = ControlState.Done; else goto case ControlState.Fail; // c = ControlState.Fail; break; } x = bijection[relationalPassIndex,X]; y = bijection[relationalPassIndex,Y]; xData = g1.vertexRecords[x]; yData = g2.vertexRecords[y]; if (relationalEdgeEnumerator == default(IEnumerator<CompoundTerm>)) { relationalEdgeLabels = Set<CompoundTerm>.EmptySet; foreach (Pair<CompoundTerm, Set<Node>> pair in xData.unorderedOutgoingEdges) { relationalEdgeLabels = relationalEdgeLabels.Add(pair.First); } relationalEdgeEnumerator = relationalEdgeLabels.GetEnumerator(); } if (relationalEdgeEnumerator.MoveNext()) { xEdgeLabel = relationalEdgeEnumerator.Current; //xtoNodes = xData.unorderedOutgoingEdges[xEdgeLabel]; if (yData.unorderedOutgoingEdges.ContainsKey(xEdgeLabel)) // Perhaps this check can be assumed true for all graphs? { //ytoNodes = yData.unorderedOutgoingEdges[xEdgeLabel]; xPartitions = GetPartitions(g1, x, xEdgeLabel); yPartitions = GetPartitions(g2, y, xEdgeLabel); //Console.WriteLine("Partitions: " + x + " has " + xPartitions.Count + "elements."); if (PartitionsAreConsistent(xPartitions,yPartitions)) goto case ControlState.NextPartition; else goto case ControlState.Fail; ////c = ControlState.NextRelationalEdge; //goto case ControlState.NextRelationalEdge; } else goto case ControlState.Fail; // c = ControlState.Fail; } else { relationalPassIndex++; relationalEdgeEnumerator = default(IEnumerator<CompoundTerm>); relationalEdgeLabels = default(Set<CompoundTerm>); if (relationalPassIndex == numberOfNodes) c = ControlState.Done; } break; case ControlState.NextPartition: if (xPartitions.Count > 0) // the other constraints have been implied by PartitionsAreConsistent { Pair<IComparable, bool> label = xPartitions.Keys.Choose(0); xtoNodes = xPartitions[label]; xPartitions = xPartitions.RemoveKey(label); ytoNodes = yPartitions[label]; yPartitions = yPartitions.RemoveKey(label); goto case ControlState.ProcessPartition; } else c = ControlState.RelationalPass; break; // It is possible that we have multiple sets of relational edges from a node. The following is done for each set. case ControlState.ProcessPartition: // xEdgeLabel has been set // xtoNodes has been set; // ytoNodes has been set; Node x1, y1; // remove all nodes that have already been matched. (previously implemented as PruneCandidates) Set<Node> xtoNodesTmp = xtoNodes; int count = xtoNodesTmp.Count; for (int i = 0; i < count; i++) { x1 = xtoNodesTmp.Choose(i); if (indexDict.ContainsKey(x1)) { y1 = bijection[indexDict[x1], Y]; if (ytoNodes.Contains(y1)) { xtoNodes = xtoNodes.Remove(x1); ytoNodes = ytoNodes.Remove(y1); } else { goto case ControlState.Fail;// c = ControlState.Fail; //goto EndOfNextRelationalEdge; //break; } } //else if (IsOrderIndependent(x1,g1)) //{ // xtoNodesOrderIndependent = xtoNodesOrderIndependent.Add(x1); // bucketOf[g1.LabelOf(x1)].g2Nodes // xtoNodes = xtoNodes.Remove(x1); // //ytoNodesOrderIndependent = ytoNodesOrderIndependent.Add(x1); //} } if (xtoNodes.Count == 0) { //c = ControlState.RelationalPass; c = ControlState.NextPartition; break; // out of the switch statement }// we do not need to check as all nodes contained in xtoNodes were already contained. //if (IsOrderIndependent(xtoNodes.Choose(0),g1)) //{ // goto case ControlState.ChooseOne; //} //else //{ btp = new BacktrackPointWithPartitions(indexDict, rangeDict, xEdgeLabel, index, relationalPassIndex, relationalEdgeLabels.Remove(xEdgeLabel), xtoNodes, ytoNodes, xPartitions, yPartitions); goto case ControlState.Choose; //} //break; #endregion #region Choose one combination of matching relational edges and add a backtrackpoint if necessary case ControlState.Choose: if (btp == null) // check used to stop when backtracking. { c = ControlState.Fail; break; } c = Choose(); break; #endregion #region Choose one combination of matching relational edges and do not add backtrackpoint case ControlState.ChooseOne: c = ChooseOne(); break; #endregion # region Process a backtrack request. case ControlState.Fail: if (backtrackStack.Count == 0) return null; else { // Reset environment to topmost backtrackpoint and continue // with the relevant Choose. btp = backtrackStack.Pop(); // Restore program state from the BacktrackPoint. index = btp.index; relationalPassIndex = btp.relationalPassIndex; indexDict = BacktrackPointWithPartitions.getCopy(btp.indexDict); xEdgeLabel = btp.outLabel; rangeDict = BacktrackPointWithPartitions.getCopy(btp.rangeDict); x = bijection[relationalPassIndex, X]; y = bijection[relationalPassIndex, Y]; xData = g1.vertexRecords[x]; yData = g2.vertexRecords[y]; xtoNodes = btp.xtoNodes; ytoNodes = btp.ytoNodes; relationalEdgeLabels = btp.relationalEdgeLabels; relationalEdgeEnumerator = btp.relationalEdgeLabels.GetEnumerator(); xPartitions = btp.xPartitions; yPartitions = btp.yPartitions; c = ControlState.Choose; } break; # endregion case ControlState.Done: goto Success; default: break; } } #region Prepare result map and return. Success: Map<Node, Node> iso = Map<Node, Node>.EmptyMap; for (int i = 0; i < numberOfNodes; i++) { iso = iso.Add(bijection[i, X], bijection[i, Y]); } return iso; #endregion }
/// <summary> /// Add a vertex into the graph being built. /// </summary> /// <param name="name"></param> /// <param name="label"></param> /// <returns></returns> public Vertex AddVertex(string name, string label) { VertexData vData = new VertexData(); int vId = getNextId(name); Vertex v = idCounter++;//new ObjectId(new Symbol(name), vId); vData.vertex = v; vData.label = vData.label.Add(new Pair<CompoundTerm, IComparable>(new CompoundTerm(new Symbol(name), new Sequence<Term>()), label)); vertexRecords.Add(v, vData); return v; }
/// <summary> /// Make sure that a vertexData record has been initialized for the vertex. /// </summary> /// <param name="vertex"></param> /// <returns>VertexData record corresponding to the argument.</returns> VertexData EnsureVertex(Vertex vertex) { VertexData result; if (!this.vertexRecords.TryGetValue(vertex, out result)) { result = new VertexData(vertex, Set<Pair<CompoundTerm, IComparable>>.EmptySet, Map<EdgeLabel, Vertex>.EmptyMap, Map<EdgeLabel, Set<Vertex>>.EmptyMap); this.vertexRecords.Add(vertex, result); } return result; }
public void IsoSingleNodeUllmann() { Vertex root1 = 1;// new ObjectId(new Symbol("Root"), 1); VertexData vd1 = new VertexData(); Vertex root2 = 1;// new ObjectId(new Symbol("Root"), 1); VertexData vd2 = new VertexData(); Dictionary<Vertex, VertexData> vr1 = new Dictionary<Vertex, VertexData>(); vr1.Add(root1, vd1); Dictionary<Vertex, VertexData> vr2 = new Dictionary<Vertex, VertexData>(); vr2.Add(root1, vd2); RootedLabeledDirectedGraph g1 = new RootedLabeledDirectedGraph(root1, vr1); RootedLabeledDirectedGraph g2 = new RootedLabeledDirectedGraph(root2, vr2); Map<Vertex, Vertex> iso = GraphIsomorphism.ComputeIsomorphismUllmann(g1, g2); Assert.AreEqual(1, iso.Count); }
internal Map<Node, Node> ComputeIsomorphism() { // We start with a functional pass. ControlState c = ControlState.InitialFunctionalPass; while (true) { switch (c) { # region Find all reachable functional matches of current active nodes x and y. case ControlState.InitialFunctionalPass: c = ExtendForOnlyFunctionalEdges(x, y); break; # endregion #region Find all relational matches after one or more functional pass. case ControlState.RelationalPass: if (relationalPassIndex >= index) { if (relationalPassIndex == numberOfNodes) c = ControlState.Done; else c = ControlState.Fail; break; } x = bijection[relationalPassIndex, X]; y = bijection[relationalPassIndex, Y]; xData = g1.vertexRecords[x]; yData = g2.vertexRecords[y]; if (relationalEdgeEnumerator == default(IEnumerator<CompoundTerm>)) { relationalEdgeLabels = Set<CompoundTerm>.EmptySet; foreach (Pair<CompoundTerm, Set<Node>> pair in xData.unorderedOutgoingEdges) { relationalEdgeLabels = relationalEdgeLabels.Add(pair.First); } relationalEdgeEnumerator = relationalEdgeLabels.GetEnumerator(); } if (relationalEdgeEnumerator.MoveNext()) { xEdgeLabel = relationalEdgeEnumerator.Current; xtoNodes = xData.unorderedOutgoingEdges[xEdgeLabel]; if (yData.unorderedOutgoingEdges.ContainsKey(xEdgeLabel)) // Perhaps this check can be assumed true for all graphs? { ytoNodes = yData.unorderedOutgoingEdges[xEdgeLabel]; c = ControlState.NextRelationalEdge; } else c = ControlState.Fail; } else { relationalPassIndex++; relationalEdgeEnumerator = default(IEnumerator<CompoundTerm>); relationalEdgeLabels = default(Set<CompoundTerm>); if (relationalPassIndex == numberOfNodes) c = ControlState.Done; } break; // It is possible that we have multiple sets of relational edges from a node. The following is done for each set. case ControlState.NextRelationalEdge: // xEdgeLabel has been set // xtoNodes has been set; // ytoNodes has been set; Node x1, y1; // remove all nodes that have already been matched. for (int i = 0; i < xtoNodes.Count; i++) { x1 = xtoNodes.Choose(i); if (indexDict.ContainsKey(x1)) { y1 = bijection[indexDict[x1], Y]; if (ytoNodes.Contains(y1)) { xtoNodes = xtoNodes.Remove(x1); ytoNodes = ytoNodes.Remove(y1); } else { c = ControlState.Fail; goto EndOfNextRelationalEdge; } } } if (xtoNodes.Count == 0) { c = ControlState.RelationalPass; break; // out of the switch statement }// we do not need to check as all nodes contained in xtoNodes were already contained. //isoExt = ExtendIsomorphism4(backtrackBuckets, backtrackStack, isoExt, xtoNodes.Choose(), ytoNodes.Choose()); btp = new BacktrackPoint(indexDict, rangeDict, xEdgeLabel, index, relationalPassIndex, relationalEdgeLabels.Remove(xEdgeLabel), xtoNodes, ytoNodes); c = ControlState.Choose; //goto case ControlState.Choose; EndOfNextRelationalEdge: break; #endregion #region Choose one combination of matching relational edges case ControlState.Choose: if (btp == null) // check used to stop when backtracking. { c = ControlState.Fail; break; } c = Choose(); break; #endregion # region Process a backtrack request. case ControlState.Fail: if (backtrackStack.Count == 0) return null; else { // Reset environment to topmost backtrackpoint and continue // with the relevant Choose from where we left off last time. btp = backtrackStack.Pop(); // Restore program state from the BacktrackPoint. index = btp.index; relationalPassIndex = btp.relationalPassIndex; indexDict = BacktrackPoint.getCopy(btp.indexDict); xEdgeLabel = btp.outLabel; rangeDict = BacktrackPoint.getCopy(btp.rangeDict); x = bijection[relationalPassIndex, X]; y = bijection[relationalPassIndex, Y]; xData = g1.vertexRecords[x]; yData = g2.vertexRecords[y]; xtoNodes = btp.xtoNodes; ytoNodes = btp.ytoNodes; relationalEdgeLabels = btp.relationalEdgeLabels; relationalEdgeEnumerator = btp.relationalEdgeLabels.GetEnumerator(); c = ControlState.Choose; } break; # endregion case ControlState.Done: goto Success; default: break; } } #region Prepare result map and return. Success: Map<Node, Node> iso = Map<Node, Node>.EmptyMap; for (int i = 0; i < numberOfNodes; i++) { iso = iso.Add(bijection[i, X], bijection[i, Y]); } return iso; #endregion }