Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 30 additions & 32 deletions src/main/java/org/graph4j/iso/general/AbstractGraphIsomorphism.java
Original file line number Diff line number Diff line change
Expand Up @@ -122,18 +122,18 @@ private List<IsomorphicGraphMapping> matchIterative(boolean onlyFirstMapping){

// if the pair is feasible, we continue, otherwise we truncate the branch
if(s.isFeasiblePair()){

// if the state is dead, we continue with the next pair
if(s.isDead()) {
continue;
}

// else we add the pair to the mapping
// add to stack the current state for restoring it later
stack.push(s);

// just like in the recursive approach, we create a copy of the current state and then we add the pair
s = getNewStateInstance(s);
s.addPair();
s.resetPreviousVertices();

// if the state is dead, we return to the previous state and continue with another candidate pair
if(s.isDead()) {
break;
}

// if this state is a goal(complete solution), we add the mapping to the list
if(s.isGoal()) {
Expand All @@ -143,8 +143,6 @@ private List<IsomorphicGraphMapping> matchIterative(boolean onlyFirstMapping){
if(onlyFirstMapping)
return mappings;
}

s.resetPreviousVertices();
}
}

Expand All @@ -170,33 +168,33 @@ private List<IsomorphicGraphMapping> matchIterative(boolean onlyFirstMapping){
protected abstract State getNewStateInstance(State s);


/* protected List<IsomorphicGraphMapping> match(boolean onlyFirstMapping){
List<IsomorphicGraphMapping> mappings = new ArrayList<>();
matchRecursive(getStateInstance(dg1, dg2), mappings, onlyFirstMapping);
// protected List<IsomorphicGraphMapping> match(boolean onlyFirstMapping){
// List<IsomorphicGraphMapping> mappings = new ArrayList<>();
// matchRecursive(getStateInstance(dg1, dg2, cache), mappings, onlyFirstMapping, 0);
//
// return mappings;
// }

return mappings;
private void matchRecursive(State s, List<IsomorphicGraphMapping> mappings, boolean onlyFirstMapping, int level) {
if(s.isGoal()){
mappings.add(s.getMapping());
return;
}

private void matchRecursive(State s, List<IsomorphicGraphMapping> mappings, boolean onlyFirstMapping) {
if(s.isGoal()){
mappings.add(s.getMapping());
return;
}
if (s.isDead())
return;

if (s.isDead())
return;
while(s.nextPair()){
if(s.isFeasiblePair()){
State newS = getNewStateInstance(s);
newS.addPair();
newS.resetPreviousVertices();

while(s.nextPair()){
if(s.isFeasiblePair()){
State newS = getNewStateInstance(s);
newS.addPair();
newS.resetPreviousVertices();

matchRecursive(newS, mappings, onlyFirstMapping);
newS.backTrack();
if(onlyFirstMapping && !mappings.isEmpty())
return;
}
matchRecursive(newS, mappings, onlyFirstMapping, level + 1);
newS.backTrack();
if(onlyFirstMapping && !mappings.isEmpty())
return;
}
}*/
}
}
}
81 changes: 72 additions & 9 deletions src/main/java/org/graph4j/iso/general/AbstractState.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,12 @@

import org.graph4j.DirectedMultigraph;
import org.graph4j.DirectedPseudograph;
import org.graph4j.Edge;
import org.graph4j.iso.IsomorphicGraphMapping;

import java.util.ArrayList;
import java.util.List;

/**
* Abstract class for the state of the search algorithm.
*
Expand Down Expand Up @@ -80,9 +84,39 @@ protected boolean compatibleVertices(int vertexIndex1, int vertexIndex2) {
}
}

if (o1.getGraph() instanceof DirectedPseudograph ps1 &&
o2.getGraph() instanceof DirectedPseudograph ps2){
return ps1.selfLoops(node_1) == ps2.selfLoops(node_2);
if (o1.getGraph() instanceof DirectedPseudograph ps1 && o2.getGraph() instanceof DirectedPseudograph ps2){
if (ps1.selfLoops(node_1) != ps2.selfLoops(node_2)) {
return false;
}

// L1 = list of all labels of self loops of vertex node_1
// L2 = list of all labels of self loops of vertex node_2

List<Object> labels1 = new ArrayList<>();
List<Object> labels2 = new ArrayList<>();

for (Edge e : ps1.outgoingEdgesFrom(node_1)) {
if (e != null && e.target() == node_1) {
labels1.add(e.label());
}
}
for (Edge e : ps2.outgoingEdgesFrom(node_2)) {
if (e != null && e.target() == node_2) {
labels2.add(e.label());
}
}

if (labels1.size() != labels2.size()) {
return false;
}

for (Object label : labels1) {
boolean removed = labels2.remove(label);
if (!removed) {
return false;
}
}
return true;
}
return true;
}
Expand All @@ -103,15 +137,44 @@ protected boolean compatibleEdges(int i1, int j1, int i2, int j2) {
int u2 = o2.getVertexNumber(i2);
int v2 = o2.getVertexNumber(j2);

if (o1.getGraph() instanceof DirectedMultigraph mg1 &&
o2.getGraph() instanceof DirectedMultigraph mg2){
return mg1.multiplicity(u1, v1) == mg2.multiplicity(u2, v2);
}
if (o1.getGraph() instanceof DirectedMultigraph mg1 && o2.getGraph() instanceof DirectedMultigraph mg2){
if (mg1.multiplicity(u1, v1) != mg2.multiplicity(u2, v2)) {
return false;
}
// L1 = list of all labels of edge (u1, v1)
// L2 = list of all labels of edge (u2, v2)
// every label from L1 must be in L2 and vice versa

// semantic equivalence
if (o1.getGraph().getEdgeLabel(u1, v1) != null && o2.getGraph().getEdgeLabel(u2, v2) != null) {
List<Object> labels1 = new ArrayList<>();
List<Object> labels2 = new ArrayList<>();

for (Edge e : mg1.outgoingEdgesFrom(u1)) {
if (e != null && e.target() == v1) {
labels1.add(e.label());
}
}
for (Edge e : mg2.outgoingEdgesFrom(u2)) {
if (e != null && e.target() == v2) {
labels2.add(e.label());
}
}

if (labels1.size() != labels2.size()) {
return false;
}

for (Object label : labels1) {
boolean removed = labels2.remove(label);
if (!removed) {
return false;
}
}
return true;
} else // not multi edges
if (o1.getGraph().getEdgeLabel(u1, v1) != null && o2.getGraph().getEdgeLabel(u2, v2) != null) {
return o1.getGraph().getEdgeLabel(u1, v1).equals(o2.getGraph().getEdgeLabel(u2, v2));
}

return true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ else if (t1in_len - core_len > 0 && t2in_len - core_len > 0) {
prev_2 = 0;
}
}
// else, check the rest of the vertices(new vertices)
// else, check the unmapped vertices
else {
while (prev_1 < n1 && core_1[prev_1] != NULL_NODE) {
prev_1++;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,84 @@ public void testDirectedPseudoGraph() {
}
}

@Test
public void testLabeledDirectedMultigraph() {
DirectedMultigraph g1 = GraphBuilder.vertices(0, 1, 2, 3, 4, 5).buildDirectedMultigraph();
DirectedMultigraph g2 = GraphBuilder.vertices(0, 1, 2, 3, 4, 5).buildDirectedMultigraph();

g1.addEdge(0, 1, "b");
g1.addEdge(0, 1, "a");
g1.addEdge(0, 1);
g1.addEdge(0, 2);

g2.addEdge(5, 3, "a");
g2.addEdge(5, 3, "b");
g2.addEdge(5, 3);
g2.addEdge(5, 4);

// System.out.println("g1: " + g1);
// System.out.println("g2: " + g2);

// System.out.println("g1 edge label of (0, 0): " + g1.getEdgeLabel(0, 0));
// System.out.println("g2 edge label of (0, 0): " + g2.getEdgeLabel(0, 0));

// System.out.println("g1 edge label of (0, 1): " + g1.getEdgeLabel(0, 1));
// System.out.println("g2 edge label of (0, 1): " + g2.getEdgeLabel(0, 1));
// System.out.println("g2 edges: " + Arrays.toString(g2.edges()));
// System.out.println("g2 neighbors of 0: " + Arrays.toString(g2.neighbors(0)));
// for (var e : g2.outgoingEdgesFrom(0)) {
// if (e == null)
// continue;
//
// int u = e.source();
// int v = e.target();
//
// System.out.println("Edge: (" + u + ", " + v + ", " + e.label() + ")");
// if (v == 1) {
// System.out.println("Edge from 0 to 1");
// }
// }


assertTrue(testIsomorphism4J(g1, g2));
List<IsomorphicGraphMapping> mapping_list = testGetAllMappings4J(g1, g2);
System.out.println("All mappings: ");
for (var m : mapping_list) {
System.out.println(m);
assertTrue(m.isValidIsomorphism());
}
}

@Test
public void testLabeledDirectedPseudoGraph() {
DirectedPseudograph g1 = GraphBuilder.vertices(0, 1, 2, 3, 4, 5).buildDirectedPseudograph();
DirectedPseudograph g2 = GraphBuilder.vertices(0, 1, 2, 3, 4, 5).buildDirectedPseudograph();

g1.addEdge(0, 0);
g1.addEdge(0, 0, "d");
g1.addEdge(0, 0, "c");
g1.addEdge(0, 1, "a");
g1.addEdge(0, 1, "b");
g1.addEdge(0, 1);
g1.addEdge(0, 2);

g2.addEdge(5, 5);
g2.addEdge(5, 5, "c");
g2.addEdge(5, 5, "d");
g2.addEdge(5, 1, "a");
g2.addEdge(5, 1, "b");
g2.addEdge(5, 1);
g2.addEdge(5, 4);

assertTrue(testIsomorphism4J(g1, g2));
List<IsomorphicGraphMapping> mapping_list = testGetAllMappings4J(g1, g2);
System.out.println("All mappings: ");
for (var m : mapping_list) {
System.out.println(m);
assertTrue(m.isValidIsomorphism());
}
}

@Test
public void testLargeGraph() {
int n = 100;
Expand Down
Loading