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 tests/ Tests for these bindings
ajax/ LTL-to-TGBA translator with web interface, using Ajax. ajax/ LTL-to-TGBA translator with web interface, using Ajax.
iface/ Interfaces to other libraries. iface/ Interfaces to other libraries.
dve2/ Interface with DiVinE2. ltsmin/ Interface with DiVinE2 and SpinS.
Third party software Third party software
-------------------- --------------------

View file

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

View file

@ -17,4 +17,4 @@
## You should have received a copy of the GNU General Public License ## You should have received a copy of the GNU General Public License
## along with this program. If not, see <http://www.gnu.org/licenses/>. ## 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 *.dve2C
*.dve.cpp *.dve.cpp
dve2check
defs defs
*.dir *.dir
*.spins
*.c
check

View file

@ -18,26 +18,26 @@
AM_CPPFLAGS = -I$(top_srcdir)/src -I$(top_builddir)/src \ AM_CPPFLAGS = -I$(top_srcdir)/src -I$(top_builddir)/src \
$(BUDDY_CPPFLAGS) -I$(top_srcdir)/ltdl $(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 lib_LTLIBRARIES = libspotltsmin.la
libspotdve2_la_LIBADD = \ libspotltsmin_la_LIBADD = \
$(top_builddir)/src/libspot.la \ $(top_builddir)/src/libspot.la \
$(top_builddir)/ltdl/libltdlc.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 modelcheck_SOURCES = modelcheck.cc
dve2check_LDADD = libspotdve2.la modelcheck_LDADD = libspotltsmin.la
check_SCRIPTS = defs 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 EXTRA_DIST = $(TESTS) beem-peterson.4.dve finite.dve
kripke.test: $(top_builddir)/src/kripketest/parse_print$(EXEEXT) 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 This directory contains an interface that presents DiVinE and PROMELA
kripke* objects for Spot. models as kripke* objects for Spot.
The DiVinE model checker [http://anna.fi.muni.cz/divine/] has a The DiVinE model checker [http://anna.fi.muni.cz/divine/] has a
specification language called DVE that makes it easy to model 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 A lot of models can be found in the BEEM database at
http://anna.fi.muni.cz/models/ http://anna.fi.muni.cz/models/
For efficient generation of the state space of the model, DiVinE The LTSmin people [http://fmt.cs.utwente.nl/tools/ltsmin/] patched
compiles the DVE input into a dynamic library that contains anything DiVinE and SpinJa to compile models as dynamic libraries. This dynamic
needed to generate the state-space. library provides a very simple C interface (no C++) and extra
information about state variables (name, type, possible values). We
The LTSmin people [http://fmt.cs.utwente.nl/tools/ltsmin/] have made a use this interface so you will need to install their version of these
patched version of DiVinE that compiles a dynamic library with a very tools to use Spot with DVE or PROMELA models.
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.
@ -47,14 +43,32 @@ model.dve2C (which is a dynamic library).
divine compile --ltsmin model.dve 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 Usage with Spot
=============== ===============
The function load_dve2() defined in dve2.hh in this directory The function load_dve2() defined in dve2.hh in this directory will
will accept "model.dve" or "model.dve2C" as file argument. accept either a model or its compiled version as file argument. In
In the former case, it will call "divine compile --ltsmin" the former case, it will call "divine compile --ltsmin model.dve" or
if "model.dve2C" does not exist or is older. Then it will "spins model.pm" depending on the file extension, only if a compiled
load "model.dve2C" dynamically. 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 load_dve2() also requires a set of atomic propositions that should
be observed in the model. These are usually the atomic propositions 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 >= 2" Process P_0's variable j is greater or equal to 2.
P_0.j This is equivalent to "P_0.j != 0". P_0.j This is equivalent to "P_0.j != 0".
Comparisons operators available are "<", ">", ">=", "<=", "==", and Comparison operators available are "<", ">", ">=", "<=", "==", and
"!=". The left operant should always be a variable and the right "!=". The left operand should always be a variable and the right
operand should always be a number, so you cannot write something operand should always be a number, so you cannot write something
like "P_0.j <= P_0.i". like "P_0.j <= P_0.i".
Because the LTL parser knows nothing about the details of the Because the LTL parser knows nothing about the details of the
languages we interface with, every atomic proposition that cannot be languages we interface with, every atomic proposition that cannot be
express using only alphanumeric characters (plus `_' and `.') should expressed using only alphanumeric characters (plus `_' and `.')
be enclosed in double quote. should be enclosed in double quote.
Caveat: "P_0.j >= 2" and " P_0.j>=2" (watch the spaces!) are Caveat: "P_0.j >= 2" and " P_0.j>=2" (watch the spaces!) are
considered to be two distinct atomic propositions with the same considered to be two distinct atomic propositions with the same

View file

@ -1,5 +1,5 @@
#!/bin/sh #!/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). # de l'Epita (LRDE).
# #
# This file is part of Spot, a model checking library. # This file is part of Spot, a model checking library.
@ -29,32 +29,47 @@ else
exit 77 exit 77
fi fi
if ! test -x "$(which spins)"; then
echo "spins not installed."
exit 77
fi
set -e 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 for opt in '' '-z'; do
# The three examples from the README. # The three examples from the README.
# (Don't run the first one using "run 0" because it would take too much # (Don't run the first one using "run 0" because it would take too much
# time with valgrind.). # 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)' \ '!GF(P_0.CS|P_1.CS|P_2.CS|P_3.CS)' \
| grep -v pages > stdout1 | grep -v pages > stdout1
# same formula, different syntax. # 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")' \ '!GF("P_0==CS"|"P_1 == CS"|"P_2 ==CS"|"P_3== CS")' \
| grep -v pages > stdout2 | grep -v pages > stdout2
cmp stdout1 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)' '!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 done
# Now check some error messages. # 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 cat stderr
grep 'Cannot open' stderr grep 'Cannot open' stderr
# the dve2C file was generated in the current directory # 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 'Xfoo | P_0.f & X"P_0.k < 2xx" | G"pos[0]"' 2>stderr
cat stderr cat stderr
grep 'variable `foo' 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 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 run 0 ${top_builddir}/src/kripketest/parse_print output | tr -d '"' > output2
tr -d '"' < output >outputF tr -d '"' < output >outputF
cmp outputF output2 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")' ${top_builddir}/src/tgbatest/ltl2tgba -e -KPoutputP '!G("pos[1] < 3")'

View file

@ -30,21 +30,20 @@
# define WEXITSTATUS(x) ((x) & 0xff) # define WEXITSTATUS(x) ((x) & 0xff)
#endif #endif
#include "dve2.hh" #include "ltsmin.hh"
#include "misc/hashfunc.hh" #include "misc/hashfunc.hh"
#include "misc/fixpool.hh" #include "misc/fixpool.hh"
#include "misc/mspool.hh" #include "misc/mspool.hh"
#include "misc/intvcomp.hh" #include "misc/intvcomp.hh"
#include "misc/intvcmp2.hh" #include "misc/intvcmp2.hh"
namespace spot namespace spot
{ {
namespace namespace
{ {
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
// DVE2 --ltsmin interface // spins interface
typedef struct transition_info { typedef struct transition_info {
int* labels; // edge labels, NULL, or pointer to the edge label(s) int* labels; // edge labels, NULL, or pointer to the edge label(s)
@ -55,29 +54,27 @@ namespace spot
transition_info_t *transition_info, transition_info_t *transition_info,
int *dst); int *dst);
struct dve2_interface struct spins_interface
{ {
lt_dlhandle handle; // handle to the dynamic library lt_dlhandle handle; // handle to the dynamic library
void (*get_initial_state)(void *to); void (*get_initial_state)(void *to);
int (*have_property)(); int (*have_property)();
int (*get_successors)(void* m, int *in, TransitionCB, void *arg); int (*get_successors)(void* m, int *in, TransitionCB, void *arg);
int (*get_state_size)();
int (*get_state_variable_count)();
const char* (*get_state_variable_name)(int var); const char* (*get_state_variable_name)(int var);
int (*get_state_variable_type)(int var); int (*get_state_variable_type)(int var);
int (*get_state_variable_type_count)(); int (*get_type_count)();
const char* (*get_state_variable_type_name)(int type); const char* (*get_type_name)(int type);
int (*get_state_variable_type_value_count)(int type); int (*get_type_value_count)(int type);
const char* (*get_state_variable_type_value)(int type, int value); const char* (*get_type_value_name)(int type, int value);
int (*get_transition_count)();
}; };
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
// STATE // 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) : pool(p), size(s), count(1)
{ {
} }
@ -89,10 +86,10 @@ namespace spot
hash_value = wang32_hash(hash_value ^ vars[i]); hash_value = wang32_hash(hash_value ^ vars[i]);
} }
dve2_state* clone() const spins_state* clone() const
{ {
++count; ++count;
return const_cast<dve2_state*>(this); return const_cast<spins_state*>(this);
} }
void destroy() const void destroy() const
@ -111,7 +108,7 @@ namespace spot
{ {
if (this == other) if (this == other)
return 0; return 0;
const dve2_state* o = down_cast<const dve2_state*>(other); const spins_state* o = down_cast<const spins_state*>(other);
assert(o); assert(o);
if (hash_value < o->hash_value) if (hash_value < o->hash_value)
return -1; return -1;
@ -122,7 +119,7 @@ namespace spot
private: private:
~dve2_state() ~spins_state()
{ {
} }
@ -134,9 +131,9 @@ namespace spot
int vars[0]; 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) : pool(p), size(s), count(1)
{ {
} }
@ -148,10 +145,10 @@ namespace spot
hash_value = wang32_hash(hash_value ^ vars[i]); hash_value = wang32_hash(hash_value ^ vars[i]);
} }
dve2_compressed_state* clone() const spins_compressed_state* clone() const
{ {
++count; ++count;
return const_cast<dve2_compressed_state*>(this); return const_cast<spins_compressed_state*>(this);
} }
void destroy() const void destroy() const
@ -170,8 +167,8 @@ namespace spot
{ {
if (this == other) if (this == other)
return 0; return 0;
const dve2_compressed_state* o = const spins_compressed_state* o =
down_cast<const dve2_compressed_state*>(other); down_cast<const spins_compressed_state*>(other);
assert(o); assert(o);
if (hash_value < o->hash_value) if (hash_value < o->hash_value)
return -1; return -1;
@ -188,7 +185,7 @@ namespace spot
private: private:
~dve2_compressed_state() ~spins_compressed_state()
{ {
} }
@ -223,8 +220,8 @@ namespace spot
{ {
callback_context* ctx = static_cast<callback_context*>(arg); callback_context* ctx = static_cast<callback_context*>(arg);
fixed_size_pool* p = static_cast<fixed_size_pool*>(ctx->pool); fixed_size_pool* p = static_cast<fixed_size_pool*>(ctx->pool);
dve2_state* out = spins_state* out =
new(p->allocate()) dve2_state(ctx->state_size, p); new(p->allocate()) spins_state(ctx->state_size, p);
memcpy(out->vars, dst, ctx->state_size * sizeof(int)); memcpy(out->vars, dst, ctx->state_size * sizeof(int));
out->compute_hash(); out->compute_hash();
ctx->transitions.push_back(out); ctx->transitions.push_back(out);
@ -238,9 +235,9 @@ namespace spot
size_t csize = ctx->state_size * 2; size_t csize = ctx->state_size * 2;
ctx->compress(dst, ctx->state_size, ctx->compressed, csize); 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); + 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)); memcpy(out->vars, ctx->compressed, csize * sizeof(int));
out->compute_hash(); out->compute_hash();
ctx->transitions.push_back(out); ctx->transitions.push_back(out);
@ -249,11 +246,11 @@ namespace spot
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
// SUCC_ITERATOR // SUCC_ITERATOR
class dve2_succ_iterator: public kripke_succ_iterator class spins_succ_iterator: public kripke_succ_iterator
{ {
public: public:
dve2_succ_iterator(const callback_context* cc, spins_succ_iterator(const callback_context* cc,
bdd cond) bdd cond)
: kripke_succ_iterator(cond), cc_(cc) : kripke_succ_iterator(cond), cc_(cc)
{ {
@ -266,7 +263,7 @@ namespace spot
kripke_succ_iterator::recycle(cond); kripke_succ_iterator::recycle(cond);
} }
~dve2_succ_iterator() ~spins_succ_iterator()
{ {
delete cc_; delete cc_;
} }
@ -327,14 +324,14 @@ namespace spot
int int
convert_aps(const ltl::atomic_prop_set* aps, convert_aps(const ltl::atomic_prop_set* aps,
const dve2_interface* d, const spins_interface* d,
bdd_dict_ptr dict, bdd_dict_ptr dict,
const ltl::formula* dead, const ltl::formula* dead,
prop_set& out) prop_set& out)
{ {
int errors = 0; 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; typedef std::map<std::string, var_info> val_map_t;
val_map_t val_map; val_map_t val_map;
@ -346,14 +343,14 @@ namespace spot
val_map[name] = v; 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; typedef std::map<std::string, int> enum_map_t;
std::vector<enum_map_t> enum_map(type_count); std::vector<enum_map_t> enum_map(type_count);
for (int i = 0; i < type_count; ++i) 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) 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(); for (ltl::atomic_prop_set::const_iterator ap = aps->begin();
@ -600,15 +597,15 @@ namespace spot
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
// KRIPKE // KRIPKE
class dve2_kripke: public kripke class spins_kripke: public kripke
{ {
public: 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) const prop_set* ps, const ltl::formula* dead, int compress)
: kripke(dict), : kripke(dict),
d_(d), d_(d),
state_size_(d_->get_state_variable_count()), state_size_(d_->get_state_size()),
dict_(dict), ps_(ps), dict_(dict), ps_(ps),
compress_(compress == 0 ? 0 compress_(compress == 0 ? 0
: compress == 1 ? int_array_array_compress : compress == 1 ? int_array_array_compress
@ -618,8 +615,8 @@ namespace spot
: int_array_array_decompress2), : int_array_array_decompress2),
uncompressed_(compress ? new int[state_size_ + 30] : 0), uncompressed_(compress ? new int[state_size_ + 30] : 0),
compressed_(compress ? new int[state_size_ * 2] : 0), compressed_(compress ? new int[state_size_ * 2] : 0),
statepool_(compress ? sizeof(dve2_compressed_state) : statepool_(compress ? sizeof(spins_compressed_state) :
(sizeof(dve2_state) + state_size_ * sizeof(int))), (sizeof(spins_state) + state_size_ * sizeof(int))),
state_condition_last_state_(0), state_condition_last_cc_(0) state_condition_last_state_(0), state_condition_last_cc_(0)
{ {
vname_ = new const char*[state_size_]; vname_ = new const char*[state_size_];
@ -632,7 +629,7 @@ namespace spot
// output. // output.
int type = d->get_state_variable_type(i); int type = d->get_state_variable_type(i);
format_filter_[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 // Register the "dead" proposition. There are three cases to
@ -666,7 +663,7 @@ namespace spot
} }
} }
~dve2_kripke() ~spins_kripke()
{ {
if (iter_cache_) if (iter_cache_)
{ {
@ -704,10 +701,10 @@ namespace spot
multiple_size_pool* p = multiple_size_pool* p =
const_cast<multiple_size_pool*>(&compstatepool_); 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); + sizeof(int) * csize);
dve2_compressed_state* res = new(mem) spins_compressed_state* res = new(mem)
dve2_compressed_state(csize, p); spins_compressed_state(csize, p);
memcpy(res->vars, compressed_, csize * sizeof(int)); memcpy(res->vars, compressed_, csize * sizeof(int));
res->compute_hash(); res->compute_hash();
return res; return res;
@ -715,7 +712,7 @@ namespace spot
else else
{ {
fixed_size_pool* p = const_cast<fixed_size_pool*>(&statepool_); 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); d_->get_initial_state(res->vars);
res->compute_hash(); res->compute_hash();
return res; return res;
@ -828,8 +825,8 @@ namespace spot
const int* vars; const int* vars;
if (compress_) if (compress_)
{ {
const dve2_compressed_state* s = const spins_compressed_state* s =
down_cast<const dve2_compressed_state*>(st); down_cast<const spins_compressed_state*>(st);
assert(s); assert(s);
decompress_(s->vars, s->size, uncompressed_, state_size_); decompress_(s->vars, s->size, uncompressed_, state_size_);
@ -837,7 +834,7 @@ namespace spot
} }
else else
{ {
const dve2_state* s = down_cast<const dve2_state*>(st); const spins_state* s = down_cast<const spins_state*>(st);
assert(s); assert(s);
vars = s->vars; vars = s->vars;
} }
@ -846,7 +843,7 @@ namespace spot
virtual virtual
dve2_succ_iterator* spins_succ_iterator*
succ_iter(const state* st) const succ_iter(const state* st) const
{ {
// This may also compute successors in state_condition_last_cc // This may also compute successors in state_condition_last_cc
@ -870,13 +867,13 @@ namespace spot
if (iter_cache_) if (iter_cache_)
{ {
dve2_succ_iterator* it = spins_succ_iterator* it =
down_cast<dve2_succ_iterator*>(iter_cache_); down_cast<spins_succ_iterator*>(iter_cache_);
it->recycle(cc, scond); it->recycle(cc, scond);
iter_cache_ = nullptr; iter_cache_ = nullptr;
return it; return it;
} }
return new dve2_succ_iterator(cc, scond); return new spins_succ_iterator(cc, scond);
} }
virtual virtual
@ -920,7 +917,7 @@ namespace spot
} }
private: private:
const dve2_interface* d_; const spins_interface* d_;
int state_size_; int state_size_;
bdd_dict_ptr dict_; bdd_dict_ptr dict_;
const char** vname_; const char** vname_;
@ -952,13 +949,32 @@ namespace spot
// LOADER // 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. // does not exist already or is older.
bool 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; struct stat s;
if (stat(filename.c_str(), &s) != 0) if (stat(filename.c_str(), &s) != 0)
@ -971,7 +987,7 @@ namespace spot
} }
std::string old = filename; std::string old = filename;
filename += "2C"; filename += compiled_ext;
// Remove any directory, because the new file will // Remove any directory, because the new file will
// be compiled in the current directory. // be compiled in the current directory.
@ -982,7 +998,7 @@ namespace spot
struct stat d; struct stat d;
if (stat(filename.c_str(), &d) == 0) if (stat(filename.c_str(), &d) == 0)
if (s.st_mtime < d.st_mtime) 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; return false;
int res = system(command.c_str()); int res = system(command.c_str());
@ -997,9 +1013,8 @@ namespace spot
return false; return false;
} }
kripke_ptr 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::atomic_prop_set* to_observe,
const ltl::formula* dead, const ltl::formula* dead,
int compress, int compress,
@ -1012,22 +1027,15 @@ namespace spot
file = "./" + file_arg; file = "./" + file_arg;
std::string ext = file.substr(file.find_last_of(".")); std::string ext = file.substr(file.find_last_of("."));
if (ext == ".dve") if (ext != ".spins" && ext != ".dve2C")
{ {
if (compile_dve2(file, verbose)) if (compile_model(file, ext, verbose))
{ {
if (verbose) if (verbose)
std::cerr << "Failed to compile `" << file_arg std::cerr << "Failed to compile `" << file_arg
<< "'." << std::endl; << "'." << std::endl;
return 0; 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 (lt_dlinit())
@ -1046,43 +1054,66 @@ namespace spot
return 0; return 0;
} }
dve2_interface* d = new dve2_interface; spins_interface* d = new spins_interface;
d->handle = h; d->handle = h;
d->get_initial_state = (void (*)(void*)) // SpinS interface.
lt_dlsym(h, "get_initial_state"); if ((d->get_initial_state = (void (*)(void*))
d->have_property = (int (*)()) lt_dlsym(h, "spins_get_initial_state")))
lt_dlsym(h, "have_property"); {
d->get_successors = (int (*)(void*, int*, TransitionCB, void*)) d->have_property = nullptr;
lt_dlsym(h, "get_successors"); d->get_successors = (int (*)(void*, int*, TransitionCB, void*))
d->get_state_variable_count = (int (*)()) lt_dlsym(h, "spins_get_successor_all");
lt_dlsym(h, "get_state_variable_count"); d->get_state_size = (int (*)())
d->get_state_variable_name = (const char* (*)(int)) lt_dlsym(h, "spins_get_state_size");
lt_dlsym(h, "get_state_variable_name"); d->get_state_variable_name = (const char* (*)(int))
d->get_state_variable_type = (int (*)(int)) lt_dlsym(h, "spins_get_state_variable_name");
lt_dlsym(h, "get_state_variable_type"); d->get_state_variable_type = (int (*)(int))
d->get_state_variable_type_count = (int (*)()) lt_dlsym(h, "spins_get_state_variable_type");
lt_dlsym(h, "get_state_variable_type_count"); d->get_type_count = (int (*)())
d->get_state_variable_type_name = (const char* (*)(int)) lt_dlsym(h, "spins_get_type_count");
lt_dlsym(h, "get_state_variable_type_name"); d->get_type_name = (const char* (*)(int))
d->get_state_variable_type_value_count = (int (*)(int)) lt_dlsym(h, "spins_get_type_name");
lt_dlsym(h, "get_state_variable_type_value_count"); d->get_type_value_count = (int (*)(int))
d->get_state_variable_type_value = (const char* (*)(int, int)) lt_dlsym(h, "spins_get_type_value_count");
lt_dlsym(h, "get_state_variable_type_value"); d->get_type_value_name = (const char* (*)(int, int))
d->get_transition_count = (int (*)()) lt_dlsym(h, "spins_get_type_value_name");
lt_dlsym(h, "get_transition_count"); }
// 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 if (!(
&& d->have_property d->get_initial_state
&& d->get_successors && d->get_successors
&& d->get_state_variable_count && d->get_state_size
&& d->get_state_variable_name && d->get_state_variable_name
&& d->get_state_variable_type && d->get_state_variable_type
&& d->get_state_variable_type_count && d->get_type_count
&& d->get_state_variable_type_name && d->get_type_name
&& d->get_state_variable_type_value_count && d->get_type_value_count
&& d->get_state_variable_type_value && d->get_type_value_name))
&& d->get_transition_count))
{ {
if (verbose) if (verbose)
std::cerr << "Failed to resolve some symbol while loading `" std::cerr << "Failed to resolve some symbol while loading `"
@ -1092,14 +1123,14 @@ namespace spot
return 0; return 0;
} }
if (d->have_property()) if (d->have_property && d->have_property())
{ {
if (verbose) if (verbose)
std::cerr << "Model with an embedded property are not supported." std::cerr << "Model with an embedded property are not supported."
<< std::endl; << std::endl;
delete d; delete d;
lt_dlexit(); lt_dlexit();
return 0; return 0;
} }
prop_set* ps = new prop_set; prop_set* ps = new prop_set;
@ -1113,6 +1144,6 @@ namespace spot
return 0; 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 // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>. // along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef SPOT_IFACE_DVE2_DVE2_HH #ifndef SPOT_IFACE_PROMELA_PROMELA_HH
# define SPOT_IFACE_DVE2_DVE2_HH # define SPOT_IFACE_PROMELA_PROMELA_HH
#include "kripke/kripke.hh" #include "kripke/kripke.hh"
#include "ltlvisit/apcollect.hh" #include "ltlvisit/apcollect.hh"
@ -28,11 +28,11 @@
namespace spot namespace spot
{ {
// \brief Load a DVE model. // \brief Load a PROMELA model.
// //
// The filename given can be either a *.dve source or a *.dve2C // The filename given can be either a *.prom source or a *.spins
// dynamic library compiled with "divine compile --ltsmin file". // dynamic library compiled with "spins file".
// When the *.dve source is supplied, the *.dve2C will be updated // When the *.prom source is supplied, the *.spins will be updated
// only if it is not newer. // only if it is not newer.
// //
// The dead parameter is used to control the behavior of the model // The dead parameter is used to control the behavior of the model
@ -48,8 +48,7 @@ namespace spot
// //
// This function returns 0 on error. // This function returns 0 on error.
// //
// \a file the name of the *.dve source file or of the *.dve2C // \a file the name of the *.prom source file or the dynamic library
// dynamic library
// \a to_observe the list of atomic propositions that should be observed // \a to_observe the list of atomic propositions that should be observed
// in the model // in the model
// \a dict the BDD dictionary to use // \a dict the BDD dictionary to use
@ -57,10 +56,10 @@ namespace spot
// dead states // dead states
// \a verbose whether to output verbose messages // \a verbose whether to output verbose messages
SPOT_API kripke_ptr 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::atomic_prop_set* to_observe,
const ltl::formula* dead = ltl::constant::true_instance(), const ltl::formula* dead = ltl::constant::true_instance(),
int compress = 0, bool verbose = true); 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 // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>. // along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "dve2.hh" #include "ltsmin.hh"
#include "tgbaalgos/dotty.hh" #include "tgbaalgos/dotty.hh"
#include "ltlenv/defaultenv.hh" #include "ltlenv/defaultenv.hh"
#include "ltlast/allnodes.hh" #include "ltlast/allnodes.hh"
@ -217,9 +217,10 @@ checked_main(int argc, char **argv)
if (output != DotFormula) if (output != DotFormula)
{ {
tm.start("loading dve2"); tm.start("loading spins");
model = spot::load_dve2(argv[1], dict, &ap, deadf, compress_states, true); model = spot::load_model(argv[1], dict, &ap, deadf,
tm.stop("loading dve2"); compress_states, true);
tm.stop("loading spins");
if (!model) if (!model)
{ {