Fixes #539. * AUTHORS: Update by indicating the status of each contributor. * Makefile.am, bench/Makefile.am, bench/dtgbasat/Makefile.am, bench/dtgbasat/gen.py, bench/emptchk/Makefile.am, bench/emptchk/defs.in, bench/ltl2tgba/Makefile.am, bench/ltl2tgba/defs.in, bench/ltl2tgba/sum.py, bench/ltlclasses/Makefile.am, bench/ltlcounter/Makefile.am, bench/spin13/Makefile.am, bench/stutter/Makefile.am, bench/stutter/stutter_invariance_formulas.cc, bench/stutter/stutter_invariance_randomgraph.cc, bench/wdba/Makefile.am, bin/Makefile.am, bin/autcross.cc, bin/autfilt.cc, bin/common_aoutput.cc, bin/common_aoutput.hh, bin/common_color.cc, bin/common_color.hh, bin/common_conv.cc, bin/common_conv.hh, bin/common_cout.cc, bin/common_cout.hh, bin/common_file.cc, bin/common_file.hh, bin/common_finput.cc, bin/common_finput.hh, bin/common_hoaread.cc, bin/common_hoaread.hh, bin/common_output.cc, bin/common_output.hh, bin/common_post.cc, bin/common_post.hh, bin/common_r.cc, bin/common_r.hh, bin/common_range.cc, bin/common_range.hh, bin/common_setup.cc, bin/common_setup.hh, bin/common_sys.hh, bin/common_trans.cc, bin/common_trans.hh, bin/dstar2tgba.cc, bin/genaut.cc, bin/genltl.cc, bin/ltl2tgba.cc, bin/ltl2tgta.cc, bin/ltlcross.cc, bin/ltldo.cc, bin/ltlfilt.cc, bin/ltlgrind.cc, bin/ltlsynt.cc, bin/man/Makefile.am, bin/options.py, bin/randaut.cc, bin/randltl.cc, bin/spot-x.cc, bin/spot.cc, configure.ac, debian/copyright, doc/Makefile.am, doc/tl/Makefile.am, elisp/Makefile.am, python/Makefile.am, python/buddy.i, python/spot/__init__.py, python/spot/aux_.py, python/spot/gen.i, python/spot/impl.i, python/spot/jupyter.py, python/spot/ltsmin.i, spot/Makefile.am, spot/gen/Makefile.am, spot/gen/automata.cc, spot/gen/automata.hh, spot/gen/formulas.cc, spot/gen/formulas.hh, spot/graph/Makefile.am, spot/graph/graph.hh, spot/graph/ngraph.hh, spot/kripke/Makefile.am, spot/kripke/fairkripke.cc, spot/kripke/fairkripke.hh, spot/kripke/fwd.hh, spot/kripke/kripke.cc, spot/kripke/kripke.hh, spot/kripke/kripkegraph.hh, spot/ltsmin/Makefile.am, spot/ltsmin/ltsmin.cc, spot/ltsmin/ltsmin.hh, spot/ltsmin/spins_interface.cc, spot/ltsmin/spins_interface.hh, spot/ltsmin/spins_kripke.hh, spot/ltsmin/spins_kripke.hxx, spot/mc/Makefile.am, spot/mc/bloemen.hh, spot/mc/bloemen_ec.hh, spot/mc/cndfs.hh, spot/mc/deadlock.hh, spot/mc/intersect.hh, spot/mc/lpar13.hh, spot/mc/mc.hh, spot/mc/mc_instanciator.hh, spot/mc/unionfind.cc, spot/mc/unionfind.hh, spot/mc/utils.hh, spot/misc/Makefile.am, spot/misc/bareword.cc, spot/misc/bareword.hh, spot/misc/bddlt.hh, spot/misc/bitset.cc, spot/misc/bitset.hh, spot/misc/bitvect.cc, spot/misc/bitvect.hh, spot/misc/casts.hh, spot/misc/clz.hh, spot/misc/common.hh, spot/misc/escape.cc, spot/misc/escape.hh, spot/misc/fixpool.hh, spot/misc/formater.cc, spot/misc/formater.hh, spot/misc/hash.hh, spot/misc/hashfunc.hh, spot/misc/intvcmp2.cc, spot/misc/intvcmp2.hh, spot/misc/intvcomp.cc, spot/misc/intvcomp.hh, spot/misc/ltstr.hh, spot/misc/memusage.cc, spot/misc/memusage.hh, spot/misc/minato.cc, spot/misc/minato.hh, spot/misc/mspool.hh, spot/misc/optionmap.cc, spot/misc/optionmap.hh, spot/misc/random.cc, spot/misc/random.hh, spot/misc/satsolver.cc, spot/misc/satsolver.hh, spot/misc/timer.cc, spot/misc/timer.hh, spot/misc/tmpfile.cc, spot/misc/tmpfile.hh, spot/misc/trival.hh, spot/misc/version.cc, spot/misc/version.hh, spot/parseaut/Makefile.am, spot/parseaut/fmterror.cc, spot/parseaut/parseaut.yy, spot/parseaut/parsedecl.hh, spot/parseaut/public.hh, spot/parseaut/scanaut.ll, spot/parsetl/Makefile.am, spot/parsetl/fmterror.cc, spot/parsetl/parsedecl.hh, spot/parsetl/parsetl.yy, spot/parsetl/scantl.ll, spot/priv/Makefile.am, spot/priv/accmap.hh, spot/priv/bddalloc.cc, spot/priv/bddalloc.hh, spot/priv/freelist.cc, spot/priv/freelist.hh, spot/priv/partitioned_relabel.cc, spot/priv/partitioned_relabel.hh, spot/priv/satcommon.cc, spot/priv/satcommon.hh, spot/priv/trim.cc, spot/priv/trim.hh, spot/priv/weight.cc, spot/priv/weight.hh, spot/ta/Makefile.am, spot/ta/ta.cc, spot/ta/ta.hh, spot/ta/taexplicit.cc, spot/ta/taexplicit.hh, spot/ta/taproduct.cc, spot/ta/taproduct.hh, spot/ta/tgta.hh, spot/ta/tgtaexplicit.cc, spot/ta/tgtaexplicit.hh, spot/ta/tgtaproduct.cc, spot/ta/tgtaproduct.hh, spot/taalgos/Makefile.am, spot/taalgos/dot.cc, spot/taalgos/dot.hh, spot/taalgos/emptinessta.cc, spot/taalgos/emptinessta.hh, spot/taalgos/minimize.cc, spot/taalgos/minimize.hh, spot/taalgos/reachiter.cc, spot/taalgos/reachiter.hh, spot/taalgos/statessetbuilder.cc, spot/taalgos/statessetbuilder.hh, spot/taalgos/stats.cc, spot/taalgos/stats.hh, spot/taalgos/tgba2ta.cc, spot/taalgos/tgba2ta.hh, spot/tl/Makefile.am, spot/tl/apcollect.cc, spot/tl/apcollect.hh, spot/tl/contain.cc, spot/tl/contain.hh, spot/tl/declenv.cc, spot/tl/declenv.hh, spot/tl/defaultenv.cc, spot/tl/defaultenv.hh, spot/tl/dot.cc, spot/tl/dot.hh, spot/tl/environment.hh, spot/tl/exclusive.cc, spot/tl/exclusive.hh, spot/tl/formula.cc, spot/tl/formula.hh, spot/tl/hierarchy.cc, spot/tl/hierarchy.hh, spot/tl/length.cc, spot/tl/length.hh, spot/tl/ltlf.cc, spot/tl/ltlf.hh, spot/tl/mark.cc, spot/tl/mark.hh, spot/tl/mutation.cc, spot/tl/mutation.hh, spot/tl/nenoform.cc, spot/tl/nenoform.hh, spot/tl/parse.hh, spot/tl/print.cc, spot/tl/print.hh, spot/tl/randomltl.cc, spot/tl/randomltl.hh, spot/tl/relabel.cc, spot/tl/relabel.hh, spot/tl/remove_x.cc, spot/tl/remove_x.hh, spot/tl/simplify.cc, spot/tl/simplify.hh, spot/tl/snf.cc, spot/tl/snf.hh, spot/tl/sonf.cc, spot/tl/sonf.hh, spot/tl/unabbrev.cc, spot/tl/unabbrev.hh, spot/twa/Makefile.am, spot/twa/acc.cc, spot/twa/acc.hh, spot/twa/bdddict.cc, spot/twa/bdddict.hh, spot/twa/bddprint.cc, spot/twa/bddprint.hh, spot/twa/formula2bdd.cc, spot/twa/formula2bdd.hh, spot/twa/fwd.hh, spot/twa/taatgba.cc, spot/twa/taatgba.hh, spot/twa/twa.cc, spot/twa/twa.hh, spot/twa/twagraph.cc, spot/twa/twagraph.hh, spot/twa/twaproduct.cc, spot/twa/twaproduct.hh, spot/twaalgos/Makefile.am, spot/twaalgos/aiger.cc, spot/twaalgos/aiger.hh, spot/twaalgos/alternation.cc, spot/twaalgos/alternation.hh, spot/twaalgos/are_isomorphic.cc, spot/twaalgos/are_isomorphic.hh, spot/twaalgos/bfssteps.cc, spot/twaalgos/bfssteps.hh, spot/twaalgos/canonicalize.cc, spot/twaalgos/canonicalize.hh, spot/twaalgos/cleanacc.cc, spot/twaalgos/cleanacc.hh, spot/twaalgos/cobuchi.cc, spot/twaalgos/cobuchi.hh, spot/twaalgos/complement.cc, spot/twaalgos/complement.hh, spot/twaalgos/complete.cc, spot/twaalgos/complete.hh, spot/twaalgos/compsusp.cc, spot/twaalgos/compsusp.hh, spot/twaalgos/contains.cc, spot/twaalgos/contains.hh, spot/twaalgos/copy.hh, spot/twaalgos/couvreurnew.cc, spot/twaalgos/couvreurnew.hh, spot/twaalgos/cycles.cc, spot/twaalgos/cycles.hh, spot/twaalgos/dbranch.cc, spot/twaalgos/dbranch.hh, spot/twaalgos/degen.cc, spot/twaalgos/degen.hh, spot/twaalgos/determinize.cc, spot/twaalgos/determinize.hh, spot/twaalgos/dot.cc, spot/twaalgos/dot.hh, spot/twaalgos/dtbasat.cc, spot/twaalgos/dtbasat.hh, spot/twaalgos/dtwasat.cc, spot/twaalgos/dtwasat.hh, spot/twaalgos/dualize.cc, spot/twaalgos/dualize.hh, spot/twaalgos/emptiness.cc, spot/twaalgos/emptiness.hh, spot/twaalgos/emptiness_stats.hh, spot/twaalgos/forq_contains.cc, spot/twaalgos/forq_contains.hh, spot/twaalgos/game.cc, spot/twaalgos/game.hh, spot/twaalgos/genem.cc, spot/twaalgos/genem.hh, spot/twaalgos/gfguarantee.cc, spot/twaalgos/gfguarantee.hh, spot/twaalgos/gtec/Makefile.am, spot/twaalgos/gtec/ce.cc, spot/twaalgos/gtec/ce.hh, spot/twaalgos/gtec/gtec.cc, spot/twaalgos/gtec/gtec.hh, spot/twaalgos/gtec/sccstack.cc, spot/twaalgos/gtec/sccstack.hh, spot/twaalgos/gtec/status.cc, spot/twaalgos/gtec/status.hh, spot/twaalgos/gv04.cc, spot/twaalgos/gv04.hh, spot/twaalgos/hoa.cc, spot/twaalgos/hoa.hh, spot/twaalgos/iscolored.cc, spot/twaalgos/iscolored.hh, spot/twaalgos/isdet.cc, spot/twaalgos/isdet.hh, spot/twaalgos/isunamb.cc, spot/twaalgos/isunamb.hh, spot/twaalgos/isweakscc.cc, spot/twaalgos/isweakscc.hh, spot/twaalgos/langmap.cc, spot/twaalgos/langmap.hh, spot/twaalgos/lbtt.cc, spot/twaalgos/lbtt.hh, spot/twaalgos/ltl2taa.cc, spot/twaalgos/ltl2taa.hh, spot/twaalgos/ltl2tgba_fm.cc, spot/twaalgos/ltl2tgba_fm.hh, spot/twaalgos/magic.cc, spot/twaalgos/magic.hh, spot/twaalgos/mask.cc, spot/twaalgos/mask.hh, spot/twaalgos/mealy_machine.cc, spot/twaalgos/mealy_machine.hh, spot/twaalgos/minimize.cc, spot/twaalgos/minimize.hh, spot/twaalgos/ndfs_result.hxx, spot/twaalgos/neverclaim.cc, spot/twaalgos/neverclaim.hh, spot/twaalgos/parity.cc, spot/twaalgos/parity.hh, spot/twaalgos/postproc.cc, spot/twaalgos/postproc.hh, spot/twaalgos/powerset.cc, spot/twaalgos/powerset.hh, spot/twaalgos/product.cc, spot/twaalgos/product.hh, spot/twaalgos/randomgraph.cc, spot/twaalgos/randomgraph.hh, spot/twaalgos/randomize.cc, spot/twaalgos/randomize.hh, spot/twaalgos/reachiter.cc, spot/twaalgos/reachiter.hh, spot/twaalgos/relabel.cc, spot/twaalgos/relabel.hh, spot/twaalgos/remfin.cc, spot/twaalgos/remfin.hh, spot/twaalgos/remprop.cc, spot/twaalgos/remprop.hh, spot/twaalgos/sbacc.cc, spot/twaalgos/sbacc.hh, spot/twaalgos/sccfilter.cc, spot/twaalgos/sccfilter.hh, spot/twaalgos/sccinfo.cc, spot/twaalgos/sccinfo.hh, spot/twaalgos/se05.cc, spot/twaalgos/se05.hh, spot/twaalgos/sepsets.cc, spot/twaalgos/sepsets.hh, spot/twaalgos/simulation.cc, spot/twaalgos/simulation.hh, spot/twaalgos/split.cc, spot/twaalgos/split.hh, spot/twaalgos/stats.cc, spot/twaalgos/stats.hh, spot/twaalgos/strength.cc, spot/twaalgos/strength.hh, spot/twaalgos/stripacc.cc, spot/twaalgos/stripacc.hh, spot/twaalgos/stutter.cc, spot/twaalgos/stutter.hh, spot/twaalgos/sum.cc, spot/twaalgos/sum.hh, spot/twaalgos/synthesis.cc, spot/twaalgos/synthesis.hh, spot/twaalgos/tau03.cc, spot/twaalgos/tau03.hh, spot/twaalgos/tau03opt.cc, spot/twaalgos/tau03opt.hh, spot/twaalgos/toparity.cc, spot/twaalgos/toparity.hh, spot/twaalgos/totgba.cc, spot/twaalgos/totgba.hh, spot/twaalgos/toweak.cc, spot/twaalgos/toweak.hh, spot/twaalgos/translate.cc, spot/twaalgos/translate.hh, spot/twaalgos/word.cc, spot/twaalgos/word.hh, spot/twaalgos/zlktree.cc, spot/twaalgos/zlktree.hh, spot/twacube/Makefile.am, spot/twacube/cube.cc, spot/twacube/cube.hh, spot/twacube/fwd.hh, spot/twacube/twacube.cc, spot/twacube/twacube.hh, spot/twacube_algos/Makefile.am, spot/twacube_algos/convert.cc, spot/twacube_algos/convert.hh, tests/Makefile.am, tests/core/385.test, tests/core/500.test, tests/core/521.test, tests/core/522.test, tests/core/acc.cc, tests/core/acc.test, tests/core/acc2.test, tests/core/acc_word.test, tests/core/accsimpl.test, tests/core/alternating.test, tests/core/autcross.test, tests/core/autcross2.test, tests/core/autcross3.test, tests/core/autcross4.test, tests/core/autcross5.test, tests/core/babiak.test, tests/core/bare.test, tests/core/basimul.test, tests/core/bdd.test, tests/core/bdddict.cc, tests/core/bdddict.test, tests/core/bitvect.cc, tests/core/bitvect.test, tests/core/bricks.cc, tests/core/bricks.test, tests/core/checkpsl.cc, tests/core/checkta.cc, tests/core/complement.test, tests/core/complementation.test, tests/core/complete.test, tests/core/consterm.cc, tests/core/consterm.test, tests/core/cube.cc, tests/core/cube.test, tests/core/cycles.test, tests/core/dbacomp.test, tests/core/dca.test, tests/core/dca2.test, tests/core/defs.in, tests/core/degendet.test, tests/core/degenid.test, tests/core/degenlskip.test, tests/core/degenscc.test, tests/core/det.test, tests/core/dfs.test, tests/core/dnfstreett.test, tests/core/dot2tex.test, tests/core/dra2dba.test, tests/core/dstar.test, tests/core/dualize.test, tests/core/dupexp.test, tests/core/emptchk.cc, tests/core/emptchk.test, tests/core/emptchke.test, tests/core/emptchkr.test, tests/core/equals.test, tests/core/equalsf.cc, tests/core/eventuniv.test, tests/core/exclusive-ltl.test, tests/core/exclusive-tgba.test, tests/core/explpro2.test, tests/core/explpro3.test, tests/core/explpro4.test, tests/core/explprod.test, tests/core/explsum.test, tests/core/format.test, tests/core/full.test, tests/core/gamehoa.test, tests/core/genaut.test, tests/core/genltl.test, tests/core/gragsa.test, tests/core/graph.cc, tests/core/graph.test, tests/core/hierarchy.test, tests/core/highlightstate.test, tests/core/ikwiad.cc, tests/core/included.test, tests/core/intvcmp2.cc, tests/core/intvcomp.cc, tests/core/intvcomp.test, tests/core/isomorph.test, tests/core/isop.test, tests/core/kind.cc, tests/core/kind.test, tests/core/kripke.test, tests/core/kripkecat.cc, tests/core/latex.test, tests/core/lbt.test, tests/core/lbttparse.test, tests/core/length.cc, tests/core/length.test, tests/core/lenient.test, tests/core/ltl2dstar.test, tests/core/ltl2dstar2.test, tests/core/ltl2dstar3.test, tests/core/ltl2dstar4.test, tests/core/ltl2neverclaim-lbtt.test, tests/core/ltl2neverclaim.test, tests/core/ltl2ta.test, tests/core/ltl2ta2.test, tests/core/ltl2tgba.test, tests/core/ltl2tgba2.test, tests/core/ltl3ba.test, tests/core/ltl3dra.test, tests/core/ltlcounter.test, tests/core/ltlcross.test, tests/core/ltlcross2.test, tests/core/ltlcross3.test, tests/core/ltlcross4.test, tests/core/ltlcross5.test, tests/core/ltlcross6.test, tests/core/ltlcrossce.test, tests/core/ltlcrossce2.test, tests/core/ltlcrossgrind.test, tests/core/ltldo.test, tests/core/ltldo2.test, tests/core/ltlf.test, tests/core/ltlfilt.test, tests/core/ltlgrind.test, tests/core/ltlrel.cc, tests/core/ltlrel.test, tests/core/ltlsynt-pgame.test, tests/core/ltlsynt.test, tests/core/ltlsynt2.test, tests/core/lunabbrev.test, tests/core/maskacc.test, tests/core/maskkeep.test, tests/core/mempool.cc, tests/core/mempool.test, tests/core/minterm.cc, tests/core/minterm.test, tests/core/minusx.test, tests/core/monitor.test, tests/core/nenoform.test, tests/core/neverclaimread.test, tests/core/ngraph.cc, tests/core/ngraph.test, tests/core/nondet.test, tests/core/obligation.test, tests/core/optba.test, tests/core/parity.cc, tests/core/parity.test, tests/core/parity2.test, tests/core/parse.test, tests/core/parseaut.test, tests/core/parseerr.test, tests/core/pdegen.test, tests/core/pgsolver.test, tests/core/prodchain.test, tests/core/prodor.test, tests/core/rabin2parity.test, tests/core/rand.test, tests/core/randaut.test, tests/core/randomize.test, tests/core/randpsl.test, tests/core/randtgba.cc, tests/core/randtgba.test, tests/core/readltl.cc, tests/core/readsave.test, tests/core/reduc.cc, tests/core/reduc.test, tests/core/reduc0.test, tests/core/reduccmp.test, tests/core/reducpsl.test, tests/core/remfin.test, tests/core/remove_x.test, tests/core/remprop.test, tests/core/renault.test, tests/core/safra.cc, tests/core/safra.test, tests/core/satmin.test, tests/core/satmin2.test, tests/core/satmin3.test, tests/core/sbacc.test, tests/core/scc.test, tests/core/sccdot.test, tests/core/sccif.cc, tests/core/sccif.test, tests/core/sccsimpl.test, tests/core/semidet.test, tests/core/sepsets.test, tests/core/serial.test, tests/core/sim2.test, tests/core/sim3.test, tests/core/sonf.test, tests/core/split.test, tests/core/spotlbtt.test, tests/core/spotlbtt2.test, tests/core/streett.test, tests/core/strength.test, tests/core/stutter-ltl.test, tests/core/stutter-tgba.test, tests/core/sugar.test, tests/core/syfco.test, tests/core/syntimpl.cc, tests/core/syntimpl.test, tests/core/taatgba.cc, tests/core/taatgba.test, tests/core/tgbagraph.test, tests/core/tostring.cc, tests/core/tostring.test, tests/core/tripprod.test, tests/core/trival.cc, tests/core/trival.test, tests/core/tunabbrev.test, tests/core/tunenoform.test, tests/core/twacube.cc, tests/core/twacube.test, tests/core/twagraph.cc, tests/core/unabbrevwm.test, tests/core/unambig.test, tests/core/unambig2.test, tests/core/uniq.test, tests/core/utf8.test, tests/core/uwrm.test, tests/core/wdba.test, tests/core/wdba2.test, tests/ltsmin/check.test, tests/ltsmin/check2.test, tests/ltsmin/check3.test, tests/ltsmin/finite.test, tests/ltsmin/finite2.test, tests/ltsmin/finite3.test, tests/ltsmin/kripke.test, tests/ltsmin/modelcheck.cc, tests/ltsmin/testconvert.cc, tests/ltsmin/testconvert.test, tests/python/298.py, tests/python/341.py, tests/python/471.py, tests/python/acc.py, tests/python/accparse2.py, tests/python/aiger.py, tests/python/alarm.py, tests/python/aliases.py, tests/python/alternating.py, tests/python/bdddict.py, tests/python/bdditer.py, tests/python/bddnqueen.py, tests/python/bugdet.py, tests/python/complement_semidet.py, tests/python/dbranch.py, tests/python/declenv.py, tests/python/decompose_scc.py, tests/python/det.py, tests/python/dualize.py, tests/python/ecfalse.py, tests/python/except.py, tests/python/forq_contains.py, tests/python/game.py, tests/python/gen.py, tests/python/genem.py, tests/python/implies.py, tests/python/interdep.py, tests/python/intrun.py, tests/python/kripke.py, tests/python/langmap.py, tests/python/ltl2tgba.py, tests/python/ltl2tgba.test, tests/python/ltlf.py, tests/python/ltlparse.py, tests/python/ltlsimple.py, tests/python/mealy.py, tests/python/merge.py, tests/python/mergedge.py, tests/python/minato.py, tests/python/misc-ec.py, tests/python/optionmap.py, tests/python/origstate.py, tests/python/otfcrash.py, tests/python/parity.py, tests/python/parsetgba.py, tests/python/pdegen.py, tests/python/powerset.py, tests/python/prodexpt.py, tests/python/randgen.py, tests/python/relabel.py, tests/python/remfin.py, tests/python/removeap.py, tests/python/rs_like.py, tests/python/satmin.py, tests/python/sbacc.py, tests/python/sccfilter.py, tests/python/sccinfo.py, tests/python/sccsplit.py, tests/python/semidet.py, tests/python/setacc.py, tests/python/setxor.py, tests/python/simplacc.py, tests/python/simstate.py, tests/python/sonf.py, tests/python/split.py, tests/python/splitedge.py, tests/python/streett_totgba.py, tests/python/streett_totgba2.py, tests/python/stutter.py, tests/python/sum.py, tests/python/synthesis.py, tests/python/toparity.py, tests/python/toweak.py, tests/python/tra2tba.py, tests/python/trival.py, tests/python/twagraph.py, tests/python/zlktree.py, tests/run.in, tests/sanity/80columns.test, tests/sanity/bin.test, tests/sanity/getenv.test, tests/sanity/includes.test, tests/sanity/ipynb.pl, tests/sanity/namedprop.test, tests/sanity/private.test, tests/sanity/readme.pl, tests/sanity/style.test, tools/man2html.pl: Update all copyright headers.
1051 lines
35 KiB
C++
1051 lines
35 KiB
C++
// -*- coding: utf-8 -*-
|
|
// Copyright (C) by the Spot authors, see the AUTHORS file for details.
|
|
//
|
|
// This file is part of Spot, a model checking library.
|
|
//
|
|
// Spot is free software; you can redistribute it and/or modify it
|
|
// under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation; either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// Spot is distributed in the hope that it will be useful, but WITHOUT
|
|
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
|
// License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
#include "config.h"
|
|
#include <spot/twaalgos/totgba.hh>
|
|
#include <spot/twaalgos/remfin.hh>
|
|
#include <spot/twaalgos/cleanacc.hh>
|
|
#include <spot/twaalgos/sccinfo.hh>
|
|
#include <spot/twa/twagraph.hh>
|
|
#include <deque>
|
|
#include <tuple>
|
|
|
|
#define TRACE 0
|
|
#if TRACE
|
|
#define trace std::cerr
|
|
#else
|
|
#define trace while (0) std::cerr
|
|
#endif
|
|
|
|
namespace spot
|
|
{
|
|
namespace
|
|
{
|
|
class dnf_to_streett_converter
|
|
{
|
|
private:
|
|
typedef std::pair<acc_cond::mark_t, acc_cond::mark_t> mark_pair;
|
|
|
|
const const_twa_graph_ptr& in_; // The given aut.
|
|
scc_info si_; // SCC information.
|
|
unsigned nb_scc_; // Number of SCC.
|
|
unsigned max_set_in_; // Max acc. set nb of in_.
|
|
bool state_based_; // Is in_ state_based ?
|
|
unsigned init_st_in_; // Initial state of in_.
|
|
bool init_reachable_; // Init reach from itself?
|
|
twa_graph_ptr res_; // Resulting automaton.
|
|
acc_cond::mark_t all_fin_; // All acc. set marked as
|
|
// Fin.
|
|
acc_cond::mark_t all_inf_; // All acc. set marked as
|
|
// Inf.
|
|
unsigned num_sets_res_; // Future nb of acc. set.
|
|
std::vector<mark_pair> all_clauses_; // All clauses.
|
|
std::vector<acc_cond::mark_t> set_to_keep_; // Set to keep for each clause
|
|
std::vector<acc_cond::mark_t> set_to_add_; // New set for each clause.
|
|
acc_cond::mark_t all_set_to_add_; // All new set to add.
|
|
std::vector<unsigned> assigned_sets_; // Set that will be add.
|
|
std::vector<std::vector<unsigned>> acc_clauses_; // Acc. clauses.
|
|
unsigned res_init_; // Future initial st.
|
|
|
|
// A state can be copied at most as many times as their are clauses for
|
|
// which it is not rejecting and must be copied one time (to remain
|
|
// consistent with the recognized language). This vector records each
|
|
// created state following this format:
|
|
// st_repr_[orig_st_nb] gives a vector<pair<clause, state>>.
|
|
std::vector<std::vector<std::pair<unsigned, unsigned>>> st_repr_;
|
|
|
|
// Split the DNF acceptance condition and get all the sets used in each
|
|
// clause. It separates those that must be seen finitely often from
|
|
// those that must be seen infinitely often.
|
|
void
|
|
split_dnf_clauses(const acc_cond::acc_code& code)
|
|
{
|
|
auto pos = &code.back();
|
|
if (pos->sub.op == acc_cond::acc_op::Or)
|
|
--pos;
|
|
auto start = &code.front();
|
|
while (pos > start)
|
|
{
|
|
const unsigned short size = pos[0].sub.size;
|
|
if (pos[0].sub.op == acc_cond::acc_op::And)
|
|
{
|
|
acc_cond::mark_t fin = {};
|
|
acc_cond::mark_t inf = {};
|
|
for (int i = 1; i <= (int)size; i += 2)
|
|
{
|
|
if (pos[-i].sub.op == acc_cond::acc_op::Fin)
|
|
fin |= pos[-i - 1].mark;
|
|
else if (pos[-i].sub.op == acc_cond::acc_op::Inf)
|
|
inf |= pos[-i - 1].mark;
|
|
else
|
|
SPOT_UNREACHABLE();
|
|
}
|
|
all_clauses_.emplace_back(fin, inf);
|
|
set_to_keep_.emplace_back(fin | inf);
|
|
}
|
|
else if (pos[0].sub.op == acc_cond::acc_op::Fin) // Fin
|
|
{
|
|
auto m1 = pos[-1].mark;
|
|
for (unsigned int s : m1.sets())
|
|
{
|
|
all_clauses_.emplace_back(acc_cond::mark_t({s}),
|
|
acc_cond::mark_t({}));
|
|
set_to_keep_.emplace_back(acc_cond::mark_t({s}));
|
|
}
|
|
}
|
|
else if (pos[0].sub.op == acc_cond::acc_op::Inf) // Inf
|
|
{
|
|
auto m2 = pos[-1].mark;
|
|
all_clauses_.emplace_back(acc_cond::mark_t({}), m2);
|
|
set_to_keep_.emplace_back(m2);
|
|
}
|
|
else
|
|
{
|
|
SPOT_UNREACHABLE();
|
|
}
|
|
pos -= size + 1;
|
|
}
|
|
#if TRACE
|
|
trace << "\nPrinting all clauses\n";
|
|
for (unsigned i = 0; i < all_clauses_.size(); ++i)
|
|
{
|
|
trace << i << " Fin:" << all_clauses_[i].first << " Inf:"
|
|
<< all_clauses_[i].second << '\n';
|
|
}
|
|
#endif
|
|
}
|
|
|
|
// Compute all the acceptance sets that will be needed:
|
|
// -Inf(x) will be converted to (Inf(x) | Fin(y)) with y appearing
|
|
// on every edge of the associated clone.
|
|
// -Fin(x) will be converted to (Inf(y) | Fin(x)) with y appearing
|
|
// nowhere.
|
|
// In the second form, Inf(y) with no occurrence of y, can be
|
|
// reused multiple times. It's called "missing_set" below.
|
|
void
|
|
assign_new_sets()
|
|
{
|
|
unsigned int next_set = 0;
|
|
unsigned int missing_set = -1U;
|
|
assigned_sets_.resize(max_set_in_, -1U);
|
|
|
|
acc_cond::mark_t all_m = all_fin_ | all_inf_;
|
|
for (unsigned set = 0; set < max_set_in_; ++set)
|
|
if (all_fin_.has(set))
|
|
{
|
|
if ((int)missing_set < 0)
|
|
{
|
|
while (all_m.has(next_set))
|
|
++next_set;
|
|
missing_set = next_set++;
|
|
}
|
|
|
|
assigned_sets_[set] = missing_set;
|
|
}
|
|
else if (all_inf_.has(set))
|
|
{
|
|
while (all_m.has(next_set))
|
|
++next_set;
|
|
|
|
assigned_sets_[set] = next_set++;
|
|
}
|
|
|
|
num_sets_res_ = std::max(next_set, max_set_in_);
|
|
}
|
|
|
|
// Precompute:
|
|
// -the sets to add for each clause,
|
|
// -all sets to add.
|
|
void
|
|
find_set_to_add()
|
|
{
|
|
assign_new_sets();
|
|
|
|
unsigned nb_clause = all_clauses_.size();
|
|
for (unsigned clause = 0; clause < nb_clause; ++clause)
|
|
{
|
|
if (all_clauses_[clause].second)
|
|
{
|
|
acc_cond::mark_t m = {};
|
|
for (unsigned set = 0; set < max_set_in_; ++set)
|
|
if (all_clauses_[clause].second.has(set))
|
|
{
|
|
assert((int)assigned_sets_[set] >= 0);
|
|
m |= acc_cond::mark_t({assigned_sets_[set]});
|
|
}
|
|
set_to_add_.push_back(m);
|
|
}
|
|
else
|
|
{
|
|
set_to_add_.emplace_back(acc_cond::mark_t({}));
|
|
}
|
|
}
|
|
|
|
all_set_to_add_ = {};
|
|
for (unsigned s = 0; s < max_set_in_; ++s)
|
|
if (all_inf_.has(s))
|
|
{
|
|
assert((int)assigned_sets_[s] >= 0);
|
|
all_set_to_add_.set(assigned_sets_[s]);
|
|
}
|
|
}
|
|
|
|
// Check whether the initial state is reachable from itself.
|
|
bool
|
|
is_init_reachable()
|
|
{
|
|
for (const auto& e : in_->edges())
|
|
for (unsigned d : in_->univ_dests(e))
|
|
if (d == init_st_in_)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
// Get all non rejecting scc for each clause of the acceptance
|
|
// condition. Actually, for each clause, an scc will be kept if it
|
|
// contains all the 'Inf' acc. sets of the clause.
|
|
void
|
|
find_probably_accepting_scc(std::vector<std::vector<unsigned>>& res)
|
|
{
|
|
res.resize(nb_scc_);
|
|
unsigned nb_clause = all_clauses_.size();
|
|
for (unsigned scc = 0; scc < nb_scc_; ++scc)
|
|
{
|
|
if (si_.is_rejecting_scc(scc))
|
|
continue;
|
|
|
|
acc_cond::mark_t acc = si_.acc_sets_of(scc);
|
|
for (unsigned clause = 0; clause < nb_clause; ++clause)
|
|
{
|
|
if ((acc & all_clauses_[clause].second)
|
|
== all_clauses_[clause].second)
|
|
res[scc].push_back(clause);
|
|
}
|
|
}
|
|
#if TRACE
|
|
trace << "accepting clauses\n";
|
|
for (unsigned i = 0; i < res.size(); ++i)
|
|
{
|
|
trace << "scc(" << i << ") -->";
|
|
for (auto elt : res[i])
|
|
trace << ' ' << elt;
|
|
if (si_.is_rejecting_scc(i))
|
|
trace << " rej";
|
|
trace << '\n';
|
|
}
|
|
trace << '\n';
|
|
#endif
|
|
}
|
|
|
|
// Add all possible representatives of the original state provided.
|
|
// Actually, this state will be copied as many times as there are clauses
|
|
// for which its SCC is not rejecting.
|
|
void
|
|
add_state(unsigned st)
|
|
{
|
|
trace << "add_state(" << st << ")\n";
|
|
if (st_repr_[st].empty())
|
|
{
|
|
unsigned st_scc = si_.scc_of(st);
|
|
if (st == init_st_in_ && !init_reachable_)
|
|
st_repr_[st].emplace_back(-1U, res_init_);
|
|
|
|
else if (!acc_clauses_[st_scc].empty())
|
|
for (const auto& clause : acc_clauses_[st_scc])
|
|
st_repr_[st].emplace_back(clause, res_->new_state());
|
|
|
|
else
|
|
st_repr_[st].emplace_back(-1U, res_->new_state());
|
|
trace << "added\n";
|
|
}
|
|
}
|
|
|
|
// Compute the mark that will be set (instead of the provided e_acc)
|
|
// according to the current clause in process. This function is only
|
|
// called for accepting SCC.
|
|
acc_cond::mark_t
|
|
get_edge_mark(const acc_cond::mark_t& e_acc,
|
|
unsigned clause)
|
|
{
|
|
assert((int)clause >= 0);
|
|
return (e_acc & set_to_keep_[clause]) | set_to_add_[clause];
|
|
}
|
|
|
|
// Set the acceptance condition once the resulting automaton is ready.
|
|
void
|
|
set_acc_condition()
|
|
{
|
|
acc_cond::acc_code p_code;
|
|
for (unsigned set = 0; set < max_set_in_; ++set)
|
|
{
|
|
if (all_fin_.has(set))
|
|
p_code &=
|
|
acc_cond::acc_code::inf(acc_cond::mark_t({assigned_sets_[set]}))
|
|
| acc_cond::acc_code::fin(acc_cond::mark_t({set}));
|
|
else if (all_inf_.has(set))
|
|
p_code &=
|
|
acc_cond::acc_code::inf(acc_cond::mark_t({set}))
|
|
| acc_cond::acc_code::fin(
|
|
acc_cond::mark_t({assigned_sets_[set]}));
|
|
}
|
|
res_->set_acceptance(num_sets_res_, p_code);
|
|
}
|
|
|
|
public:
|
|
dnf_to_streett_converter(const const_twa_graph_ptr& in,
|
|
const acc_cond::acc_code& code)
|
|
: in_(in),
|
|
si_(scc_info(in, scc_info_options::TRACK_STATES
|
|
| scc_info_options::TRACK_SUCCS)),
|
|
nb_scc_(si_.scc_count()),
|
|
max_set_in_(code.used_sets().max_set()),
|
|
state_based_(in->prop_state_acc() == true),
|
|
init_st_in_(in->get_init_state_number()),
|
|
init_reachable_(is_init_reachable())
|
|
{
|
|
trace << "State based ? " << state_based_ << '\n';
|
|
std::tie(all_inf_, all_fin_) = code.used_inf_fin_sets();
|
|
split_dnf_clauses(code);
|
|
find_set_to_add();
|
|
find_probably_accepting_scc(acc_clauses_);
|
|
}
|
|
|
|
~dnf_to_streett_converter()
|
|
{}
|
|
|
|
twa_graph_ptr run(bool original_states)
|
|
{
|
|
res_ = make_twa_graph(in_->get_dict());
|
|
res_->copy_ap_of(in_);
|
|
st_repr_.resize(in_->num_states());
|
|
res_init_ = res_->new_state();
|
|
res_->set_init_state(res_init_);
|
|
|
|
for (unsigned scc = 0; scc < nb_scc_; ++scc)
|
|
{
|
|
if (!si_.is_useful_scc(scc))
|
|
continue;
|
|
trace << "scc #" << scc << '\n';
|
|
|
|
bool rej_scc = acc_clauses_[scc].empty();
|
|
for (auto st : si_.states_of(scc))
|
|
{
|
|
add_state(st);
|
|
for (const auto& e : in_->out(st))
|
|
{
|
|
trace << "working_on_edge(" << st << ',' << e.dst << ")\n";
|
|
|
|
unsigned dst_scc = si_.scc_of(e.dst);
|
|
if (!si_.is_useful_scc(dst_scc))
|
|
continue;
|
|
add_state(e.dst);
|
|
bool same_scc = scc == dst_scc;
|
|
|
|
if (st == init_st_in_)
|
|
{
|
|
for (const auto& p_dst : st_repr_[e.dst])
|
|
res_->new_edge(res_init_, p_dst.second, e.cond, {});
|
|
if (!init_reachable_)
|
|
continue;
|
|
}
|
|
|
|
if (!rej_scc)
|
|
for (const auto& p_src : st_repr_[st])
|
|
for (const auto& p_dst : st_repr_[e.dst])
|
|
{
|
|
trace << "repr(" << p_src.second << ','
|
|
<< p_dst.second << ")\n";
|
|
|
|
if (same_scc && p_src.first == p_dst.first)
|
|
res_->new_edge(p_src.second, p_dst.second, e.cond,
|
|
get_edge_mark(e.acc, p_src.first));
|
|
|
|
else if (!same_scc)
|
|
res_->new_edge(p_src.second, p_dst.second, e.cond,
|
|
state_based_ ?
|
|
get_edge_mark(e.acc, p_src.first)
|
|
: acc_cond::mark_t({}));
|
|
}
|
|
else
|
|
{
|
|
assert(st_repr_[st].size() == 1);
|
|
unsigned src = st_repr_[st][0].second;
|
|
|
|
acc_cond::mark_t m = {};
|
|
if (same_scc || state_based_)
|
|
m = e.acc | all_set_to_add_;
|
|
|
|
for (const auto& p_dst : st_repr_[e.dst])
|
|
res_->new_edge(src, p_dst.second, e.cond, m);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Mapping between each state of the resulting automaton and the
|
|
// original state of the input automaton.
|
|
if (original_states)
|
|
{
|
|
auto orig_states = new std::vector<unsigned>();
|
|
orig_states->resize(res_->num_states(), -1U);
|
|
res_->set_named_prop("original-states", orig_states);
|
|
|
|
auto orig_clauses = new std::vector<unsigned>();
|
|
orig_clauses->resize(res_->num_states(), -1U);
|
|
res_->set_named_prop("original-clauses", orig_clauses);
|
|
|
|
unsigned orig_num_states = in_->num_states();
|
|
for (unsigned orig = 0; orig < orig_num_states; ++orig)
|
|
{
|
|
if (!si_.is_useful_scc(si_.scc_of(orig)))
|
|
continue;
|
|
for (const auto& p : st_repr_[orig])
|
|
{
|
|
(*orig_states)[p.second] = orig;
|
|
(*orig_clauses)[p.second] = p.first;
|
|
}
|
|
}
|
|
}
|
|
|
|
set_acc_condition();
|
|
res_->prop_state_acc(state_based_);
|
|
return res_;
|
|
}
|
|
};
|
|
}
|
|
|
|
|
|
twa_graph_ptr
|
|
dnf_to_streett(const const_twa_graph_ptr& in, bool original_states)
|
|
{
|
|
const acc_cond::acc_code& code = in->get_acceptance();
|
|
if (!code.is_dnf())
|
|
throw std::runtime_error("dnf_to_streett() should only be"
|
|
" called on automata with DNF acceptance");
|
|
if (code.is_t() || code.is_f() || in->acc().is_streett() > 0)
|
|
return make_twa_graph(in, twa::prop_set::all());
|
|
|
|
dnf_to_streett_converter dnf_to_streett(in, code);
|
|
return dnf_to_streett.run(original_states);
|
|
}
|
|
|
|
|
|
namespace
|
|
{
|
|
struct st2gba_state
|
|
{
|
|
acc_cond::mark_t pend;
|
|
unsigned s;
|
|
|
|
st2gba_state(unsigned st, acc_cond::mark_t bv = acc_cond::mark_t::all()):
|
|
pend(bv), s(st)
|
|
{
|
|
}
|
|
};
|
|
|
|
struct st2gba_state_hash
|
|
{
|
|
size_t
|
|
operator()(const st2gba_state& s) const noexcept
|
|
{
|
|
std::hash<acc_cond::mark_t> h;
|
|
return s.s ^ h(s.pend);
|
|
}
|
|
};
|
|
|
|
struct st2gba_state_equal
|
|
{
|
|
bool
|
|
operator()(const st2gba_state& left,
|
|
const st2gba_state& right) const
|
|
{
|
|
if (left.s != right.s)
|
|
return false;
|
|
return left.pend == right.pend;
|
|
}
|
|
};
|
|
|
|
typedef std::vector<acc_cond::mark_t> terms_t;
|
|
|
|
terms_t cnf_terms(const acc_cond::acc_code& code)
|
|
{
|
|
assert(!code.empty());
|
|
terms_t res;
|
|
auto pos = &code.back();
|
|
auto end = &code.front();
|
|
if (pos->sub.op == acc_cond::acc_op::And)
|
|
--pos;
|
|
while (pos >= end)
|
|
{
|
|
auto term_end = pos - 1 - pos->sub.size;
|
|
bool inor = pos->sub.op == acc_cond::acc_op::Or;
|
|
if (inor)
|
|
--pos;
|
|
acc_cond::mark_t m = {};
|
|
while (pos > term_end)
|
|
{
|
|
assert(pos->sub.op == acc_cond::acc_op::Inf);
|
|
m |= pos[-1].mark;
|
|
pos -= 2;
|
|
}
|
|
if (inor)
|
|
res.emplace_back(m);
|
|
else
|
|
for (unsigned i: m.sets())
|
|
res.emplace_back(acc_cond::mark_t({i}));
|
|
}
|
|
return res;
|
|
}
|
|
}
|
|
|
|
|
|
// Specialized conversion for Streett -> TGBA
|
|
// ============================================
|
|
//
|
|
// Christof Löding's Diploma Thesis: Methods for the
|
|
// Transformation of ω-Automata: Complexity and Connection to
|
|
// Second Order Logic. Section 3.4.3, gives a transition
|
|
// from Streett with |Q| states to BA with |Q|*(4^n-3^n+2)
|
|
// states, if n is the number of acceptance pairs.
|
|
//
|
|
// Duret-Lutz et al. (ATVA'2009): On-the-fly Emptiness Check of
|
|
// Transition-based Streett Automata. Section 3.3 contains a
|
|
// conversion from transition-based Streett Automata to TGBA using
|
|
// the generalized Büchi acceptance to limit the explosion. It goes
|
|
// from Streett with |Q| states to (T)GBA with |Q|*(2^n+1) states.
|
|
// However the definition of the number of acceptance sets in that
|
|
// paper is suboptimal: only n are needed, not 2^n.
|
|
//
|
|
// This implements this second version.
|
|
twa_graph_ptr
|
|
streett_to_generalized_buchi(const const_twa_graph_ptr& in)
|
|
{
|
|
// While "t" is Streett, it is also generalized Büchi, so
|
|
// do not do anything.
|
|
if (in->acc().is_generalized_buchi())
|
|
return std::const_pointer_cast<twa_graph>(in);
|
|
|
|
std::vector<acc_cond::rs_pair> pairs;
|
|
bool res = in->acc().is_streett_like(pairs);
|
|
if (!res)
|
|
throw std::runtime_error("streett_to_generalized_buchi() should only be"
|
|
" called on automata with Streett-like"
|
|
" acceptance");
|
|
|
|
// In Streett acceptance, inf sets are odd, while fin sets are
|
|
// even.
|
|
acc_cond::mark_t inf;
|
|
acc_cond::mark_t fin;
|
|
std::tie(inf, fin) = in->get_acceptance().used_inf_fin_sets();
|
|
unsigned p = inf.count();
|
|
// At some point we will remove anything that is not used as Inf.
|
|
acc_cond::mark_t to_strip = in->acc().all_sets() - inf;
|
|
acc_cond::mark_t inf_alone = {};
|
|
acc_cond::mark_t fin_alone = {};
|
|
|
|
if (!p)
|
|
return remove_fin(in);
|
|
|
|
unsigned numsets = in->acc().num_sets();
|
|
std::vector<acc_cond::mark_t> fin_to_infpairs(numsets,
|
|
acc_cond::mark_t({}));
|
|
std::vector<acc_cond::mark_t> inf_to_finpairs(numsets,
|
|
acc_cond::mark_t({}));
|
|
for (auto pair: pairs)
|
|
{
|
|
if (pair.fin)
|
|
for (unsigned mark: pair.fin.sets())
|
|
fin_to_infpairs[mark] |= pair.inf;
|
|
else
|
|
inf_alone |= pair.inf;
|
|
|
|
if (pair.inf)
|
|
for (unsigned mark: pair.inf.sets())
|
|
inf_to_finpairs[mark] |= pair.fin;
|
|
else
|
|
fin_alone |= pair.fin;
|
|
}
|
|
// If we have something like (Fin(0)|Inf(1))&Fin(0), then 0 is in
|
|
// fin_alone, but we also have fin_to_infpair[0] = {1}. This should
|
|
// really be simplified to Fin(0).
|
|
for (auto mark: fin_alone.sets())
|
|
fin_to_infpairs[mark] = {};
|
|
|
|
scc_info si(in, scc_info_options::NONE);
|
|
|
|
// Compute the acceptance sets present in each SCC
|
|
unsigned nscc = si.scc_count();
|
|
std::vector<std::tuple<acc_cond::mark_t, acc_cond::mark_t,
|
|
bool, bool>> sccfi;
|
|
sccfi.reserve(nscc);
|
|
for (unsigned s = 0; s < nscc; ++s)
|
|
{
|
|
auto acc = si.acc_sets_of(s); // {0,1,2,3,4,6,7,9}
|
|
auto acc_fin = acc & fin; // {0, 2, 4,6}
|
|
auto acc_inf = acc & inf; // { 1, 3, 7,9}
|
|
// Fin sets that are alone either because the acceptance
|
|
// condition has no matching Inf, or because the SCC does not
|
|
// intersect the matching Inf.
|
|
acc_cond::mark_t fin_wo_inf = {};
|
|
for (unsigned mark: acc_fin.sets())
|
|
if (!fin_to_infpairs[mark] || (fin_to_infpairs[mark] - acc_inf))
|
|
fin_wo_inf.set(mark);
|
|
|
|
// Inf sets that *do* have a matching Fin in the acceptance
|
|
// condition but without matching Fin in the SCC: they can be
|
|
// considered as always present in the SCC.
|
|
acc_cond::mark_t inf_wo_fin = {};
|
|
for (unsigned mark: inf.sets())
|
|
if (inf_to_finpairs[mark] && (inf_to_finpairs[mark] - acc_fin))
|
|
inf_wo_fin.set(mark);
|
|
|
|
sccfi.emplace_back(fin_wo_inf, inf_wo_fin,
|
|
!acc_fin, !acc_inf);
|
|
}
|
|
|
|
auto out = make_twa_graph(in->get_dict());
|
|
out->copy_ap_of(in);
|
|
out->prop_copy(in, {false, false, false, false, false, true});
|
|
out->set_generalized_buchi(p);
|
|
|
|
// Map st2gba pairs to the state numbers used in out.
|
|
typedef std::unordered_map<st2gba_state, unsigned,
|
|
st2gba_state_hash,
|
|
st2gba_state_equal> bs2num_map;
|
|
bs2num_map bs2num;
|
|
|
|
// Queue of states to be processed.
|
|
typedef std::deque<st2gba_state> queue_t;
|
|
queue_t todo;
|
|
|
|
st2gba_state s(in->get_init_state_number());
|
|
bs2num[s] = out->new_state();
|
|
todo.emplace_back(s);
|
|
|
|
bool sbacc = in->prop_state_acc().is_true();
|
|
|
|
// States of the original automaton are marked with s.pend == -1U.
|
|
const acc_cond::mark_t orig_copy = acc_cond::mark_t::all();
|
|
|
|
while (!todo.empty())
|
|
{
|
|
s = todo.front();
|
|
todo.pop_front();
|
|
unsigned src = bs2num[s];
|
|
|
|
unsigned scc_src = si.scc_of(s.s);
|
|
bool maybe_acc_scc = !si.is_rejecting_scc(scc_src);
|
|
|
|
acc_cond::mark_t scc_fin_wo_inf;
|
|
acc_cond::mark_t scc_inf_wo_fin;
|
|
bool no_fin;
|
|
bool no_inf;
|
|
std::tie(scc_fin_wo_inf, scc_inf_wo_fin, no_fin, no_inf)
|
|
= sccfi[scc_src];
|
|
|
|
for (auto& t: in->out(s.s))
|
|
{
|
|
acc_cond::mark_t pend = s.pend;
|
|
acc_cond::mark_t acc = {};
|
|
|
|
bool maybe_acc = maybe_acc_scc && (scc_src == si.scc_of(t.dst));
|
|
if (pend != orig_copy)
|
|
{
|
|
if (!maybe_acc)
|
|
continue;
|
|
// No point going to some place we will never leave
|
|
if (t.acc & scc_fin_wo_inf)
|
|
continue;
|
|
// For any Fin set we see, we want to see the
|
|
// corresponding Inf set.
|
|
for (unsigned mark: (t.acc & fin).sets())
|
|
pend |= fin_to_infpairs[mark];
|
|
|
|
// If we see some Inf set immediately, they are not
|
|
// pending anymore.
|
|
pend -= t.acc & inf;
|
|
|
|
// Label this transition with all non-pending
|
|
// inf sets. The strip will shift everything
|
|
// to the correct numbers in the targets.
|
|
acc = (inf - pend).strip(to_strip);
|
|
// Adjust the pending sets to what will be necessary
|
|
// required on the destination state.
|
|
if (sbacc)
|
|
{
|
|
auto a = in->state_acc_sets(t.dst);
|
|
if (a & scc_fin_wo_inf)
|
|
continue;
|
|
for (unsigned m: (a & fin).sets())
|
|
pend |= fin_to_infpairs[m];
|
|
|
|
pend -= a & inf;
|
|
}
|
|
pend |= inf_alone;
|
|
}
|
|
else if (no_fin && maybe_acc)
|
|
{
|
|
// If the acceptance is (Fin(0) | Inf(1)) & Inf(2)
|
|
// but we do not see any Fin set in this SCC, a
|
|
// mark {2} should become {1,2} before striping.
|
|
acc = (t.acc | scc_inf_wo_fin).strip(to_strip);
|
|
}
|
|
assert((acc & out->acc().all_sets()) == acc);
|
|
|
|
st2gba_state d(t.dst, pend);
|
|
// Have we already seen this destination?
|
|
unsigned dest;
|
|
auto dres = bs2num.emplace(d, 0);
|
|
if (!dres.second)
|
|
{
|
|
dest = dres.first->second;
|
|
}
|
|
else // No, this is a new state
|
|
{
|
|
dest = dres.first->second = out->new_state();
|
|
todo.emplace_back(d);
|
|
}
|
|
out->new_edge(src, dest, t.cond, acc);
|
|
|
|
// Nondeterministically jump to level ∅. We need to do
|
|
// that only once per cycle. As an approximation, we
|
|
// only do that for transitions where t.src >= t.dst as
|
|
// this has to occur at least once per cycle.
|
|
if (pend == orig_copy && (t.src >= t.dst) && maybe_acc && !no_fin)
|
|
{
|
|
acc_cond::mark_t stpend = {};
|
|
if (sbacc)
|
|
{
|
|
auto a = in->state_acc_sets(t.dst);
|
|
if (a & scc_fin_wo_inf)
|
|
continue;
|
|
for (unsigned m: (a & fin).sets())
|
|
stpend |= fin_to_infpairs[m];
|
|
|
|
stpend -= a & inf;
|
|
}
|
|
st2gba_state d(t.dst, stpend | inf_alone);
|
|
// Have we already seen this destination?
|
|
unsigned dest;
|
|
auto dres = bs2num.emplace(d, 0);
|
|
if (!dres.second)
|
|
{
|
|
dest = dres.first->second;
|
|
}
|
|
else // No, this is a new state
|
|
{
|
|
dest = dres.first->second = out->new_state();
|
|
todo.emplace_back(d);
|
|
}
|
|
out->new_edge(src, dest, t.cond);
|
|
}
|
|
}
|
|
}
|
|
simplify_acceptance_here(out);
|
|
if (out->acc().is_f())
|
|
{
|
|
// "f" is not generalized-Büchi. Just return an
|
|
// empty automaton instead.
|
|
auto res = make_twa_graph(out->get_dict());
|
|
res->set_generalized_buchi(0);
|
|
res->set_init_state(res->new_state());
|
|
res->prop_stutter_invariant(true);
|
|
res->prop_weak(true);
|
|
res->prop_complete(false);
|
|
return res;
|
|
}
|
|
return out;
|
|
}
|
|
|
|
twa_graph_ptr
|
|
streett_to_generalized_buchi_maybe(const const_twa_graph_ptr& in)
|
|
{
|
|
static unsigned min = [&]() {
|
|
const char* c = getenv("SPOT_STREETT_CONV_MIN");
|
|
if (!c)
|
|
return 3;
|
|
errno = 0;
|
|
int val = strtol(c, nullptr, 10);
|
|
if (val < 0 || errno != 0)
|
|
throw std::runtime_error("unexpected value for SPOT_STREETT_CONV_MIN");
|
|
return val;
|
|
}();
|
|
|
|
std::vector<acc_cond::rs_pair> pairs;
|
|
bool res = in->acc().is_streett_like(pairs);
|
|
if (!res || min == 0 || min > pairs.size())
|
|
return nullptr;
|
|
else
|
|
return streett_to_generalized_buchi(in);
|
|
}
|
|
|
|
|
|
/// \brief Take an automaton with any acceptance condition and return
|
|
/// an equivalent Generalized Büchi automaton.
|
|
twa_graph_ptr
|
|
to_generalized_buchi(const const_twa_graph_ptr& aut)
|
|
{
|
|
auto maybe = streett_to_generalized_buchi_maybe(aut);
|
|
if (maybe)
|
|
return maybe;
|
|
|
|
auto res = remove_fin(cleanup_acceptance(aut));
|
|
if (res->acc().is_generalized_buchi())
|
|
return res;
|
|
|
|
auto cnf = res->get_acceptance().to_cnf();
|
|
// If we are very lucky, building a CNF actually gave us a GBA...
|
|
if (cnf.empty() ||
|
|
(cnf.size() == 2 && cnf.back().sub.op == acc_cond::acc_op::Inf))
|
|
{
|
|
res->set_acceptance(res->num_sets(), cnf);
|
|
cleanup_acceptance_here(res);
|
|
return res;
|
|
}
|
|
|
|
// Handle false specifically. We want the output
|
|
// an automaton with Acceptance: t, that has a single
|
|
// state without successor.
|
|
if (cnf.is_f())
|
|
{
|
|
assert(!cnf.front().mark);
|
|
res = make_twa_graph(aut->get_dict());
|
|
res->set_init_state(res->new_state());
|
|
res->prop_state_acc(true);
|
|
res->prop_weak(true);
|
|
res->prop_universal(true);
|
|
res->prop_stutter_invariant(true);
|
|
return res;
|
|
}
|
|
|
|
auto terms = cnf_terms(cnf);
|
|
unsigned nterms = terms.size();
|
|
assert(nterms > 0);
|
|
res->set_generalized_buchi(nterms);
|
|
|
|
for (auto& t: res->edges())
|
|
{
|
|
acc_cond::mark_t cur_m = t.acc;
|
|
acc_cond::mark_t new_m = {};
|
|
for (unsigned n = 0; n < nterms; ++n)
|
|
if (cur_m & terms[n])
|
|
new_m.set(n);
|
|
t.acc = new_m;
|
|
}
|
|
return res;
|
|
}
|
|
|
|
namespace
|
|
{
|
|
// If the DNF is
|
|
// Fin(1)&Inf(2)&Inf(4) | Fin(2)&Fin(3)&Inf(1) |
|
|
// Inf(1)&Inf(3) | Inf(1)&Inf(2) | Fin(4)
|
|
// this returns the following vector of pairs:
|
|
// [({1}, {2,4})
|
|
// ({2,3}, {1}),
|
|
// ({}, {1,3}),
|
|
// ({}, {2}),
|
|
// ({4}, t)]
|
|
static std::vector<std::pair<acc_cond::mark_t, acc_cond::mark_t>>
|
|
split_dnf_acc(const acc_cond::acc_code& acc)
|
|
{
|
|
std::vector<std::pair<acc_cond::mark_t, acc_cond::mark_t>> res;
|
|
if (acc.empty())
|
|
{
|
|
res.emplace_back(acc_cond::mark_t({}), acc_cond::mark_t({}));
|
|
return res;
|
|
}
|
|
auto pos = &acc.back();
|
|
if (pos->sub.op == acc_cond::acc_op::Or)
|
|
--pos;
|
|
auto start = &acc.front();
|
|
while (pos > start)
|
|
{
|
|
if (pos->sub.op == acc_cond::acc_op::Fin)
|
|
{
|
|
// We have only a Fin term, without Inf. In this case
|
|
// only, the Fin() may encode a disjunction of sets.
|
|
for (auto s: pos[-1].mark.sets())
|
|
res.emplace_back(acc_cond::mark_t({s}), acc_cond::mark_t({}));
|
|
pos -= pos->sub.size + 1;
|
|
}
|
|
else
|
|
{
|
|
// We have a conjunction of Fin and Inf sets.
|
|
auto end = pos - pos->sub.size - 1;
|
|
acc_cond::mark_t fin = {};
|
|
acc_cond::mark_t inf = {};
|
|
while (pos > end)
|
|
{
|
|
switch (pos->sub.op)
|
|
{
|
|
case acc_cond::acc_op::And:
|
|
--pos;
|
|
break;
|
|
case acc_cond::acc_op::Fin:
|
|
fin |= pos[-1].mark;
|
|
assert(pos[-1].mark.count() == 1);
|
|
pos -= 2;
|
|
break;
|
|
case acc_cond::acc_op::Inf:
|
|
inf |= pos[-1].mark;
|
|
pos -= 2;
|
|
break;
|
|
case acc_cond::acc_op::FinNeg:
|
|
case acc_cond::acc_op::InfNeg:
|
|
case acc_cond::acc_op::Or:
|
|
SPOT_UNREACHABLE();
|
|
break;
|
|
}
|
|
}
|
|
assert(pos == end);
|
|
res.emplace_back(fin, inf);
|
|
}
|
|
}
|
|
return res;
|
|
}
|
|
|
|
|
|
static twa_graph_ptr
|
|
to_generalized_rabin_aux(const const_twa_graph_ptr& aut,
|
|
bool share_inf, bool complement)
|
|
{
|
|
auto res = cleanup_acceptance(aut);
|
|
auto oldacc = res->get_acceptance();
|
|
if (complement)
|
|
res->set_acceptance(res->acc().num_sets(), oldacc.complement());
|
|
|
|
{
|
|
std::vector<unsigned> pairs;
|
|
if (res->acc().is_generalized_rabin(pairs))
|
|
{
|
|
if (complement)
|
|
res->set_acceptance(res->acc().num_sets(), oldacc);
|
|
return res;
|
|
}
|
|
}
|
|
auto dnf = res->get_acceptance().to_dnf();
|
|
if (dnf.is_f())
|
|
{
|
|
if (complement)
|
|
res->set_acceptance(0, acc_cond::acc_code::t());
|
|
return res;
|
|
}
|
|
|
|
auto v = split_dnf_acc(dnf);
|
|
|
|
// Decide how we will rename each input set.
|
|
//
|
|
// inf_rename is only used if hoa_style=false, to
|
|
// reuse previously used Inf sets.
|
|
|
|
unsigned ns = res->num_sets();
|
|
std::vector<acc_cond::mark_t> rename(ns);
|
|
std::vector<unsigned> inf_rename(ns);
|
|
|
|
unsigned next_set = 0;
|
|
// The output acceptance conditions.
|
|
acc_cond::acc_code code =
|
|
complement ? acc_cond::acc_code::t() : acc_cond::acc_code::f();
|
|
for (auto& i: v)
|
|
{
|
|
unsigned fin_set = 0U;
|
|
|
|
if (!complement)
|
|
{
|
|
for (auto s: i.first.sets())
|
|
rename[s].set(next_set);
|
|
fin_set = next_set++;
|
|
}
|
|
|
|
acc_cond::mark_t infsets = {};
|
|
|
|
if (share_inf)
|
|
for (auto s: i.second.sets())
|
|
{
|
|
unsigned n = inf_rename[s];
|
|
if (n == 0)
|
|
n = inf_rename[s] = next_set++;
|
|
rename[s].set(n);
|
|
infsets.set(n);
|
|
}
|
|
else // HOA style
|
|
{
|
|
for (auto s: i.second.sets())
|
|
{
|
|
unsigned n = next_set++;
|
|
rename[s].set(n);
|
|
infsets.set(n);
|
|
}
|
|
}
|
|
|
|
// The definition of Streett wants the Fin first in clauses,
|
|
// so we do the same for generalized Streett since HOA does
|
|
// not specify anything. See
|
|
// https://github.com/adl/hoaf/issues/62
|
|
if (complement)
|
|
{
|
|
for (auto s: i.first.sets())
|
|
rename[s].set(next_set);
|
|
fin_set = next_set++;
|
|
|
|
auto pair = acc_cond::inf({fin_set});
|
|
pair |= acc_cond::acc_code::fin(infsets);
|
|
pair &= std::move(code);
|
|
code = std::move(pair);
|
|
}
|
|
else
|
|
{
|
|
auto pair = acc_cond::acc_code::inf(infsets);
|
|
pair &= acc_cond::fin({fin_set});
|
|
pair |= std::move(code);
|
|
code = std::move(pair);
|
|
}
|
|
}
|
|
|
|
// Fix the automaton
|
|
res->set_acceptance(next_set, code);
|
|
for (auto& e: res->edges())
|
|
{
|
|
acc_cond::mark_t m = {};
|
|
for (auto s: e.acc.sets())
|
|
m |= rename[s];
|
|
e.acc = m;
|
|
}
|
|
return res;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
twa_graph_ptr
|
|
to_generalized_rabin(const const_twa_graph_ptr& aut,
|
|
bool share_inf)
|
|
{
|
|
return to_generalized_rabin_aux(aut, share_inf, false);
|
|
}
|
|
|
|
twa_graph_ptr
|
|
to_generalized_streett(const const_twa_graph_ptr& aut,
|
|
bool share_fin)
|
|
{
|
|
return to_generalized_rabin_aux(aut, share_fin, true);
|
|
}
|
|
}
|