I want to detect the non existence of a cycle in a graph using Datalog (which is a declarative logic programming language).
The proposed solution was:
(set-option :fixedpoint.engine datalog)
(define-sort s () Int)
(declare-rel edge (s s))
(declare-rel path (s s))
(declare-var a s)
(declare-var b s)
(declare-var c s)
(rule (=> (edge a b) (path a b)) P-1)
(rule (=> (and (path a b) (path b c)) (path a c)) P-2)
(rule (edge 1 2) E-1)
(rule (edge 2 3) E-2)
(rule (edge 3 1) E-3)
(declare-rel cycle (s))
(rule (=> (path a a) (cycle a)))
(query cycle :print-answer true)
But my question is how can i get SAT when there is no cycle in the graph and UNSAT when there exists a cycle.
One suggestion (but that does not meet my need) is:
(set-option :fixedpoint.engine datalog)
(define-sort s () Int)
(declare-rel edge (s s))
(declare-rel path (s s))
(declare-var a s)
(declare-var b s)
(declare-var c s)
(rule (=> (edge a b) (path a b)))
(rule (=> (and (path a b) (path b c)) (path a c)))
(rule (edge 1 2) r-1)
(rule (edge 2 3) r-2)
(rule (edge 3 1) r-3)
(assert (not (path a a)))
(check-sat)
(get-model)
which returns as result:
> z3 test.txt
sat
(model
(define-fun a () Int
0)
(define-fun path ((x!0 Int) (x!1 Int)) Bool
(ite (and (= x!0 0) (= x!1 0)) false
false))
)
I don't understand why z3 assign 0 to the variables while I only have 1, 2 and 3 as vertices?
Another suggestion was :
(set-option :fixedpoint.engine datalog)
(define-sort s () Int)
(declare-rel edge (s s))
(declare-rel path (s s))
(declare-var a s)
(declare-var b s)
(declare-var c s)
(rule (=> (edge a b) (path a b)))
(rule (=> (and (path a b) (path b c)) (path a c)))
(rule (edge 1 2) r-1)
(rule (edge 2 3) r-2)
(rule (edge 3 1) r-3)
(assert
(=> (path a a)
false
)
)
(check-sat)
(get-model)
Which returns the result:
> z3 test2.txt
sat
(model
(define-fun a () Int
0)
(define-fun path ((x!0 Int) (x!1 Int)) Bool
(ite (and (= x!0 0) (= x!1 0)) false
false))
)
Any idea to resolve this problem?
Note: I need to use Datalog for reasons of complexity.
a
is simply an integer: you did not constrain it to be a vertex, so it can be chosen as0
by the solver. Define a vertex predicate , and require(vertex a)
somewhere. E.g.(assert (not (and (vertex a) (path a a))))
$\endgroup$