Adding support for promela models via SpinS.

* configure.ac, iface/Makefile.am: Adjust.
* iface/dve2/finite.test, iface/dve2/.gitignore, iface/dve2/Makefile.am,
iface/dve2/README, iface/dve2/beem-peterson.4.dve,
iface/dve2/dve2check.test, iface/dve2/defs.in, iface/dve2/finite.dve,
iface/ltsmin/finite.test, iface/dve2/kripke.test, iface/dve2/dve2.cc,
iface/dve2/dve2.hh, iface/dve2/dve2check.cc: Move to iface/ltsmin.
* iface/ltsmin/.gitignore, iface/ltsmin/Makefile.am,
iface/ltsmin/README, iface/ltsmin/beem-peterson.4.dve,
iface/ltsmin/check.test, iface/ltsmin/defs.in, iface/ltsmin/finite.dve,
iface/ltsmin/finite.test, iface/ltsmin/kripke.test,
iface/ltsmin/ltsmin.cc, iface/ltsmin/ltsmin.hh,
iface/ltsmin/modelcheck.cc: Factorize dve2 and spins interface in
iface/ltsmin/
* iface/ltsmin/elevator2.1.pm, iface/ltsmin/finite.pm: Test promela
models.
* README: Document iface/ltsmin/ directory.
This commit is contained in:
Thibaud Michaud 2014-11-03 15:16:56 +01:00 committed by Alexandre Duret-Lutz
parent 6dd2749c25
commit dd4b821d93
18 changed files with 396 additions and 232 deletions

2
README
View file

@ -180,7 +180,7 @@ wrap/ Wrappers for other languages.
tests/ Tests for these bindings
ajax/ LTL-to-TGBA translator with web interface, using Ajax.
iface/ Interfaces to other libraries.
dve2/ Interface with DiVinE2.
ltsmin/ Interface with DiVinE2 and SpinS.
Third party software
--------------------

View file

@ -169,8 +169,8 @@ AC_CONFIG_FILES([
doc/Makefile
doc/tl/Makefile
doc/org/init.el
iface/dve2/defs
iface/dve2/Makefile
iface/ltsmin/defs
iface/ltsmin/Makefile
iface/Makefile
lib/Makefile
src/bin/Makefile

View file

@ -17,4 +17,4 @@
## You should have received a copy of the GNU General Public License
## along with this program. If not, see <http://www.gnu.org/licenses/>.
SUBDIRS = dve2
SUBDIRS = ltsmin

View file

@ -1,57 +0,0 @@
#!/bin/sh
# Copyright (C) 2011, 2013 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/>.
. ./defs
divine compile > output 2>&1
if grep -i ltsmin output; then
:
else
echo "divine not installed, or no ltsmin interface"
exit 77
fi
set -e
run 0 ../dve2check -gm $srcdir/finite.dve '"P.a < 10"' > stdout
test `grep ' -> ' stdout | wc -l` = 25
test `grep 'P.a=' stdout | wc -l` = 15
run 0 ../dve2check -dtrue -gm $srcdir/finite.dve '"P.a < 10"' > stdout2
cmp stdout stdout2
run 0 ../dve2check -dfalse -gm $srcdir/finite.dve '"P.a < 10"' > stdout
test `grep ' -> ' stdout | wc -l` = 19
test `grep 'P.a=' stdout | wc -l` = 15
# the same with compressed states
run 0 ../dve2check -z -dfalse -gm $srcdir/finite.dve '"P.a < 10"' > stdout
test `grep ' -> ' stdout | wc -l` = 19
test `grep 'P.a=' stdout | wc -l` = 15
run 0 ../dve2check -ddead -E $srcdir/finite.dve \
'!(G(dead -> ("P.a==3" | "P.b==3")))'
run 0 ../dve2check -ddead -e $srcdir/finite.dve \
'!(G(dead -> ("P.a==2" | "P.b==3")))'
# This used to segfault because of a bug in
# tgba_product::transition_annotation.
run 0 ../dve2check -gp $srcdir/finite.dve true

View file

@ -1,5 +1,7 @@
*.dve2C
*.dve.cpp
dve2check
defs
*.dir
*.spins
*.c
check

View file

@ -18,26 +18,26 @@
AM_CPPFLAGS = -I$(top_srcdir)/src -I$(top_builddir)/src \
$(BUDDY_CPPFLAGS) -I$(top_srcdir)/ltdl
AM_CXXFLAGS = $(WARNING_CXXFLAGS)
AM_CXXFLAGS = $(WARNING_CXXFLAGS) -lpthread
dve2dir = $(pkgincludedir)/iface/dve2
ltsmindir = $(pkgincludedir)/iface/ltsmin
dve2_HEADERS = dve2.hh
ltsmin_HEADERS = ltsmin.hh
lib_LTLIBRARIES = libspotdve2.la
libspotdve2_la_LIBADD = \
lib_LTLIBRARIES = libspotltsmin.la
libspotltsmin_la_LIBADD = \
$(top_builddir)/src/libspot.la \
$(top_builddir)/ltdl/libltdlc.la
libspotdve2_la_SOURCES = dve2.cc
libspotltsmin_la_SOURCES = ltsmin.cc
noinst_PROGRAMS = dve2check
noinst_PROGRAMS = modelcheck
dve2check_SOURCES = dve2check.cc
dve2check_LDADD = libspotdve2.la
modelcheck_SOURCES = modelcheck.cc
modelcheck_LDADD = libspotltsmin.la
check_SCRIPTS = defs
TESTS = dve2check.test finite.test kripke.test
TESTS = check.test finite.test kripke.test
EXTRA_DIST = $(TESTS) beem-peterson.4.dve finite.dve
kripke.test: $(top_builddir)/src/kripketest/parse_print$(EXEEXT)

View file

@ -1,5 +1,5 @@
This directory contains an interface that presents DiVinE models as
kripke* objects for Spot.
This directory contains an interface that presents DiVinE and PROMELA
models as kripke* objects for Spot.
The DiVinE model checker [http://anna.fi.muni.cz/divine/] has a
specification language called DVE that makes it easy to model
@ -9,16 +9,12 @@ processes synchonizing through channels
A lot of models can be found in the BEEM database at
http://anna.fi.muni.cz/models/
For efficient generation of the state space of the model, DiVinE
compiles the DVE input into a dynamic library that contains anything
needed to generate the state-space.
The LTSmin people [http://fmt.cs.utwente.nl/tools/ltsmin/] have made a
patched version of DiVinE that compiles a dynamic library with a very
simple C interface (no C++) and extra information about state
variables (name, type, possible values). We are using this interface,
therefore you need to install their version of DiVinE in order to use
Spot's DVE interface.
The LTSmin people [http://fmt.cs.utwente.nl/tools/ltsmin/] patched
DiVinE and SpinJa to compile models as dynamic libraries. This dynamic
library provides a very simple C interface (no C++) and extra
information about state variables (name, type, possible values). We
use this interface so you will need to install their version of these
tools to use Spot with DVE or PROMELA models.
@ -47,14 +43,32 @@ model.dve2C (which is a dynamic library).
divine compile --ltsmin model.dve
Installation of SpinS
======================
The extended version of SpinJa is called SpinS and should be included
with LTSmin.
You can download LTSmin from their website:
[http://fmt.cs.utwente.nl/tools/ltsmin/] and install it following the
INSTALL instructions.
To compile a promela model, simply run the following command:
spins model.pm
It should create a dynamic library called model.pm.spins in the
current directory.
Usage with Spot
===============
The function load_dve2() defined in dve2.hh in this directory
will accept "model.dve" or "model.dve2C" as file argument.
In the former case, it will call "divine compile --ltsmin"
if "model.dve2C" does not exist or is older. Then it will
load "model.dve2C" dynamically.
The function load_dve2() defined in dve2.hh in this directory will
accept either a model or its compiled version as file argument. In
the former case, it will call "divine compile --ltsmin model.dve" or
"spins model.pm" depending on the file extension, only if a compiled
model with the corresponding file extension (.dve2C or .spins) does
not exist or is older. Then it will load the compiled model
dynamically.
load_dve2() also requires a set of atomic propositions that should
be observed in the model. These are usually the atomic propositions
@ -89,15 +103,15 @@ Usage with Spot
"P_0.j >= 2" Process P_0's variable j is greater or equal to 2.
P_0.j This is equivalent to "P_0.j != 0".
Comparisons operators available are "<", ">", ">=", "<=", "==", and
"!=". The left operant should always be a variable and the right
Comparison operators available are "<", ">", ">=", "<=", "==", and
"!=". The left operand should always be a variable and the right
operand should always be a number, so you cannot write something
like "P_0.j <= P_0.i".
Because the LTL parser knows nothing about the details of the
languages we interface with, every atomic proposition that cannot be
express using only alphanumeric characters (plus `_' and `.') should
be enclosed in double quote.
expressed using only alphanumeric characters (plus `_' and `.')
should be enclosed in double quote.
Caveat: "P_0.j >= 2" and " P_0.j>=2" (watch the spaces!) are
considered to be two distinct atomic propositions with the same

View file

@ -1,5 +1,5 @@
#!/bin/sh
# Copyright (C) 2011, 2012 Laboratoire de Recherche et Développement
# Copyright (C) 2011, 2012, 2014 Laboratoire de Recherche et Développement
# de l'Epita (LRDE).
#
# This file is part of Spot, a model checking library.
@ -29,32 +29,47 @@ else
exit 77
fi
if ! test -x "$(which spins)"; then
echo "spins not installed."
exit 77
fi
set -e
# Promela
for opt in '' '-z'; do
run 0 ../modelcheck $opt -E $srcdir/elevator2.1.pm \
'!G("req[1]==1" -> (F("p==1" && "cabin_0._pc==2")))'
run 0 ../modelcheck $opt -e $srcdir/elevator2.1.pm \
'F("p==2")'
done
# dve2
for opt in '' '-z'; do
# The three examples from the README.
# (Don't run the first one using "run 0" because it would take too much
# time with valgrind.).
../dve2check $opt -E $srcdir/beem-peterson.4.dve \
../modelcheck $opt -E $srcdir/beem-peterson.4.dve \
'!GF(P_0.CS|P_1.CS|P_2.CS|P_3.CS)' \
| grep -v pages > stdout1
# same formula, different syntax.
../dve2check $opt -E $srcdir/beem-peterson.4.dve \
../modelcheck $opt -E $srcdir/beem-peterson.4.dve \
'!GF("P_0==CS"|"P_1 == CS"|"P_2 ==CS"|"P_3== CS")' \
| grep -v pages > stdout2
cmp stdout1 stdout2
run 0 ../dve2check $opt -e $srcdir/beem-peterson.4.dve \
run 0 ../modelcheck $opt -e $srcdir/beem-peterson.4.dve \
'!G(P_0.wait -> F P_0.CS)'
run 0 ../dve2check $opt -e $srcdir/beem-peterson.4.dve '!G("pos[1] < 3")'
run 0 ../modelcheck $opt -e $srcdir/beem-peterson.4.dve '!G("pos[1] < 3")'
done
# Now check some error messages.
run 1 ../dve2check foo.dve "F(P_0.CS)" 2>stderr
run 1 ../modelcheck foo.dve "F(P_0.CS)" 2>stderr
cat stderr
grep 'Cannot open' stderr
# the dve2C file was generated in the current directory
run 1 ../dve2check beem-peterson.4.dve2C \
run 1 ../modelcheck beem-peterson.4.dve2C \
'Xfoo | P_0.f & X"P_0.k < 2xx" | G"pos[0]"' 2>stderr
cat stderr
grep 'variable `foo' stderr

View file

@ -0,0 +1,61 @@
byte req[4];
int t=0;
int p=0;
byte v=0;
active proctype cabin() {
idle: if
:: v>0; goto mov;
fi;
mov: if
:: t==p; goto open;
:: d_step {t<p;p = p-1;} goto mov;
:: d_step {t>p;p = p+1;} goto mov;
fi;
open: if
:: d_step {req[p] = 0;v = 0;} goto idle;
fi;
}
active proctype environment() {
read: if
:: d_step {req[0]==0;req[0] = 1;} goto read;
:: d_step {req[1]==0;req[1] = 1;} goto read;
:: d_step {req[2]==0;req[2] = 1;} goto read;
:: d_step {req[3]==0;req[3] = 1;} goto read;
fi;
}
active proctype controller() {
byte ldir=0;
wait: if
:: d_step {v==0;t = t+(2*ldir)-1;} goto work;
fi;
work: if
:: d_step {t<0 || t==4;ldir = 1-ldir;} goto wait;
:: t>=0 && t<4 && req[t]==1; goto done;
:: d_step {t>=0 && t<4 && req[t]==0;t = t+(2*ldir)-1;} goto work;
fi;
done: if
:: v = 1; goto wait;
fi;
}

8
iface/ltsmin/finite.pm Normal file
View file

@ -0,0 +1,8 @@
active proctype P() {
int a = 0;
int b = 0;
x: if
:: d_step {a < 3 && b < 3; a = a + 1; } goto x;
:: d_step {a < 3 && b < 3; b = b + 1; } goto x;
fi;
}

90
iface/ltsmin/finite.test Executable file
View file

@ -0,0 +1,90 @@
#!/bin/sh
# Copyright (C) 2011, 2013 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/>.
. ./defs
divine compile > output 2>&1
if grep -i ltsmin output; then
:
else
echo "divine not installed, or no ltsmin interface"
exit 77
fi
if ! test -x "$(which spins)"; then
echo "spins not installed."
exit 77
fi
set -e
run 0 ../modelcheck -gm $srcdir/finite.dve '"P.a < 10"' > stdout
test `grep ' -> ' stdout | wc -l` = 25
test `grep 'P.a=' stdout | wc -l` = 15
run 0 ../modelcheck -dtrue -gm $srcdir/finite.dve '"P.a < 10"' > stdout2
cmp stdout stdout2
run 0 ../modelcheck -dfalse -gm $srcdir/finite.dve '"P.a < 10"' > stdout
test `grep ' -> ' stdout | wc -l` = 19
test `grep 'P.a=' stdout | wc -l` = 15
# the same with compressed states
run 0 ../modelcheck -z -dfalse -gm $srcdir/finite.dve '"P.a < 10"' > stdout
test `grep ' -> ' stdout | wc -l` = 19
test `grep 'P.a=' stdout | wc -l` = 15
run 0 ../modelcheck -ddead -E $srcdir/finite.dve \
'!(G(dead -> ("P.a==3" | "P.b==3")))'
run 0 ../modelcheck -ddead -e $srcdir/finite.dve \
'!(G(dead -> ("P.a==2" | "P.b==3")))'
# This used to segfault because of a bug in
# tgba_product::transition_annotation.
run 0 ../modelcheck -gp $srcdir/finite.dve true
# Same tests with finite.pm.
# Compile it beforehand to avoid compiler's output interference.
spins $srcdir/finite.pm
run 0 ../modelcheck -gm $srcdir/finite.pm.spins '"P_0.a < 10"' > stdout
test `grep ' -> ' stdout | wc -l` = 25
test `grep 'P_0.a=' stdout | wc -l` = 15
run 0 ../modelcheck -dtrue -gm $srcdir/finite.pm.spins '"P_0.a < 10"' > stdout2
diff stdout stdout2
run 0 ../modelcheck -dfalse -gm $srcdir/finite.pm.spins '"P_0.a < 10"' > stdout
test `grep ' -> ' stdout | wc -l` = 19
test `grep 'P_0.a=' stdout | wc -l` = 15
# the same with compressed states
run 0 ../modelcheck -z -dfalse -gm $srcdir/finite.pm.spins '"P_0.a < 10"' \
> stdout
test `grep ' -> ' stdout | wc -l` = 19
test `grep 'P_0.a=' stdout | wc -l` = 15
run 0 ../modelcheck -ddead -E $srcdir/finite.pm.spins \
'!(G(dead -> ("P_0.a==3" | "P_0.b==3")))'
run 0 ../modelcheck -ddead -e $srcdir/finite.pm.spins \
'!(G(dead -> ("P_0.a==2" | "P_0.b==3")))'
run 0 ../modelcheck -gp $srcdir/finite.pm.spins true

View file

@ -33,10 +33,10 @@ fi
set -e
run 0 ../dve2check -gK ${srcdir}/finite.dve 'F("P.a > 5")' > output
run 0 ../modelcheck -gK ${srcdir}/finite.dve 'F("P.a > 5")' > output
run 0 ${top_builddir}/src/kripketest/parse_print output | tr -d '"' > output2
tr -d '"' < output >outputF
cmp outputF output2
../dve2check -gK $srcdir/beem-peterson.4.dve '!G("pos[1] < 3")' > outputP
../modelcheck -gK $srcdir/beem-peterson.4.dve '!G("pos[1] < 3")' > outputP
${top_builddir}/src/tgbatest/ltl2tgba -e -KPoutputP '!G("pos[1] < 3")'

View file

@ -30,21 +30,20 @@
# define WEXITSTATUS(x) ((x) & 0xff)
#endif
#include "dve2.hh"
#include "ltsmin.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
// spins interface
typedef struct transition_info {
int* labels; // edge labels, NULL, or pointer to the edge label(s)
@ -55,29 +54,27 @@ namespace spot
transition_info_t *transition_info,
int *dst);
struct dve2_interface
struct spins_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)();
int (*get_state_size)();
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)();
int (*get_type_count)();
const char* (*get_type_name)(int type);
int (*get_type_value_count)(int type);
const char* (*get_type_value_name)(int type, int value);
};
////////////////////////////////////////////////////////////////////////
// STATE
struct dve2_state: public state
struct spins_state: public state
{
dve2_state(int s, fixed_size_pool* p)
spins_state(int s, fixed_size_pool* p)
: pool(p), size(s), count(1)
{
}
@ -89,10 +86,10 @@ namespace spot
hash_value = wang32_hash(hash_value ^ vars[i]);
}
dve2_state* clone() const
spins_state* clone() const
{
++count;
return const_cast<dve2_state*>(this);
return const_cast<spins_state*>(this);
}
void destroy() const
@ -111,7 +108,7 @@ namespace spot
{
if (this == other)
return 0;
const dve2_state* o = down_cast<const dve2_state*>(other);
const spins_state* o = down_cast<const spins_state*>(other);
assert(o);
if (hash_value < o->hash_value)
return -1;
@ -122,7 +119,7 @@ namespace spot
private:
~dve2_state()
~spins_state()
{
}
@ -134,9 +131,9 @@ namespace spot
int vars[0];
};
struct dve2_compressed_state: public state
struct spins_compressed_state: public state
{
dve2_compressed_state(int s, multiple_size_pool* p)
spins_compressed_state(int s, multiple_size_pool* p)
: pool(p), size(s), count(1)
{
}
@ -148,10 +145,10 @@ namespace spot
hash_value = wang32_hash(hash_value ^ vars[i]);
}
dve2_compressed_state* clone() const
spins_compressed_state* clone() const
{
++count;
return const_cast<dve2_compressed_state*>(this);
return const_cast<spins_compressed_state*>(this);
}
void destroy() const
@ -170,8 +167,8 @@ namespace spot
{
if (this == other)
return 0;
const dve2_compressed_state* o =
down_cast<const dve2_compressed_state*>(other);
const spins_compressed_state* o =
down_cast<const spins_compressed_state*>(other);
assert(o);
if (hash_value < o->hash_value)
return -1;
@ -188,7 +185,7 @@ namespace spot
private:
~dve2_compressed_state()
~spins_compressed_state()
{
}
@ -223,8 +220,8 @@ namespace spot
{
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);
spins_state* out =
new(p->allocate()) spins_state(ctx->state_size, p);
memcpy(out->vars, dst, ctx->state_size * sizeof(int));
out->compute_hash();
ctx->transitions.push_back(out);
@ -238,9 +235,9 @@ namespace spot
size_t csize = ctx->state_size * 2;
ctx->compress(dst, ctx->state_size, ctx->compressed, csize);
void* mem = p->allocate(sizeof(dve2_compressed_state)
void* mem = p->allocate(sizeof(spins_compressed_state)
+ sizeof(int) * csize);
dve2_compressed_state* out = new(mem) dve2_compressed_state(csize, p);
spins_compressed_state* out = new(mem) spins_compressed_state(csize, p);
memcpy(out->vars, ctx->compressed, csize * sizeof(int));
out->compute_hash();
ctx->transitions.push_back(out);
@ -249,11 +246,11 @@ namespace spot
////////////////////////////////////////////////////////////////////////
// SUCC_ITERATOR
class dve2_succ_iterator: public kripke_succ_iterator
class spins_succ_iterator: public kripke_succ_iterator
{
public:
dve2_succ_iterator(const callback_context* cc,
spins_succ_iterator(const callback_context* cc,
bdd cond)
: kripke_succ_iterator(cond), cc_(cc)
{
@ -266,7 +263,7 @@ namespace spot
kripke_succ_iterator::recycle(cond);
}
~dve2_succ_iterator()
~spins_succ_iterator()
{
delete cc_;
}
@ -327,14 +324,14 @@ namespace spot
int
convert_aps(const ltl::atomic_prop_set* aps,
const dve2_interface* d,
const spins_interface* d,
bdd_dict_ptr dict,
const ltl::formula* dead,
prop_set& out)
{
int errors = 0;
int state_size = d->get_state_variable_count();
int state_size = d->get_state_size();
typedef std::map<std::string, var_info> val_map_t;
val_map_t val_map;
@ -346,14 +343,14 @@ namespace spot
val_map[name] = v;
}
int type_count = d->get_state_variable_type_count();
int type_count = d->get_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);
int enum_count = d->get_type_value_count(i);
for (int j = 0; j < enum_count; ++j)
enum_map[i].emplace(d->get_state_variable_type_value(i, j), j);
enum_map[i].emplace(d->get_type_value_name(i, j), j);
}
for (ltl::atomic_prop_set::const_iterator ap = aps->begin();
@ -600,15 +597,15 @@ namespace spot
////////////////////////////////////////////////////////////////////////
// KRIPKE
class dve2_kripke: public kripke
class spins_kripke: public kripke
{
public:
dve2_kripke(const dve2_interface* d, const bdd_dict_ptr& dict,
spins_kripke(const spins_interface* d, const bdd_dict_ptr& dict,
const prop_set* ps, const ltl::formula* dead, int compress)
: kripke(dict),
d_(d),
state_size_(d_->get_state_variable_count()),
state_size_(d_->get_state_size()),
dict_(dict), ps_(ps),
compress_(compress == 0 ? 0
: compress == 1 ? int_array_array_compress
@ -618,8 +615,8 @@ namespace spot
: 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))),
statepool_(compress ? sizeof(spins_compressed_state) :
(sizeof(spins_state) + state_size_ * sizeof(int))),
state_condition_last_state_(0), state_condition_last_cc_(0)
{
vname_ = new const char*[state_size_];
@ -632,7 +629,7 @@ namespace spot
// output.
int type = d->get_state_variable_type(i);
format_filter_[i] =
(d->get_state_variable_type_value_count(type) != 1);
(d->get_type_value_count(type) != 1);
}
// Register the "dead" proposition. There are three cases to
@ -666,7 +663,7 @@ namespace spot
}
}
~dve2_kripke()
~spins_kripke()
{
if (iter_cache_)
{
@ -704,10 +701,10 @@ namespace spot
multiple_size_pool* p =
const_cast<multiple_size_pool*>(&compstatepool_);
void* mem = p->allocate(sizeof(dve2_compressed_state)
void* mem = p->allocate(sizeof(spins_compressed_state)
+ sizeof(int) * csize);
dve2_compressed_state* res = new(mem)
dve2_compressed_state(csize, p);
spins_compressed_state* res = new(mem)
spins_compressed_state(csize, p);
memcpy(res->vars, compressed_, csize * sizeof(int));
res->compute_hash();
return res;
@ -715,7 +712,7 @@ namespace spot
else
{
fixed_size_pool* p = const_cast<fixed_size_pool*>(&statepool_);
dve2_state* res = new(p->allocate()) dve2_state(state_size_, p);
spins_state* res = new(p->allocate()) spins_state(state_size_, p);
d_->get_initial_state(res->vars);
res->compute_hash();
return res;
@ -828,8 +825,8 @@ namespace spot
const int* vars;
if (compress_)
{
const dve2_compressed_state* s =
down_cast<const dve2_compressed_state*>(st);
const spins_compressed_state* s =
down_cast<const spins_compressed_state*>(st);
assert(s);
decompress_(s->vars, s->size, uncompressed_, state_size_);
@ -837,7 +834,7 @@ namespace spot
}
else
{
const dve2_state* s = down_cast<const dve2_state*>(st);
const spins_state* s = down_cast<const spins_state*>(st);
assert(s);
vars = s->vars;
}
@ -846,7 +843,7 @@ namespace spot
virtual
dve2_succ_iterator*
spins_succ_iterator*
succ_iter(const state* st) const
{
// This may also compute successors in state_condition_last_cc
@ -870,13 +867,13 @@ namespace spot
if (iter_cache_)
{
dve2_succ_iterator* it =
down_cast<dve2_succ_iterator*>(iter_cache_);
spins_succ_iterator* it =
down_cast<spins_succ_iterator*>(iter_cache_);
it->recycle(cc, scond);
iter_cache_ = nullptr;
return it;
}
return new dve2_succ_iterator(cc, scond);
return new spins_succ_iterator(cc, scond);
}
virtual
@ -920,7 +917,7 @@ namespace spot
}
private:
const dve2_interface* d_;
const spins_interface* d_;
int state_size_;
bdd_dict_ptr dict_;
const char** vname_;
@ -952,13 +949,32 @@ namespace spot
// LOADER
// Call divine to compile "foo.dve" as "foo.dve2C" if the latter
// Call spins to compile "foo.prom" as "foo.prom.spins" if the latter
// does not exist already or is older.
bool
compile_dve2(std::string& filename, bool verbose)
compile_model(std::string& filename, std::string& ext, bool verbose)
{
std::string command;
std::string compiled_ext;
std::string command = "divine compile --ltsmin " + filename;
if (ext == ".prom" || ext == ".pm" || ext == ".pml")
{
command = "spins " + filename;
compiled_ext = ".spins";
}
else if (ext == ".dve")
{
command = "divine compile --ltsmin " + filename;
compiled_ext = "2C";
}
else
{
if (verbose)
std::cerr << "Unknown extension `" << ext
<< "'. Use `.prom', `.pm', `.pml', `.dve', `.dve2C' or"\
"`.prom.spins'." << std::endl;
return false;
}
struct stat s;
if (stat(filename.c_str(), &s) != 0)
@ -971,7 +987,7 @@ namespace spot
}
std::string old = filename;
filename += "2C";
filename += compiled_ext;
// Remove any directory, because the new file will
// be compiled in the current directory.
@ -982,7 +998,7 @@ namespace spot
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.
// The .prom.spins is up-to-date, no need to recompile it.
return false;
int res = system(command.c_str());
@ -997,9 +1013,8 @@ namespace spot
return false;
}
kripke_ptr
load_dve2(const std::string& file_arg, const bdd_dict_ptr& dict,
load_model(const std::string& file_arg, const bdd_dict_ptr& dict,
const ltl::atomic_prop_set* to_observe,
const ltl::formula* dead,
int compress,
@ -1012,22 +1027,15 @@ namespace spot
file = "./" + file_arg;
std::string ext = file.substr(file.find_last_of("."));
if (ext == ".dve")
if (ext != ".spins" && ext != ".dve2C")
{
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 (compile_model(file, ext, verbose))
{
if (verbose)
std::cerr << "Failed to compile `" << file_arg
<< "'." << std::endl;
return 0;
}
}
if (lt_dlinit())
@ -1046,43 +1054,66 @@ namespace spot
return 0;
}
dve2_interface* d = new dve2_interface;
spins_interface* d = new spins_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");
// SpinS interface.
if ((d->get_initial_state = (void (*)(void*))
lt_dlsym(h, "spins_get_initial_state")))
{
d->have_property = nullptr;
d->get_successors = (int (*)(void*, int*, TransitionCB, void*))
lt_dlsym(h, "spins_get_successor_all");
d->get_state_size = (int (*)())
lt_dlsym(h, "spins_get_state_size");
d->get_state_variable_name = (const char* (*)(int))
lt_dlsym(h, "spins_get_state_variable_name");
d->get_state_variable_type = (int (*)(int))
lt_dlsym(h, "spins_get_state_variable_type");
d->get_type_count = (int (*)())
lt_dlsym(h, "spins_get_type_count");
d->get_type_name = (const char* (*)(int))
lt_dlsym(h, "spins_get_type_name");
d->get_type_value_count = (int (*)(int))
lt_dlsym(h, "spins_get_type_value_count");
d->get_type_value_name = (const char* (*)(int, int))
lt_dlsym(h, "spins_get_type_value_name");
}
// dve2 interface.
else
{
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_size = (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_type_count = (int (*)())
lt_dlsym(h, "get_state_variable_type_count");
d->get_type_name = (const char* (*)(int))
lt_dlsym(h, "get_state_variable_type_name");
d->get_type_value_count = (int (*)(int))
lt_dlsym(h, "get_state_variable_type_value_count");
d->get_type_value_name = (const char* (*)(int, int))
lt_dlsym(h, "get_state_variable_type_value");
}
if (!(d->get_initial_state
&& d->have_property
if (!(
d->get_initial_state
&& d->get_successors
&& d->get_state_variable_count
&& d->get_state_size
&& 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))
&& d->get_type_count
&& d->get_type_name
&& d->get_type_value_count
&& d->get_type_value_name))
{
if (verbose)
std::cerr << "Failed to resolve some symbol while loading `"
@ -1092,14 +1123,14 @@ namespace spot
return 0;
}
if (d->have_property())
if (d->have_property && d->have_property())
{
if (verbose)
std::cerr << "Model with an embedded property are not supported."
<< std::endl;
delete d;
lt_dlexit();
return 0;
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;
@ -1113,6 +1144,6 @@ namespace spot
return 0;
}
return std::make_shared<dve2_kripke>(d, dict, ps, dead, compress);
return std::make_shared<spins_kripke>(d, dict, ps, dead, compress);
}
}

View file

@ -17,8 +17,8 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef SPOT_IFACE_DVE2_DVE2_HH
# define SPOT_IFACE_DVE2_DVE2_HH
#ifndef SPOT_IFACE_PROMELA_PROMELA_HH
# define SPOT_IFACE_PROMELA_PROMELA_HH
#include "kripke/kripke.hh"
#include "ltlvisit/apcollect.hh"
@ -28,11 +28,11 @@
namespace spot
{
// \brief Load a DVE model.
// \brief Load a PROMELA model.
//
// The filename given can be either a *.dve source or a *.dve2C
// dynamic library compiled with "divine compile --ltsmin file".
// When the *.dve source is supplied, the *.dve2C will be updated
// The filename given can be either a *.prom source or a *.spins
// dynamic library compiled with "spins file".
// When the *.prom source is supplied, the *.spins will be updated
// only if it is not newer.
//
// The dead parameter is used to control the behavior of the model
@ -48,8 +48,7 @@ namespace spot
//
// This function returns 0 on error.
//
// \a file the name of the *.dve source file or of the *.dve2C
// dynamic library
// \a file the name of the *.prom source file or the dynamic library
// \a to_observe the list of atomic propositions that should be observed
// in the model
// \a dict the BDD dictionary to use
@ -57,10 +56,10 @@ namespace spot
// dead states
// \a verbose whether to output verbose messages
SPOT_API kripke_ptr
load_dve2(const std::string& file, const bdd_dict_ptr& dict,
load_model(const std::string& file, const bdd_dict_ptr& dict,
const ltl::atomic_prop_set* to_observe,
const ltl::formula* dead = ltl::constant::true_instance(),
int compress = 0, bool verbose = true);
}
#endif // SPOT_IFACE_DVE2_DVE2_HH
#endif // SPOT_IFACE_PROMELA_PROMELA_HH

View file

@ -17,7 +17,7 @@
// 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 "dve2.hh"
#include "ltsmin.hh"
#include "tgbaalgos/dotty.hh"
#include "ltlenv/defaultenv.hh"
#include "ltlast/allnodes.hh"
@ -217,9 +217,10 @@ checked_main(int argc, char **argv)
if (output != DotFormula)
{
tm.start("loading dve2");
model = spot::load_dve2(argv[1], dict, &ap, deadf, compress_states, true);
tm.stop("loading dve2");
tm.start("loading spins");
model = spot::load_model(argv[1], dict, &ap, deadf,
compress_states, true);
tm.stop("loading spins");
if (!model)
{