* NEWS: Mention this. * COPYING: Replace by GPL v3. * src/sanity/style.test: Check files with the wrong license, in case we forgot to update it during a merge. * Makefile.am, bench/Makefile.am, bench/emptchk/Makefile.am, bench/emptchk/defs.in, bench/emptchk/ltl-human.sh, bench/emptchk/ltl-random.sh, bench/emptchk/pml-clserv.sh, bench/emptchk/pml-eeaean.sh, bench/emptchk/pml2tgba.pl, bench/ltl2tgba/big, bench/ltl2tgba/defs.in, bench/ltl2tgba/known, bench/ltl2tgba/lbtt2csv.pl, bench/ltl2tgba/ltl2baw.in, bench/ltl2tgba/parseout.pl, bench/ltl2tgba/small, bench/ltlclasses/Makefile.am, bench/ltlclasses/defs.in, bench/ltlclasses/run, bench/ltlcounter/Makefile.am, bench/ltlcounter/defs.in, bench/ltlcounter/run, bench/scc-stats/Makefile.am, bench/scc-stats/stats.cc, bench/split-product/Makefile.am, bench/split-product/cutscc.cc, bench/split-product/pml2tgba.pl, bench/wdba/Makefile.am, bench/wdba/defs.in, bench/wdba/run, configure.ac, doc/Makefile.am, doc/dot.in, doc/tl/Makefile.am, iface/Makefile.am, iface/dve2/Makefile.am, iface/dve2/defs.in, iface/dve2/dve2.cc, iface/dve2/dve2.hh, iface/dve2/dve2check.cc, iface/dve2/dve2check.test, iface/dve2/finite.test, iface/dve2/kripke.test, iface/gspn/Makefile.am, iface/gspn/common.cc, iface/gspn/common.hh, iface/gspn/dcswave.test, iface/gspn/dcswaveeltl.test, iface/gspn/dcswavefm.test, iface/gspn/dcswaveltl.test, iface/gspn/dottygspn.cc, iface/gspn/dottyssp.cc, iface/gspn/gspn.cc, iface/gspn/gspn.hh, iface/gspn/ltlgspn.cc, iface/gspn/simple.test, iface/gspn/ssp.cc, iface/gspn/ssp.hh, iface/gspn/udcsefm.test, iface/gspn/udcseltl.test, iface/gspn/udcsfm.test, iface/gspn/udcsltl.test, src/Makefile.am, src/bin/Makefile.am, src/bin/common_cout.cc, src/bin/common_cout.hh, src/bin/common_finput.cc, src/bin/common_finput.hh, src/bin/common_output.cc, src/bin/common_output.hh, src/bin/common_post.cc, src/bin/common_post.hh, src/bin/common_r.cc, src/bin/common_r.hh, src/bin/common_range.cc, src/bin/common_range.hh, src/bin/common_setup.cc, src/bin/common_setup.hh, src/bin/common_sys.hh, src/bin/genltl.cc, src/bin/ltl2tgba.cc, src/bin/ltl2tgta.cc, src/bin/ltlfilt.cc, src/bin/man/Makefile.am, src/bin/randltl.cc, src/eltlparse/Makefile.am, src/eltlparse/eltlparse.yy, src/eltlparse/eltlscan.ll, src/eltlparse/fmterror.cc, src/eltlparse/parsedecl.hh, src/eltlparse/public.hh, src/eltltest/Makefile.am, src/eltltest/acc.cc, src/eltltest/acc.test, src/eltltest/defs.in, src/eltltest/nfa.cc, src/eltltest/nfa.test, src/evtgba/Makefile.am, src/evtgba/evtgba.cc, src/evtgba/evtgba.hh, src/evtgba/evtgbaiter.hh, src/evtgba/explicit.cc, src/evtgba/explicit.hh, src/evtgba/product.cc, src/evtgba/product.hh, src/evtgba/symbol.cc, src/evtgba/symbol.hh, src/evtgbaalgos/Makefile.am, src/evtgbaalgos/dotty.cc, src/evtgbaalgos/dotty.hh, src/evtgbaalgos/reachiter.cc, src/evtgbaalgos/reachiter.hh, src/evtgbaalgos/save.cc, src/evtgbaalgos/save.hh, src/evtgbaalgos/tgba2evtgba.cc, src/evtgbaalgos/tgba2evtgba.hh, src/evtgbaparse/Makefile.am, src/evtgbaparse/evtgbaparse.yy, src/evtgbaparse/evtgbascan.ll, src/evtgbaparse/fmterror.cc, src/evtgbaparse/parsedecl.hh, src/evtgbaparse/public.hh, src/evtgbatest/Makefile.am, src/evtgbatest/defs.in, src/evtgbatest/explicit.cc, src/evtgbatest/explicit.test, src/evtgbatest/ltl2evtgba.cc, src/evtgbatest/ltl2evtgba.test, src/evtgbatest/product.cc, src/evtgbatest/product.test, src/evtgbatest/readsave.cc, src/evtgbatest/readsave.test, src/kripke/Makefile.am, src/kripke/fairkripke.cc, src/kripke/fairkripke.hh, src/kripke/kripke.cc, src/kripke/kripke.hh, src/kripke/kripkeexplicit.cc, src/kripke/kripkeexplicit.hh, src/kripke/kripkeprint.cc, src/kripke/kripkeprint.hh, src/kripkeparse/Makefile.am, src/kripkeparse/fmterror.cc, src/kripkeparse/kripkeparse.yy, src/kripkeparse/kripkescan.ll, src/kripkeparse/parsedecl.hh, src/kripkeparse/public.hh, src/kripkeparse/scankripke.ll, src/kripketest/Makefile.am, src/kripketest/bad_parsing.test, src/kripketest/defs.in, src/kripketest/kripke.test, src/kripketest/parse_print_test.cc, src/ltlast/Makefile.am, src/ltlast/allnodes.hh, src/ltlast/atomic_prop.cc, src/ltlast/atomic_prop.hh, src/ltlast/automatop.cc, src/ltlast/automatop.hh, src/ltlast/binop.cc, src/ltlast/binop.hh, src/ltlast/bunop.cc, src/ltlast/bunop.hh, src/ltlast/constant.cc, src/ltlast/constant.hh, src/ltlast/formula.cc, src/ltlast/formula.hh, src/ltlast/formula_tree.cc, src/ltlast/formula_tree.hh, src/ltlast/multop.cc, src/ltlast/multop.hh, src/ltlast/nfa.cc, src/ltlast/nfa.hh, src/ltlast/predecl.hh, src/ltlast/refformula.cc, src/ltlast/refformula.hh, src/ltlast/unop.cc, src/ltlast/unop.hh, src/ltlast/visitor.hh, src/ltlenv/Makefile.am, src/ltlenv/declenv.cc, src/ltlenv/declenv.hh, src/ltlenv/defaultenv.cc, src/ltlenv/defaultenv.hh, src/ltlenv/environment.hh, src/ltlparse/Makefile.am, src/ltlparse/fmterror.cc, src/ltlparse/ltlfile.cc, src/ltlparse/ltlfile.hh, src/ltlparse/ltlparse.yy, src/ltlparse/ltlscan.ll, src/ltlparse/parsedecl.hh, src/ltlparse/public.hh, src/ltltest/Makefile.am, src/ltltest/consterm.cc, src/ltltest/consterm.test, src/ltltest/defs.in, src/ltltest/equals.cc, src/ltltest/equals.test, src/ltltest/kind.cc, src/ltltest/kind.test, src/ltltest/length.cc, src/ltltest/length.test, src/ltltest/lunabbrev.test, src/ltltest/nenoform.test, src/ltltest/parse.test, src/ltltest/parseerr.test, src/ltltest/readltl.cc, src/ltltest/reduc.cc, src/ltltest/reduc.test, src/ltltest/reduccmp.test, src/ltltest/reducpsl.test, src/ltltest/syntimpl.cc, src/ltltest/syntimpl.test, src/ltltest/tostring.cc, src/ltltest/tostring.test, src/ltltest/tunabbrev.test, src/ltltest/tunenoform.test, src/ltltest/utf8.test, src/ltltest/uwrm.test, src/ltlvisit/Makefile.am, src/ltlvisit/apcollect.cc, src/ltlvisit/apcollect.hh, src/ltlvisit/clone.cc, src/ltlvisit/clone.hh, src/ltlvisit/contain.cc, src/ltlvisit/contain.hh, src/ltlvisit/destroy.cc, src/ltlvisit/destroy.hh, src/ltlvisit/dotty.cc, src/ltlvisit/dotty.hh, src/ltlvisit/dump.cc, src/ltlvisit/dump.hh, src/ltlvisit/lbt.cc, src/ltlvisit/lbt.hh, src/ltlvisit/length.cc, src/ltlvisit/length.hh, src/ltlvisit/lunabbrev.cc, src/ltlvisit/lunabbrev.hh, src/ltlvisit/mark.cc, src/ltlvisit/mark.hh, src/ltlvisit/nenoform.cc, src/ltlvisit/nenoform.hh, src/ltlvisit/postfix.cc, src/ltlvisit/postfix.hh, src/ltlvisit/randomltl.cc, src/ltlvisit/randomltl.hh, src/ltlvisit/reduce.cc, src/ltlvisit/reduce.hh, src/ltlvisit/relabel.cc, src/ltlvisit/relabel.hh, src/ltlvisit/simpfg.cc, src/ltlvisit/simpfg.hh, src/ltlvisit/simplify.cc, src/ltlvisit/simplify.hh, src/ltlvisit/snf.cc, src/ltlvisit/snf.hh, src/ltlvisit/tostring.cc, src/ltlvisit/tostring.hh, src/ltlvisit/tunabbrev.cc, src/ltlvisit/tunabbrev.hh, src/ltlvisit/wmunabbrev.cc, src/ltlvisit/wmunabbrev.hh, src/misc/Makefile.am, src/misc/acccompl.cc, src/misc/acccompl.hh, src/misc/accconv.cc, src/misc/accconv.hh, src/misc/bareword.cc, src/misc/bareword.hh, src/misc/bddalloc.cc, src/misc/bddalloc.hh, src/misc/bddlt.hh, src/misc/bddop.cc, src/misc/bddop.hh, src/misc/casts.hh, src/misc/escape.cc, src/misc/escape.hh, src/misc/fixpool.hh, src/misc/freelist.cc, src/misc/freelist.hh, src/misc/hash.hh, src/misc/hashfunc.hh, src/misc/intvcmp2.cc, src/misc/intvcmp2.hh, src/misc/intvcomp.cc, src/misc/intvcomp.hh, src/misc/ltstr.hh, src/misc/memusage.cc, src/misc/memusage.hh, src/misc/minato.cc, src/misc/minato.hh, src/misc/modgray.cc, src/misc/modgray.hh, src/misc/mspool.hh, src/misc/optionmap.cc, src/misc/optionmap.hh, src/misc/random.cc, src/misc/random.hh, src/misc/timer.cc, src/misc/timer.hh, src/misc/unique_ptr.hh, src/misc/version.cc, src/misc/version.hh, src/neverparse/Makefile.am, src/neverparse/fmterror.cc, src/neverparse/neverclaimparse.yy, src/neverparse/neverclaimscan.ll, src/neverparse/parsedecl.hh, src/neverparse/public.hh, src/saba/Makefile.am, src/saba/explicitstateconjunction.cc, src/saba/explicitstateconjunction.hh, src/saba/saba.cc, src/saba/saba.hh, src/saba/sabacomplementtgba.cc, src/saba/sabacomplementtgba.hh, src/saba/sabastate.hh, src/saba/sabasucciter.hh, src/sabaalgos/Makefile.am, src/sabaalgos/sabadotty.cc, src/sabaalgos/sabadotty.hh, src/sabaalgos/sabareachiter.cc, src/sabaalgos/sabareachiter.hh, src/sabatest/Makefile.am, src/sabatest/defs.in, src/sabatest/sabacomplementtgba.cc, src/sanity/Makefile.am, src/sanity/readme.test, src/sanity/style.test, src/ta/Makefile.am, src/ta/ta.cc, src/ta/ta.hh, src/ta/taexplicit.cc, src/ta/taexplicit.hh, src/ta/taproduct.cc, src/ta/taproduct.hh, src/ta/tgta.cc, src/ta/tgta.hh, src/ta/tgtaexplicit.cc, src/ta/tgtaexplicit.hh, src/ta/tgtaproduct.cc, src/ta/tgtaproduct.hh, src/taalgos/Makefile.am, src/taalgos/dotty.cc, src/taalgos/dotty.hh, src/taalgos/emptinessta.cc, src/taalgos/emptinessta.hh, src/taalgos/minimize.cc, src/taalgos/minimize.hh, src/taalgos/reachiter.cc, src/taalgos/reachiter.hh, src/taalgos/statessetbuilder.cc, src/taalgos/statessetbuilder.hh, src/taalgos/stats.cc, src/taalgos/stats.hh, src/taalgos/tgba2ta.cc, src/taalgos/tgba2ta.hh, src/tgba/Makefile.am, src/tgba/bdddict.cc, src/tgba/bdddict.hh, src/tgba/bddprint.cc, src/tgba/bddprint.hh, src/tgba/formula2bdd.cc, src/tgba/formula2bdd.hh, src/tgba/futurecondcol.cc, src/tgba/futurecondcol.hh, src/tgba/public.hh, src/tgba/sba.hh, src/tgba/state.hh, src/tgba/statebdd.cc, src/tgba/statebdd.hh, src/tgba/succiter.hh, src/tgba/succiterconcrete.cc, src/tgba/succiterconcrete.hh, src/tgba/taatgba.cc, src/tgba/taatgba.hh, src/tgba/tgba.cc, src/tgba/tgba.hh, src/tgba/tgbabddconcrete.cc, src/tgba/tgbabddconcrete.hh, src/tgba/tgbabddconcretefactory.cc, src/tgba/tgbabddconcretefactory.hh, src/tgba/tgbabddconcreteproduct.cc, src/tgba/tgbabddconcreteproduct.hh, src/tgba/tgbabddcoredata.cc, src/tgba/tgbabddcoredata.hh, src/tgba/tgbabddfactory.hh, src/tgba/tgbaexplicit.cc, src/tgba/tgbaexplicit.hh, src/tgba/tgbakvcomplement.cc, src/tgba/tgbakvcomplement.hh, src/tgba/tgbaproduct.cc, src/tgba/tgbaproduct.hh, src/tgba/tgbasafracomplement.cc, src/tgba/tgbasafracomplement.hh, src/tgba/tgbascc.cc, src/tgba/tgbascc.hh, src/tgba/tgbasgba.cc, src/tgba/tgbasgba.hh, src/tgba/tgbatba.cc, src/tgba/tgbatba.hh, src/tgba/tgbaunion.cc, src/tgba/tgbaunion.hh, src/tgba/wdbacomp.cc, src/tgba/wdbacomp.hh, src/tgbaalgos/Makefile.am, src/tgbaalgos/bfssteps.cc, src/tgbaalgos/bfssteps.hh, src/tgbaalgos/cutscc.cc, src/tgbaalgos/cutscc.hh, src/tgbaalgos/cycles.cc, src/tgbaalgos/cycles.hh, src/tgbaalgos/degen.cc, src/tgbaalgos/degen.hh, src/tgbaalgos/dotty.cc, src/tgbaalgos/dotty.hh, src/tgbaalgos/dottydec.cc, src/tgbaalgos/dottydec.hh, src/tgbaalgos/dupexp.cc, src/tgbaalgos/dupexp.hh, src/tgbaalgos/eltl2tgba_lacim.cc, src/tgbaalgos/eltl2tgba_lacim.hh, src/tgbaalgos/emptiness.cc, src/tgbaalgos/emptiness.hh, src/tgbaalgos/emptiness_stats.hh, src/tgbaalgos/gtec/Makefile.am, src/tgbaalgos/gtec/ce.cc, src/tgbaalgos/gtec/ce.hh, src/tgbaalgos/gtec/explscc.cc, src/tgbaalgos/gtec/explscc.hh, src/tgbaalgos/gtec/gtec.cc, src/tgbaalgos/gtec/gtec.hh, src/tgbaalgos/gtec/nsheap.cc, src/tgbaalgos/gtec/nsheap.hh, src/tgbaalgos/gtec/sccstack.cc, src/tgbaalgos/gtec/sccstack.hh, src/tgbaalgos/gtec/status.cc, src/tgbaalgos/gtec/status.hh, src/tgbaalgos/gv04.cc, src/tgbaalgos/gv04.hh, src/tgbaalgos/isdet.cc, src/tgbaalgos/isdet.hh, src/tgbaalgos/isweakscc.cc, src/tgbaalgos/isweakscc.hh, src/tgbaalgos/lbtt.cc, src/tgbaalgos/lbtt.hh, src/tgbaalgos/ltl2taa.cc, src/tgbaalgos/ltl2taa.hh, src/tgbaalgos/ltl2tgba_fm.cc, src/tgbaalgos/ltl2tgba_fm.hh, src/tgbaalgos/ltl2tgba_lacim.cc, src/tgbaalgos/ltl2tgba_lacim.hh, src/tgbaalgos/magic.cc, src/tgbaalgos/magic.hh, src/tgbaalgos/minimize.cc, src/tgbaalgos/minimize.hh, src/tgbaalgos/ndfs_result.hxx, src/tgbaalgos/neverclaim.cc, src/tgbaalgos/neverclaim.hh, src/tgbaalgos/postproc.cc, src/tgbaalgos/postproc.hh, src/tgbaalgos/powerset.cc, src/tgbaalgos/powerset.hh, src/tgbaalgos/projrun.cc, src/tgbaalgos/projrun.hh, src/tgbaalgos/randomgraph.cc, src/tgbaalgos/randomgraph.hh, src/tgbaalgos/reachiter.cc, src/tgbaalgos/reachiter.hh, src/tgbaalgos/reducerun.cc, src/tgbaalgos/reducerun.hh, src/tgbaalgos/reductgba_sim.cc, src/tgbaalgos/reductgba_sim.hh, src/tgbaalgos/replayrun.cc, src/tgbaalgos/replayrun.hh, src/tgbaalgos/rundotdec.cc, src/tgbaalgos/rundotdec.hh, src/tgbaalgos/safety.cc, src/tgbaalgos/safety.hh, src/tgbaalgos/save.cc, src/tgbaalgos/save.hh, src/tgbaalgos/scc.cc, src/tgbaalgos/scc.hh, src/tgbaalgos/sccfilter.cc, src/tgbaalgos/sccfilter.hh, src/tgbaalgos/se05.cc, src/tgbaalgos/se05.hh, src/tgbaalgos/simulation.cc, src/tgbaalgos/simulation.hh, src/tgbaalgos/stats.cc, src/tgbaalgos/stats.hh, src/tgbaalgos/tau03.cc, src/tgbaalgos/tau03.hh, src/tgbaalgos/tau03opt.cc, src/tgbaalgos/tau03opt.hh, src/tgbaalgos/weight.cc, src/tgbaalgos/weight.hh, src/tgbaparse/Makefile.am, src/tgbaparse/fmterror.cc, src/tgbaparse/parsedecl.hh, src/tgbaparse/public.hh, src/tgbaparse/tgbaparse.yy, src/tgbaparse/tgbascan.ll, src/tgbatest/Makefile.am, src/tgbatest/babiak.test, src/tgbatest/bddprod.test, src/tgbatest/complementation.cc, src/tgbatest/complementation.test, src/tgbatest/cycles.test, src/tgbatest/defs.in, src/tgbatest/degendet.test, src/tgbatest/degenid.test, src/tgbatest/dfs.test, src/tgbatest/dupexp.test, src/tgbatest/eltl2tgba.test, src/tgbatest/emptchk.test, src/tgbatest/emptchke.test, src/tgbatest/emptchkr.test, src/tgbatest/explicit.cc, src/tgbatest/explicit.test, src/tgbatest/explicit2.cc, src/tgbatest/explicit2.test, src/tgbatest/explpro2.test, src/tgbatest/explpro3.test, src/tgbatest/explpro4.test, src/tgbatest/explprod.cc, src/tgbatest/explprod.test, src/tgbatest/intvcmp2.cc, src/tgbatest/intvcomp.cc, src/tgbatest/intvcomp.test, src/tgbatest/kv.test, src/tgbatest/ltl2neverclaim.test, src/tgbatest/ltl2ta.test, src/tgbatest/ltl2tgba.cc, src/tgbatest/ltl2tgba.test, src/tgbatest/ltlcounter.test, src/tgbatest/ltlprod.cc, src/tgbatest/ltlprod.test, src/tgbatest/mixprod.cc, src/tgbatest/mixprod.test, src/tgbatest/neverclaimread.test, src/tgbatest/nondet.test, src/tgbatest/obligation.test, src/tgbatest/powerset.cc, src/tgbatest/randpsl.test, src/tgbatest/randtgba.cc, src/tgbatest/randtgba.test, src/tgbatest/readsave.test, src/tgbatest/renault.test, src/tgbatest/scc.test, src/tgbatest/sccsimpl.test, src/tgbatest/spotlbtt.test, src/tgbatest/spotlbtt2.test, src/tgbatest/taatgba.cc, src/tgbatest/taatgba.test, src/tgbatest/tgbaread.cc, src/tgbatest/tgbaread.test, src/tgbatest/tripprod.cc, src/tgbatest/tripprod.test, src/tgbatest/wdba.test, src/tgbatest/wdba2.test, wrap/Makefile.am, wrap/python/Makefile.am, wrap/python/ajax/Makefile.am, wrap/python/ajax/spot.in, wrap/python/buddy.i, wrap/python/spot.i, wrap/python/tests/Makefile.am, wrap/python/tests/alarm.py, wrap/python/tests/bddnqueen.py, wrap/python/tests/implies.py, wrap/python/tests/interdep.py, wrap/python/tests/ltl2tgba.py, wrap/python/tests/ltl2tgba.test, wrap/python/tests/ltlparse.py, wrap/python/tests/ltlsimple.py, wrap/python/tests/minato.py, wrap/python/tests/modgray.py, wrap/python/tests/optionmap.py, wrap/python/tests/parsetgba.py, wrap/python/tests/run.in, wrap/python/tests/setxor.py: Update licence version, and replace the FSF address by a URL.
1099 lines
26 KiB
C++
1099 lines
26 KiB
C++
// -*- coding: utf-8 -*-
|
|
// Copyright (C) 2011, 2012 Laboratoire de Recherche et Développement
|
|
// de l'Epita (LRDE)
|
|
//
|
|
// 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 <ltdl.h>
|
|
#include <cstring>
|
|
#include <cstdlib>
|
|
#include <vector>
|
|
#include <sstream>
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
|
|
// MinGW does not define this.
|
|
#ifndef WEXITSTATUS
|
|
# define WEXITSTATUS(x) ((x) & 0xff)
|
|
#endif
|
|
|
|
#include "dve2.hh"
|
|
#include "misc/hashfunc.hh"
|
|
#include "misc/fixpool.hh"
|
|
#include "misc/mspool.hh"
|
|
#include "misc/intvcomp.hh"
|
|
#include "misc/intvcmp2.hh"
|
|
|
|
|
|
namespace spot
|
|
{
|
|
namespace
|
|
{
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// DVE2 --ltsmin interface
|
|
|
|
typedef struct transition_info {
|
|
int* labels; // edge labels, NULL, or pointer to the edge label(s)
|
|
int group; // holds transition group or -1 if unknown
|
|
} transition_info_t;
|
|
|
|
typedef void (*TransitionCB)(void *ctx,
|
|
transition_info_t *transition_info,
|
|
int *dst);
|
|
|
|
struct dve2_interface
|
|
{
|
|
lt_dlhandle handle; // handle to the dynamic library
|
|
void (*get_initial_state)(void *to);
|
|
int (*have_property)();
|
|
int (*get_successors)(void* m, int *in, TransitionCB, void *arg);
|
|
|
|
int (*get_state_variable_count)();
|
|
const char* (*get_state_variable_name)(int var);
|
|
int (*get_state_variable_type)(int var);
|
|
int (*get_state_variable_type_count)();
|
|
const char* (*get_state_variable_type_name)(int type);
|
|
int (*get_state_variable_type_value_count)(int type);
|
|
const char* (*get_state_variable_type_value)(int type, int value);
|
|
int (*get_transition_count)();
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// STATE
|
|
|
|
struct dve2_state: public state
|
|
{
|
|
dve2_state(int s, fixed_size_pool* p)
|
|
: pool(p), size(s), count(1)
|
|
{
|
|
}
|
|
|
|
void compute_hash()
|
|
{
|
|
hash_value = 0;
|
|
for (int i = 0; i < size; ++i)
|
|
hash_value = wang32_hash(hash_value ^ vars[i]);
|
|
}
|
|
|
|
dve2_state* clone() const
|
|
{
|
|
++count;
|
|
return const_cast<dve2_state*>(this);
|
|
}
|
|
|
|
void destroy() const
|
|
{
|
|
if (--count)
|
|
return;
|
|
pool->deallocate(this);
|
|
}
|
|
|
|
size_t hash() const
|
|
{
|
|
return hash_value;
|
|
}
|
|
|
|
int compare(const state* other) const
|
|
{
|
|
if (this == other)
|
|
return 0;
|
|
const dve2_state* o = down_cast<const dve2_state*>(other);
|
|
assert(o);
|
|
if (hash_value < o->hash_value)
|
|
return -1;
|
|
if (hash_value > o->hash_value)
|
|
return 1;
|
|
return memcmp(vars, o->vars, size * sizeof(*vars));
|
|
}
|
|
|
|
private:
|
|
|
|
~dve2_state()
|
|
{
|
|
}
|
|
|
|
public:
|
|
fixed_size_pool* pool;
|
|
size_t hash_value: 32;
|
|
int size: 16;
|
|
mutable unsigned count: 16;
|
|
int vars[0];
|
|
};
|
|
|
|
struct dve2_compressed_state: public state
|
|
{
|
|
dve2_compressed_state(int s, multiple_size_pool* p)
|
|
: pool(p), size(s), count(1)
|
|
{
|
|
}
|
|
|
|
void compute_hash()
|
|
{
|
|
hash_value = 0;
|
|
for (int i = 0; i < size; ++i)
|
|
hash_value = wang32_hash(hash_value ^ vars[i]);
|
|
}
|
|
|
|
dve2_compressed_state* clone() const
|
|
{
|
|
++count;
|
|
return const_cast<dve2_compressed_state*>(this);
|
|
}
|
|
|
|
void destroy() const
|
|
{
|
|
if (--count)
|
|
return;
|
|
pool->deallocate(this, sizeof(*this) + size * sizeof(*vars));
|
|
}
|
|
|
|
size_t hash() const
|
|
{
|
|
return hash_value;
|
|
}
|
|
|
|
int compare(const state* other) const
|
|
{
|
|
if (this == other)
|
|
return 0;
|
|
const dve2_compressed_state* o =
|
|
down_cast<const dve2_compressed_state*>(other);
|
|
assert(o);
|
|
if (hash_value < o->hash_value)
|
|
return -1;
|
|
if (hash_value > o->hash_value)
|
|
return 1;
|
|
|
|
if (size < o->size)
|
|
return -1;
|
|
if (size > o->size)
|
|
return 1;
|
|
|
|
return memcmp(vars, o->vars, size * sizeof(*vars));
|
|
}
|
|
|
|
private:
|
|
|
|
~dve2_compressed_state()
|
|
{
|
|
}
|
|
|
|
public:
|
|
multiple_size_pool* pool;
|
|
size_t hash_value: 32;
|
|
int size: 16;
|
|
mutable unsigned count: 16;
|
|
int vars[0];
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// CALLBACK FUNCTION for transitions.
|
|
|
|
struct callback_context
|
|
{
|
|
typedef std::list<state*> transitions_t;
|
|
transitions_t transitions;
|
|
int state_size;
|
|
void* pool;
|
|
int* compressed;
|
|
void (*compress)(const int*, size_t, int*, size_t&);
|
|
|
|
~callback_context()
|
|
{
|
|
callback_context::transitions_t::const_iterator it;
|
|
for (it = transitions.begin(); it != transitions.end(); ++it)
|
|
(*it)->destroy();
|
|
}
|
|
};
|
|
|
|
void transition_callback(void* arg, transition_info_t*, int *dst)
|
|
{
|
|
callback_context* ctx = static_cast<callback_context*>(arg);
|
|
fixed_size_pool* p = static_cast<fixed_size_pool*>(ctx->pool);
|
|
dve2_state* out =
|
|
new(p->allocate()) dve2_state(ctx->state_size, p);
|
|
memcpy(out->vars, dst, ctx->state_size * sizeof(int));
|
|
out->compute_hash();
|
|
ctx->transitions.push_back(out);
|
|
}
|
|
|
|
void transition_callback_compress(void* arg, transition_info_t*, int *dst)
|
|
{
|
|
callback_context* ctx = static_cast<callback_context*>(arg);
|
|
multiple_size_pool* p = static_cast<multiple_size_pool*>(ctx->pool);
|
|
|
|
size_t csize = ctx->state_size * 2;
|
|
ctx->compress(dst, ctx->state_size, ctx->compressed, csize);
|
|
|
|
void* mem = p->allocate(sizeof(dve2_compressed_state)
|
|
+ sizeof(int) * csize);
|
|
dve2_compressed_state* out = new(mem) dve2_compressed_state(csize, p);
|
|
memcpy(out->vars, ctx->compressed, csize * sizeof(int));
|
|
out->compute_hash();
|
|
ctx->transitions.push_back(out);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// SUCC_ITERATOR
|
|
|
|
class dve2_succ_iterator: public kripke_succ_iterator
|
|
{
|
|
public:
|
|
|
|
dve2_succ_iterator(const callback_context* cc,
|
|
bdd cond)
|
|
: kripke_succ_iterator(cond), cc_(cc)
|
|
{
|
|
}
|
|
|
|
~dve2_succ_iterator()
|
|
{
|
|
delete cc_;
|
|
}
|
|
|
|
virtual
|
|
void first()
|
|
{
|
|
it_ = cc_->transitions.begin();
|
|
}
|
|
|
|
virtual
|
|
void next()
|
|
{
|
|
++it_;
|
|
}
|
|
|
|
virtual
|
|
bool done() const
|
|
{
|
|
return it_ == cc_->transitions.end();
|
|
}
|
|
|
|
virtual
|
|
state* current_state() const
|
|
{
|
|
return (*it_)->clone();
|
|
}
|
|
|
|
private:
|
|
const callback_context* cc_;
|
|
callback_context::transitions_t::const_iterator it_;
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// PREDICATE EVALUATION
|
|
|
|
typedef enum { OP_EQ, OP_NE, OP_LT, OP_GT, OP_LE, OP_GE } relop;
|
|
|
|
struct one_prop
|
|
{
|
|
int var_num;
|
|
relop op;
|
|
int val;
|
|
int bddvar; // if "var_num op val" is true, output bddvar,
|
|
// else its negation
|
|
};
|
|
typedef std::vector<one_prop> prop_set;
|
|
|
|
|
|
struct var_info
|
|
{
|
|
int num;
|
|
int type;
|
|
};
|
|
|
|
|
|
int
|
|
convert_aps(const ltl::atomic_prop_set* aps,
|
|
const dve2_interface* d,
|
|
bdd_dict* dict,
|
|
const ltl::formula* dead,
|
|
prop_set& out)
|
|
{
|
|
int errors = 0;
|
|
|
|
int state_size = d->get_state_variable_count();
|
|
typedef std::map<std::string, var_info> val_map_t;
|
|
val_map_t val_map;
|
|
|
|
for (int i = 0; i < state_size; ++i)
|
|
{
|
|
const char* name = d->get_state_variable_name(i);
|
|
int type = d->get_state_variable_type(i);
|
|
var_info v = { i , type };
|
|
val_map[name] = v;
|
|
}
|
|
|
|
int type_count = d->get_state_variable_type_count();
|
|
typedef std::map<std::string, int> enum_map_t;
|
|
std::vector<enum_map_t> enum_map(type_count);
|
|
for (int i = 0; i < type_count; ++i)
|
|
{
|
|
int enum_count = d->get_state_variable_type_value_count(i);
|
|
for (int j = 0; j < enum_count; ++j)
|
|
enum_map[i]
|
|
.insert(std::make_pair(d->get_state_variable_type_value(i, j),
|
|
j));
|
|
}
|
|
|
|
for (ltl::atomic_prop_set::const_iterator ap = aps->begin();
|
|
ap != aps->end(); ++ap)
|
|
{
|
|
if (*ap == dead)
|
|
continue;
|
|
|
|
std::string str = (*ap)->name();
|
|
const char* s = str.c_str();
|
|
|
|
// Skip any leading blank.
|
|
while (*s && (*s == ' ' || *s == '\t'))
|
|
++s;
|
|
if (!*s)
|
|
{
|
|
std::cerr << "Proposition `" << str
|
|
<< "' cannot be parsed." << std::endl;
|
|
++errors;
|
|
continue;
|
|
}
|
|
|
|
|
|
char* name = (char*) malloc(str.size() + 1);
|
|
char* name_p = name;
|
|
char* lastdot = 0;
|
|
while (*s && (*s != '=') && *s != '<' && *s != '!' && *s != '>')
|
|
{
|
|
|
|
if (*s == ' ' || *s == '\t')
|
|
++s;
|
|
else
|
|
{
|
|
if (*s == '.')
|
|
lastdot = name_p;
|
|
*name_p++ = *s++;
|
|
}
|
|
}
|
|
*name_p = 0;
|
|
|
|
if (name == name_p)
|
|
{
|
|
std::cerr << "Proposition `" << str
|
|
<< "' cannot be parsed." << std::endl;
|
|
free(name);
|
|
++errors;
|
|
continue;
|
|
}
|
|
|
|
// Lookup the name
|
|
val_map_t::const_iterator ni = val_map.find(name);
|
|
if (ni == val_map.end())
|
|
{
|
|
// We may have a name such as X.Y.Z
|
|
// If it is not a known variable, it might mean
|
|
// an enumerated variable X.Y with value Z.
|
|
if (lastdot)
|
|
{
|
|
*lastdot++ = 0;
|
|
ni = val_map.find(name);
|
|
}
|
|
|
|
if (ni == val_map.end())
|
|
{
|
|
std::cerr << "No variable `" << name
|
|
<< "' found in model (for proposition `"
|
|
<< str << "')." << std::endl;
|
|
free(name);
|
|
++errors;
|
|
continue;
|
|
}
|
|
|
|
// We have found the enumerated variable, and lastdot is
|
|
// pointing to its expected value.
|
|
int type_num = ni->second.type;
|
|
enum_map_t::const_iterator ei = enum_map[type_num].find(lastdot);
|
|
if (ei == enum_map[type_num].end())
|
|
{
|
|
std::cerr << "No state `" << lastdot
|
|
<< "' known for variable `"
|
|
<< name << "'." << std::endl;
|
|
std::cerr << "Possible states are:";
|
|
for (ei = enum_map[type_num].begin();
|
|
ei != enum_map[type_num].end(); ++ei)
|
|
std::cerr << " " << ei->first;
|
|
std::cerr << std::endl;
|
|
|
|
free(name);
|
|
++errors;
|
|
continue;
|
|
}
|
|
|
|
// At this point, *s should be 0.
|
|
if (*s)
|
|
{
|
|
std::cerr << "Trailing garbage `" << s
|
|
<< "' at end of proposition `"
|
|
<< str << "'." << std::endl;
|
|
free(name);
|
|
++errors;
|
|
continue;
|
|
}
|
|
|
|
// Record that X.Y must be equal to Z.
|
|
int v = dict->register_proposition(*ap, d);
|
|
one_prop p = { ni->second.num, OP_EQ, ei->second, v };
|
|
out.push_back(p);
|
|
free(name);
|
|
continue;
|
|
}
|
|
|
|
int var_num = ni->second.num;
|
|
|
|
if (!*s) // No operator? Assume "!= 0".
|
|
{
|
|
int v = dict->register_proposition(*ap, d);
|
|
one_prop p = { var_num, OP_NE, 0, v };
|
|
out.push_back(p);
|
|
free(name);
|
|
continue;
|
|
}
|
|
|
|
relop op;
|
|
|
|
switch (*s)
|
|
{
|
|
case '!':
|
|
if (s[1] != '=')
|
|
goto report_error;
|
|
op = OP_NE;
|
|
s += 2;
|
|
break;
|
|
case '=':
|
|
if (s[1] != '=')
|
|
goto report_error;
|
|
op = OP_EQ;
|
|
s += 2;
|
|
break;
|
|
case '<':
|
|
if (s[1] == '=')
|
|
{
|
|
op = OP_LE;
|
|
s += 2;
|
|
}
|
|
else
|
|
{
|
|
op = OP_LT;
|
|
++s;
|
|
}
|
|
break;
|
|
case '>':
|
|
if (s[1] == '=')
|
|
{
|
|
op = OP_GE;
|
|
s += 2;
|
|
}
|
|
else
|
|
{
|
|
op = OP_GT;
|
|
++s;
|
|
}
|
|
break;
|
|
default:
|
|
report_error:
|
|
std::cerr << "Unexpected `" << s
|
|
<< "' while parsing atomic proposition `" << str
|
|
<< "'." << std::endl;
|
|
++errors;
|
|
free(name);
|
|
continue;
|
|
}
|
|
|
|
while (*s && (*s == ' ' || *s == '\t'))
|
|
++s;
|
|
|
|
int val = 0; // Initialize to kill a warning from old compilers.
|
|
int type_num = ni->second.type;
|
|
if (type_num == 0 || (*s >= '0' && *s <= '9') || *s == '-')
|
|
{
|
|
char* s_end;
|
|
val = strtol(s, &s_end, 10);
|
|
if (s == s_end)
|
|
{
|
|
std::cerr << "Failed to parse `" << s
|
|
<< "' as an integer." << std::endl;
|
|
++errors;
|
|
free(name);
|
|
continue;
|
|
}
|
|
s = s_end;
|
|
}
|
|
else
|
|
{
|
|
// We are in a case such as P_0 == S, trying to convert
|
|
// the string S into an integer.
|
|
const char* end = s;
|
|
while (*end && *end != ' ' && *end != '\t')
|
|
++end;
|
|
std::string st(s, end);
|
|
|
|
// Lookup the string.
|
|
enum_map_t::const_iterator ei = enum_map[type_num].find(st);
|
|
if (ei == enum_map[type_num].end())
|
|
{
|
|
std::cerr << "No state `" << st
|
|
<< "' known for variable `"
|
|
<< name << "'." << std::endl;
|
|
std::cerr << "Possible states are:";
|
|
for (ei = enum_map[type_num].begin();
|
|
ei != enum_map[type_num].end(); ++ei)
|
|
std::cerr << " " << ei->first;
|
|
std::cerr << std::endl;
|
|
|
|
free(name);
|
|
++errors;
|
|
continue;
|
|
}
|
|
s = end;
|
|
val = ei->second;
|
|
}
|
|
|
|
free(name);
|
|
|
|
while (*s && (*s == ' ' || *s == '\t'))
|
|
++s;
|
|
if (*s)
|
|
{
|
|
std::cerr << "Unexpected `" << s
|
|
<< "' while parsing atomic proposition `" << str
|
|
<< "'." << std::endl;
|
|
++errors;
|
|
continue;
|
|
}
|
|
|
|
|
|
int v = dict->register_proposition(*ap, d);
|
|
one_prop p = { var_num, op, val, v };
|
|
out.push_back(p);
|
|
}
|
|
|
|
return errors;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// KRIPKE
|
|
|
|
class dve2_kripke: public kripke
|
|
{
|
|
public:
|
|
|
|
dve2_kripke(const dve2_interface* d, bdd_dict* dict, const prop_set* ps,
|
|
const ltl::formula* dead, int compress)
|
|
: d_(d),
|
|
state_size_(d_->get_state_variable_count()),
|
|
dict_(dict), ps_(ps),
|
|
compress_(compress == 0 ? 0
|
|
: compress == 1 ? int_array_array_compress
|
|
: int_array_array_compress2),
|
|
decompress_(compress == 0 ? 0
|
|
: compress == 1 ? int_array_array_decompress
|
|
: int_array_array_decompress2),
|
|
uncompressed_(compress ? new int[state_size_ + 30] : 0),
|
|
compressed_(compress ? new int[state_size_ * 2] : 0),
|
|
statepool_(compress ? sizeof(dve2_compressed_state) :
|
|
(sizeof(dve2_state) + state_size_ * sizeof(int))),
|
|
state_condition_last_state_(0), state_condition_last_cc_(0)
|
|
{
|
|
vname_ = new const char*[state_size_];
|
|
format_filter_ = new bool[state_size_];
|
|
for (int i = 0; i < state_size_; ++i)
|
|
{
|
|
vname_[i] = d_->get_state_variable_name(i);
|
|
// We don't want to print variables that can take a single
|
|
// value (e.g. process with a single state) to shorten the
|
|
// output.
|
|
int type = d->get_state_variable_type(i);
|
|
format_filter_[i] =
|
|
(d->get_state_variable_type_value_count(type) != 1);
|
|
}
|
|
|
|
// Register the "dead" proposition. There are three cases to
|
|
// consider:
|
|
// * If DEAD is "false", it means we are not interested in finite
|
|
// sequences of the system.
|
|
// * If DEAD is "true", we want to check finite sequences as well
|
|
// as infinite sequences, but do not need to distinguish them.
|
|
// * If DEAD is any other string, this is the name a property
|
|
// that should be true when looping on a dead state, and false
|
|
// otherwise.
|
|
// We handle these three cases by setting ALIVE_PROP and DEAD_PROP
|
|
// appropriately. ALIVE_PROP is the bdd that should be ANDed
|
|
// to all transitions leaving a live state, while DEAD_PROP should
|
|
// be ANDed to all transitions leaving a dead state.
|
|
if (dead == ltl::constant::false_instance())
|
|
{
|
|
alive_prop = bddtrue;
|
|
dead_prop = bddfalse;
|
|
}
|
|
else if (dead == ltl::constant::true_instance())
|
|
{
|
|
alive_prop = bddtrue;
|
|
dead_prop = bddtrue;
|
|
}
|
|
else
|
|
{
|
|
int var = dict->register_proposition(dead, d_);
|
|
dead_prop = bdd_ithvar(var);
|
|
alive_prop = bdd_nithvar(var);
|
|
}
|
|
}
|
|
|
|
~dve2_kripke()
|
|
{
|
|
delete[] format_filter_;
|
|
delete[] vname_;
|
|
if (compress_)
|
|
{
|
|
delete[] uncompressed_;
|
|
delete[] compressed_;
|
|
}
|
|
lt_dlclose(d_->handle);
|
|
|
|
dict_->unregister_all_my_variables(d_);
|
|
|
|
delete d_;
|
|
delete ps_;
|
|
lt_dlexit();
|
|
|
|
if (state_condition_last_state_)
|
|
state_condition_last_state_->destroy();
|
|
delete state_condition_last_cc_; // Might be 0 already.
|
|
}
|
|
|
|
virtual
|
|
state* get_init_state() const
|
|
{
|
|
if (compress_)
|
|
{
|
|
d_->get_initial_state(uncompressed_);
|
|
size_t csize = state_size_ * 2;
|
|
compress_(uncompressed_, state_size_, compressed_, csize);
|
|
|
|
multiple_size_pool* p =
|
|
const_cast<multiple_size_pool*>(&compstatepool_);
|
|
void* mem = p->allocate(sizeof(dve2_compressed_state)
|
|
+ sizeof(int) * csize);
|
|
dve2_compressed_state* res = new(mem)
|
|
dve2_compressed_state(csize, p);
|
|
memcpy(res->vars, compressed_, csize * sizeof(int));
|
|
res->compute_hash();
|
|
return res;
|
|
}
|
|
else
|
|
{
|
|
fixed_size_pool* p = const_cast<fixed_size_pool*>(&statepool_);
|
|
dve2_state* res = new(p->allocate()) dve2_state(state_size_, p);
|
|
d_->get_initial_state(res->vars);
|
|
res->compute_hash();
|
|
return res;
|
|
}
|
|
}
|
|
|
|
bdd
|
|
compute_state_condition_aux(const int* vars) const
|
|
{
|
|
bdd res = bddtrue;
|
|
for (prop_set::const_iterator i = ps_->begin();
|
|
i != ps_->end(); ++i)
|
|
{
|
|
int l = vars[i->var_num];
|
|
int r = i->val;
|
|
|
|
bool cond = false;
|
|
switch (i->op)
|
|
{
|
|
case OP_EQ:
|
|
cond = (l == r);
|
|
break;
|
|
case OP_NE:
|
|
cond = (l != r);
|
|
break;
|
|
case OP_LT:
|
|
cond = (l < r);
|
|
break;
|
|
case OP_GT:
|
|
cond = (l > r);
|
|
break;
|
|
case OP_LE:
|
|
cond = (l <= r);
|
|
break;
|
|
case OP_GE:
|
|
cond = (l >= r);
|
|
break;
|
|
}
|
|
|
|
if (cond)
|
|
res &= bdd_ithvar(i->bddvar);
|
|
else
|
|
res &= bdd_nithvar(i->bddvar);
|
|
}
|
|
return res;
|
|
}
|
|
|
|
callback_context* build_cc(const int* vars, int& t) const
|
|
{
|
|
callback_context* cc = new callback_context;
|
|
cc->state_size = state_size_;
|
|
cc->pool =
|
|
const_cast<void*>(compress_
|
|
? static_cast<const void*>(&compstatepool_)
|
|
: static_cast<const void*>(&statepool_));
|
|
cc->compress = compress_;
|
|
cc->compressed = compressed_;
|
|
t = d_->get_successors(0, const_cast<int*>(vars),
|
|
compress_
|
|
? transition_callback_compress
|
|
: transition_callback,
|
|
cc);
|
|
assert((unsigned)t == cc->transitions.size());
|
|
return cc;
|
|
}
|
|
|
|
bdd
|
|
compute_state_condition(const state* st) const
|
|
{
|
|
// If we just computed it, don't do it twice.
|
|
if (st == state_condition_last_state_)
|
|
return state_condition_last_cond_;
|
|
|
|
if (state_condition_last_state_)
|
|
{
|
|
state_condition_last_state_->destroy();
|
|
delete state_condition_last_cc_; // Might be 0 already.
|
|
state_condition_last_cc_ = 0;
|
|
}
|
|
|
|
const int* vars = get_vars(st);
|
|
|
|
bdd res = compute_state_condition_aux(vars);
|
|
int t;
|
|
callback_context* cc = build_cc(vars, t);
|
|
|
|
if (t)
|
|
{
|
|
res &= alive_prop;
|
|
}
|
|
else
|
|
{
|
|
res &= dead_prop;
|
|
|
|
// Add a self-loop to dead-states if we care about these.
|
|
if (res != bddfalse)
|
|
cc->transitions.push_back(st->clone());
|
|
}
|
|
|
|
state_condition_last_cc_ = cc;
|
|
state_condition_last_cond_ = res;
|
|
state_condition_last_state_ = st->clone();
|
|
|
|
return res;
|
|
}
|
|
|
|
const int*
|
|
get_vars(const state* st) const
|
|
{
|
|
const int* vars;
|
|
if (compress_)
|
|
{
|
|
const dve2_compressed_state* s =
|
|
down_cast<const dve2_compressed_state*>(st);
|
|
assert(s);
|
|
|
|
decompress_(s->vars, s->size, uncompressed_, state_size_);
|
|
vars = uncompressed_;
|
|
}
|
|
else
|
|
{
|
|
const dve2_state* s = down_cast<const dve2_state*>(st);
|
|
assert(s);
|
|
vars = s->vars;
|
|
}
|
|
return vars;
|
|
}
|
|
|
|
|
|
virtual
|
|
dve2_succ_iterator*
|
|
succ_iter(const state* local_state,
|
|
const state*, const tgba*) const
|
|
{
|
|
// This may also compute successors in state_condition_last_cc
|
|
bdd scond = compute_state_condition(local_state);
|
|
|
|
callback_context* cc;
|
|
if (state_condition_last_cc_)
|
|
{
|
|
cc = state_condition_last_cc_;
|
|
state_condition_last_cc_ = 0; // Now owned by the iterator.
|
|
}
|
|
else
|
|
{
|
|
int t;
|
|
cc = build_cc(get_vars(local_state), t);
|
|
|
|
// Add a self-loop to dead-states if we care about these.
|
|
if (t == 0 && scond != bddfalse)
|
|
cc->transitions.push_back(local_state->clone());
|
|
}
|
|
|
|
return new dve2_succ_iterator(cc, scond);
|
|
}
|
|
|
|
virtual
|
|
bdd
|
|
state_condition(const state* st) const
|
|
{
|
|
return compute_state_condition(st);
|
|
}
|
|
|
|
virtual
|
|
std::string format_state(const state *st) const
|
|
{
|
|
const int* vars = get_vars(st);
|
|
|
|
std::stringstream res;
|
|
|
|
if (state_size_ == 0)
|
|
return "empty state";
|
|
|
|
int i = 0;
|
|
for (;;)
|
|
{
|
|
if (!format_filter_[i])
|
|
{
|
|
++i;
|
|
continue;
|
|
}
|
|
res << vname_[i] << "=" << vars[i];
|
|
++i;
|
|
if (i == state_size_)
|
|
break;
|
|
res << ", ";
|
|
}
|
|
return res.str();
|
|
}
|
|
|
|
virtual
|
|
spot::bdd_dict* get_dict() const
|
|
{
|
|
return dict_;
|
|
}
|
|
|
|
private:
|
|
const dve2_interface* d_;
|
|
int state_size_;
|
|
bdd_dict* dict_;
|
|
const char** vname_;
|
|
bool* format_filter_;
|
|
const prop_set* ps_;
|
|
bdd alive_prop;
|
|
bdd dead_prop;
|
|
void (*compress_)(const int*, size_t, int*, size_t&);
|
|
void (*decompress_)(const int*, size_t, int*, size_t);
|
|
int* uncompressed_;
|
|
int* compressed_;
|
|
fixed_size_pool statepool_;
|
|
multiple_size_pool compstatepool_;
|
|
|
|
// This cache is used to speedup repeated calls to state_condition()
|
|
// and get_succ().
|
|
// If state_condition_last_state_ != 0, then state_condition_last_cond_
|
|
// contain its (recently computed) condition. If additionally
|
|
// state_condition_last_cc_ != 0, then it contains the successors.
|
|
mutable const state* state_condition_last_state_;
|
|
mutable bdd state_condition_last_cond_;
|
|
mutable callback_context* state_condition_last_cc_;
|
|
};
|
|
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
// LOADER
|
|
|
|
|
|
// Call divine to compile "foo.dve" as "foo.dve2C" if the latter
|
|
// does not exist already or is older.
|
|
bool
|
|
compile_dve2(std::string& filename, bool verbose)
|
|
{
|
|
|
|
std::string command = "divine compile --ltsmin " + filename;
|
|
|
|
struct stat s;
|
|
if (stat(filename.c_str(), &s) != 0)
|
|
{
|
|
if (verbose)
|
|
{
|
|
std::cerr << "Cannot open " << filename << std::endl;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
std::string old = filename;
|
|
filename += "2C";
|
|
|
|
// Remove any directory, because the new file will
|
|
// be compiled in the current directory.
|
|
size_t pos = filename.find_last_of("/\\");
|
|
if (pos != std::string::npos)
|
|
filename = "./" + filename.substr(pos + 1);
|
|
|
|
struct stat d;
|
|
if (stat(filename.c_str(), &d) == 0)
|
|
if (s.st_mtime < d.st_mtime)
|
|
// The dve2C is up-to-date, no need to recompile it.
|
|
return false;
|
|
|
|
int res = system(command.c_str());
|
|
if (res)
|
|
{
|
|
if (verbose)
|
|
std::cerr << "Execution of `" << command.c_str()
|
|
<< "' returned exit code " << WEXITSTATUS(res)
|
|
<< "." << std::endl;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
kripke*
|
|
load_dve2(const std::string& file_arg, bdd_dict* dict,
|
|
const ltl::atomic_prop_set* to_observe,
|
|
const ltl::formula* dead,
|
|
int compress,
|
|
bool verbose)
|
|
{
|
|
std::string file;
|
|
if (file_arg.find_first_of("/\\") != std::string::npos)
|
|
file = file_arg;
|
|
else
|
|
file = "./" + file_arg;
|
|
|
|
std::string ext = file.substr(file.find_last_of("."));
|
|
if (ext == ".dve")
|
|
{
|
|
if (compile_dve2(file, verbose))
|
|
{
|
|
if (verbose)
|
|
std::cerr << "Failed to compile `" << file_arg
|
|
<< "'." << std::endl;
|
|
return 0;
|
|
}
|
|
}
|
|
else if (ext != ".dve2C")
|
|
{
|
|
if (verbose)
|
|
std::cerr << "Unknown extension `" << ext
|
|
<< "'. Use `.dve' or `.dve2C'." << std::endl;
|
|
return 0;
|
|
}
|
|
|
|
if (lt_dlinit())
|
|
{
|
|
if (verbose)
|
|
std::cerr << "Failed to initialize libltdl." << std::endl;
|
|
return 0;
|
|
}
|
|
|
|
lt_dlhandle h = lt_dlopen(file.c_str());
|
|
if (!h)
|
|
{
|
|
if (verbose)
|
|
std::cerr << "Failed to load `" << file << "'." << std::endl;
|
|
lt_dlexit();
|
|
return 0;
|
|
}
|
|
|
|
dve2_interface* d = new dve2_interface;
|
|
d->handle = h;
|
|
|
|
d->get_initial_state = (void (*)(void*))
|
|
lt_dlsym(h, "get_initial_state");
|
|
d->have_property = (int (*)())
|
|
lt_dlsym(h, "have_property");
|
|
d->get_successors = (int (*)(void*, int*, TransitionCB, void*))
|
|
lt_dlsym(h, "get_successors");
|
|
d->get_state_variable_count = (int (*)())
|
|
lt_dlsym(h, "get_state_variable_count");
|
|
d->get_state_variable_name = (const char* (*)(int))
|
|
lt_dlsym(h, "get_state_variable_name");
|
|
d->get_state_variable_type = (int (*)(int))
|
|
lt_dlsym(h, "get_state_variable_type");
|
|
d->get_state_variable_type_count = (int (*)())
|
|
lt_dlsym(h, "get_state_variable_type_count");
|
|
d->get_state_variable_type_name = (const char* (*)(int))
|
|
lt_dlsym(h, "get_state_variable_type_name");
|
|
d->get_state_variable_type_value_count = (int (*)(int))
|
|
lt_dlsym(h, "get_state_variable_type_value_count");
|
|
d->get_state_variable_type_value = (const char* (*)(int, int))
|
|
lt_dlsym(h, "get_state_variable_type_value");
|
|
d->get_transition_count = (int (*)())
|
|
lt_dlsym(h, "get_transition_count");
|
|
|
|
if (!(d->get_initial_state
|
|
&& d->have_property
|
|
&& d->get_successors
|
|
&& d->get_state_variable_count
|
|
&& d->get_state_variable_name
|
|
&& d->get_state_variable_type
|
|
&& d->get_state_variable_type_count
|
|
&& d->get_state_variable_type_name
|
|
&& d->get_state_variable_type_value_count
|
|
&& d->get_state_variable_type_value
|
|
&& d->get_transition_count))
|
|
{
|
|
if (verbose)
|
|
std::cerr << "Failed to resolve some symbol while loading `"
|
|
<< file << "'" << std::endl;
|
|
delete d;
|
|
lt_dlexit();
|
|
return 0;
|
|
}
|
|
|
|
if (d->have_property())
|
|
{
|
|
if (verbose)
|
|
std::cerr << "Model with an embedded property are not supported."
|
|
<< std::endl;
|
|
delete d;
|
|
lt_dlexit();
|
|
return 0;
|
|
}
|
|
|
|
prop_set* ps = new prop_set;
|
|
int errors = convert_aps(to_observe, d, dict, dead, *ps);
|
|
if (errors)
|
|
{
|
|
delete ps;
|
|
dict->unregister_all_my_variables(d);
|
|
delete d;
|
|
lt_dlexit();
|
|
return 0;
|
|
}
|
|
|
|
return new dve2_kripke(d, dict, ps, dead, compress);
|
|
}
|
|
}
|