I am trying to formalize reachability property, such that I can find a satisfiable solution if there exists, a path of length 4 (which means if there are 3 intermediate nodes through which, 2 desired nodes are connected). Note: I am restricting it to only find a path of length 4. Following is what I did:
from z3 import*
# link between two nodes
L= Function('L', IntSort(), IntSort(),BoolSort())
# path between two nodes
p=Function('p', IntSort(), IntSort(), BoolSort())
u=Int('u')
x=Int('x')
y=Int('y')
z=Int('z')
i=Int('i')
j=Int('j')
s=Solver()
s.add(x>=0, x<=5, y>=0,y<=5, u>=0,u<=5,i>=0,i<=5, j>=0,j<=5,z>=0,z<=5)
# no self link or path
si1= ForAll(i, And (L(i,i)==False,p(i,i)==False))
si2=ForAll([x,y], p(x,y)==p(y,x))
# To fix source and destination
si3= ForAll([u,x,y], And(L(u,x)==False, L(y,u)==False) )
# To fix the length of path
si4=ForAll([x,y], Exists([i,j,z] , And( L(x,i)==True, L(i,j)==True,L(j,z)==True,L(z,y)==True) ) )
si5=ForAll([x,y,z], Implies (And (p(x,y)==True, L(x,z)==False,L(y,z)==False), L(x,y)==True))
#s.add(L(1,2)==True,L(2,3)==True, L(3,4)==True,L(4,5)==True)
s.add( Implies (p(x,y)==True, Exists([x,y], And(si1==True,si2==True,si3==True,si4==True,si5==True))) )
#s.add(p(x,y)==True)
result=s.check()
model = s.model()
print result, model ,model[p].else_value()
It returns me SAT, but now the problem is that, If I un-comment/add s.add(p(x,y)==True) It returns me unsat, rather it should return me a SAT result. Because there exist a path between x and y. Even if I manually mention (which is a naive approach)
s.add(L(1,2)==True,L(2,3)==True, L(3,4)==True,L(4,5)==True)
it still returns me x=0 and y=3, where as this is not a satisfiable solution, the first satisfiable solution should be x=0 and y=4 as per
si4=ForAll([x,y], Exists([i,j,z] , And( L(x,i)==True, L(i,j)==True,L(j,z)==True,L(z,y)==True) ) )
Where am I wrong?