Decls d=null, d2=null;
Formula ans1, ans2;
// "R in A ->op B" means for each tuple a in A, there are "op" tuples in r that begins with a.
Expression atuple=null, ar=r;
for(int i=a.arity(); i>0; i--) {
Variable v=Variable.unary("");
if (a.arity()==1) d=v.oneOf(a); else if (d==null) d=v.oneOf(Relation.UNIV); else d=v.oneOf(Relation.UNIV).and(d);
ar=v.join(ar);
if (atuple==null) atuple=v; else atuple=atuple.product(v);
}
ans1=isIn(ar, ab.right);
switch(ab.op) {
case ISSEQ_ARROW_LONE:
case ANY_ARROW_LONE: case SOME_ARROW_LONE: case ONE_ARROW_LONE: case LONE_ARROW_LONE: ans1=ar.lone().and(ans1); break;
case ANY_ARROW_ONE: case SOME_ARROW_ONE: case ONE_ARROW_ONE: case LONE_ARROW_ONE: ans1=ar.one().and(ans1); break;
case ANY_ARROW_SOME: case SOME_ARROW_SOME: case ONE_ARROW_SOME: case LONE_ARROW_SOME: ans1=ar.some().and(ans1); break;
}
if (a.arity()>1) { Formula tmp=isIn(atuple, ab.left); if (tmp!=Formula.TRUE) ans1=tmp.implies(ans1); }
ans1=ans1.forAll(d);
// "R in A op-> B" means for each tuple b in B, there are "op" tuples in r that end with b.
Expression btuple=null, rb=r;
for(int i=b.arity(); i>0; i--) {
Variable v=Variable.unary("");
if (b.arity()==1) d2=v.oneOf(b); else if (d2==null) d2=v.oneOf(Relation.UNIV); else d2=v.oneOf(Relation.UNIV).and(d2);
rb=rb.join(v);
if (btuple==null) btuple=v; else btuple=v.product(btuple);
}
ans2=isIn(rb, ab.left);
switch(ab.op) {
case LONE_ARROW_ANY: case LONE_ARROW_SOME: case LONE_ARROW_ONE: case LONE_ARROW_LONE: ans2=rb.lone().and(ans2); break;
case ONE_ARROW_ANY: case ONE_ARROW_SOME: case ONE_ARROW_ONE: case ONE_ARROW_LONE: ans2=rb.one().and(ans2); break;