mirror of
https://github.com/Jaxan/satuio.git
synced 2025-04-27 14:47:46 +02:00
Mor efficient CNF, no n^2 anymore, but the construction only takes reachable states in a path
This commit is contained in:
parent
8b2750e07a
commit
c8e587526d
1 changed files with 56 additions and 32 deletions
88
uio.py
88
uio.py
|
@ -16,7 +16,9 @@ def measure_time(*str):
|
||||||
start = now
|
start = now
|
||||||
|
|
||||||
|
|
||||||
# Automaton
|
# *********************
|
||||||
|
# Reading the automaton
|
||||||
|
# *********************
|
||||||
|
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parser.add_argument('filename', help='File of the mealy machine (dot format)')
|
parser.add_argument('filename', help='File of the mealy machine (dot format)')
|
||||||
|
@ -55,7 +57,9 @@ with open(args.filename) as file:
|
||||||
measure_time('Constructed automaton with', len(states), 'states and', len(alphabet), 'symbols')
|
measure_time('Constructed automaton with', len(states), 'states and', len(alphabet), 'symbols')
|
||||||
|
|
||||||
|
|
||||||
# Solver setup
|
# ********************
|
||||||
|
# Seting up the solver
|
||||||
|
# ********************
|
||||||
|
|
||||||
vpool = IDPool()
|
vpool = IDPool()
|
||||||
solver = Solver(name=solver_name)
|
solver = Solver(name=solver_name)
|
||||||
|
@ -101,7 +105,9 @@ def unique(lits):
|
||||||
measure_time('Setup solver')
|
measure_time('Setup solver')
|
||||||
|
|
||||||
|
|
||||||
# Construction
|
# ********************
|
||||||
|
# Constructing the CNF
|
||||||
|
# ********************
|
||||||
|
|
||||||
# Guessing the word:
|
# Guessing the word:
|
||||||
# variable x_('in', i, a) says: on place i there is an input a
|
# variable x_('in', i, a) says: on place i there is an input a
|
||||||
|
@ -111,40 +117,56 @@ for i in range(length):
|
||||||
# We should only enable one base state (this allows for an optimisation later)
|
# We should only enable one base state (this allows for an optimisation later)
|
||||||
unique([bvar(base) for base in bases])
|
unique([bvar(base) for base in bases])
|
||||||
|
|
||||||
for s in tqdm(states, desc="simple stuff"):
|
# For each state s, we construct a path of possible successor states,
|
||||||
for i in range(length):
|
# following the guessed word. This path should be consistent with delta,
|
||||||
# variable x_('out', s, i, a) says: on place i there is an output o of the path s
|
# and we also record the outputs along this path. The output are later
|
||||||
unique([ovar(s, i, o) for o in outputs])
|
# used to decide whether we found a different output.
|
||||||
|
for s in tqdm(states, desc="CNF construction"):
|
||||||
|
# current set of possible states we're in
|
||||||
|
current_set = set([s])
|
||||||
|
# set of successors for the next iteration of i
|
||||||
|
next_set = set()
|
||||||
|
|
||||||
if i == 0:
|
|
||||||
# The paths start in the corresponding state
|
|
||||||
# This could be used to reduce some variables, but I'm lazy now
|
|
||||||
solver.add_clause([svar(s, 0, s)])
|
|
||||||
else:
|
|
||||||
# variable x_('state', s, i, t) denotes the path through the automaton starting in s
|
|
||||||
unique([svar(s, i, t) for t in states])
|
|
||||||
|
|
||||||
# The path is consistent with the delta function
|
|
||||||
# The outputs correspond to the output along the path
|
|
||||||
# I have merged these loops, it was slightly faster
|
|
||||||
for s in tqdm(states, desc="paths & outputs"):
|
|
||||||
for i in range(length):
|
for i in range(length):
|
||||||
for t in states:
|
# Only one successor state should be enable (probably redundant)
|
||||||
sv = svar(s, i, t)
|
# For i == 0, this is a single state (namely s)
|
||||||
for a in alphabet:
|
unique([svar(s, i, t) for t in current_set])
|
||||||
av = avar(i, a)
|
|
||||||
# We couple i with i+1, and so skip the last iteration
|
# We keep track of the possible outputs
|
||||||
if i < length-1:
|
possible_outputs = set()
|
||||||
# x_('s', s, i, t) /\ x_('in', i, a) => x_('s', s, i+1, delta(t, a))
|
|
||||||
# == -x_('s', s, i, t) \/ -x_('in', i, a) \/ x_('s', s, i+1, delta(t, a))
|
for a in alphabet:
|
||||||
next_t = delta[(t, a)]
|
av = avar(i, a)
|
||||||
solver.add_clause([-sv, -av, svar(s, i+1, next_t)])
|
|
||||||
|
for t in current_set:
|
||||||
|
sv = svar(s, i, t)
|
||||||
|
output = labda[(t, a)]
|
||||||
|
possible_outputs.add(output)
|
||||||
|
|
||||||
|
# Constraint: when in state t and input a, we output o
|
||||||
# x_('s', state, i, t) /\ x_('in', i, a) => x_('o', i, labda(t, a))
|
# x_('s', state, i, t) /\ x_('in', i, a) => x_('o', i, labda(t, a))
|
||||||
# == -x_('s', state, i, t) \/ -x_('in', i, a) \/ x_('o', i, labda(t, a))
|
# == -x_('s', state, i, t) \/ -x_('in', i, a) \/ x_('o', i, labda(t, a))
|
||||||
output = labda[(t, a)]
|
|
||||||
solver.add_clause([-sv, -av, ovar(s, i, output)])
|
solver.add_clause([-sv, -av, ovar(s, i, output)])
|
||||||
|
|
||||||
|
# when i == length-1 we don't need to consider successors
|
||||||
|
if i < length-1:
|
||||||
|
next_t = delta[(t, a)]
|
||||||
|
next_set.add(next_t)
|
||||||
|
|
||||||
|
# Constraint: when in state t and input a, we go to next_t
|
||||||
|
# x_('s', s, i, t) /\ x_('in', i, a) => x_('s', s, i+1, delta(t, a))
|
||||||
|
# == -x_('s', s, i, t) \/ -x_('in', i, a) \/ x_('s', s, i+1, delta(t, a))
|
||||||
|
solver.add_clause([-sv, -av, svar(s, i+1, next_t)])
|
||||||
|
|
||||||
|
# Only one output should be enabled
|
||||||
|
# variable x_('out', s, i, a) says: on place i there is an output o of the path s
|
||||||
|
unique([ovar(s, i, o) for o in possible_outputs])
|
||||||
|
|
||||||
|
# Next iteration with successor states
|
||||||
|
current_set = next_set
|
||||||
|
next_set = set()
|
||||||
|
|
||||||
|
|
||||||
# If(f) the output of a state is different than the one from our base state,
|
# If(f) the output of a state is different than the one from our base state,
|
||||||
# then, we encode that in a new variable. This is only needed when the base
|
# then, we encode that in a new variable. This is only needed when the base
|
||||||
# state is active, so the first literal in these clauses is -bvar(base).
|
# state is active, so the first literal in these clauses is -bvar(base).
|
||||||
|
@ -177,7 +199,9 @@ for s in tqdm(states, desc="diff2"):
|
||||||
measure_time('Constructed CNF with', solver.nof_clauses(), 'clauses and', solver.nof_vars(), 'variables')
|
measure_time('Constructed CNF with', solver.nof_clauses(), 'clauses and', solver.nof_vars(), 'variables')
|
||||||
|
|
||||||
|
|
||||||
# Solving
|
# ******************
|
||||||
|
# Solving and output
|
||||||
|
# ******************
|
||||||
|
|
||||||
for s in bases:
|
for s in bases:
|
||||||
print('*** UIO for state', s)
|
print('*** UIO for state', s)
|
||||||
|
|
Loading…
Add table
Reference in a new issue