Examples of Usage¶
Encoding First-Order Expressible Property¶
In the following code block, a graph structure is created.
The first-order formula of an independent set of size 3,
written as
(~ edg(x1,x2)) & (~ edg(x1,x3)) & (~ edg(x2,x3)) & (~ x1=x2) & (~ x1=x3) & (~
x2=x3), is converted into a list of Prop formula objects [g, ] + li,
with which Cnf object mgr is created.
The CNF encoded from f is generated to f.cnf in
DIMACS CNF format .
from pygplib import Fog, op, GrSt, Cnf, Prop
# V1 ------- V3
# | |
# | |
# V2---V5 |
# | | |
# | | |
# V4---V7 V6
vertex_list = [1,2,3,4,5,6,7]
edge_list = [(1,2),(1,3),(2,4),(2,5),(3,6),(4,7),(5,7)]
st = GrSt(vertex_list, edge_list, encoding="edge", prefix="V")
f = Fog.read("(~ edg(x1,x2)) & (~ edg(x1,x3)) & (~ edg(x2,x3)) & (~ x1=x2) & (~ x1=x3) & (~ x2=x3)")
g = op.perform_boolean_encoding(f, st)
li = [st.compute_domain_constraint(v) \
for v in op.get_free_vars(f)]
mgr = Cnf( [g, ] + li )
with open("f.cnf","w") as out:
mgr.write(stream=out)
Solving First-Order Expressible Property¶
In the following code block, which continues the previous code block,
a solution is computed with pysat,
a toolkit for SAT-based prototyping in Python .
The pygplib in itself does not provide any functionality of
solving formulas, and is independent of pysat module.
Please see the instruction page
for the installation of pysat.
from pysat.formula import CNF
from pysat.solvers import Solver
cnf = CNF(from_clauses=[mgr.get_clause(i) for i in range(mgr.get_ncls())])
with Solver(bootstrap_with=cnf) as solver:
if solver.solve():
print("SATISFIABLE")
ext_assign = solver.get_model() # external CNF vars.
int_assign = mgr.decode_assignment(ext_assign) # internal CNF vars.
fo_assign = st.decode_assignment(int_assign) # first-order vars.
ans = [st.object_to_vertex(fo_assign[key]) \
for key in fo_assign.keys()]
print(ans) # solution
else:
print("UNSATISFIABLE")
In the following code block, all solutions are enumerated.
from pysat.formula import CNF
from pysat.solvers import Solver
cnf = CNF(from_clauses=[mgr.get_clause(i) for i in range(mgr.get_ncls())])
with Solver(bootstrap_with=cnf) as solver:
for ext_assign in solver.enum_models():
int_assign = mgr.decode_assignment(ext_assign) # internal CNF vars.
fo_assign = st.decode_assignment(int_assign) # first-order vars.
ans = [st.object_to_vertex(fo_assign[key]) \
for key in fo_assign.keys()]
print(ans) # solution
The output is as follows.
Note that [7,6,1] and [7,1,6] are distinguished: they diff
in the assignments to x2 and x3.
Solutions here mean the permutations of all independent sets of size 3.
[7, 6, 1]
[7, 2, 3]
[7, 2, 6]
[5, 1, 4]
[5, 1, 6]
[7, 1, 6]
(The remaining part omitted)
The number of solutions can be exactly counted by model counters such as sharpSAT .
$ sharpSAT f.cnf
(The first part omited)
# solutions
48
# END
time: 0.108726s
The number of solutions can be approximately counted by ApproxMC .
import pyapproxmc
c = pyapproxmc.Counter()
for i in range(mgr.get_ncls()):
c.add_clause(list(mgr.get_clause(i)))
count = c.count()
print("Approximate count is: %d*2**%d" % (count[0], count[1]))
The output is as follows.
Approximate count is: 48*2**0
Sampling Solutions of First-Order Expressible Property¶
In the following code block, which uses mgr created in the previous code block,
solutions are randomly
generated using unigen,
UniGen approximately uniform sampler .
The pygplib in itself does not provide any functionality of
solving formulas, and is independent of unigen module.
Please see the instruction page
for the installation of unigen.
from pyunigen import Sampler
num = 5 # number of samples
c = Sampler()
for i in range(mgr.get_ncls()):
c.add_clause(list(mgr.get_clause(i)))
cells, hashes, samples = c.sample(num)
for ext_assign in samples:
int_assign = mgr.decode_assignment(ext_assign) # internal CNF vars.
fo_assign = st.decode_assignment(int_assign) # first-order vars.
ans = [st.object_to_vertex(fo_assign[key]) \
for key in fo_assign.keys()]
print(ans) # solution
The output is as follows.
[4, 5, 3]
[1, 4, 5]
[1, 5, 6]
[4, 1, 5]
[4, 3, 5]
Solution sampling with walksat is as follows:
$ echo $(cat f.cnf | grep -v ^c) | walksat -numsol 5
Solving Reconfiguration Problems of First-Order Property¶
examples/recon.py is a reconfiguration problem solver.
It covers reconfiguration problems for first-order expresssible properties.
A set of formulas as well as a graph are supposed to be given in files.
This program uses Python modules pysat and argparser.
Please see the instruction page of pysat
and that of argparse .
$ python examples/recon.py -t TJ -e "edge" data/sample.col data/sample1.phi
c SATISFIABLE
a 3 4 5
a 1 4 5
a 1 4 6
a 1 7 6
a 2 7 6
c compile_time 0.1260545253753662
c solve_time 0.001790761947631836
c whole_time 0.46629762649536133
$ cat data/sample1.phi
s (~ x1=x2 & ~ edg(x1,x2)) & (~ x1=x3 & ~ edg(x1,x3)) & (~ x2=x3 & ~ edg(x2,x3))
i x1=V3 & x2=V4 & x3=V5
f x1=V2 & x2=V7 & x3=V6
The lines starting with s, i, and f specify a property each
state must satisfy, a property of the initial state, and a property of
the final state, respectively. In stead of specifying transition
relation between states in formula-file, we specified -t TJ in the
command line, which means Token Jumping.
Note that initial/final state property is not equality relation as set. Indeed, the assignment x1=V7, x2=V2, x3=V6 for the final state is not satisfying. To avoid this, the following is a useful notation to indicate set equality relation.
$ cat data/sample4.phi
s (~ x1=x2 & ~ edg(x1,x2)) & (~ x1=x3 & ~ edg(x1,x3)) & (~ x2=x3 & ~ edg(x2,x3))
i 3 4 5
f 2 7 6
The final state constraint f 2 7 6 is equivalent to the following
formula.
(x1=V2 | x1=V7 | x1=V6) & (x2=V2 | x2=V7 | x2=V6) &
(x3=V2 | x3=V7 | x3=V6) & (x1=V2 | x2=V2 | x3=V2) &
(x1=V7 | x2=V7 | x3=V7) & (x1=V6 | x2=V6 | x3=V6)
usage: recon.py [-h] [-b BOUND] [-t TRANS] [-e ENCODING] arg1 arg2
positional arguments:
arg1 dimacs graph file
arg2 formula file
optional arguments:
-h, --help show this help message and exit
-b BOUND, --bound BOUND
Specify maximum bound
-t TRANS, --trans TRANS
Specify transition relation (TS or TJ)
-e ENCODING, --encoding ENCODING Specify ENCODING type (edge, clique, direct, log)