In [1]:
import spot
from spot.seminator import seminator
spot.setup()

The seminator() function can also perform complementation of automata. This works by converting the input into a semi-deterministic TBA, and then applying the NCSB construction, that produces a TBA. Two versions of the semi-deterministic construction are available:

  • "spot" is the implementation available in Spot, which a a transition-based adaptation of the NCSB construction described in this TACAS'16 paper
  • "pldi" is a variant described in section 5 of this PLDI'18 paper, implemented in Seminator for transition-based automata.

If complement=True is passed to the seminator() function, the smallest output produced by these two construction is used. To force one construction, use complement="spot" or complement="pldi".

The postproc_comp argument controls whether the result of the NCSB complementations should be postprocessed or not. It default to True unless the pure=True option is given.

Here is a case where the output where the "spot" variant is better than the "pldi" one (after simplification of the result):


In [2]:
f = spot.formula('G(a | (b U (Gc | Gd)))')
aut = f.translate(); aut


Out[2]:
Inf( ) [Büchi] 0 0 I->0 0->0 a 1 1 0->1 !a & d 2 2 0->2 !a & c 3 3 0->3 !a & b 1->1 d 2->2 c 3->1 d 3->2 c 3->3 b

In [3]:
neg1 = seminator(aut, complement="spot"); neg1


Out[3]:
Inf( ) [Büchi] 7 7 I->7 7->7 a 0 0 7->0 !a & !b & !c & !d 1 1 7->1 !a & !b & !c & d 2 2 7->2 !a & !b & c & !d 3 3 7->3 !a & !b & c & d 4 4 7->4 (!a & b & !c & !d) | (!a & b & c & d) 5 5 7->5 !a & b & !c & d 6 6 7->6 !a & b & c & !d 0->0 1 1->0 !d 1->1 d 2->0 !c 2->2 c 3->0 !c & !d 3->1 !c & d 3->2 c & !d 3->3 c & d 4->0 !b & !c & !d 4->1 !b & !c & d 4->2 !b & c & !d 4->3 !b & c & d 4->4 b & !c & !d 4->4 b & c & d 4->5 b & !c & d 4->6 b & c & !d 5->0 !b & !c & !d 5->1 !b & !c & d 5->2 !b & c & !d 5->3 !b & c & d 5->4 b & !c & !d 5->5 b & d 5->6 b & c & !d 6->0 !b & !c & !d 6->1 !b & !c & d 6->2 !b & c & !d 6->3 !b & c & d 6->4 b & !c & !d 6->5 b & !c & d 6->6 b & c

In [4]:
neg2 = seminator(aut, complement="pldi"); neg2


Out[4]:
Inf( ) [Büchi] 0 0 I->0 0->0 a 1 1 0->1 !a & !b & !c & !d 2 2 0->2 !a & !b & !c & d 3 3 0->3 !a & !b & c & !d 4 4 0->4 !a & !b & c & d 5 5 0->5 !a & b & !c & !d 6 6 0->6 !a & b & !c & d 7 7 0->7 !a & b & c & !d 8 8 0->8 !a & b & c & d 1->1 1 2->1 !d 2->2 d 3->1 !c 3->3 c 4->1 !c & !d 4->2 !c & d 4->3 c & !d 4->4 c & d 5->1 !b & !c & !d 5->2 !b & !c & d 5->3 !b & c & !d 5->4 !b & c & d 5->5 b & !c & !d 5->6 b & !c & d 5->7 b & c & !d 5->8 b & c & d 6->1 !b & !c & !d 6->2 !b & !c & d 6->3 !b & c & !d 6->4 !b & c & d 6->5 b & !c & !d 6->6 b & d 6->7 b & c & !d 7->1 !b & !c & !d 7->2 !b & !c & d 7->3 !b & c & !d 7->4 !b & c & d 7->5 b & !c & !d 7->6 b & !c & d 7->7 b & c 8->1 !b & !c & !d 8->2 !b & !c & d 8->3 !b & c & !d 8->4 !b & c & d 8->5 b & !c & !d 8->6 b & !c & d 8->7 b & c & !d 8->8 b & c & d

In [5]:
nf = spot.formula_Not(f)
assert neg1.equivalent_to(nf)
assert neg2.equivalent_to(nf)

Here is a case where it is the opposite:


In [6]:
f2 = spot.formula('G(a | X(!a | (a U (a & !b & X(a & b)))))')

In [7]:
aut2 = f2.translate(); aut2


Out[7]:
Inf( ) [Büchi] 0 0 I->0 0->0 a 1 1 0->1 !a 1->1 !a 2 2 1->2 a 3 3 1->3 a & !b 2->2 a 2->3 a & !b 3->0 a & b

In [8]:
neg3 = seminator(aut2, complement="spot"); neg3


Out[8]:
[Büchi] 0 0 I->0 1 1 0->1 !a 2 2 0->2 !a 3 3 0->3 a 4 4 0->4 a 1->1 !a 1->2 !a 5 5 1->5 a & !b 6 6 1->6 a & b 7 7 2->7 a & !b 8 8 2->8 a & b 3->1 !a 3->3 a 3->4 a 4->2 !a 5->4 a & b 5->5 a & !b 9 9 5->9 a & b 6->5 a & !b 6->6 a & b 7->7 a & !b 10 10 7->10 !a 8->7 a & !b 8->8 a & b 8->10 !a 9->1 !a 9->4 a 9->5 a & !b 9->9 a & b 11 11 9->11 a & !b 10->10 1 11->1 !a 11->4 a & !b 11->11 a & !b

In [9]:
neg4 = seminator(aut2, complement="pldi"); neg4


Out[9]:
[Büchi] 0 0 I->0 0->0 a 1 1 0->1 !a 1->1 !a 2 2 1->2 a & !b 3 3 1->3 a & b 4 4 1->4 a & !b 5 5 1->5 a & b 2->0 a & b 2->2 a & !b 3->2 a & !b 3->3 a & b 4->4 a & !b 6 6 4->6 !a 5->4 a & !b 5->5 a & b 5->6 !a 6->6 1

In [10]:
nf2 = spot.formula_Not(f2)
assert neg3.equivalent_to(nf2)
assert neg4.equivalent_to(nf2)