private static Type resolveClosure (Type parent, Type child) {
LinkedHashSet<PrimSig> nodes = new LinkedHashSet<PrimSig>();
DirectedGraph<PrimSig> graph = new DirectedGraph<PrimSig>();
// For each (v1->v2) in childType, add (v1->v2) into the graph.
for (ProductType c:child) if (c.arity()==2) {
PrimSig a=c.get(0), b=c.get(1);
nodes.add(a);
nodes.add(b);
graph.addEdge(a,b);
}
// For each distinct v1 and v2 in the graph where v1&v2!=empty, add the edges v1->v2 and v2->v1.
for (PrimSig a:nodes) for (PrimSig b:nodes) if (a!=b && a.intersects(b)) graph.addEdge(a,b);
// For each a->b in ParentType:
// 1) add a
// 2) add b
// 3) if a has subtypes/supertypes in the graph, connect between a and them.
// 4) if b has subtypes/supertypes in the graph, connect between b and them.
for (ProductType p:parent) if (p.arity()==2) {
PrimSig a=p.get(0), b=p.get(1);
// Add edges between a and all its subtypes and supertypes
if (!nodes.contains(a)) {
for (PrimSig x:nodes) if (a.intersects(x)) { graph.addEdge(a,x); graph.addEdge(x,a); }
nodes.add(a);
}
// Add edges between b and all its subtypes and supertypes
if (!nodes.contains(b)) {
for (PrimSig x:nodes) if (b.intersects(x)) { graph.addEdge(b,x); graph.addEdge(x,b); }
nodes.add(b);
}
}
// For each c1->c2 in childType, add c1->c2 into the finalType if there exists p1->p2 in parentType
// such that p1->..->c1->c2->..->p2 is a path in the graph.
Type answer=Type.EMPTY;
for (ProductType c:child) if (c.arity()==2) {
PrimSig c1=c.get(0), c2=c.get(1);
for (ProductType p:parent) if (p.arity()==2) {
PrimSig p1=p.get(0), p2=p.get(1);
if (graph.hasPath(p1,c1) && graph.hasPath(c2,p2)) { answer=answer.merge(c); break; }
}
}
return answer;
}