Compare commits

..

2 commits

Author SHA1 Message Date
bdae5563c6 ltlfilt: add --sonf and --sonf-aps flags
* bin/ltlfilt.cc: Here.
* NEWS: Mention new ltlfilt flags.
* tests/Makefile.am, tests/core/sonf.test: Test these flags.
2022-03-03 12:42:26 +01:00
0505ee9310 tl: implement suffix operator normal form
* spot/tl/Makefile.am: New sonf files
* spot/tl/sonf.cc,spot/tl/sonf.hh: Here.
* python/spot/impl.i: include sonf.hh header
* doc/spot.bib: add entry for the SONF paper
* tests/python/formulas.ipynb: show sample usage
* tests/python/spot.py: test automata equivalence before/after SONF
* NEWS: mention the change
2022-03-03 09:13:04 +01:00
327 changed files with 12007 additions and 41491 deletions

View file

@ -3,9 +3,9 @@
(require-final-newline . t) (require-final-newline . t)
(mode . global-whitespace) (mode . global-whitespace)
(bug-reference-bug-regexp (bug-reference-bug-regexp
. "\\(?1:\\(?:[Ff]ix\\(?:es\\)? \\|[Ii]ssue \\)#\\(?2:[0-9]+\\)\\)") . "\\(?:[Ff]ix\\(es\\)? \\|[Ii]ssue \\)#\\(?2:[0-9]+\\)")
(bug-reference-url-format (bug-reference-url-format
. "https://gitlab.lre.epita.fr/spot/spot/issues/%s") . "https://gitlab.lrde.epita.fr/spot/spot/issues/%s")
(mode . bug-reference) (mode . bug-reference)
(magit-branch-adjust-remote-upstream-alist ("origin/next" . "/")))) (magit-branch-adjust-remote-upstream-alist ("origin/next" . "/"))))
(c++-mode . ((c-default-style . "gnu") (c++-mode . ((c-default-style . "gnu")

2
.gitignore vendored
View file

@ -4,7 +4,6 @@ configure
config.log config.log
config.status config.status
aclocal.m4 aclocal.m4
ltargz.m4
autom4te.cache autom4te.cache
libtool libtool
auto auto
@ -82,4 +81,3 @@ GTAGS
*.dsc *.dsc
*.gcov *.gcov
spot.spec spot.spec
default.nix

View file

@ -19,12 +19,12 @@ debian-stable-gcc:
- branches - branches
except: except:
- /wip/ - /wip/
image: gitlab-registry.lre.epita.fr/spot/buildenv/debian:stable image: gitlab-registry.lrde.epita.fr/spot/buildenv/debian:stable
script: script:
- autoreconf -vfi - autoreconf -vfi
- ./configure --enable-max-accsets=256 --enable-pthread - ./configure --enable-max-accsets=256
- make - make
- make distcheck DISTCHECK_CONFIGURE_FLAGS='--enable-max-accsets=256 --enable-pthread' - make distcheck
artifacts: artifacts:
when: always when: always
paths: paths:
@ -32,47 +32,22 @@ debian-stable-gcc:
- ./*.log - ./*.log
- ./*.tar.gz - ./*.tar.gz
# We build on Debian unstable because we want an up-to-date Automake.
# (See issue #512.) We do not run distcheck here to speedup this build
# that several other builds depend upon. Other builds will run distcheck.
make-dist:
stage: build
only:
- branches
except:
- /wip/
image: gitlab-registry.lre.epita.fr/spot/buildenv/debian
script:
- autoreconf -vfi
- ./configure --disable-static --enable-doxygen
- make
- make dist
- autoconf --trace='AC_INIT:$2' > VERSION
artifacts:
when: always
paths:
- spot-*/_build/sub/tests/*/*.log
- ./*.log
- ./*.tar.gz
- VERSION
# We --disable-devel for coverage, because debug mode replaces
# SPOT_UNREACHABLE by an assertion wich is never reachable, lowering
# our coverage.
debian-unstable-gcc-coverage: debian-unstable-gcc-coverage:
stage: build stage: build
only: only:
- branches - branches
except: except:
- /wip/ - /wip/
image: gitlab-registry.lre.epita.fr/spot/buildenv/debian image: gitlab-registry.lrde.epita.fr/spot/buildenv/debian
script: script:
- autoreconf -vfi - autoreconf -vfi
- ./configure CXX='g++ --coverage' --disable-devel --enable-warnings --disable-static --enable-doxygen - ./configure CXX='g++ --coverage' --enable-devel --disable-static --enable-doxygen
- make - make
- make check - make check
- gcovr --xml-pretty --exclude-unreachable-branches --print-summary -o coverage.xml --root $PWD -e 'bin/spot.cc' -e 'bin/spot-x.cc' -e 'spot/bricks/.*' -e 'spot/parse.*/scan.*.cc' -e 'spot/parse.*/parse.*.cc' -e 'utf8/.*' -e 'python/.*' -e 'buddy/.*' -e 'doc/org/tmp/.*' --html-details coverage.html --html-tab-size 8 --fail-under-line 90.7 - lcov --capture --directory . --no-external --output spot.info
coverage: /^\s*lines:\s*\d+.\d+\%/ - lcov --remove spot.info '*/bin/spot.cc' '*/bin/spot-x.cc' '*/spot/parse*/scan*.cc' '*/spot/parse*/parse*.cc' '*/utf8/*' '*/python/*' '*/buddy/*' '*/doc/org/tmp/*' --output spot2.info
- lcov --summary spot2.info
- genhtml --legend --demangle-cpp --output-directory coverage spot2.info
artifacts: artifacts:
when: always when: always
paths: paths:
@ -80,57 +55,38 @@ debian-unstable-gcc-coverage:
- ./*.log - ./*.log
- doc/spot.html/ - doc/spot.html/
- doc/userdoc/ - doc/userdoc/
- coverage*.html - coverage/
- coverage*.css
- ./*.tar.gz - ./*.tar.gz
reports: - spot2.info
coverage_report:
coverage_format: cobertura
path: coverage.xml
debian-unstable-gcc-pypy: debian-unstable-gcc-pypy:
stage: build2 stage: build
needs:
- job: make-dist
artifacts: true
variables:
GIT_STRATEGY: none
only: only:
- branches - branches
except: except:
- /wip/ - /wip/
image: gitlab-registry.lre.epita.fr/spot/buildenv/debian image: gitlab-registry.lrde.epita.fr/spot/buildenv/debian
script: script:
- VERSION=`cat VERSION` - autoreconf -vfi
- tar xvf spot-$VERSION.tar.gz
- cd spot-$VERSION
- ./configure PYTHON=/usr/bin/pypy3 --disable-static - ./configure PYTHON=/usr/bin/pypy3 --disable-static
- make - make
- make check TESTS='$(TESTS_python) $(TESTS_ipython)' - make check TESTS='$(TESTS_python) $(TESTS_ipython)'
artifacts: artifacts:
when: always when: always
paths: paths:
- spot-*/tests/*/*.log - tests/*/*.log
- spot-*/*.log - ./*.log
# With emacs now using gcc for on-the-fly compilation,
# we cannot rebuild the documentation using gcc-snapshot. So we start
# from the tarball instead.
debian-gcc-snapshot: debian-gcc-snapshot:
stage: build2 stage: build
needs:
- job: make-dist
artifacts: true
only: only:
- branches - branches
except: except:
- /wip/ - /wip/
image: gitlab-registry.lre.epita.fr/spot/buildenv/debian image: gitlab-registry.lrde.epita.fr/spot/buildenv/debian
script: script:
- export PATH="/usr/lib/gcc-snapshot/bin:$PATH" LD_LIBRARY_PATH="/usr/lib/gcc-snapshot/lib:$LD_LIBRARY_PATH" - export PATH="/usr/lib/gcc-snapshot/bin:$PATH" LD_LIBRARY_PATH="/usr/lib/gcc-snapshot/lib:$LD_LIBRARY_PATH"
- VERSION=`cat VERSION` - autoreconf -vfi
- tar xvf spot-$VERSION.tar.gz
- cd spot-$VERSION
- ./configure --with-included-ltdl CXX='g++' - ./configure --with-included-ltdl CXX='g++'
- make - make
- make distcheck DISTCHECK_CONFIGURE_FLAGS='--with-included-ltdl' - make distcheck DISTCHECK_CONFIGURE_FLAGS='--with-included-ltdl'
@ -138,8 +94,11 @@ debian-gcc-snapshot:
artifacts: artifacts:
when: always when: always
paths: paths:
- spot-*/tests/*/*.log - ./spot-*/_build/sub/tests/*/*.log
- spot-*/*.log - ./*.log
- doc/spot.html/
- doc/userdoc/
- ./*.tar.gz
alpine-gcc: alpine-gcc:
stage: build stage: build
@ -147,12 +106,12 @@ alpine-gcc:
- branches - branches
except: except:
- /wip/ - /wip/
image: gitlab-registry.lre.epita.fr/spot/buildenv/alpine image: gitlab-registry.lrde.epita.fr/spot/buildenv/alpine
script: script:
- autoreconf -vfi - autoreconf -vfi
- ./configure - ./configure
- make - make
- make distcheck DISTCHECK_CONFIGURE_FLAGS='--enable-pthread' || { chmod -R u+w ./spot-*; false; } - make distcheck || { chmod -R u+w ./spot-*; false; }
artifacts: artifacts:
when: always when: always
paths: paths:
@ -166,7 +125,7 @@ arch-clang:
- branches - branches
except: except:
- /wip/ - /wip/
image: gitlab-registry.lre.epita.fr/spot/buildenv/arch image: gitlab-registry.lrde.epita.fr/spot/buildenv/arch
script: script:
- autoreconf -vfi - autoreconf -vfi
- ./configure --prefix ~/install_dir CC='clang -Qunused-arguments' CXX='clang++ -Qunused-arguments' --enable-devel --enable-c++20 --enable-doxygen - ./configure --prefix ~/install_dir CC='clang -Qunused-arguments' CXX='clang++ -Qunused-arguments' --enable-devel --enable-c++20 --enable-doxygen
@ -179,30 +138,22 @@ arch-clang:
- ./*.log - ./*.log
arch-gcc-glibcxxdebug: arch-gcc-glibcxxdebug:
stage: build2 stage: build
needs:
- job: make-dist
artifacts: true
variables:
GIT_STRATEGY: none
only: only:
- branches - branches
except: except:
- /wip/ - /wip/
image: gitlab-registry.lre.epita.fr/spot/buildenv/arch image: gitlab-registry.lrde.epita.fr/spot/buildenv/arch
script: script:
- VERSION=`cat VERSION` - autoreconf -vfi
- tar xvf spot-$VERSION.tar.gz - ./configure --enable-devel --enable-c++20 --enable-glibcxx-debug
- mkdir build-$VERSION
- cd build-$VERSION
- ../spot-$VERSION/configure --enable-devel --enable-c++20 --enable-glibcxx-debug
- make - make
- make distcheck DISTCHECK_CONFIGURE_FLAGS='--enable-devel --enable-c++20 --enable-glibcxx-debug' - make distcheck DISTCHECK_CONFIGURE_FLAGS='--enable-devel --enable-c++20 --enable-glibcxx-debug'
artifacts: artifacts:
when: on_failure when: on_failure
paths: paths:
- build-*/spot-*/_build/sub/tests/*/*.log - ./spot-*/_build/sub/tests/*/*.log
- build-*/*.log - ./*.log
mingw-shared: mingw-shared:
stage: build2 stage: build2
@ -210,17 +161,15 @@ mingw-shared:
# We start from the tarball generated from a non-cross-compiling # We start from the tarball generated from a non-cross-compiling
# job, so that all generated files are included, especially those # job, so that all generated files are included, especially those
# built from the executables. # built from the executables.
- job: make-dist - job: debian-stable-gcc
artifacts: true artifacts: true
variables:
GIT_STRATEGY: none
only: only:
- branches - branches
except: except:
- /wip/ - /wip/
image: gitlab-registry.lre.epita.fr/spot/buildenv/debian image: gitlab-registry.lrde.epita.fr/spot/buildenv/debian
script: script:
- VERSION=`cat VERSION` - VERSION=`autoconf --trace='AC_INIT:$2'`
- tar xvf spot-$VERSION.tar.gz - tar xvf spot-$VERSION.tar.gz
- cd spot-$VERSION - cd spot-$VERSION
- ./configure CC=i686-w64-mingw32-gcc CXX=i686-w64-mingw32-g++-posix --host i686-w64-mingw32 --disable-python - ./configure CC=i686-w64-mingw32-gcc CXX=i686-w64-mingw32-g++-posix --host i686-w64-mingw32 --disable-python
@ -237,17 +186,15 @@ mingw-static:
# We start from the tarball generated from a non-cross-compiling # We start from the tarball generated from a non-cross-compiling
# job, so that all generated files are included, especially those # job, so that all generated files are included, especially those
# built from the executables. # built from the executables.
- job: make-dist - job: debian-stable-gcc
artifacts: true artifacts: true
variables:
GIT_STRATEGY: none
only: only:
- branches - branches
except: except:
- /wip/ - /wip/
image: gitlab-registry.lre.epita.fr/spot/buildenv/debian image: gitlab-registry.lrde.epita.fr/spot/buildenv/debian
script: script:
- VERSION=`cat VERSION` - VERSION=`autoconf --trace='AC_INIT:$2'`
- tar xvf spot-$VERSION.tar.gz - tar xvf spot-$VERSION.tar.gz
- cd spot-$VERSION - cd spot-$VERSION
- mkdir install_dir - mkdir install_dir
@ -267,19 +214,17 @@ mingw-static:
debpkg-stable: debpkg-stable:
stage: build stage: build
variables:
GIT_STRATEGY: none
only: only:
- /-deb$/ - /-deb$/
- master - master
- next - next
- stable - stable
script: script:
- docker pull gitlab-registry.lre.epita.fr/spot/buildenv/debian:stable - docker pull gitlab-registry.lrde.epita.fr/spot/buildenv/debian:stable
- vol=spot-stable-$CI_COMMIT_SHA-$CI_PIPELINE_ID - vol=spot-stable-$CI_COMMIT_SHA
- docker volume create $vol - docker volume create $vol
- exitcode=0 - exitcode=0
- docker run -v $vol:/build/result --name helper-$vol gitlab-registry.lre.epita.fr/spot/buildenv/debian:stable ./build-spot.sh $CI_COMMIT_REF_NAME -j${NBPROC-1} || exitcode=$? - docker run -v $vol:/build/result --name helper-$vol gitlab-registry.lrde.epita.fr/spot/buildenv/debian:stable ./build-spot.sh $CI_COMMIT_REF_NAME -j${NBPROC-1} || exitcode=$?
- docker cp helper-$vol:/build/result _build_stable || exitcode=$? - docker cp helper-$vol:/build/result _build_stable || exitcode=$?
- docker rm helper-$vol || exitcode=$? - docker rm helper-$vol || exitcode=$?
- docker volume rm $vol || exitcode=$? - docker volume rm $vol || exitcode=$?
@ -293,8 +238,6 @@ debpkg-stable:
debpkg-stable-i386: debpkg-stable-i386:
stage: build2 stage: build2
variables:
GIT_STRATEGY: none
only: only:
- /-deb$/ - /-deb$/
- master - master
@ -303,11 +246,11 @@ debpkg-stable-i386:
tags: ["x86"] tags: ["x86"]
needs: ["debpkg-stable"] needs: ["debpkg-stable"]
script: script:
- docker pull gitlab-registry.lre.epita.fr/spot/buildenv/debian-i386:stable - docker pull gitlab-registry.lrde.epita.fr/spot/buildenv/debian-i386:stable
- vol=spot-stable-$CI_COMMIT_SHA-$CI_PIPELINE_ID - vol=spot-stable-$CI_COMMIT_SHA
- docker volume create $vol - docker volume create $vol
- exitcode=0 - exitcode=0
- docker create -v $vol:/build/result --name helper-$vol gitlab-registry.lre.epita.fr/spot/buildenv/debian-i386:stable ./bin-spot.sh -j${NBPROC-1} || exitcode=$? - docker create -v $vol:/build/result --name helper-$vol gitlab-registry.lrde.epita.fr/spot/buildenv/debian-i386:stable ./bin-spot.sh -j${NBPROC-1} || exitcode=$?
- docker cp _build_stable/. helper-$vol:/build/result || exitcode=$? - docker cp _build_stable/. helper-$vol:/build/result || exitcode=$?
- rm -rf _build_stable - rm -rf _build_stable
- docker start -a helper-$vol || exitcode=$? - docker start -a helper-$vol || exitcode=$?
@ -324,17 +267,15 @@ debpkg-stable-i386:
debpkg-unstable: debpkg-unstable:
stage: build stage: build
variables:
GIT_STRATEGY: none
only: only:
- /-deb$/ - /-deb$/
- next - next
script: script:
- docker pull gitlab-registry.lre.epita.fr/spot/buildenv/debian - docker pull gitlab-registry.lrde.epita.fr/spot/buildenv/debian
- vol=spot-unstable-$CI_COMMIT_SHA-$CI_PIPELINE_ID - vol=spot-unstable-$CI_COMMIT_SHA
- docker volume create $vol - docker volume create $vol
- exitcode=0 - exitcode=0
- docker run -v $vol:/build/result --name helper-$vol gitlab-registry.lre.epita.fr/spot/buildenv/debian ./build-spot.sh $CI_COMMIT_REF_NAME -j${NBPROC-1} || exitcode=$? - docker run -v $vol:/build/result --name helper-$vol gitlab-registry.lrde.epita.fr/spot/buildenv/debian ./build-spot.sh $CI_COMMIT_REF_NAME -j${NBPROC-1} || exitcode=$?
- docker cp helper-$vol:/build/result _build_unstable || exitcode=$? - docker cp helper-$vol:/build/result _build_unstable || exitcode=$?
- docker rm helper-$vol || exitcode=$? - docker rm helper-$vol || exitcode=$?
- docker volume rm $vol || exitcode=$? - docker volume rm $vol || exitcode=$?
@ -348,19 +289,17 @@ debpkg-unstable:
debpkg-unstable-i386: debpkg-unstable-i386:
stage: build2 stage: build2
variables:
GIT_STRATEGY: none
only: only:
- /-deb$/ - /-deb$/
- next - next
tags: ["x86"] tags: ["x86"]
needs: ["debpkg-unstable"] needs: ["debpkg-unstable"]
script: script:
- docker pull gitlab-registry.lre.epita.fr/spot/buildenv/debian-i386 - docker pull gitlab-registry.lrde.epita.fr/spot/buildenv/debian-i386
- vol=spot-unstable-$CI_COMMIT_SHA-$CI_PIPELINE_ID - vol=spot-unstable-$CI_COMMIT_SHA
- docker volume create $vol - docker volume create $vol
- exitcode=0 - exitcode=0
- docker create -v $vol:/build/result --name helper-$vol gitlab-registry.lre.epita.fr/spot/buildenv/debian-i386 ./bin-spot.sh -j${NBPROC-1} || exitcode=$? - docker create -v $vol:/build/result --name helper-$vol gitlab-registry.lrde.epita.fr/spot/buildenv/debian-i386 ./bin-spot.sh -j${NBPROC-1} || exitcode=$?
- docker cp _build_unstable/. helper-$vol:/build/result || exitcode=$? - docker cp _build_unstable/. helper-$vol:/build/result || exitcode=$?
- rm -rf _build_unstable - rm -rf _build_unstable
- docker start -a helper-$vol || exitcode=$? - docker start -a helper-$vol || exitcode=$?
@ -382,7 +321,7 @@ rpm-pkg:
- master - master
- next - next
- stable - stable
image: gitlab-registry.lre.epita.fr/spot/buildenv/fedora image: gitlab-registry.lrde.epita.fr/spot/buildenv/fedora
script: script:
- autoreconf -vfi - autoreconf -vfi
- ./configure - ./configure
@ -401,8 +340,6 @@ rpm-pkg:
publish-rpm: publish-rpm:
stage: publish stage: publish
variables:
GIT_STRATEGY: none
only: only:
- /-rpm$/ - /-rpm$/
- next - next
@ -413,7 +350,6 @@ publish-rpm:
- rpm-pkg - rpm-pkg
script: script:
- case $CI_COMMIT_REF_NAME in stable) rput fedora stable *.rpm;; next) rput fedora unstable *.rpm;; esac - case $CI_COMMIT_REF_NAME in stable) rput fedora stable *.rpm;; next) rput fedora unstable *.rpm;; esac
- rm -rf ./*
publish-stable: publish-stable:
only: only:
@ -421,23 +357,15 @@ publish-stable:
tags: tags:
- dput - dput
stage: publish stage: publish
variables:
GIT_STRATEGY: none
dependencies: dependencies:
- debpkg-stable-i386 - debpkg-stable-i386
- make-dist
script: script:
- cd _build_stable - cd _build_stable
- ls -l - ls -l
- dput lrde `ls -t *amd64.changes | head -1` `ls -t *i386.changes | head -1` - dput lrde *.changes
- cd ..
- ls -l
- tgz=`ls spot-*.tar.* | head -n 1` - tgz=`ls spot-*.tar.* | head -n 1`
- case $tgz in *[0-9].tar.*) scp $tgz doc@perso:/var/www/dload/spot/;; esac - case $tgz in *[0-9].tar.*) scp $tgz doc@perso:/var/www/dload/spot/;; esac
- rm -rf ./* - curl -X POST -F ref=master -F token=$TRIGGER_SPOT_WEB -F "variables[spot_branch]=stable" https://gitlab.lrde.epita.fr/api/v4/projects/131/trigger/pipeline
- curl -X POST -F ref=master -F token=$TRIGGER_SPOT_WEB -F "variables[spot_branch]=stable" https://gitlab.lre.epita.fr/api/v4/projects/131/trigger/pipeline
- curl -X POST "https://archive.softwareheritage.org/api/1/origin/save/git/url/https://gitlab.lre.epita.fr/spot/spot/"
- curl "https://web.archive.org/save/https://www.lrde.epita.fr/dload/spot/$tgz"
publish-unstable: publish-unstable:
only: only:
@ -445,18 +373,14 @@ publish-unstable:
tags: tags:
- dput - dput
stage: publish stage: publish
variables:
GIT_STRATEGY: none
dependencies: dependencies:
- debpkg-unstable-i386 - debpkg-unstable-i386
script: script:
- cd _build_unstable - cd _build_unstable
- ls -l - ls -l
- dput lrde `ls -t *amd64.changes | head -1` `ls -t *i386.changes | head -1` - dput lrde *.changes
- cd .. - curl -X POST -F ref=master -F token=$TRIGGER_SPOT_WEB -F "variables[spot_branch]=next" https://gitlab.lrde.epita.fr/api/v4/projects/131/trigger/pipeline
- rm -rf _build_unstable - curl -X POST -F ref=master -F token=$TRIGGER_SANDBOX https://gitlab.lrde.epita.fr/api/v4/projects/181/trigger/pipeline
- curl -X POST -F ref=master -F token=$TRIGGER_SPOT_WEB -F "variables[spot_branch]=next" https://gitlab.lre.epita.fr/api/v4/projects/131/trigger/pipeline
- curl -X POST -F ref=master -F token=$TRIGGER_SANDBOX https://gitlab.lre.epita.fr/api/v4/projects/181/trigger/pipeline
raspbian: raspbian:
stage: build stage: build

View file

@ -1,20 +0,0 @@
Ala-Eddine Ben-Salem <ala@lrde.epita.fr> <ala@gaborone.lrde.epita.fr>
Ala-Eddine Ben-Salem <ala@lrde.epita.fr> <ala@pret-move.rsr.lip6.fr>
Ala-Eddine Ben-Salem <ala@lrde.epita.fr> <ala@gaborone.lrde.epita.fr>
Antoine Martin <amartin@lrde.epita.fr> <antoine97.martin@gmail.com>
Arthur Remaud <aremaud@lrde.epita.fr> <aremaud@avignon.lrde.epita.fr>
Arthur Remaud <aremaud@lrde.epita.fr> <aremaud@node7.lrde.epita.fr>
Damien Lefortier <dam@lrde.epita.fr> <eg@feather.vurt>
Felix Abecassis <felix.abecassis@lrde.epita.fr> <abecassis@bosc-guerard.lrde.epita.fr>
Felix Abecassis <felix.abecassis@lrde.epita.fr> <abecassis@scalea.lrde.epita.fr>
Felix Abecassis <felix.abecassis@lrde.epita.fr> <abecassis@lrde.epita.fr>
Guillaume Sadegh <sadegh@lrde.epita.fr>
Guillaume Sadegh <sadegh@lrde.epita.fr> <guillaume.sadegh@lrde.epita.fr>
Henrich Lauko <xlauko@mail.muni.cz>
Henrich Lauko <xlauko@mail.muni.cz> <henrich.lau@gmail.com>
Jerome Dubois <jdubois@lrde.epita.fr> Jérôme Dubois <jdubois@lrde.epita.fr>
Philipp Schlehuber-Caissier <philipp@lrde.epita.fr>
Thibaud Michaud <thibaud.michaud@epita.fr> <michau_n@epita.fr>
Thomas Badie <badie@lrde.epita.fr> <badie@champoteux.lrde.epita.fr>
Rachid Rebiha <rebiha>
Thomas Martinez <martinez>

50
HACKING
View file

@ -5,11 +5,11 @@ Bootstraping from the GIT repository
Spot's gitlab page is at Spot's gitlab page is at
https://gitlab.lre.epita.fr/spot/spot https://gitlab.lrde.epita.fr/spot/spot
The GIT repository can be cloned with The GIT repository can be cloned with
git clone https://gitlab.lre.epita.fr/spot/spot.git git clone https://gitlab.lrde.epita.fr/spot/spot.git
Some files in SPOT's source tree are generated. They are distributed Some files in SPOT's source tree are generated. They are distributed
so that users do not need to install tools to rebuild them, but we so that users do not need to install tools to rebuild them, but we
@ -25,7 +25,7 @@ since the generated files they produce are distributed.)
GNU Automake >= 1.11 GNU Automake >= 1.11
GNU Libtool >= 2.4 GNU Libtool >= 2.4
GNU Flex >= 2.6 GNU Flex >= 2.6
GNU Bison >= 3.3 GNU Bison >= 3.0
GNU Emacs (preferably >= 24 but it may work with older versions) GNU Emacs (preferably >= 24 but it may work with older versions)
org-mode >= 9.1 (the version that comes bundled with your emacs org-mode >= 9.1 (the version that comes bundled with your emacs
version is likely out-of-date; but distribution often have version is likely out-of-date; but distribution often have
@ -290,8 +290,8 @@ would understand with:
make check LOG_DRIVER=$PWD/tools/test-driver-teamcity make check LOG_DRIVER=$PWD/tools/test-driver-teamcity
C++ Coding conventions Coding conventions
====================== ==================
Here some of the conventions we follow in Spot, so that the code looks Here some of the conventions we follow in Spot, so that the code looks
homogeneous. Please follow these strictly. Since this is free homogeneous. Please follow these strictly. Since this is free
@ -682,43 +682,3 @@ Other style recommandations
* Always code as if the person who ends up maintaining your code is * Always code as if the person who ends up maintaining your code is
a violent psychopath who knows where you live. a violent psychopath who knows where you live.
Coding conventions for Python Tests
===================================
Unless you have some specific reason to write test cases in C++ (for
instance do test some specific C++ constructions, or to use valgrind),
prefer writing test cases in Python. Writing test cases in C++
requires some compilation, which slows down the test suite. Doing the
same test in Python is therefore faster, and it has the added benefit
of ensuring that the Python bindings works.
We have two types of Python tests: Python scripts or jupyter
notebooks. Jupyter notebooks are usually used for a sequence of
examples and comments that can also serve as part of the
documentation. Such jupyter notebooks should be added to the list of
code examples in doc/org/tut.org. Testing a notebook is done by the
tests/python/ipnbdoctest.py scripts, which evaluate each cells, and
checks that the obtainted result is equivalent to the result saved in
the notebook. The process is a bit slow, so plain Python scripts
should be prefered for most tests.
If you do need a notebook to tests Jupyter-specific code but this
notebook should not be shown in the documentation, use a filename
starting with '_'.
Tests written as Python scripts should follow the same convention as
shell scripts: exit 0 for PASS, exit 77 for SKIP, and any other exit
code for FAIL.
Do not use assert() in those scripts, as (1) asserts can be disabled,
and (2) they provide poor insights in case of failures. Instead do
from unittest import TestCase
tc = TestCase()
and then use tc.assertTrue(...), tc.assertEqual(..., ...),
tc.assertIn(..., ...), etc. In case of failures, those will print
useful messages in the trace of the tests. For instance multiline
strings that should have been equal will be presented with a diff.

View file

@ -1,5 +1,5 @@
## -*- coding: utf-8 -*- ## -*- coding: utf-8 -*-
## Copyright (C) 2011-2017, 2020, 2022 Laboratoire de Recherche et Développement ## Copyright (C) 2011-2017, 2020 Laboratoire de Recherche et Développement
## de l'Epita (LRDE). ## de l'Epita (LRDE).
## Copyright (C) 2003, 2005 Laboratoire d'Informatique de Paris 6 (LIP6), ## Copyright (C) 2003, 2005 Laboratoire d'Informatique de Paris 6 (LIP6),
## département Systèmes Répartis Coopératifs (SRC), Université Pierre ## département Systèmes Répartis Coopératifs (SRC), Université Pierre
@ -36,9 +36,8 @@ DOC_SUBDIR = doc
SUBDIRS = picosat buddy lib ltdl spot bin tests $(PYTHON_SUBDIR) $(DOC_SUBDIR) \ SUBDIRS = picosat buddy lib ltdl spot bin tests $(PYTHON_SUBDIR) $(DOC_SUBDIR) \
$(NEVER_SUBDIRS) $(NEVER_SUBDIRS)
UTF8 = utf8/README.md utf8/LICENSE utf8/utf8.h \ UTF8 = utf8/README.md utf8/utf8.h \
utf8/utf8/checked.h utf8/utf8/core.h utf8/utf8/unchecked.h \ utf8/utf8/checked.h utf8/utf8/core.h utf8/utf8/unchecked.h
utf8/utf8/cpp11.h utf8/utf8/cpp17.h
DEBIAN = \ DEBIAN = \
debian/changelog \ debian/changelog \
@ -69,8 +68,7 @@ EXTRA_DIST = HACKING ChangeLog.1 tools/gitlog-to-changelog \
tools/help2man tools/man2html.pl \ tools/help2man tools/man2html.pl \
tools/test-driver-teamcity $(UTF8) $(DEBIAN) \ tools/test-driver-teamcity $(UTF8) $(DEBIAN) \
m4/gnulib-cache.m4 .dir-locals.el \ m4/gnulib-cache.m4 .dir-locals.el \
spot.spec spot.spec.in \ spot.spec spot.spec.in
default.nix default.nix.in
dist-hook: gen-ChangeLog dist-hook: gen-ChangeLog
@ -116,6 +114,3 @@ deb: dist
spot.spec: configure.ac spot.spec.in spot.spec: configure.ac spot.spec.in
sed 's/[@]VERSION[@]/$(VERSION)/;s/[@]GITPATCH[@]/@@@$(GITPATCH)/;s/@@@\.//' spot.spec.in > $@.tmp && mv $@.tmp $@ sed 's/[@]VERSION[@]/$(VERSION)/;s/[@]GITPATCH[@]/@@@$(GITPATCH)/;s/@@@\.//' spot.spec.in > $@.tmp && mv $@.tmp $@
default.nix: configure.ac default.nix.in
sed 's/[@]VERSION[@]/$(VERSION)/' default.nix.in > $@.tmp && mv $@.tmp $@

329
NEWS
View file

@ -1,155 +1,9 @@
New in spot 2.11.5.dev (not yet released) New in spot 2.10.4.dev (net yet released)
Library:
- The following new trivial simplifications have been implemented for SEREs:
- f|[+] = [+] if f rejects [*0]
- f|[*] = [*] if f accepts [*0]
- f&&[+] = f if f rejects [*0]
- b:b[*i..j] = b[*max(i,1)..j]
- b[*i..j]:b[*k..l] = b[*max(i,1)+max(k,1)-1, j+l-1]
- The HOA parser is a bit smarter when merging multiple initial
states into a single initial state (Spot's automaton class
supports only one): it now reuse the edges leaving initial states
without incoming transitions.
- spot::bdd_to_cnf_formula() is a new variant of spot::bdd_to_formula()
that converts a BDD into a CNF instead of a DNF.
New in spot 2.11.5 (2023-04-20)
Bug fixes:
- Fix spurious failure of ltlsynt2.test when Python is not installed
(issue #530).
- Building from the git repository would fail to report a missing
emacs (issue #528).
- Fix exception raised by aut1.intersecting_run(aut2).as_twa()
because the run did not match transitions present in aut1
verbatim. We also changed the behavior of as_twa() to not merge
identical states.
- Fix segfaults occuring in determinization of 1-state terminal
automata.
- Fix incorrect assertion in game solver when the edge vector
contains deleted transitions.
New in spot 2.11.4 (2023-02-10)
Python:
- spot.acd() no longer depends on jQuery for interactivity.
Bug fixes:
- When merging initial states from state-based automata with
multiple initial states (because Spot supports only one), the HOA
parser could break state-based acceptance. (Issue #522.)
- autfilt --highlight-word refused to work on automata with Fin
acceptance for historical reasons, however the code has been
perfectly able to handle this for a while. (Issue #523.)
- delay_branching_here(), a new optimization of Spot 2.11 had an
incorrect handling of states without successors, causing some
segfaults. (Issue #524.)
- Running delay_branching_here() on state-based automata (this was not
done in Spot so far) may require the output to use transition-based
acceptance. (Issue #525.)
- to_finite(), introduce in 2.11, had a bug that could break the
completeness of automata and trigger an exception from the HOA
printer. (Issue #526.)
New in spot 2.11.3 (2022-12-09)
Bug fixes:
- Automata-based implication checks, used to simplify formulas were
slower than necessary because the translator was configured to
favor determinism unnecessarily. (Issue #521.)
- Automata-based implication checks for f&g and f|g could be
very slow when those n-ary operator had two many arguments.
They have been limited to 16 operands, but this value can be changed
with option -x tls-max-ops=N. (Issue #521 too.)
- Running ltl_to_tgba_fm() with an output_aborter (which is done
during automata-based implication checks) would leak memory on
abort.
- configure --with-pythondir should also redefine pyexecdir,
otherwise, libraries get installed in the wrong place on Debian.
(Issue #512.)
- The HOA parser used to silently declare unused and undefined states
(e.g., when the State: header declare many more states than the body
of the file). It now warns about those.
- 'autfilt -c ...' should display a match count even in presence of
parse errors.
- Calling solve_parity_game() multiple times on the same automaton
used to append the new strategy to the existing one instead of
overwriting it.
New in spot 2.11.2 (2022-10-26)
Command-line tools:
- The --stats specifications %s, %e, %t for printing the number of
(reachable) states, edges, and transitions, learned to support
options [r], [u], [a] to indicate if only reachable, unreachable,
or all elements should be counted.
Library:
- spot::reduce_parity() now has a "layered" option to force all
transition in the same parity layer to receive the same color;
like acd_transform() would do.
Bugs fixed:
- Fix pkg-config files containing @LIBSPOT_PTHREAD@ (issue #520)
- spot::relabel_bse() was incorrectly relabeling some dependent
Boolean subexpressions in SERE. (Note that this had no
consequence on automata translated from those SERE.)
New in spot 2.11.1 (2022-10-10)
Bugs fixed:
- Fix a build issue preventing the update of website (issue #516).
- Fix a compilation error with clang-14 on FreeBSD (issue #515).
New in spot 2.11 (2022-10-08)
Build:
- configure will now diagnose situations where Python bindings will
be installed in a directory that is not part of Python's search
path. A new configure option --with-pythondir can be used to
modify this installation path.
- A new configure option --enable-pthread enables the compilation of
Spot with -pthread, and render available the parallel version of
some algorithms. If Spot is compiled with -pthread enabled, any
user linking with Spot should also link with the pthread library.
In order to not break existing build setups using Spot, this
option is currently disabled by default in this release. We plan
to turn it on by default in some future release. Third-party
project using Spot may want to start linking with -pthread in
prevision for this change.
Command-line tools: Command-line tools:
- autfilt has a new options --aliases=drop|keep to specify - autfilt has a new options --aliases=drop|keep to specify
if the HOA printer should attempt to preserve aliases if the output code should attempt to preserve aliases
present in the HOA input. This defaults to "keep". present in the HOA input. This defaults to "keep".
- autfilt has a new --to-finite option, illustrated on - autfilt has a new --to-finite option, illustrated on
@ -160,38 +14,6 @@ New in spot 2.11 (2022-10-08)
associated option --sonf-aps allows listing the newly introduced associated option --sonf-aps allows listing the newly introduced
atomic propositions. atomic propositions.
- autcross learned a --language-complemented option to assist in the
case one is testing tools that complement automata. (issue #504).
- ltlsynt has a new option --tlsf that takes the filename of a TLSF
specification and calls syfco (which must be installed) to convert
it into an LTL formula.
- ltlsynt has a new option --from-pgame that takes a parity game in
extended HOA format, as used in the Synthesis Competition.
- ltlsynt has a new option --hide-status to hide the REALIZABLE or
UNREALIZABLE output expected by SYNTCOMP. (This line is
superfluous, because the exit status of ltlsynt already indicate
whether the formula is realizable or not.)
- ltlsynt has a new option --dot to request GraphViz output instead
of most output. This works for displaying Mealy machines, games,
or AIG circuits. See https://spot.lrde.epita.fr/ltlsynt.html for
examples.
- genaut learned the --cyclist-trace-nba and --cyclist-proof-dba
options. Those are used to generate pairs of automata that should
include each other, and are used to show a regression (in speed)
present in Spot 2.10.x and fixed in 2.11.
- genltl learned --eil-gsi to generate a familly a function whose
translation and simplification used to be very slow. In particular
genltl --eil-gsi=23 | ltlfilt --from-ltlf | ltl2tgba
was reported as taking 9 days. This is now instantaneous.
Library: Library:
- The new function suffix_operator_normal_form() implements - The new function suffix_operator_normal_form() implements
@ -208,20 +30,16 @@ New in spot 2.11 (2022-10-08)
- tgba_determinize() learned to fill the "original-classes" property. - tgba_determinize() learned to fill the "original-classes" property.
States of the determinized automaton that correspond to the same States of the determinized automaton that correspond to the same
subset of states of the original automaton belong to the same subset of states of the original automaton belong to the same
class. Filling this property is only done on demand as it inccurs class. Filling this property is only done on demand has it inccurs
a small overhead. on small overhead.
- sbacc() learned to take the "original-classes" property into - sbacc() learned to take the "original-classes" property into
account and to preserve it. account and preserve it.
- The HOA parser and printer learned to map the synthesis-outputs - The HOA parser and printer learned to map the synthesis-outputs
property of Spot to the controllable-AP header for the Extended property of Spot to the controllable-AP header for the Extended
HOA format used in SyntComp. https://arxiv.org/abs/1912.05793 HOA format used in SyntComp. https://arxiv.org/abs/1912.05793
- The automaton parser learned to parse games in the PGSolver format.
See the bottom of https://spot.lrde.epita.fr/ipynb/games.html for
an example.
- "aliases" is a new named property that is filled by the HOA parser - "aliases" is a new named property that is filled by the HOA parser
using the list of aliases declared in the HOA file, and then used using the list of aliases declared in the HOA file, and then used
by the HOA printer on a best-effort basis. Aliases can be used to by the HOA printer on a best-effort basis. Aliases can be used to
@ -248,147 +66,14 @@ New in spot 2.11 (2022-10-08)
- purge_dead_states() will now also remove edges labeled by false - purge_dead_states() will now also remove edges labeled by false
(except self-loops). (except self-loops).
- When parsing formulas with a huge number of operands for an n-ary
operator (for instance 'p1 | p2 | ... | p1000') the LTL parser
would construct that formula two operand at a time, and the
formula constructor for that operator would be responsible for
inlining, sorting, deduplicating, ... all operands at each step.
This resulted in a worst-than-quadratic slowdown. This is now
averted in the parser by delaying the construction of such n-ary
nodes until all children are known.
- complement() used to always turn tautological acceptance conditions
into Büchi. It now only does that if the automaton is modified.
- The zielonka_tree construction was optimized using the same
memoization trick that is used in ACD. Additionally it can now be
run with additional options to abort when the tree as an unwanted
shape, or to turn the tree into a DAG.
- contains() can now take a twa as a second argument, not just a
twa_graph. This allows for instance to do contains(ltl, kripke)
to obtain a simple model checker (that returns true or false,
without counterexample).
- degeneralize() and degeneralize_tba() learned to work on
generalized-co-Büchi as well.
- product() learned that the product of two co-Büchi automata
is a co-Büchi automaton. And product_or() learned that the
"or"-product of two Büchi automata is a Büchi automaton.
- spot::postprocessor has a new extra option "merge-states-min" that
indicates above how many states twa_graph::merge_states() (which
perform a very cheap pass to fuse states with identicall
succesors) should be called before running simulation-based
reductions.
- A new function delay_branching_here(aut) can be used to simplify
some non-deterministic branching. If two transitions (q₁,,M,q₂)
and (q₁,,M,q₃) differ only by their destination state, and are
the only incoming transitions of their destination states, then q₂
and q₃ can be merged (taking the union of their outgoing
transitions). This is cheap function is automatically called by
spot::translate() after translation of a formula to GBA, before
further simplification. This was introduced to help with automata
produced from formulas output by "genltl --eil-gsi" (see above).
- spot::postprocessor has new configuration variable branch-post
that can be used to control the use of branching-postponement
(disabled by default) or delayed-branching (see above, enabled by
default). See the spot-x(7) man page for details.
- spot::postprocessor is now using acd_transform() by default when
building parity automata. Setting option "acd=0" will revert
to using "to_parity()" instead.
- to_parity() has been almost entirely rewritten and is a bit
faster.
- When asked to build parity automata, spot::translator is now more
aggressively using LTL decomposition, as done in the Generic
acceptance case before paritizing the result. This results in
much smaller automata in many cases.
- spot::parallel_policy is an object that can be passed to some
algorithm to specify how many threads can be used if Spot has been
compiled with --enable-pthread. Currently, only
twa_graph::merge_states() supports it.
Python bindings:
- The to_str() method of automata can now export a parity game into
the PG-Solver format by passing option 'pg'. See
https://spot.lrde.epita.fr/ipynb/games.html for an example.
Deprectation notice:
- spot::pg_print() has been deprecated in favor of spot::print_pg()
for consistency with the rest of the API.
Bugs fixed:
- calling twa_graph::new_univ_edge(src, begin, end, cond, acc) could
produce unexpected result if begin and end where already pointing
into the universal edge vector, since the later can be
reallocated during that process.
- Printing an alternating automaton with print_dot() using 'u' to
hide true state could produce some incorrect GraphViz output if
the automaton as a true state as part of a universal group.
- Due to an optimization introduces in 2.10 to parse HOA label more
efficiently, the automaton parser could crash when parsing random
input (not HOA) containing '[' (issue #509).
New in spot 2.10.6 (2022-05-18)
Bugs fixed:
- Fix compilation error on MacOS X.
- Using -Ffile/N to read column N of a CSV file would not reset the
/N specification for the next file.
- make_twa_graph() will now preserve state number when copying a
kripke_graph object. As a consequence, print_dot() and
print_hoa() will now use state numbers matching those of the
kripke_graph (issue #505).
- Fix several compilation warning introduced by newer versions
of GCC and Clang.
New in spot 2.10.5 (2022-05-03)
Bugs fixed: Bugs fixed:
- reduce_parity() produced incorrect results when applied to - reduce_parity() produced incorrect results when applied to
automata with deleted edges. automata with deleted edges.
- An optimization of Zielonka could result in incorrect results - work around a portability issue in Flex 2.6.4 preventing
in some cases.
- ltlsynt --print-pg incorrectly solved the game in addition to
printing it.
- ltlsynt would fail if only one of --ins or --outs was set, and
if it was set empty.
- Work around a portability issue in Flex 2.6.4 preventing
compilation on OpenBSD. compilation on OpenBSD.
- Do not use the seq command in test cases, it is not available
everywhere.
- Do not erase the previous contents of the PYTHONPATH environment
variable when running tests, prepend to it instead.
- Simplify Debian instructions for LTO build to work around newer
libtool version.
- Fix invalid read in digraph::sort_edges_of_(), currently unused in
Spot.
New in spot 2.10.4 (2022-02-01) New in spot 2.10.4 (2022-02-01)
Bug fixed: Bug fixed:
@ -1748,7 +1433,7 @@ New in spot 2.6.2 (2018-09-28)
- We no longer distribute the Python-based CGI script + javascript - We no longer distribute the Python-based CGI script + javascript
code for the online translator. Its replacement has its own code for the online translator. Its replacement has its own
repository: https://gitlab.lre.epita.fr/spot/spot-web-app/ repository: https://gitlab.lrde.epita.fr/spot/spot-web-app/
Library: Library:

50
README
View file

@ -110,16 +110,16 @@ Spot follows the traditional `./configure && make && make check &&
make install' process. People unfamiliar with the GNU Build System make install' process. People unfamiliar with the GNU Build System
should read the file INSTALL for generic instructions. should read the file INSTALL for generic instructions.
If you plan to use the Python bindings, we recommend you use the If you plan to use the Python binding, we recommend you use one
following --prefix options when calling configure: of the following --prefix options when calling configure:
--prefix ~/.local --prefix /usr
--prefix /usr/local (the default)
--prefix ~/.local (if you do not have root permissions)
The reason is that ~/.local/lib/python3.X/site-packages, where Spot's The reason is that all these locations are usually automatically
Python bindings will be installed, is automatically searched by searched by Python. If you use a different prefix directory, you may
Python. If you use a different prefix directory, you may have to tune have to tune the PYTHONPATH environment variable.
the PYTHONPATH environment variable, or use the --with-pythondir
option to specify different installation paths.
In addition to its usual options, ./configure will accept some In addition to its usual options, ./configure will accept some
flags specific to Spot: flags specific to Spot:
@ -173,12 +173,6 @@ flags specific to Spot:
client code should be compiled with -D_GLIBCXX_DEBUG as well. This client code should be compiled with -D_GLIBCXX_DEBUG as well. This
options should normally only be useful to run Spot's test-suite. options should normally only be useful to run Spot's test-suite.
--enable-pthread
Build and link with the -pthread option, and activate a few
parallel variants of the algorithms. This is currently disabled
by default, as it require all third-party tools using Spot to
build with -pthread as well.
--enable-c++20 --enable-c++20
Build everything in C++20 mode. We use that in our build farm to Build everything in C++20 mode. We use that in our build farm to
ensure that Spot can be used in C++20 projects as well. ensure that Spot can be used in C++20 projects as well.
@ -250,31 +244,17 @@ To test the Python bindings, try running
>>> import spot >>> import spot
>>> print(spot.version()) >>> print(spot.version())
If you installed Spot with a prefix that is not searched by Python by If you installed Spot with a prefix that is not one of those suggested
default it is likely that the above import statement will fail to in the "Building and installing" section, it is likely that the above
locate the spot package. You can show the list of directories that import statement will fail to locate the spot package. You can show
are searched by Python using: the list of directories that are searched by Python using:
% python3 % python3
>>> import sys >>> import sys
>>> print(sys.path) >>> print(sys.path)
And you can modify that list of searched directories using the And you can modify that list of searched directories using the
PYTHONPATH environment variable. Alternatively, you can instruct Spot PYTHONPATH environment variable.
to install its Python files in one of those directory using the
--with-pythondir configure option. As an example, an issue in
distributions derived from Debian is that if you run
./configure && make && make install
Python files get installed in /usr/local/lib/python3.X/site-packages
while Debian's version of Python only looks for them into
/usr/local/lib/python3.X/dist-packages instead. You can fix that by
instructing configure that you want packages installed into the right
directory instead:
./configure --with-pythondir=/usr/local/lib/python3.X/dist-packages \
&& make && make install
To test if man pages can be found, simply try: To test if man pages can be found, simply try:
@ -339,13 +319,13 @@ bench/ Benchmarks for ...
wdba/ ... WDBA minimization (for obligation properties). wdba/ ... WDBA minimization (for obligation properties).
python/ Python bindings for Spot and BuDDy python/ Python bindings for Spot and BuDDy
Third-party software Third party software
-------------------- --------------------
buddy/ A customized version of BuDDy 2.3 (a BDD library). buddy/ A customized version of BuDDy 2.3 (a BDD library).
ltdl/ Libtool's portable dlopen() wrapper library. ltdl/ Libtool's portable dlopen() wrapper library.
lib/ Gnulib's portability modules. lib/ Gnulib's portability modules.
utf8/ Trifunovic's utf-8 routines. https://github.com/nemtrif/utfcpp utf8/ Nemanja Trifunovic's utf-8 routines.
elisp/ Related emacs modes, used for building the documentation. elisp/ Related emacs modes, used for building the documentation.
picosat/ A distribution of PicoSAT 965 (a satsolver library). picosat/ A distribution of PicoSAT 965 (a satsolver library).
spot/bricks/ A collection of useful C++ code provided by DiVinE spot/bricks/ A collection of useful C++ code provided by DiVinE

12
THANKS
View file

@ -11,12 +11,9 @@ Christian Dax
Christopher Ziegler Christopher Ziegler
Clément Tamines Clément Tamines
David Müller David Müller
Dávid Smolka
Edmond Irani Liu
Ernesto Posse Ernesto Posse
Étienne Renault Étienne Renault
Fabrice Kordon Fabrice Kordon
Fangyi Zhou
Felix Klaedtke Felix Klaedtke
Florian Perlié-Long Florian Perlié-Long
František Blahoudek František Blahoudek
@ -24,7 +21,6 @@ Gerard J. Holzmann
Hashim Ali Hashim Ali
Heikki Tauriainen Heikki Tauriainen
Henrich Lauko Henrich Lauko
Jacopo Binchi
Jan Strejček Jan Strejček
Jean-Michel Couvreur Jean-Michel Couvreur
Jean-Michel Ilié Jean-Michel Ilié
@ -45,18 +41,14 @@ Michael Weber
Mikuláš Klokočka Mikuláš Klokočka
Ming-Hsien Tsai Ming-Hsien Tsai
Nikos Gorogiannis Nikos Gorogiannis
Ondřej Lengál
Paul Guénézan Paul Guénézan
Pierre Ganty
Raven Beutner
Reuben Rowe Reuben Rowe
Roei Nahum Roei Nahum
Rüdiger Ehlers Rüdiger Ehlers
Shachar Itzhaky
Shengping Shaw
Shufang Zhu
Silien Hong Silien Hong
Simon Jantsch Simon Jantsch
Shengping Shaw
Shufang Zhu
Sonali Dutta Sonali Dutta
Tereza Šťastná Tereza Šťastná
Tobias Meggendorfer. Tobias Meggendorfer.

View file

@ -1,5 +1,5 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# Copyright (C) 2016-2018, 2023 Laboratoire de Recherche et Développement de # Copyright (C) 2016-2018 Laboratoire de Recherche et Développement de
# l'Epita (LRDE). # l'Epita (LRDE).
# #
# This file is part of Spot, a model checking library. # This file is part of Spot, a model checking library.
@ -55,12 +55,12 @@ class BenchConfig(object):
if line[0] == '#' or line.isspace(): if line[0] == '#' or line.isspace():
continue continue
elif line[0:2] == "sh": elif line[0:2] == "sh":
sh = re.search('sh (.+)$', line).group(1) sh = re.search('sh (.+?)$', line).group(1)
continue continue
else: else:
name = re.search('(.+?):', line).group(1) name = re.search('(.+?):', line).group(1)
code = re.search(':(.+?)>', line).group(1) code = re.search(':(.+?)>', line).group(1)
xoptions = re.search('>(.+)$', line).group(1) xoptions = re.search('>(.+?)$', line).group(1)
b = Bench(name=name, code=code, xoptions=xoptions) b = Bench(name=name, code=code, xoptions=xoptions)
self.l.append(b) self.l.append(b)
self.sh.append(sh) self.sh.append(sh)

View file

@ -1,6 +1,6 @@
// -*- coding: utf-8 -*- // -*- coding: utf-8 -*-
// Copyright (C) 2014, 2015, 2016, 2017, 2022 Laboratoire de Recherche // Copyright (C) 2014, 2015, 2016, 2017 Laboratoire de Recherche et
// et Développement de l'Epita (LRDE). // Développement de l'Epita (LRDE).
// //
// This file is part of Spot, a model checking library. // This file is part of Spot, a model checking library.
// //
@ -28,7 +28,7 @@
#include <spot/misc/timer.hh> #include <spot/misc/timer.hh>
#include <argp.h> #include <argp.h>
static const char argp_program_doc[] = ""; const char argp_program_doc[] ="";
const struct argp_child children[] = const struct argp_child children[] =
{ {

View file

@ -1,6 +1,6 @@
// -*- coding: utf-8 -*- // -*- coding: utf-8 -*-
// Copyright (C) 2017-2020, 2022-2023 Laboratoire de Recherche et // Copyright (C) 2017-2020 Laboratoire de Recherche et Développement de
// Développement de l'Epita (LRDE). // l'Epita (LRDE).
// //
// This file is part of Spot, a model checking library. // This file is part of Spot, a model checking library.
// //
@ -51,7 +51,7 @@
#include <spot/misc/escape.hh> #include <spot/misc/escape.hh>
#include <spot/misc/timer.hh> #include <spot/misc/timer.hh>
static const char argp_program_doc[] = "\ const char argp_program_doc[] ="\
Call several tools that process automata and cross-compare their output \ Call several tools that process automata and cross-compare their output \
to detect bugs, or to gather statistics. The list of automata to use \ to detect bugs, or to gather statistics. The list of automata to use \
should be supplied on standard input, or using the -F option.\v\ should be supplied on standard input, or using the -F option.\v\
@ -64,7 +64,6 @@ Exit status:\n\
enum { enum {
OPT_BOGUS = 256, OPT_BOGUS = 256,
OPT_COMPLEMENTED,
OPT_CSV, OPT_CSV,
OPT_HIGH, OPT_HIGH,
OPT_FAIL_ON_TIMEOUT, OPT_FAIL_ON_TIMEOUT,
@ -95,8 +94,6 @@ static const argp_option options[] =
"consider timeouts as errors", 0 }, "consider timeouts as errors", 0 },
{ "language-preserved", OPT_LANG, nullptr, 0, { "language-preserved", OPT_LANG, nullptr, 0,
"expect that each tool preserves the input language", 0 }, "expect that each tool preserves the input language", 0 },
{ "language-complemented", OPT_COMPLEMENTED, nullptr, 0,
"expect that each tool complements the input language", 0 },
{ "no-checks", OPT_NOCHECKS, nullptr, 0, { "no-checks", OPT_NOCHECKS, nullptr, 0,
"do not perform any sanity checks", 0 }, "do not perform any sanity checks", 0 },
/**************************************************/ /**************************************************/
@ -147,7 +144,6 @@ static bool fail_on_timeout = false;
static bool stop_on_error = false; static bool stop_on_error = false;
static bool no_checks = false; static bool no_checks = false;
static bool opt_language_preserved = false; static bool opt_language_preserved = false;
static bool opt_language_complemented = false;
static bool opt_omit = false; static bool opt_omit = false;
static const char* csv_output = nullptr; static const char* csv_output = nullptr;
static unsigned round_num = 0; static unsigned round_num = 0;
@ -162,7 +158,7 @@ parse_opt(int key, char* arg, struct argp_state*)
switch (key) switch (key)
{ {
case 'F': case 'F':
jobs.emplace_back(arg, job_type::AUT_FILENAME); jobs.emplace_back(arg, true);
break; break;
case 'q': case 'q':
quiet = true; quiet = true;
@ -174,9 +170,6 @@ parse_opt(int key, char* arg, struct argp_state*)
bogus_output_filename = arg; bogus_output_filename = arg;
break; break;
} }
case OPT_COMPLEMENTED:
opt_language_complemented = true;
break;
case OPT_CSV: case OPT_CSV:
csv_output = arg ? arg : "-"; csv_output = arg ? arg : "-";
break; break;
@ -216,7 +209,7 @@ parse_opt(int key, char* arg, struct argp_state*)
break; break;
case ARGP_KEY_ARG: case ARGP_KEY_ARG:
if (arg[0] == '-' && !arg[1]) if (arg[0] == '-' && !arg[1])
jobs.emplace_back(arg, job_type::AUT_FILENAME); jobs.emplace_back(arg, true);
else else
tools_push_autproc(arg); tools_push_autproc(arg);
break; break;
@ -345,6 +338,7 @@ struct in_statistics
struct out_statistics struct out_statistics
{ {
// If OK is false, output statistics are not available. // If OK is false, output statistics are not available.
bool ok; bool ok;
const char* status_str; const char* status_str;
@ -352,7 +346,7 @@ struct out_statistics
double time; double time;
aut_statistics output; aut_statistics output;
out_statistics() noexcept out_statistics()
: ok(false), : ok(false),
status_str(nullptr), status_str(nullptr),
status_code(0), status_code(0),
@ -539,32 +533,25 @@ namespace
const spot::const_twa_graph_ptr& aut_j, const spot::const_twa_graph_ptr& aut_j,
size_t i, size_t j) size_t i, size_t j)
{ {
auto is_really_comp = [lc = opt_language_complemented,
ts = tools.size()](unsigned i) {
return lc && i == ts;
};
if (aut_i->num_sets() + aut_j->num_sets() > if (aut_i->num_sets() + aut_j->num_sets() >
spot::acc_cond::mark_t::max_accsets()) spot::acc_cond::mark_t::max_accsets())
{ {
if (!quiet) if (!quiet)
std::cerr << "info: building " << autname(i, is_really_comp(i)) std::cerr << "info: building " << autname(i)
<< '*' << autname(j, !is_really_comp(j)) << '*' << autname(j, true)
<< " requires more acceptance sets than supported\n"; << " requires more acceptance sets than supported\n";
return false; return false;
} }
if (verbose) if (verbose)
std::cerr << "info: check_empty " std::cerr << "info: check_empty "
<< autname(i, is_really_comp(i)) << autname(i) << '*' << autname(j, true) << '\n';
<< '*' << autname(j, !is_really_comp(j)) << '\n';
auto w = aut_i->intersecting_word(aut_j); auto w = aut_i->intersecting_word(aut_j);
if (w) if (w)
{ {
std::ostream& err = global_error(); std::ostream& err = global_error();
err << "error: " << autname(i, is_really_comp(i)) err << "error: " << autname(i) << '*' << autname(j, true)
<< '*' << autname(j, !is_really_comp(j))
<< (" is nonempty; both automata accept the infinite word:\n" << (" is nonempty; both automata accept the infinite word:\n"
" "); " ");
example() << *w << '\n'; example() << *w << '\n';
@ -613,7 +600,7 @@ namespace
return src.str(); return src.str();
}(); }();
input_statistics.emplace_back(in_statistics()); input_statistics.push_back(in_statistics());
input_statistics[round_num].input_source = std::move(source); input_statistics[round_num].input_source = std::move(source);
if (auto name = input->get_named_prop<std::string>("automaton-name")) if (auto name = input->get_named_prop<std::string>("automaton-name"))
@ -634,15 +621,12 @@ namespace
int problems = 0; int problems = 0;
size_t m = tools.size(); size_t m = tools.size();
size_t mi = m + opt_language_preserved + opt_language_complemented; size_t mi = m + opt_language_preserved;
std::vector<spot::twa_graph_ptr> pos(mi); std::vector<spot::twa_graph_ptr> pos(mi);
std::vector<spot::twa_graph_ptr> neg(mi); std::vector<spot::twa_graph_ptr> neg(mi);
vector_tool_statistics stats(m); vector_tool_statistics stats(m);
// For --language-complemented, we store the input automata in if (opt_language_preserved)
// pos and will compute its complement in neg. Before running
// checks we will swap both automata.
if (opt_language_preserved || opt_language_complemented)
pos[mi - 1] = input; pos[mi - 1] = input;
if (verbose) if (verbose)
@ -658,7 +642,7 @@ namespace
problems += prob; problems += prob;
} }
spot::cleanup_tmpfiles(); spot::cleanup_tmpfiles();
output_statistics.emplace_back(std::move(stats)); output_statistics.push_back(std::move(stats));
if (verbose) if (verbose)
{ {
@ -734,9 +718,6 @@ namespace
}; };
} }
if (opt_language_complemented)
std::swap(pos[mi - 1], neg[mi - 1]);
// Just make a circular implication check // Just make a circular implication check
// A0 <= A1, A1 <= A2, ..., AN <= A0 // A0 <= A1, A1 <= A2, ..., AN <= A0
unsigned ok = 0; unsigned ok = 0;
@ -843,15 +824,10 @@ main(int argc, char** argv)
check_no_automaton(); check_no_automaton();
if (s == 1 && !no_checks if (s == 1 && !opt_language_preserved && !no_checks)
&& !opt_language_preserved error(2, 0, "Since --language-preserved is not used, you need "
&& !opt_language_complemented) "at least two tools to compare.");
error(2, 0, "Since --language-preserved and --language-complemented "
"are not used, you need at least two tools to compare.");
if (opt_language_preserved && opt_language_complemented)
error(2, 0, "Options --language-preserved and --language-complemented "
"are incompatible.");
setup_color(); setup_color();
setup_sig_handler(); setup_sig_handler();

View file

@ -1,5 +1,5 @@
// -*- coding: utf-8 -*- // -*- coding: utf-8 -*-
// Copyright (C) 2013-2023 Laboratoire de Recherche et Développement // Copyright (C) 2013-2022 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.
@ -448,7 +448,7 @@ struct canon_aut
std::vector<tr_t> edges; std::vector<tr_t> edges;
std::string acc; std::string acc;
explicit canon_aut(const spot::const_twa_graph_ptr& aut) canon_aut(const spot::const_twa_graph_ptr& aut)
: num_states(aut->num_states()) : num_states(aut->num_states())
, edges(aut->edge_vector().begin() + 1, , edges(aut->edge_vector().begin() + 1,
aut->edge_vector().end()) aut->edge_vector().end())
@ -713,12 +713,10 @@ ensure_deterministic(const spot::twa_graph_ptr& aut, bool nonalt = false)
return p.run(aut); return p.run(aut);
} }
static spot::twa_graph_ptr static spot::twa_graph_ptr ensure_tba(spot::twa_graph_ptr aut)
ensure_tba(spot::twa_graph_ptr aut,
spot::postprocessor::output_type type = spot::postprocessor::Buchi)
{ {
spot::postprocessor p; spot::postprocessor p;
p.set_type(type); p.set_type(spot::postprocessor::Buchi);
p.set_pref(spot::postprocessor::Any); p.set_pref(spot::postprocessor::Any);
p.set_level(spot::postprocessor::Low); p.set_level(spot::postprocessor::Low);
return p.run(aut); return p.run(aut);
@ -728,14 +726,12 @@ ensure_tba(spot::twa_graph_ptr aut,
static spot::twa_graph_ptr static spot::twa_graph_ptr
product(spot::twa_graph_ptr left, spot::twa_graph_ptr right) product(spot::twa_graph_ptr left, spot::twa_graph_ptr right)
{ {
// Are we likely to fail because of too many colors? if ((type == spot::postprocessor::Buchi)
if ((left->num_sets() + right->num_sets() > && (left->num_sets() + right->num_sets() >
spot::acc_cond::mark_t::max_accsets()) spot::acc_cond::mark_t::max_accsets()))
&& (type == spot::postprocessor::Buchi
|| type == spot::postprocessor::CoBuchi))
{ {
left = ensure_tba(left, type); left = ensure_tba(left);
right = ensure_tba(right, type); right = ensure_tba(right);
} }
return spot::product(left, right); return spot::product(left, right);
} }
@ -743,34 +739,16 @@ product(spot::twa_graph_ptr left, spot::twa_graph_ptr right)
static spot::twa_graph_ptr static spot::twa_graph_ptr
product_or(spot::twa_graph_ptr left, spot::twa_graph_ptr right) product_or(spot::twa_graph_ptr left, spot::twa_graph_ptr right)
{ {
// Are we likely to fail because of too many colors? if ((type == spot::postprocessor::Buchi)
if ((left->num_sets() + right->num_sets() > && (left->num_sets() + right->num_sets() >
spot::acc_cond::mark_t::max_accsets()) spot::acc_cond::mark_t::max_accsets()))
&& (type == spot::postprocessor::Buchi
|| type == spot::postprocessor::CoBuchi))
{ {
left = ensure_tba(left, type); left = ensure_tba(left);
right = ensure_tba(right, type); right = ensure_tba(right);
} }
return spot::product_or(left, right); return spot::product_or(left, right);
} }
static spot::twa_graph_ptr
word_to_aut(const char* word, const char *argname)
{
try
{
return spot::parse_word(word, opt->dict)->as_automaton();
}
catch (const spot::parse_error& e)
{
error(2, 0, "failed to parse the argument of --%s:\n%s",
argname, e.what());
}
SPOT_UNREACHABLE();
return nullptr;
}
static int static int
parse_opt(int key, char* arg, struct argp_state*) parse_opt(int key, char* arg, struct argp_state*)
{ {
@ -783,7 +761,7 @@ parse_opt(int key, char* arg, struct argp_state*)
automaton_format = Count; automaton_format = Count;
break; break;
case 'F': case 'F':
jobs.emplace_back(arg, job_type::AUT_FILENAME); jobs.emplace_back(arg, true);
break; break;
case 'n': case 'n':
opt_max_count = to_pos_int(arg, "-n/--max-count"); opt_max_count = to_pos_int(arg, "-n/--max-count");
@ -792,14 +770,17 @@ parse_opt(int key, char* arg, struct argp_state*)
opt_nth = parse_range(arg, 0, std::numeric_limits<int>::max()); opt_nth = parse_range(arg, 0, std::numeric_limits<int>::max());
break; break;
case 'u': case 'u':
opt->uniq = std::make_unique<unique_aut_t>(); opt->uniq = std::unique_ptr<unique_aut_t>(new std::set<canon_aut>());
break; break;
case 'v': case 'v':
opt_invert = true; opt_invert = true;
break; break;
case 'x': case 'x':
if (const char* opt = extra_options.parse_options(arg)) {
const char* opt = extra_options.parse_options(arg);
if (opt)
error(2, 0, "failed to parse --options near '%s'", opt); error(2, 0, "failed to parse --options near '%s'", opt);
}
break; break;
case OPT_ALIASES: case OPT_ALIASES:
opt_aliases = XARGMATCH("--aliases", arg, aliases_args, aliases_types); opt_aliases = XARGMATCH("--aliases", arg, aliases_args, aliases_types);
@ -815,7 +796,16 @@ parse_opt(int key, char* arg, struct argp_state*)
opt_art_sccs_set = true; opt_art_sccs_set = true;
break; break;
case OPT_ACCEPT_WORD: case OPT_ACCEPT_WORD:
opt->acc_words.emplace_back(word_to_aut(arg, "accept-word")); try
{
opt->acc_words.push_back(spot::parse_word(arg, opt->dict)
->as_automaton());
}
catch (const spot::parse_error& e)
{
error(2, 0, "failed to parse the argument of --accept-word:\n%s",
e.what());
}
break; break;
case OPT_ACCEPTANCE_IS: case OPT_ACCEPTANCE_IS:
{ {
@ -968,7 +958,16 @@ parse_opt(int key, char* arg, struct argp_state*)
"%d should be followed by a comma and WORD", res); "%d should be followed by a comma and WORD", res);
arg = endptr + 1; arg = endptr + 1;
} }
opt->hl_words.emplace_back(word_to_aut(arg, "highlight-word"), res); try
{
opt->hl_words.emplace_back(spot::parse_word(arg, opt->dict)
->as_automaton(), res);
}
catch (const spot::parse_error& e)
{
error(2, 0, "failed to parse the argument of --highlight-word:\n%s",
e.what());
}
} }
break; break;
case OPT_HIGHLIGHT_LANGUAGES: case OPT_HIGHLIGHT_LANGUAGES:
@ -989,7 +988,7 @@ parse_opt(int key, char* arg, struct argp_state*)
if (!opt->included_in) if (!opt->included_in)
opt->included_in = aut; opt->included_in = aut;
else else
opt->included_in = ::product_or(opt->included_in, aut); opt->included_in = spot::product_or(opt->included_in, aut);
} }
break; break;
case OPT_INHERENTLY_WEAK_SCCS: case OPT_INHERENTLY_WEAK_SCCS:
@ -1152,7 +1151,16 @@ parse_opt(int key, char* arg, struct argp_state*)
opt_art_sccs_set = true; opt_art_sccs_set = true;
break; break;
case OPT_REJECT_WORD: case OPT_REJECT_WORD:
opt->rej_words.emplace_back(word_to_aut(arg, "reject-word")); try
{
opt->rej_words.push_back(spot::parse_word(arg, opt->dict)
->as_automaton());
}
catch (const spot::parse_error& e)
{
error(2, 0, "failed to parse the argument of --reject-word:\n%s",
e.what());
}
break; break;
case OPT_REM_AP: case OPT_REM_AP:
opt->rem_ap.add_ap(arg); opt->rem_ap.add_ap(arg);
@ -1244,7 +1252,7 @@ parse_opt(int key, char* arg, struct argp_state*)
opt_art_sccs_set = true; opt_art_sccs_set = true;
break; break;
case ARGP_KEY_ARG: case ARGP_KEY_ARG:
jobs.emplace_back(arg, job_type::AUT_FILENAME); jobs.emplace_back(arg, true);
break; break;
default: default:
@ -1277,7 +1285,7 @@ namespace
static static
bool match_acceptance(spot::twa_graph_ptr aut) bool match_acceptance(spot::twa_graph_ptr aut)
{ {
const spot::acc_cond& acc = aut->acc(); auto& acc = aut->acc();
switch (opt_acceptance_is) switch (opt_acceptance_is)
{ {
case ACC_Any: case ACC_Any:
@ -1332,7 +1340,8 @@ namespace
{ {
bool max; bool max;
bool odd; bool odd;
if (!acc.is_parity(max, odd, true)) bool is_p = acc.is_parity(max, odd, true);
if (!is_p)
return false; return false;
switch (opt_acceptance_is) switch (opt_acceptance_is)
{ {
@ -1445,7 +1454,7 @@ namespace
if (matched && opt_acceptance_is) if (matched && opt_acceptance_is)
matched = match_acceptance(aut); matched = match_acceptance(aut);
if (matched && (opt_sccs_set || opt_art_sccs_set)) if (matched && (opt_sccs_set | opt_art_sccs_set))
{ {
spot::scc_info si(aut); spot::scc_info si(aut);
unsigned n = si.scc_count(); unsigned n = si.scc_count();
@ -1525,14 +1534,14 @@ namespace
&& spot::contains(aut, opt->equivalent_pos); && spot::contains(aut, opt->equivalent_pos);
if (matched && !opt->acc_words.empty()) if (matched && !opt->acc_words.empty())
for (const spot::twa_graph_ptr& word_aut: opt->acc_words) for (auto& word_aut: opt->acc_words)
if (spot::product(aut, word_aut)->is_empty()) if (spot::product(aut, word_aut)->is_empty())
{ {
matched = false; matched = false;
break; break;
} }
if (matched && !opt->rej_words.empty()) if (matched && !opt->rej_words.empty())
for (const spot::twa_graph_ptr& word_aut: opt->rej_words) for (auto& word_aut: opt->rej_words)
if (!spot::product(aut, word_aut)->is_empty()) if (!spot::product(aut, word_aut)->is_empty())
{ {
matched = false; matched = false;
@ -1666,9 +1675,14 @@ namespace
aut->accepting_run()->highlight(opt_highlight_accepting_run); aut->accepting_run()->highlight(opt_highlight_accepting_run);
if (!opt->hl_words.empty()) if (!opt->hl_words.empty())
for (auto& [word_aut, color]: opt->hl_words) for (auto& word_aut: opt->hl_words)
if (auto run = spot::product(aut, word_aut)->accepting_run()) {
run->project(aut)->highlight(color); if (aut->acc().uses_fin_acceptance())
error(2, 0,
"--highlight-word does not yet work with Fin acceptance");
if (auto run = spot::product(aut, word_aut.first)->accepting_run())
run->project(aut)->highlight(word_aut.second);
}
timer.stop(); timer.stop();
if (opt->uniq) if (opt->uniq)
@ -1743,17 +1757,15 @@ main(int argc, char** argv)
post.set_level(level); post.set_level(level);
autfilt_processor processor(post, o.dict); autfilt_processor processor(post, o.dict);
int err = processor.run(); if (processor.run())
return 2;
// Diagnose unused -x options
extra_options.report_unused_options();
if (automaton_format == Count) if (automaton_format == Count)
std::cout << match_count << std::endl; std::cout << match_count << std::endl;
// Diagnose unused -x options
if (!err)
extra_options.report_unused_options();
else
return 2;
check_cout(); check_cout();
return match_count ? 0 : 1; return match_count ? 0 : 1;
}); });

View file

@ -1,5 +1,5 @@
// -*- coding: utf-8 -*- // -*- coding: utf-8 -*-
// Copyright (C) 2012-2023 Laboratoire de Recherche et Développement // Copyright (C) 2012-2021 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.
@ -41,7 +41,7 @@
#include <spot/twaalgos/isdet.hh> #include <spot/twaalgos/isdet.hh>
automaton_format_t automaton_format = Hoa; automaton_format_t automaton_format = Hoa;
const char* automaton_format_opt = nullptr; static const char* automaton_format_opt = nullptr;
const char* opt_name = nullptr; const char* opt_name = nullptr;
static const char* opt_output = nullptr; static const char* opt_output = nullptr;
static const char* stats = ""; static const char* stats = "";
@ -203,18 +203,12 @@ static const argp_option io_options[] =
"to specify additional options as in --hoa=opt)", 0 }, "to specify additional options as in --hoa=opt)", 0 },
{ "%M, %m", 0, nullptr, OPTION_DOC | OPTION_NO_USAGE, { "%M, %m", 0, nullptr, OPTION_DOC | OPTION_NO_USAGE,
"name of the automaton", 0 }, "name of the automaton", 0 },
{ "%S, %s, %[LETTER]S, %[LETTER]s", { "%S, %s", 0, nullptr, OPTION_DOC | OPTION_NO_USAGE,
0, nullptr, OPTION_DOC | OPTION_NO_USAGE, "number of reachable states", 0 },
"number of states (add one LETTER to select (r) reachable [default], " { "%E, %e", 0, nullptr, OPTION_DOC | OPTION_NO_USAGE,
"(u) unreachable, (a) all).", 0 }, "number of reachable edges", 0 },
{ "%E, %e, %[LETTER]E, %[LETTER]e", { "%T, %t", 0, nullptr, OPTION_DOC | OPTION_NO_USAGE,
0, nullptr, OPTION_DOC | OPTION_NO_USAGE, "number of reachable transitions", 0 },
"number of edges (add one LETTER to select (r) reachable [default], "
"(u) unreachable, (a) all).", 0 },
{ "%T, %t, %[LETTER]E, %[LETTER]e",
0, nullptr, OPTION_DOC | OPTION_NO_USAGE,
"number of transitions (add one LETTER to select (r) reachable "
"[default], (u) unreachable, (a) all).", 0 },
{ "%A, %a", 0, nullptr, OPTION_DOC | OPTION_NO_USAGE, { "%A, %a", 0, nullptr, OPTION_DOC | OPTION_NO_USAGE,
"number of acceptance sets", 0 }, "number of acceptance sets", 0 },
{ "%G, %g, %[LETTERS]G, %[LETTERS]g", 0, nullptr, { "%G, %g, %[LETTERS]G, %[LETTERS]g", 0, nullptr,
@ -274,15 +268,12 @@ static const argp_option o_options[] =
"to specify additional options as in --hoa=opt)", 0 }, "to specify additional options as in --hoa=opt)", 0 },
{ "%m", 0, nullptr, OPTION_DOC | OPTION_NO_USAGE, { "%m", 0, nullptr, OPTION_DOC | OPTION_NO_USAGE,
"name of the automaton", 0 }, "name of the automaton", 0 },
{ "%s, %[LETTER]s", 0, nullptr, OPTION_DOC | OPTION_NO_USAGE, { "%s", 0, nullptr, OPTION_DOC | OPTION_NO_USAGE,
"number of states (add one LETTER to select (r) reachable [default], " "number of reachable states", 0 },
"(u) unreachable, (a) all).", 0 }, { "%e", 0, nullptr, OPTION_DOC | OPTION_NO_USAGE,
{ "%e, %[LETTER]e", 0, nullptr, OPTION_DOC | OPTION_NO_USAGE, "number of reachable edges", 0 },
"number of edges (add one LETTER to select (r) reachable [default], " { "%t", 0, nullptr, OPTION_DOC | OPTION_NO_USAGE,
"(u) unreachable, (a) all).", 0 }, "number of reachable transitions", 0 },
{ "%t, %[LETTER]t", 0, nullptr, OPTION_DOC | OPTION_NO_USAGE,
"number of transitions (add one LETTER to select (r) reachable "
"[default], (u) unreachable, (a) all).", 0 },
{ "%a", 0, nullptr, OPTION_DOC | OPTION_NO_USAGE, { "%a", 0, nullptr, OPTION_DOC | OPTION_NO_USAGE,
"number of acceptance sets", 0 }, "number of acceptance sets", 0 },
{ "%g, %[LETTERS]g", 0, nullptr, { "%g, %[LETTERS]g", 0, nullptr,
@ -453,7 +444,7 @@ hoa_stat_printer::print(const spot::const_parsed_aut_ptr& haut,
const spot::const_twa_graph_ptr& aut, const spot::const_twa_graph_ptr& aut,
spot::formula f, spot::formula f,
const char* filename, int loc, const char* filename, int loc,
const spot::process_timer& ptimer, spot::process_timer& ptimer,
const char* csv_prefix, const char* csv_suffix) const char* csv_prefix, const char* csv_suffix)
{ {
timer_ = ptimer; timer_ = ptimer;
@ -481,15 +472,15 @@ hoa_stat_printer::print(const spot::const_parsed_aut_ptr& haut,
if (has('T')) if (has('T'))
{ {
spot::twa_sub_statistics s = sub_stats_reachable(haut->aut); spot::twa_sub_statistics s = sub_stats_reachable(haut->aut);
haut_states_.set(s.states, haut->aut->num_states()); haut_states_ = s.states;
haut_edges_.set(s.edges, haut->aut->num_edges()); haut_edges_ = s.edges;
haut_trans_.set(s.transitions, count_all_transitions(haut->aut)); haut_trans_ = s.transitions;
} }
else if (has('E') || has('S')) else if (has('E') || has('S'))
{ {
spot::twa_statistics s = stats_reachable(haut->aut); spot::twa_statistics s = stats_reachable(haut->aut);
haut_states_.set(s.states, haut->aut->num_states()); haut_states_ = s.states;
haut_edges_.set(s.edges, haut->aut->num_edges()); haut_edges_ = s.edges;
} }
if (has('M')) if (has('M'))
{ {
@ -633,10 +624,10 @@ automaton_printer::print(const spot::twa_graph_ptr& aut,
outputnamer.print(haut, aut, f, filename, loc, ptimer, outputnamer.print(haut, aut, f, filename, loc, ptimer,
csv_prefix, csv_suffix); csv_prefix, csv_suffix);
std::string fname = outputname.str(); std::string fname = outputname.str();
auto [it, b] = outputfiles.try_emplace(fname, nullptr); auto p = outputfiles.emplace(fname, nullptr);
if (b) if (p.second)
it->second.reset(new output_file(fname.c_str())); p.first->second.reset(new output_file(fname.c_str()));
out = &it->second->ostream(); out = &p.first->second->ostream();
} }
// Output it. // Output it.

View file

@ -1,6 +1,6 @@
// -*- coding: utf-8 -*- // -*- coding: utf-8 -*-
// Copyright (C) 2014-2018, 2020, 2022, 2023 Laboratoire de Recherche // Copyright (C) 2014-2018, 2020 Laboratoire de Recherche et
// et Développement de l'Epita (LRDE). // Développement de l'Epita (LRDE).
// //
// This file is part of Spot, a model checking library. // This file is part of Spot, a model checking library.
// //
@ -47,7 +47,6 @@ enum automaton_format_t {
// The format to use in output_automaton() // The format to use in output_automaton()
extern automaton_format_t automaton_format; extern automaton_format_t automaton_format;
extern const char* automaton_format_opt;
// Set to the argument of --name, else nullptr. // Set to the argument of --name, else nullptr.
extern const char* opt_name; extern const char* opt_name;
// Output options // Output options
@ -155,7 +154,7 @@ public:
print(const spot::const_parsed_aut_ptr& haut, print(const spot::const_parsed_aut_ptr& haut,
const spot::const_twa_graph_ptr& aut, const spot::const_twa_graph_ptr& aut,
spot::formula f, spot::formula f,
const char* filename, int loc, const spot::process_timer& ptimer, const char* filename, int loc, spot::process_timer& ptimer,
const char* csv_prefix, const char* csv_suffix); const char* csv_prefix, const char* csv_suffix);
private: private:
@ -166,9 +165,9 @@ private:
spot::printable_value<std::string> aut_word_; spot::printable_value<std::string> aut_word_;
spot::printable_value<std::string> haut_word_; spot::printable_value<std::string> haut_word_;
spot::printable_acc_cond haut_gen_acc_; spot::printable_acc_cond haut_gen_acc_;
spot::printable_size haut_states_; spot::printable_value<unsigned> haut_states_;
spot::printable_size haut_edges_; spot::printable_value<unsigned> haut_edges_;
spot::printable_long_size haut_trans_; spot::printable_value<unsigned long long> haut_trans_;
spot::printable_value<unsigned> haut_acc_; spot::printable_value<unsigned> haut_acc_;
printable_varset haut_ap_; printable_varset haut_ap_;
printable_varset aut_ap_; printable_varset aut_ap_;
@ -196,7 +195,7 @@ class automaton_printer
std::map<std::string, std::unique_ptr<output_file>> outputfiles; std::map<std::string, std::unique_ptr<output_file>> outputfiles;
public: public:
explicit automaton_printer(stat_style input = no_input); automaton_printer(stat_style input = no_input);
~automaton_printer(); ~automaton_printer();
void void

View file

@ -1,5 +1,5 @@
// -*- coding: utf-8 -*- // -*- coding: utf-8 -*-
// Copyright (C) 2015, 2018, 2023 Laboratoire de Recherche et Développement // Copyright (C) 2015, 2018 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.
@ -25,15 +25,10 @@ int
to_int(const char* s, const char* where) to_int(const char* s, const char* where)
{ {
char* endptr; char* endptr;
errno = 0; int res = strtol(s, &endptr, 10);
long int lres = strtol(s, &endptr, 10);
if (*endptr) if (*endptr)
error(2, 0, "failed to parse '%s' as an integer (in argument of %s).", error(2, 0, "failed to parse '%s' as an integer (in argument of %s).",
s, where); s, where);
int res = lres;
if (res != lres || errno == ERANGE)
error(2, 0, "value '%s' is too large for an int (in argument of %s).",
s, where);
return res; return res;
} }
@ -50,17 +45,11 @@ unsigned
to_unsigned (const char *s, const char* where) to_unsigned (const char *s, const char* where)
{ {
char* endptr; char* endptr;
errno = 0; unsigned res = strtoul(s, &endptr, 10);
unsigned long lres = strtoul(s, &endptr, 10);
if (*endptr) if (*endptr)
error(2, 0, error(2, 0,
"failed to parse '%s' as an unsigned integer (in argument of %s).", "failed to parse '%s' as an unsigned integer (in argument of %s).",
s, where); s, where);
unsigned res = lres;
if (res != lres || errno == ERANGE)
error(2, 0,
"value '%s' is too large for a unsigned int (in argument of %s).",
s, where);
return res; return res;
} }
@ -68,9 +57,8 @@ float
to_float(const char* s, const char* where) to_float(const char* s, const char* where)
{ {
char* endptr; char* endptr;
errno = 0;
float res = strtof(s, &endptr); float res = strtof(s, &endptr);
if (*endptr || errno == ERANGE) if (*endptr)
error(2, 0, "failed to parse '%s' as a float (in argument of %s)", error(2, 0, "failed to parse '%s' as a float (in argument of %s)",
s, where); s, where);
return res; return res;
@ -92,9 +80,8 @@ to_longs(const char* arg)
while (*arg) while (*arg)
{ {
char* endptr; char* endptr;
errno = 0;
long value = strtol(arg, &endptr, 10); long value = strtol(arg, &endptr, 10);
if (endptr == arg || errno) if (endptr == arg)
error(2, 0, "failed to parse '%s' as an integer.", arg); error(2, 0, "failed to parse '%s' as an integer.", arg);
res.push_back(value); res.push_back(value);
while (*endptr == ' ' || *endptr == ',') while (*endptr == ' ' || *endptr == ',')

View file

@ -1,6 +1,6 @@
// -*- coding: utf-8 -*- // -*- coding: utf-8 -*-
// Copyright (C) 2015, 2016, 2022, 2023 Laboratoire de Recherche et // Copyright (C) 2015, 2016 Laboratoire de Recherche et Développement de
// Développement de l'Epita (LRDE). // l'Epita (LRDE).
// //
// This file is part of Spot, a model checking library. // This file is part of Spot, a model checking library.
// //
@ -21,27 +21,25 @@
#include <error.h> #include <error.h>
#include <iostream> #include <iostream>
output_file::output_file(const char* name, bool force_append)
output_file::output_file(const char* name)
{ {
std::ios_base::openmode mode = std::ios_base::trunc; std::ios_base::openmode mode = std::ios_base::trunc;
if (name[0] == '>' && name[1] == '>') if (name[0] == '>' && name[1] == '>')
{ {
mode = std::ios_base::app;
append_ = true; append_ = true;
name += 2; name += 2;
} }
if (force_append)
append_ = true;
if (append_)
mode = std::ios_base::app;
if (name[0] == '-' && name[1] == 0) if (name[0] == '-' && name[1] == 0)
{ {
os_ = &std::cout; os_ = &std::cout;
return; return;
} }
of_ = std::make_unique<std::ofstream>(name, mode); of_ = new std::ofstream(name, mode);
if (!*of_) if (!*of_)
error(2, errno, "cannot open '%s'", name); error(2, errno, "cannot open '%s'", name);
os_ = of_.get(); os_ = of_;
} }

View file

@ -1,6 +1,6 @@
// -*- coding: utf-8 -*- // -*- coding: utf-8 -*-
// Copyright (C) 2015-2016, 2022-2023 Laboratoire de Recherche et // Copyright (C) 2015, 2016 Laboratoire de Recherche et Développement de
// Développement de l'Epita (LRDE). // l'Epita (LRDE).
// //
// This file is part of Spot, a model checking library. // This file is part of Spot, a model checking library.
// //
@ -21,22 +21,27 @@
#include "common_sys.hh" #include "common_sys.hh"
#include <iosfwd> #include <iosfwd>
#include <memory>
#include <fstream> #include <fstream>
#include <error.h>
class output_file class output_file
{ {
std::ostream* os_; std::ostream* os_;
std::unique_ptr<std::ofstream> of_; std::ofstream* of_ = nullptr;
bool append_ = false; bool append_ = false;
public: public:
// Open a file for output. "-" is interpreted as stdout. // Open a file for output. "-" is interpreted as stdout.
// Names that start with ">>" are opened for append. // Names that start with ">>" are opened for append.
// The function calls error() on... error. // The function calls error() on... error.
output_file(const char* name, bool force_append = false); output_file(const char* name);
void close(const std::string& name); void close(const std::string& name);
~output_file()
{
delete of_;
}
bool append() const bool append() const
{ {
return append_; return append_;

View file

@ -1,6 +1,6 @@
// -*- coding: utf-8 -*- // -*- coding: utf-8 -*-
// Copyright (C) 2012-2017, 2019, 2021-2023 Laboratoire de Recherche // Copyright (C) 2012-2017, 2019, 2021 Laboratoire de Recherche et
// et Développement de l'Epita (LRDE). // Développement de l'Epita (LRDE).
// //
// This file is part of Spot, a model checking library. // This file is part of Spot, a model checking library.
// //
@ -68,10 +68,10 @@ parse_opt_finput(int key, char* arg, struct argp_state*)
switch (key) switch (key)
{ {
case 'f': case 'f':
jobs.emplace_back(arg, job_type::LTL_STRING); jobs.emplace_back(arg, false);
break; break;
case 'F': case 'F':
jobs.emplace_back(arg, job_type::LTL_FILENAME); jobs.emplace_back(arg, true);
break; break;
case OPT_LBT: case OPT_LBT:
lbt_input = true; lbt_input = true;
@ -96,6 +96,12 @@ parse_formula(const std::string& s)
(s, spot::default_environment::instance(), false, lenient); (s, spot::default_environment::instance(), false, lenient);
} }
job_processor::job_processor()
: abort_run(false), real_filename(nullptr),
col_to_read(0), prefix(nullptr), suffix(nullptr)
{
}
job_processor::~job_processor() job_processor::~job_processor()
{ {
if (real_filename) if (real_filename)
@ -297,22 +303,8 @@ job_processor::process_stream(std::istream& is,
} }
int int
job_processor::process_aut_file(const char*) job_processor::process_file(const char* filename)
{ {
throw std::runtime_error("process_aut_file not defined for this tool");
}
int
job_processor::process_tlsf_file(const char*)
{
throw std::runtime_error("process_tlsf_file not defined for this tool");
}
int
job_processor::process_ltl_file(const char* filename)
{
col_to_read = 0;
// Special case for stdin. // Special case for stdin.
if (filename[0] == '-' && filename[1] == 0) if (filename[0] == '-' && filename[1] == 0)
return process_stream(std::cin, filename); return process_stream(std::cin, filename);
@ -364,25 +356,12 @@ int
job_processor::run() job_processor::run()
{ {
int error = 0; int error = 0;
for (const auto& j: jobs) for (auto& j: jobs)
{ {
switch (j.type) if (!j.file_p)
{
case job_type::LTL_STRING:
error |= process_string(j.str); error |= process_string(j.str);
break; else
case job_type::LTL_FILENAME: error |= process_file(j.str);
error |= process_ltl_file(j.str);
break;
case job_type::AUT_FILENAME:
error |= process_aut_file(j.str);
break;
case job_type::TLSF_FILENAME:
error |= process_tlsf_file(j.str);
break;
default:
throw std::runtime_error("unexpected job type");
}
if (abort_run) if (abort_run)
break; break;
} }
@ -397,7 +376,7 @@ void check_no_formula()
error(2, 0, "No formula to translate? Run '%s --help' for help.\n" error(2, 0, "No formula to translate? Run '%s --help' for help.\n"
"Use '%s -' to force reading formulas from the standard " "Use '%s -' to force reading formulas from the standard "
"input.", program_name, program_name); "input.", program_name, program_name);
jobs.emplace_back("-", job_type::LTL_FILENAME); jobs.emplace_back("-", true);
} }
void check_no_automaton() void check_no_automaton()
@ -408,5 +387,5 @@ void check_no_automaton()
error(2, 0, "No automaton to process? Run '%s --help' for help.\n" error(2, 0, "No automaton to process? Run '%s --help' for help.\n"
"Use '%s -' to force reading automata from the standard " "Use '%s -' to force reading automata from the standard "
"input.", program_name, program_name); "input.", program_name, program_name);
jobs.emplace_back("-", job_type::AUT_FILENAME); jobs.emplace_back("-", true);
} }

View file

@ -1,6 +1,6 @@
// -*- coding: utf-8 -*- // -*- coding: utf-8 -*-
// Copyright (C) 2012-2017, 2022, 2023 Laboratoire de Recherche et // Copyright (C) 2012-2017 Laboratoire de Recherche et Développement
// 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.
// //
@ -25,18 +25,13 @@
#include <vector> #include <vector>
#include <spot/tl/parse.hh> #include <spot/tl/parse.hh>
enum class job_type : char { LTL_STRING,
LTL_FILENAME,
AUT_FILENAME,
TLSF_FILENAME };
struct job struct job
{ {
const char* str; const char* str;
job_type type; bool file_p; // true if str is a filename, false if it is a formula
job(const char* str, job_type type) noexcept job(const char* str, bool file_p) noexcept
: str(str), type(type) : str(str), file_p(file_p)
{ {
} }
}; };
@ -56,11 +51,9 @@ spot::parsed_formula parse_formula(const std::string& s);
class job_processor class job_processor
{ {
protected: protected:
bool abort_run = false; // Set to true in process_formula() to abort run(). bool abort_run; // Set to true in process_formula() to abort run().
public: public:
job_processor() = default; job_processor();
job_processor(const job_processor&) = delete;
job_processor& operator=(const job_processor&) = delete;
virtual ~job_processor(); virtual ~job_processor();
@ -75,21 +68,15 @@ public:
process_stream(std::istream& is, const char* filename); process_stream(std::istream& is, const char* filename);
virtual int virtual int
process_ltl_file(const char* filename); process_file(const char* filename);
virtual int
process_aut_file(const char* filename);
virtual int
process_tlsf_file(const char* filename);
virtual int virtual int
run(); run();
char* real_filename = nullptr; char* real_filename;
long int col_to_read = 0; long int col_to_read;
char* prefix = nullptr; char* prefix;
char* suffix = nullptr; char* suffix;
}; };
// Report and error message or add a default job depending on whether // Report and error message or add a default job depending on whether

View file

@ -1,6 +1,6 @@
// -*- coding: utf-8 -*- // -*- coding: utf-8 -*-
// Copyright (C) 2015, 2017, 2018, 2022 Laboratoire de Recherche et // Copyright (C) 2015, 2017, 2018 Laboratoire de Recherche et Développement de
// Développement de l'Epita (LRDE). // l'Epita (LRDE).
// //
// This file is part of Spot, a model checking library. // This file is part of Spot, a model checking library.
// //
@ -80,10 +80,8 @@ public:
} }
int int
process_aut_file(const char* filename) override process_file(const char* filename) override
{ {
col_to_read = 0;
// If we have a filename like "foo/NN" such // If we have a filename like "foo/NN" such
// that: // that:
// ① foo/NN is not a file, // ① foo/NN is not a file,

View file

@ -1,5 +1,5 @@
// -*- coding: utf-8 -*- // -*- coding: utf-8 -*-
// Copyright (C) 2012-2019, 2023 Laboratoire de Recherche et Développement // Copyright (C) 2012-2019 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.
@ -23,7 +23,6 @@
#include "common_setup.hh" #include "common_setup.hh"
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
#include <memory>
#include <spot/tl/print.hh> #include <spot/tl/print.hh>
#include <spot/tl/length.hh> #include <spot/tl/length.hh>
#include <spot/tl/apcollect.hh> #include <spot/tl/apcollect.hh>
@ -298,9 +297,9 @@ namespace
}; };
} }
static std::unique_ptr<formula_printer> format; static formula_printer* format = nullptr;
static std::ostringstream outputname; static std::ostringstream outputname;
static std::unique_ptr<formula_printer> outputnamer; static formula_printer* outputnamer = nullptr;
static std::map<std::string, std::unique_ptr<output_file>> outputfiles; static std::map<std::string, std::unique_ptr<output_file>> outputfiles;
int int
@ -321,7 +320,7 @@ parse_opt_output(int key, char* arg, struct argp_state*)
output_format = lbt_output; output_format = lbt_output;
break; break;
case 'o': case 'o':
outputnamer = std::make_unique<formula_printer>(outputname, arg); outputnamer = new formula_printer(outputname, arg);
break; break;
case 'p': case 'p':
full_parenth = true; full_parenth = true;
@ -342,7 +341,8 @@ parse_opt_output(int key, char* arg, struct argp_state*)
output_format = wring_output; output_format = wring_output;
break; break;
case OPT_FORMAT: case OPT_FORMAT:
format = std::make_unique<formula_printer>(std::cout, arg); delete format;
format = new formula_printer(std::cout, arg);
break; break;
default: default:
return ARGP_ERR_UNKNOWN; return ARGP_ERR_UNKNOWN;
@ -417,10 +417,10 @@ output_formula_checked(spot::formula f, spot::process_timer* ptimer,
formula_with_location fl = { f, filename, linenum, prefix, suffix }; formula_with_location fl = { f, filename, linenum, prefix, suffix };
outputnamer->print(fl, ptimer); outputnamer->print(fl, ptimer);
std::string fname = outputname.str(); std::string fname = outputname.str();
auto [it, b] = outputfiles.try_emplace(fname, nullptr); auto p = outputfiles.emplace(fname, nullptr);
if (b) if (p.second)
it->second.reset(new output_file(fname.c_str())); p.first->second.reset(new output_file(fname.c_str()));
out = &it->second->ostream(); out = &p.first->second->ostream();
} }
output_formula(*out, f, ptimer, filename, linenum, prefix, suffix); output_formula(*out, f, ptimer, filename, linenum, prefix, suffix);
*out << output_terminator; *out << output_terminator;

View file

@ -1,5 +1,5 @@
// -*- coding: utf-8 -*- // -*- coding: utf-8 -*-
// Copyright (C) 2012, 2014, 2016, 2023 Laboratoire de Recherche et // Copyright (C) 2012, 2014, 2016 Laboratoire de Recherche et
// Développement de l'Epita (LRDE). // Développement de l'Epita (LRDE).
// //
// This file is part of Spot, a model checking library. // This file is part of Spot, a model checking library.
@ -36,17 +36,13 @@ parse_range(const char* str, int missing_left, int missing_right)
{ {
range res; range res;
char* end; char* end;
errno = 0; res.min = strtol(str, &end, 10);
long lres = strtol(str, &end, 10);
res.min = lres;
if (res.min != lres || errno == ERANGE)
error(2, 0, "start of range '%s' is too large for an int.", str);
if (end == str) if (end == str)
{ {
// No leading number. It's OK as long as the string is not // No leading number. It's OK as long as the string is not
// empty. // empty.
if (!*end) if (!*end)
error(2, 0, "invalid empty range"); error(1, 0, "invalid empty range");
res.min = missing_left; res.min = missing_left;
} }
if (!*end) if (!*end)
@ -70,23 +66,19 @@ parse_range(const char* str, int missing_left, int missing_right)
{ {
// Parse the next integer. // Parse the next integer.
char* end2; char* end2;
errno = 0; res.max = strtol(end, &end2, 10);
lres = strtol(end, &end2, 10);
res.max = lres;
if (res.max != lres || errno == ERANGE)
error(2, 0, "end of range '%s' is too large for an int.", str);
if (str == end2) if (str == end2)
error(2, 0, "invalid range '%s' " error(1, 0, "invalid range '%s' "
"(should start with digits, dots, or colon)", str); "(should start with digits, dots, or colon)", str);
if (end == end2) if (end == end2)
error(2, 0, "invalid range '%s' (missing end?)", str); error(1, 0, "invalid range '%s' (missing end?)", str);
if (*end2) if (*end2)
error(2, 0, "invalid range '%s' (trailing garbage?)", str); error(1, 0, "invalid range '%s' (trailing garbage?)", str);
} }
} }
if (res.min < 0 || res.max < 0) if (res.min < 0 || res.max < 0)
error(2, 0, "invalid range '%s': values must be positive", str); error(1, 0, "invalid range '%s': values must be positive", str);
return res; return res;
} }

View file

@ -1,5 +1,5 @@
// -*- coding: utf-8 -*- // -*- coding: utf-8 -*-
// Copyright (C) 2012-2023 Laboratoire de Recherche et Développement // Copyright (C) 2012-2022 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.
@ -20,14 +20,13 @@
#include "common_setup.hh" #include "common_setup.hh"
#include "common_aoutput.hh" #include "common_aoutput.hh"
#include <argp.h> #include "argp.h"
#include <closeout.h> #include "closeout.h"
#include <cstdlib> #include <cstdlib>
#include <unistd.h> #include <unistd.h>
#include <iostream> #include <iostream>
#include <signal.h> #include <signal.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <error.h>
#include <spot/misc/tmpfile.hh> #include <spot/misc/tmpfile.hh>
static void static void
@ -36,7 +35,7 @@ display_version(FILE *stream, struct argp_state*)
fputs(program_name, stream); fputs(program_name, stream);
fputs(" (" PACKAGE_NAME ") " PACKAGE_VERSION "\n\ fputs(" (" PACKAGE_NAME ") " PACKAGE_VERSION "\n\
\n\ \n\
Copyright (C) 2023 Laboratoire de Recherche de l'Epita (LRE)\n\ Copyright (C) 2022 Laboratoire de Recherche et Développement de l'Epita.\n\
License GPLv3+: \ License GPLv3+: \
GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.\n\ GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.\n\
This is free software: you are free to change and redistribute it.\n\ This is free software: you are free to change and redistribute it.\n\

View file

@ -1,6 +1,6 @@
// -*- coding: utf-8 -*- // -*- coding: utf-8 -*-
// Copyright (C) 2012-2013, 2018-2019, 2023 Laboratoire de Recherche // Copyright (C) 2012, 2013, 2018, 2019 Laboratoire de Recherche et
// et Développement de l'Epita (LRDE). // Développement de l'Epita (LRDE).
// //
// This file is part of Spot, a model checking library. // This file is part of Spot, a model checking library.
// //
@ -34,5 +34,5 @@ int protected_main(char** progname, std::function<int()> mainfun);
// Diagnose exceptions. // Diagnose exceptions.
[[noreturn]] void handle_any_exception(); [[noreturn]] void handle_any_exception();
#define BEGIN_EXCEPTION_PROTECT try { (void)0 #define BEGIN_EXCEPTION_PROTECT try { (void)0;
#define END_EXCEPTION_PROTECT } catch (...) { handle_any_exception(); } #define END_EXCEPTION_PROTECT } catch (...) { handle_any_exception(); }

View file

@ -1,5 +1,5 @@
// -*- coding: utf-8 -*- // -*- coding: utf-8 -*-
// Copyright (C) 2015-2023 Laboratoire de Recherche et Développement // Copyright (C) 2015-2022 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.
@ -27,7 +27,6 @@
#include <sys/wait.h> #include <sys/wait.h>
#include <fcntl.h> #include <fcntl.h>
#include <iomanip> #include <iomanip>
#include <fstream>
#if __has_include(<spawn.h>) #if __has_include(<spawn.h>)
#define HAVE_SPAWN_H 1 #define HAVE_SPAWN_H 1
#include <spawn.h> #include <spawn.h>
@ -53,7 +52,7 @@ struct shorthands_t
}; };
#define SHORTHAND(PRE, POST) { PRE, std::regex("^" PRE), POST } #define SHORTHAND(PRE, POST) { PRE, std::regex("^" PRE), POST }
static const shorthands_t shorthands_ltl[] = { static shorthands_t shorthands_ltl[] = {
SHORTHAND("delag", " %f>%O"), SHORTHAND("delag", " %f>%O"),
SHORTHAND("lbt", " <%L>%O"), SHORTHAND("lbt", " <%L>%O"),
SHORTHAND("ltl2ba", " -f %s>%O"), SHORTHAND("ltl2ba", " -f %s>%O"),
@ -73,7 +72,7 @@ static const shorthands_t shorthands_ltl[] = {
SHORTHAND("owl.* ltl-utilities\\b", " -f %f"), SHORTHAND("owl.* ltl-utilities\\b", " -f %f"),
}; };
static const shorthands_t shorthands_autproc[] = { static shorthands_t shorthands_autproc[] = {
SHORTHAND("autfilt", " %H>%O"), SHORTHAND("autfilt", " %H>%O"),
SHORTHAND("dra2dpa", " <%H>%O"), SHORTHAND("dra2dpa", " <%H>%O"),
SHORTHAND("dstar2tgba", " %H>%O"), SHORTHAND("dstar2tgba", " %H>%O"),
@ -85,7 +84,7 @@ static const shorthands_t shorthands_autproc[] = {
" <%H>%O"), " <%H>%O"),
}; };
static void show_shorthands(const shorthands_t* begin, const shorthands_t* end) static void show_shorthands(shorthands_t* begin, shorthands_t* end)
{ {
std::cout std::cout
<< ("If a COMMANDFMT does not use any %-sequence, and starts with one of\n" << ("If a COMMANDFMT does not use any %-sequence, and starts with one of\n"
@ -100,8 +99,7 @@ static void show_shorthands(const shorthands_t* begin, const shorthands_t* end)
} }
tool_spec::tool_spec(const char* spec, tool_spec::tool_spec(const char* spec, shorthands_t* begin, shorthands_t* end,
const shorthands_t* begin, const shorthands_t* end,
bool is_ref) noexcept bool is_ref) noexcept
: spec(spec), cmd(spec), name(spec), reference(is_ref) : spec(spec), cmd(spec), name(spec), reference(is_ref)
{ {
@ -114,11 +112,11 @@ tool_spec::tool_spec(const char* spec,
{ {
if (*pos == '{') if (*pos == '{')
++count; ++count;
else if (*pos == '}' && --count == 0) else if (*pos == '}')
if (!--count)
{ {
name = strndup(cmd + 1, pos - cmd - 1); name = strndup(cmd + 1, pos - cmd - 1);
cmd = pos + 1; cmd = pos + 1;
// skip leading whitespace
while (*cmd == ' ' || *cmd == '\t') while (*cmd == ' ' || *cmd == '\t')
++cmd; ++cmd;
break; break;
@ -148,11 +146,11 @@ tool_spec::tool_spec(const char* spec,
auto& p = *begin++; auto& p = *begin++;
if (std::regex_search(basename, p.rprefix)) if (std::regex_search(basename, p.rprefix))
{ {
size_t m = strlen(p.suffix); int m = strlen(p.suffix);
size_t q = strlen(cmd); int q = strlen(cmd);
char* tmp = static_cast<char*>(malloc(q + m + 1)); char* tmp = static_cast<char*>(malloc(q + m + 1));
memcpy(tmp, cmd, q); strcpy(tmp, cmd);
memcpy(tmp + q, p.suffix, m + 1); strcpy(tmp + q, p.suffix);
cmd = tmp; cmd = tmp;
allocated = true; allocated = true;
break; break;
@ -463,92 +461,6 @@ autproc_runner::round_automaton(spot::const_twa_graph_ptr aut, unsigned serial)
filename_automaton.new_round(aut, serial); filename_automaton.new_round(aut, serial);
} }
std::string
read_stdout_of_command(char* const* args)
{
#if HAVE_SPAWN_H
int cout_pipe[2];
if (int err = pipe(cout_pipe))
error(2, err, "pipe() failed");
posix_spawn_file_actions_t actions;
if (int err = posix_spawn_file_actions_init(&actions))
error(2, err, "posix_spawn_file_actions_init() failed");
posix_spawn_file_actions_addclose(&actions, STDIN_FILENO);
posix_spawn_file_actions_addclose(&actions, cout_pipe[0]);
posix_spawn_file_actions_adddup2(&actions, cout_pipe[1], STDOUT_FILENO);
posix_spawn_file_actions_addclose(&actions, cout_pipe[1]);
pid_t pid;
if (int err = posix_spawnp(&pid, args[0], &actions, nullptr, args, environ))
error(2, err, "failed to run '%s'", args[0]);
if (int err = posix_spawn_file_actions_destroy(&actions))
error(2, err, "posix_spawn_file_actions_destroy() failed");
if (close(cout_pipe[1]) < 0)
error(2, errno, "closing write-side of pipe failed");
std::string results;
ssize_t bytes_read;
for (;;)
{
static char buffer[512];
bytes_read = read(cout_pipe[0], buffer, sizeof(buffer));
if (bytes_read > 0)
results.insert(results.end(), buffer, buffer + bytes_read);
else
break;
}
if (bytes_read < 0)
error(2, bytes_read, "failed to read from pipe");
if (cout_pipe[0] < 0)
error(2, errno, "closing read-side of pipe failed");
int exit_code = 0;
if (waitpid(pid, &exit_code, 0) == -1)
error(2, errno, "waitpid() failed");
if (exit_code)
error(2, 0, "'%s' exited with status %d", args[0], exit_code);
return results;
#else
// We could provide a pipe+fork+exec alternative implementation, but
// systems without posix_spawn() might also not have fork and exec.
// For instance MinGW does not. So let's fallback to system+tmpfile
// instead for maximum portability.
char prefix[30];
snprintf(prefix, sizeof prefix, "spot-tmp");
spot::temporary_file* tmpfile = spot::create_tmpfile(prefix);
std::string tmpname = tmpfile->name();
std::ostringstream cmd;
for (auto t = args; *t != nullptr; ++t)
spot::quote_shell_string(cmd, *t) << ' ';
cmd << '>';
spot::quote_shell_string(cmd, tmpfile->name());
std::string cmdstr = cmd.str();
int exit_code = system(cmdstr.c_str());
if (exit_code < 0)
error(2, errno, "failed to execute %s", cmdstr.c_str());
if (exit_code > 0)
error(2, 0, "'%s' exited with status %d", args[0], exit_code);
std::ifstream ifs(tmpname, std::ifstream::in);
if (!ifs)
error(2, 0, "failed to open %s (output of %s)", tmpname.c_str(), args[0]);
ifs.exceptions(std::ifstream::failbit | std::ifstream::badbit);
std::stringstream buffer;
buffer << ifs.rdbuf();
delete tmpfile;
return buffer.str();
#endif
}
std::atomic<bool> timed_out{false}; std::atomic<bool> timed_out{false};
unsigned timeout_count = 0; unsigned timeout_count = 0;
@ -612,7 +524,7 @@ get_arg(const char*& cmd)
{ {
const char* start = cmd; const char* start = cmd;
std::string arg; std::string arg;
while (char c = *cmd) while (int c = *cmd)
{ {
switch (c) switch (c)
{ {
@ -642,14 +554,14 @@ get_arg(const char*& cmd)
goto end_loop; goto end_loop;
case '\'': case '\'':
{ {
char d = '\0'; int d = 0;
while ((d = *++cmd)) while ((d = *++cmd))
{ {
if (d == '\'') if (d == '\'')
break; break;
arg.push_back(d); arg.push_back(d);
} }
if (d == '\0') if (d == 0)
return nullptr; return nullptr;
} }
break; break;
@ -794,7 +706,6 @@ parse_simple_command(const char* cmd)
return res; return res;
} }
#ifndef HAVE_SPAWN_H #ifndef HAVE_SPAWN_H
static void static void
exec_command(const char* cmd) exec_command(const char* cmd)
@ -840,6 +751,8 @@ exec_command(const char* cmd)
SPOT_UNREACHABLE(); SPOT_UNREACHABLE();
return; return;
} }
#else
extern char **environ;
#endif #endif
int int

View file

@ -1,5 +1,5 @@
// -*- coding: utf-8 -*- // -*- coding: utf-8 -*-
// Copyright (C) 2015-2018, 2020, 2022 Laboratoire de Recherche et // Copyright (C) 2015-2018, 2020 Laboratoire de Recherche et
// Développement de l'Epita (LRDE). // Développement de l'Epita (LRDE).
// //
// This file is part of Spot, a model checking library. // This file is part of Spot, a model checking library.
@ -51,8 +51,7 @@ struct tool_spec
// Whether the tool is a reference. // Whether the tool is a reference.
bool reference; bool reference;
tool_spec(const char* spec, tool_spec(const char* spec, shorthands_t* begin, shorthands_t* end,
const shorthands_t* begin, const shorthands_t* end,
bool is_ref) noexcept; bool is_ref) noexcept;
tool_spec(const tool_spec& other) noexcept; tool_spec(const tool_spec& other) noexcept;
tool_spec& operator=(const tool_spec& other); tool_spec& operator=(const tool_spec& other);
@ -72,7 +71,7 @@ struct quoted_formula final: public spot::printable_value<spot::formula>
struct filed_formula final: public spot::printable struct filed_formula final: public spot::printable
{ {
explicit filed_formula(const quoted_formula& ltl) : f_(ltl) filed_formula(const quoted_formula& ltl) : f_(ltl)
{ {
} }
@ -90,7 +89,9 @@ struct filed_formula final: public spot::printable
struct filed_automaton final: public spot::printable struct filed_automaton final: public spot::printable
{ {
filed_automaton() = default; filed_automaton()
{
}
void print(std::ostream& os, const char* pos) const override; void print(std::ostream& os, const char* pos) const override;
@ -111,7 +112,7 @@ struct printable_result_filename final:
unsigned translator_num; unsigned translator_num;
printable_result_filename(); printable_result_filename();
~printable_result_filename() override; ~printable_result_filename();
void reset(unsigned n); void reset(unsigned n);
void cleanup(); void cleanup();
@ -125,7 +126,7 @@ protected:
spot::bdd_dict_ptr dict; spot::bdd_dict_ptr dict;
// Round-specific variables // Round-specific variables
quoted_formula ltl_formula; quoted_formula ltl_formula;
filed_formula filename_formula{ltl_formula}; filed_formula filename_formula = ltl_formula;
// Run-specific variables // Run-specific variables
printable_result_filename output; printable_result_filename output;
public: public:
@ -150,7 +151,7 @@ protected:
public: public:
using spot::formater::has; using spot::formater::has;
explicit autproc_runner(// whether we accept the absence of output autproc_runner(// whether we accept the absence of output
// specifier // specifier
bool no_output_allowed = false); bool no_output_allowed = false);
void round_automaton(spot::const_twa_graph_ptr aut, unsigned serial); void round_automaton(spot::const_twa_graph_ptr aut, unsigned serial);
@ -174,9 +175,3 @@ int exec_with_timeout(const char* cmd);
#define exec_with_timeout(cmd) system(cmd) #define exec_with_timeout(cmd) system(cmd)
#define setup_sig_handler() while (0); #define setup_sig_handler() while (0);
#endif // !ENABLE_TIMEOUT #endif // !ENABLE_TIMEOUT
// Run a command (whose args[0], args[1], etc. are given by args), and
// return its captured stdout. Stderr is not captured. Will abort
// with an error message if the command is not found, or if it exit
// with a non-zero status code.
std::string read_stdout_of_command(char* const* args);

View file

@ -1,5 +1,5 @@
// -*- coding: utf-8 -*- // -*- coding: utf-8 -*-
// Copyright (C) 2013-2019, 2022, 2023 Laboratoire de Recherche et Développement // Copyright (C) 2013-2019 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.
@ -89,7 +89,7 @@ parse_opt(int key, char* arg, struct argp_state*)
switch (key) switch (key)
{ {
case 'F': case 'F':
jobs.emplace_back(arg, job_type::AUT_FILENAME); jobs.emplace_back(arg, true);
break; break;
case 'x': case 'x':
{ {
@ -99,7 +99,7 @@ parse_opt(int key, char* arg, struct argp_state*)
} }
break; break;
case ARGP_KEY_ARG: case ARGP_KEY_ARG:
jobs.emplace_back(arg, job_type::AUT_FILENAME); jobs.emplace_back(arg, true);
break; break;
default: default:
return ARGP_ERR_UNKNOWN; return ARGP_ERR_UNKNOWN;
@ -117,7 +117,7 @@ namespace
spot::postprocessor& post; spot::postprocessor& post;
automaton_printer printer; automaton_printer printer;
explicit dstar_processor(spot::postprocessor& post) dstar_processor(spot::postprocessor& post)
: hoa_processor(spot::make_bdd_dict()), post(post), printer(aut_input) : hoa_processor(spot::make_bdd_dict()), post(post), printer(aut_input)
{ {
} }

View file

@ -1,6 +1,6 @@
// -*- coding: utf-8 -*- // -*- coding: utf-8 -*-
// Copyright (C) 2017-2019, 2022-2023 Laboratoire de Recherche et // Copyright (C) 2017-2019 Laboratoire de Recherche et Développement
// 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.
// //
@ -43,8 +43,7 @@
using namespace spot; using namespace spot;
static const char argp_program_doc[] = const char argp_program_doc[] ="Generate ω-automata from predefined patterns.";
"Generate ω-automata from predefined patterns.";
static const argp_option options[] = static const argp_option options[] =
{ {
@ -63,11 +62,6 @@ static const argp_option options[] =
{ "m-nba", gen::AUT_M_NBA, "RANGE", 0, { "m-nba", gen::AUT_M_NBA, "RANGE", 0,
"An NBA with N+1 states whose determinization needs at least " "An NBA with N+1 states whose determinization needs at least "
"N! states", 0}, "N! states", 0},
{ "cyclist-trace-nba", gen::AUT_CYCLIST_TRACE_NBA, "RANGE", 0,
"An NBA with N+2 states that should include cyclist-proof-dba=B.", 0},
{ "cyclist-proof-dba", gen::AUT_CYCLIST_PROOF_DBA, "RANGE", 0,
"A DBA with N+2 states that should be included "
"in cyclist-trace-nba=B.", 0},
RANGE_DOC, RANGE_DOC,
/**************************************************/ /**************************************************/
{ nullptr, 0, nullptr, 0, "Miscellaneous options:", -1 }, { nullptr, 0, nullptr, 0, "Miscellaneous options:", -1 },
@ -128,7 +122,7 @@ output_pattern(gen::aut_pattern_id pattern, int n)
static void static void
run_jobs() run_jobs()
{ {
for (const auto& j: jobs) for (auto& j: jobs)
{ {
int inc = (j.range.max < j.range.min) ? -1 : 1; int inc = (j.range.max < j.range.min) ? -1 : 1;
int n = j.range.min; int n = j.range.min;

View file

@ -1,6 +1,6 @@
// -*- coding: utf-8 -*- // -*- coding: utf-8 -*-
// Copyright (C) 2012, 2013, 2015-2019, 2022-2023 Laboratoire de // Copyright (C) 2012, 2013, 2015-2019 Laboratoire de Recherche et
// Recherche et Développement de l'Epita (LRDE). // Développement de l'Epita (LRDE).
// //
// This file is part of Spot, a model checking library. // This file is part of Spot, a model checking library.
// //
@ -45,7 +45,7 @@
using namespace spot; using namespace spot;
static const char argp_program_doc[] = "\ const char argp_program_doc[] ="\
Generate temporal logic formulas from predefined patterns."; Generate temporal logic formulas from predefined patterns.";
// We reuse the values from gen::ltl_pattern_id as option keys. // We reuse the values from gen::ltl_pattern_id as option keys.
@ -84,8 +84,6 @@ static const argp_option options[] =
{ "eh-patterns", gen::LTL_EH_PATTERNS, "RANGE", OPTION_ARG_OPTIONAL, { "eh-patterns", gen::LTL_EH_PATTERNS, "RANGE", OPTION_ARG_OPTIONAL,
"Etessami and Holzmann [Concur'00] patterns " "Etessami and Holzmann [Concur'00] patterns "
"(range should be included in 1..12)", 0 }, "(range should be included in 1..12)", 0 },
{ "eil-gsi", gen::LTL_EIL_GSI, "RANGE", 0,
"G[0..n]((a S b) -> c) rewritten using future operators", 0 },
{ "fxg-or", gen::LTL_FXG_OR, "RANGE", 0, { "fxg-or", gen::LTL_FXG_OR, "RANGE", 0,
"F(p0 | XG(p1 | XG(p2 | ... XG(pn))))", 0}, "F(p0 | XG(p1 | XG(p2 | ... XG(pn))))", 0},
{ "gf-equiv", gen::LTL_GF_EQUIV, "RANGE", 0, { "gf-equiv", gen::LTL_GF_EQUIV, "RANGE", 0,
@ -317,7 +315,7 @@ output_pattern(gen::ltl_pattern_id pattern, int n, int n2)
static void static void
run_jobs() run_jobs()
{ {
for (const auto& j: jobs) for (auto& j: jobs)
{ {
int inc = (j.range.max < j.range.min) ? -1 : 1; int inc = (j.range.max < j.range.min) ? -1 : 1;
int n = j.range.min; int n = j.range.min;

View file

@ -1,6 +1,6 @@
// -*- coding: utf-8 -*- // -*- coding: utf-8 -*-
// Copyright (C) 2012-2019, 2022-2023 Laboratoire de Recherche et // Copyright (C) 2012-2019 Laboratoire de Recherche et Développement
// 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.
// //
@ -105,9 +105,10 @@ parse_opt(int key, char* arg, struct argp_state*)
break; break;
case ARGP_KEY_ARG: case ARGP_KEY_ARG:
// FIXME: use stat() to distinguish filename from string? // FIXME: use stat() to distinguish filename from string?
jobs.emplace_back(arg, ((*arg == '-' && !arg[1]) if (*arg == '-' && !arg[1])
? job_type::LTL_FILENAME jobs.emplace_back(arg, true);
: job_type::LTL_STRING)); else
jobs.emplace_back(arg, false);
break; break;
default: default:
@ -124,10 +125,10 @@ namespace
{ {
public: public:
spot::translator& trans; spot::translator& trans;
automaton_printer printer{ltl_input}; automaton_printer printer;
explicit trans_processor(spot::translator& trans) trans_processor(spot::translator& trans)
: trans(trans) : trans(trans), printer(ltl_input)
{ {
} }

View file

@ -1,6 +1,6 @@
// -*- coding: utf-8 -*- // -*- coding: utf-8 -*-
// Copyright (C) 2012-2020, 2022-2023 Laboratoire de Recherche et // Copyright (C) 2012-2020 Laboratoire de Recherche et Développement
// 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.
// //
@ -46,7 +46,7 @@
#include <spot/taalgos/minimize.hh> #include <spot/taalgos/minimize.hh>
#include <spot/misc/optionmap.hh> #include <spot/misc/optionmap.hh>
static const char argp_program_doc[] = "\ const char argp_program_doc[] ="\
Translate linear-time formulas (LTL/PSL) into Testing Automata.\n\n\ Translate linear-time formulas (LTL/PSL) into Testing Automata.\n\n\
By default it outputs a transition-based generalized Testing Automaton \ By default it outputs a transition-based generalized Testing Automaton \
the smallest Transition-based Generalized Büchi Automata, \ the smallest Transition-based Generalized Büchi Automata, \
@ -148,9 +148,10 @@ parse_opt(int key, char* arg, struct argp_state*)
break; break;
case ARGP_KEY_ARG: case ARGP_KEY_ARG:
// FIXME: use stat() to distinguish filename from string? // FIXME: use stat() to distinguish filename from string?
jobs.emplace_back(arg, ((*arg == '-' && !arg[1]) if (*arg == '-' && !arg[1])
? job_type::LTL_FILENAME jobs.emplace_back(arg, true);
: job_type::LTL_STRING)); else
jobs.emplace_back(arg, false);
break; break;
default: default:
@ -168,7 +169,7 @@ namespace
public: public:
spot::translator& trans; spot::translator& trans;
explicit trans_processor(spot::translator& trans) trans_processor(spot::translator& trans)
: trans(trans) : trans(trans)
{ {
} }

View file

@ -1,6 +1,6 @@
// -*- coding: utf-8 -*- // -*- coding: utf-8 -*-
// Copyright (C) 2012-2020, 2022, 2023 Laboratoire de Recherche et // Copyright (C) 2012-2020 Laboratoire de Recherche et Développement
// 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.
// //
@ -69,7 +69,7 @@
#include <spot/misc/tmpfile.hh> #include <spot/misc/tmpfile.hh>
#include <spot/misc/timer.hh> #include <spot/misc/timer.hh>
static const char argp_program_doc[] = "\ const char argp_program_doc[] ="\
Call several LTL/PSL translators and cross-compare their output to detect \ Call several LTL/PSL translators and cross-compare their output to detect \
bugs, or to gather statistics. The list of formulas to use should be \ bugs, or to gather statistics. The list of formulas to use should be \
supplied on standard input, or using the -f or -F options.\v\ supplied on standard input, or using the -f or -F options.\v\
@ -264,32 +264,55 @@ end_error()
struct statistics struct statistics
{ {
statistics()
: ok(false),
alternating(false),
status_str(nullptr),
status_code(0),
time(0),
states(0),
edges(0),
transitions(0),
acc(0),
scc(0),
nonacc_scc(0),
terminal_scc(0),
weak_scc(0),
strong_scc(0),
nondetstates(0),
nondeterministic(false),
terminal_aut(false),
weak_aut(false),
strong_aut(false)
{
}
// If OK is false, only the status_str, status_code, and time fields // If OK is false, only the status_str, status_code, and time fields
// should be valid. // should be valid.
bool ok = false; bool ok;
bool alternating = false; bool alternating;
const char* status_str = nullptr; const char* status_str;
int status_code = 0; int status_code;
double time = 0.0; double time;
unsigned states = 0; unsigned states;
unsigned edges = 0; unsigned edges;
unsigned long long transitions = 0; unsigned long long transitions;
unsigned acc = 0; unsigned acc;
unsigned scc = 0; unsigned scc;
unsigned nonacc_scc = 0; unsigned nonacc_scc;
unsigned terminal_scc = 0; unsigned terminal_scc;
unsigned weak_scc = 0; unsigned weak_scc;
unsigned strong_scc = 0; unsigned strong_scc;
unsigned nondetstates = 0; unsigned nondetstates;
bool nondeterministic = false; bool nondeterministic;
bool terminal_aut = false; bool terminal_aut;
bool weak_aut = false; bool weak_aut;
bool strong_aut = false; bool strong_aut;
std::vector<double> product_states; std::vector<double> product_states;
std::vector<double> product_transitions; std::vector<double> product_transitions;
std::vector<double> product_scc; std::vector<double> product_scc;
bool ambiguous = false; bool ambiguous;
bool complete = false; bool complete;
std::string hoa_str; std::string hoa_str;
static void static void
@ -461,7 +484,7 @@ parse_opt(int key, char* arg, struct argp_state*)
break; break;
case ARGP_KEY_ARG: case ARGP_KEY_ARG:
if (arg[0] == '-' && !arg[1]) if (arg[0] == '-' && !arg[1])
jobs.emplace_back(arg, job_type::LTL_FILENAME); jobs.emplace_back(arg, true);
else else
tools_push_trans(arg); tools_push_trans(arg);
break; break;
@ -558,7 +581,7 @@ namespace
class xtranslator_runner final: public translator_runner class xtranslator_runner final: public translator_runner
{ {
public: public:
explicit xtranslator_runner(spot::bdd_dict_ptr dict) xtranslator_runner(spot::bdd_dict_ptr dict)
: translator_runner(dict) : translator_runner(dict)
{ {
} }
@ -1072,7 +1095,9 @@ namespace
} }
// Make sure we do not translate the same formula twice. // Make sure we do not translate the same formula twice.
if (!allow_dups && !unique_set.insert(f).second) if (!allow_dups)
{
if (!unique_set.insert(f).second)
{ {
if (!quiet) if (!quiet)
std::cerr std::cerr
@ -1081,6 +1106,7 @@ namespace
"should not be ignored.\n\n"); "should not be ignored.\n\n");
return 0; return 0;
} }
}
int problems = 0; int problems = 0;

View file

@ -1,6 +1,6 @@
// -*- coding: utf-8 -*- // -*- coding: utf-8 -*-
// Copyright (C) 2015-2020, 2022-2023 Laboratoire de Recherche et // Copyright (C) 2015-2020 Laboratoire de Recherche et Développement
// 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.
// //
@ -47,7 +47,7 @@
#include <spot/twaalgos/totgba.hh> #include <spot/twaalgos/totgba.hh>
#include <spot/parseaut/public.hh> #include <spot/parseaut/public.hh>
static const char argp_program_doc[] = "\ const char argp_program_doc[] ="\
Run LTL/PSL formulas through another program, performing conversion\n\ Run LTL/PSL formulas through another program, performing conversion\n\
of input and output as required."; of input and output as required.";
@ -193,7 +193,7 @@ parse_opt(int key, char* arg, struct argp_state*)
break; break;
case ARGP_KEY_ARG: case ARGP_KEY_ARG:
if (arg[0] == '-' && !arg[1]) if (arg[0] == '-' && !arg[1])
jobs.emplace_back(arg, job_type::LTL_FILENAME); jobs.emplace_back(arg, true);
else else
tools_push_trans(arg); tools_push_trans(arg);
break; break;
@ -209,7 +209,7 @@ namespace
class xtranslator_runner final: public translator_runner class xtranslator_runner final: public translator_runner
{ {
public: public:
explicit xtranslator_runner(spot::bdd_dict_ptr dict) xtranslator_runner(spot::bdd_dict_ptr dict)
: translator_runner(dict, true) : translator_runner(dict, true)
{ {
} }
@ -224,6 +224,8 @@ namespace
format(command, tools[translator_num].cmd); format(command, tools[translator_num].cmd);
std::string cmd = command.str(); std::string cmd = command.str();
//std::cerr << "Running [" << l << translator_num << "]: "
// << cmd << std::endl;
timer.start(); timer.start();
int es = exec_with_timeout(cmd.c_str()); int es = exec_with_timeout(cmd.c_str());
timer.stop(); timer.stop();
@ -310,7 +312,7 @@ namespace
spot::printable_value<std::string> inputf; spot::printable_value<std::string> inputf;
public: public:
explicit processor(spot::postprocessor& post) processor(spot::postprocessor& post)
: runner(dict), best_printer(best_stream, best_format), post(post) : runner(dict), best_printer(best_stream, best_format), post(post)
{ {
printer.add_stat('T', &cmdname); printer.add_stat('T', &cmdname);
@ -321,7 +323,9 @@ namespace
best_printer.declare('f', &inputf); best_printer.declare('f', &inputf);
} }
~processor() override = default; ~processor()
{
}
int int
process_string(const std::string& input, process_string(const std::string& input,

View file

@ -1,5 +1,5 @@
// -*- coding: utf-8 -*- // -*- coding: utf-8 -*-
// Copyright (C) 2012-2023 Laboratoire de Recherche et Développement // Copyright (C) 2012-2021 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.
@ -59,7 +59,7 @@
#include <spot/twaalgos/totgba.hh> #include <spot/twaalgos/totgba.hh>
#include <spot/twaalgos/word.hh> #include <spot/twaalgos/word.hh>
static const char argp_program_doc[] = "\ const char argp_program_doc[] ="\
Read a list of formulas and output them back after some optional processing.\v\ Read a list of formulas and output them back after some optional processing.\v\
Exit status:\n\ Exit status:\n\
0 if some formulas were output (skipped syntax errors do not count)\n\ 0 if some formulas were output (skipped syntax errors do not count)\n\
@ -387,7 +387,7 @@ parse_opt(int key, char* arg, struct argp_state*)
break; break;
case ARGP_KEY_ARG: case ARGP_KEY_ARG:
// FIXME: use stat() to distinguish filename from string? // FIXME: use stat() to distinguish filename from string?
jobs.emplace_back(arg, job_type::LTL_FILENAME); jobs.emplace_back(arg, true);
break; break;
case OPT_ACCEPT_WORD: case OPT_ACCEPT_WORD:
try try
@ -586,7 +586,7 @@ namespace
fset_t unique_set; fset_t unique_set;
spot::relabeling_map relmap; spot::relabeling_map relmap;
explicit ltl_processor(spot::tl_simplifier& simpl) ltl_processor(spot::tl_simplifier& simpl)
: simpl(simpl) : simpl(simpl)
{ {
} }
@ -722,7 +722,7 @@ namespace
matched &= !syntactic_si || f.is_syntactic_stutter_invariant(); matched &= !syntactic_si || f.is_syntactic_stutter_invariant();
if (matched && (ap_n.min > 0 || ap_n.max >= 0)) if (matched && (ap_n.min > 0 || ap_n.max >= 0))
{ {
spot::atomic_prop_set* s = atomic_prop_collect(f); auto s = atomic_prop_collect(f);
int n = s->size(); int n = s->size();
delete s; delete s;
matched &= (ap_n.min <= 0) || (n >= ap_n.min); matched &= (ap_n.min <= 0) || (n >= ap_n.min);
@ -761,7 +761,7 @@ namespace
aut = ltl_to_tgba_fm(f, simpl.get_dict(), true); aut = ltl_to_tgba_fm(f, simpl.get_dict(), true);
if (matched && !opt->acc_words.empty()) if (matched && !opt->acc_words.empty())
for (const spot::twa_graph_ptr& word_aut: opt->acc_words) for (auto& word_aut: opt->acc_words)
if (spot::product(aut, word_aut)->is_empty()) if (spot::product(aut, word_aut)->is_empty())
{ {
matched = false; matched = false;
@ -769,7 +769,7 @@ namespace
} }
if (matched && !opt->rej_words.empty()) if (matched && !opt->rej_words.empty())
for (const spot::twa_graph_ptr& word_aut: opt->rej_words) for (auto& word_aut: opt->rej_words)
if (!spot::product(aut, word_aut)->is_empty()) if (!spot::product(aut, word_aut)->is_empty())
{ {
matched = false; matched = false;
@ -843,12 +843,12 @@ namespace
{ {
// Sort the formulas alphabetically. // Sort the formulas alphabetically.
std::map<std::string, spot::formula> m; std::map<std::string, spot::formula> m;
for (const auto& [newformula, oldname]: relmap) for (auto& p: relmap)
m.emplace(str_psl(newformula), oldname); m.emplace(str_psl(p.first), p.second);
for (const auto& [newname, oldname]: m) for (auto& p: m)
stream_formula(opt->output_define->ostream() stream_formula(opt->output_define->ostream()
<< "#define " << newname << " (", << "#define " << p.first << " (",
oldname, filename, p.second, filename,
std::to_string(linenum).c_str()) << ")\n"; std::to_string(linenum).c_str()) << ")\n";
} }
one_match = true; one_match = true;
@ -876,7 +876,7 @@ main(int argc, char** argv)
exit(err); exit(err);
if (jobs.empty()) if (jobs.empty())
jobs.emplace_back("-", job_type::LTL_FILENAME); jobs.emplace_back("-", 1);
if (boolean_to_isop && simplification_level == 0) if (boolean_to_isop && simplification_level == 0)
simplification_level = 1; simplification_level = 1;

View file

@ -1,5 +1,5 @@
// -*- coding: utf-8 -*- // -*- coding: utf-8 -*-
// Copyright (C) 2014-2019, 2022 Laboratoire de Recherche et // Copyright (C) 2014, 2015, 2016, 2017, 2018, 2019 Laboratoire de Recherche et
// Développement de l'Epita (LRDE). // Développement de l'Epita (LRDE).
// //
// This file is part of Spot, a model checking library. // This file is part of Spot, a model checking library.
@ -143,7 +143,7 @@ parse_opt(int key, char* arg, struct argp_state*)
break; break;
case ARGP_KEY_ARG: case ARGP_KEY_ARG:
// FIXME: use stat() to distinguish filename from string? // FIXME: use stat() to distinguish filename from string?
jobs.emplace_back(arg, job_type::LTL_FILENAME); jobs.emplace_back(arg, true);
break; break;
case OPT_AP2CONST: case OPT_AP2CONST:
opt_all = 0; opt_all = 0;

View file

@ -1,5 +1,5 @@
// -*- coding: utf-8 -*- // -*- coding: utf-8 -*-
// Copyright (C) 2017-2023 Laboratoire de Recherche et Développement // Copyright (C) 2017-2021 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.
@ -23,10 +23,8 @@
#include "common_aoutput.hh" #include "common_aoutput.hh"
#include "common_finput.hh" #include "common_finput.hh"
#include "common_hoaread.hh"
#include "common_setup.hh" #include "common_setup.hh"
#include "common_sys.hh" #include "common_sys.hh"
#include "common_trans.hh"
#include <spot/misc/bddlt.hh> #include <spot/misc/bddlt.hh>
#include <spot/misc/escape.hh> #include <spot/misc/escape.hh>
@ -37,7 +35,6 @@
#include <spot/twaalgos/aiger.hh> #include <spot/twaalgos/aiger.hh>
#include <spot/twaalgos/game.hh> #include <spot/twaalgos/game.hh>
#include <spot/twaalgos/hoa.hh> #include <spot/twaalgos/hoa.hh>
#include <spot/twaalgos/dot.hh>
#include <spot/twaalgos/minimize.hh> #include <spot/twaalgos/minimize.hh>
#include <spot/twaalgos/mealy_machine.hh> #include <spot/twaalgos/mealy_machine.hh>
#include <spot/twaalgos/product.hh> #include <spot/twaalgos/product.hh>
@ -47,12 +44,8 @@
enum enum
{ {
OPT_ALGO = 256, OPT_ALGO = 256,
OPT_BYPASS,
OPT_CSV, OPT_CSV,
OPT_DECOMPOSE, OPT_DECOMPOSE,
OPT_DOT,
OPT_FROM_PGAME,
OPT_HIDE,
OPT_INPUT, OPT_INPUT,
OPT_OUTPUT, OPT_OUTPUT,
OPT_PRINT, OPT_PRINT,
@ -60,7 +53,6 @@ enum
OPT_PRINT_HOA, OPT_PRINT_HOA,
OPT_REAL, OPT_REAL,
OPT_SIMPLIFY, OPT_SIMPLIFY,
OPT_TLSF,
OPT_VERBOSE, OPT_VERBOSE,
OPT_VERIFY OPT_VERIFY
}; };
@ -73,17 +65,11 @@ static const argp_option options[] =
"comma-separated list of controllable (a.k.a. output) atomic" "comma-separated list of controllable (a.k.a. output) atomic"
" propositions", 0}, " propositions", 0},
{ "ins", OPT_INPUT, "PROPS", 0, { "ins", OPT_INPUT, "PROPS", 0,
"comma-separated list of uncontrollable (a.k.a. input) atomic" "comma-separated list of controllable (a.k.a. output) atomic"
" propositions", 0}, " propositions", 0},
{ "tlsf", OPT_TLSF, "FILENAME", 0,
"Read a TLSF specification from FILENAME, and call syfco to "
"convert it into LTL", 0 },
{ "from-pgame", OPT_FROM_PGAME, "FILENAME", 0,
"Read a parity game in Extended HOA format instead of building it.",
0 },
/**************************************************/ /**************************************************/
{ nullptr, 0, nullptr, 0, "Fine tuning:", 10 }, { nullptr, 0, nullptr, 0, "Fine tuning:", 10 },
{ "algo", OPT_ALGO, "sd|ds|ps|lar|lar.old|acd", 0, { "algo", OPT_ALGO, "sd|ds|ps|lar|lar.old", 0,
"choose the algorithm for synthesis:" "choose the algorithm for synthesis:"
" \"sd\": translate to tgba, split, then determinize;" " \"sd\": translate to tgba, split, then determinize;"
" \"ds\": translate to tgba, determinize, then split;" " \"ds\": translate to tgba, determinize, then split;"
@ -91,19 +77,13 @@ static const argp_option options[] =
" \"lar\": translate to a deterministic automaton with arbitrary" " \"lar\": translate to a deterministic automaton with arbitrary"
" acceptance condition, then use LAR to turn to parity," " acceptance condition, then use LAR to turn to parity,"
" then split (default);" " then split (default);"
" \"lar.old\": old version of LAR, for benchmarking;" " \"lar.old\": old version of LAR, for benchmarking.\n", 0 },
" \"acd\": translate to a deterministic automaton with arbitrary"
" acceptance condition, then use ACD to turn to parity,"
" then split.\n", 0 },
{ "bypass", OPT_BYPASS, "yes|no", 0,
"whether to try to avoid to construct a parity game "
"(enabled by default)", 0},
{ "decompose", OPT_DECOMPOSE, "yes|no", 0, { "decompose", OPT_DECOMPOSE, "yes|no", 0,
"whether to decompose the specification as multiple output-disjoint " "whether to decompose the specification as multiple output-disjoint "
"problems to solve independently (enabled by default)", 0 }, "problems to solve independently (enabled by default)", 0 },
{ "simplify", OPT_SIMPLIFY, "no|bisim|bwoa|sat|bisim-sat|bwoa-sat", 0, { "simplify", OPT_SIMPLIFY, "no|bisim|bwoa|sat|bisim-sat|bwoa-sat", 0,
"simplification to apply to the controller (no) nothing, " "simplification to apply to the controler (no) nothing, "
"(bisim) bisimulation-based reduction, (bwoa) bisimulation-based " "(bisim) bisimulation-based reduction, (bwoa) bissimulation-based "
"reduction with output assignment, (sat) SAT-based minimization, " "reduction with output assignment, (sat) SAT-based minimization, "
"(bisim-sat) SAT after bisim, (bwoa-sat) SAT after bwoa. Defaults " "(bisim-sat) SAT after bisim, (bwoa-sat) SAT after bwoa. Defaults "
"to 'bwoa'.", 0 }, "to 'bwoa'.", 0 },
@ -117,34 +97,25 @@ static const argp_option options[] =
"realizability only, do not compute a winning strategy", 0}, "realizability only, do not compute a winning strategy", 0},
{ "aiger", OPT_PRINT_AIGER, "ite|isop|both[+ud][+dc]" { "aiger", OPT_PRINT_AIGER, "ite|isop|both[+ud][+dc]"
"[+sub0|sub1|sub2]", OPTION_ARG_OPTIONAL, "[+sub0|sub1|sub2]", OPTION_ARG_OPTIONAL,
"encode the winning strategy as an AIG circuit and print it in AIGER" "prints a winning strategy as an AIGER circuit. The first, and only "
" format. The first word indicates the encoding to used: \"ite\" for " "mandatory option defines the method to be used. \"ite\" for "
"If-Then-Else normal form; " "If-then-else normal form; "
"\"isop\" for irreducible sum of products; " "\"isop\" for irreducible sum of producs; "
"\"both\" tries both and keeps the smaller one. " "\"both\" tries both encodings and keeps the smaller one. "
"Other options further " "The other options further "
"refine the encoding, see aiger::encode_bdd. Defaults to \"ite\".", 0 }, "refine the encoding, see aiger::encode_bdd.", 0},
{ "dot", OPT_DOT, "options", OPTION_ARG_OPTIONAL, { "verbose", OPT_VERBOSE, nullptr, 0,
"Use dot format when printing the result (game, strategy, or " "verbose mode", -1 },
"AIG circuit, depending on other options). The options that " { "verify", OPT_VERIFY, nullptr, 0,
"may be passed to --dot depend on the nature of what is printed. " "verifies the strategy or (if demanded) aiger against the spec.", -1 },
"For games and strategies, standard automata rendering "
"options are supported (e.g., see ltl2tgba --dot). For AIG circuit, "
"use (h) for horizontal and (v) for vertical layouts.", 0 },
{ "csv", OPT_CSV, "[>>]FILENAME", OPTION_ARG_OPTIONAL, { "csv", OPT_CSV, "[>>]FILENAME", OPTION_ARG_OPTIONAL,
"output statistics as CSV in FILENAME or on standard output " "output statistics as CSV in FILENAME or on standard output "
"(if '>>' is used to request append mode, the header line is " "(if '>>' is used to request append mode, the header line is "
"not output)", 0 }, "not output)", 0 },
{ "hide-status", OPT_HIDE, nullptr, 0,
"Hide the REALIZABLE or UNREALIZABLE line. (Hint: exit status "
"is enough of an indication.)", 0 },
/**************************************************/ /**************************************************/
{ nullptr, 0, nullptr, 0, "Miscellaneous options:", -1 }, { nullptr, 0, nullptr, 0, "Miscellaneous options:", -1 },
{ "extra-options", 'x', "OPTS", 0, { "extra-options", 'x', "OPTS", 0,
"fine-tuning options (see spot-x (7))", 0 }, "fine-tuning options (see spot-x (7))", 0 },
{ "verbose", OPT_VERBOSE, nullptr, 0, "verbose mode", 0 },
{ "verify", OPT_VERIFY, nullptr, 0,
"verify the strategy or (if demanded) AIG against the formula", 0 },
{ nullptr, 0, nullptr, 0, nullptr, 0 }, { nullptr, 0, nullptr, 0, nullptr, 0 },
}; };
@ -152,19 +123,20 @@ static const struct argp_child children[] =
{ {
{ &finput_argp_headless, 0, nullptr, 0 }, { &finput_argp_headless, 0, nullptr, 0 },
{ &aoutput_argp, 0, nullptr, 0 }, { &aoutput_argp, 0, nullptr, 0 },
//{ &aoutput_o_format_argp, 0, nullptr, 0 },
{ &misc_argp, 0, nullptr, 0 }, { &misc_argp, 0, nullptr, 0 },
{ nullptr, 0, nullptr, 0 } { nullptr, 0, nullptr, 0 }
}; };
static const char argp_program_doc[] = "\ const char argp_program_doc[] = "\
Synthesize a controller from its LTL specification.\v\ Synthesize a controller from its LTL specification.\v\
Exit status:\n\ Exit status:\n\
0 if all input problems were realizable\n\ 0 if the input problem is realizable\n\
1 if at least one input problem was not realizable\n\ 1 if the input problem is not realizable\n\
2 if any error has been reported"; 2 if any error has been reported";
static std::optional<std::vector<std::string>> all_output_aps; static std::vector<std::string> all_output_aps;
static std::optional<std::vector<std::string>> all_input_aps; static std::vector<std::string> all_input_aps;
static const char* opt_csv = nullptr; static const char* opt_csv = nullptr;
static bool opt_print_pg = false; static bool opt_print_pg = false;
@ -173,10 +145,8 @@ static const char* opt_print_hoa_args = nullptr;
static bool opt_real = false; static bool opt_real = false;
static bool opt_do_verify = false; static bool opt_do_verify = false;
static const char* opt_print_aiger = nullptr; static const char* opt_print_aiger = nullptr;
static const char* opt_dot_arg = nullptr;
static bool opt_dot = false;
static spot::synthesis_info* gi; static spot::synthesis_info* gi;
static bool show_status = true;
static char const *const algo_names[] = static char const *const algo_names[] =
{ {
@ -184,8 +154,7 @@ static char const *const algo_names[] =
"sd", "sd",
"ps", "ps",
"lar", "lar",
"lar.old", "lar.old"
"acd",
}; };
static char const *const algo_args[] = static char const *const algo_args[] =
@ -195,7 +164,6 @@ static char const *const algo_args[] =
"dpasplit", "ps", "dpasplit", "ps",
"lar", "lar",
"lar.old", "lar.old",
"acd",
nullptr nullptr
}; };
static spot::synthesis_info::algo const algo_types[] = static spot::synthesis_info::algo const algo_types[] =
@ -205,24 +173,9 @@ static spot::synthesis_info::algo const algo_types[] =
spot::synthesis_info::algo::DPA_SPLIT, spot::synthesis_info::algo::DPA_SPLIT, spot::synthesis_info::algo::DPA_SPLIT, spot::synthesis_info::algo::DPA_SPLIT,
spot::synthesis_info::algo::LAR, spot::synthesis_info::algo::LAR,
spot::synthesis_info::algo::LAR_OLD, spot::synthesis_info::algo::LAR_OLD,
spot::synthesis_info::algo::ACD,
}; };
ARGMATCH_VERIFY(algo_args, algo_types); ARGMATCH_VERIFY(algo_args, algo_types);
static const char* const bypass_args[] =
{
"yes", "true", "enabled", "1",
"no", "false", "disabled", "0",
nullptr
};
static bool bypass_values[] =
{
true, true, true, true,
false, false, false, false,
};
ARGMATCH_VERIFY(bypass_args, bypass_values);
bool opt_bypass = true;
static const char* const decompose_args[] = static const char* const decompose_args[] =
{ {
"yes", "true", "enabled", "1", "yes", "true", "enabled", "1",
@ -268,22 +221,7 @@ namespace
}; };
static void static void
dispatch_print_hoa(const spot::const_twa_graph_ptr& game) print_csv(const spot::formula& f)
{
if (opt_dot)
spot::print_dot(std::cout, game, opt_print_hoa_args);
else if (opt_print_pg)
spot::print_pg(std::cout, game);
else
spot::print_hoa(std::cout, game, opt_print_hoa_args) << '\n';
}
// If filename is passed, it is printed instead of the formula. We
// use that when processing games since we have no formula to print.
// It would be cleaner to have two columns: one for location (that's
// filename + line number if known), and one for formula (if known).
static void
print_csv(const spot::formula& f, const char* filename = nullptr)
{ {
auto& vs = gi->verbose_stream; auto& vs = gi->verbose_stream;
auto& bv = gi->bv; auto& bv = gi->bv;
@ -292,9 +230,7 @@ namespace
if (vs) if (vs)
*vs << "writing CSV to " << opt_csv << '\n'; *vs << "writing CSV to " << opt_csv << '\n';
static bool not_first_time = false; output_file outf(opt_csv);
output_file outf(opt_csv, not_first_time);
not_first_time = true; // force append on next print.
std::ostream& out = outf.ostream(); std::ostream& out = outf.ostream();
// Do not output the header line if we append to a file. // Do not output the header line if we append to a file.
@ -319,15 +255,10 @@ namespace
out << '\n'; out << '\n';
} }
std::ostringstream os; std::ostringstream os;
if (filename)
os << filename;
else
os << f; os << f;
spot::escape_rfc4180(out << '"', os.str()) << "\","; spot::escape_rfc4180(out << '"', os.str());
// if a filename was given, assume the game has been read directly out << "\",\"" << algo_names[(int) gi->s]
if (!filename) << "\"," << bv->total_time
out << '"' << algo_names[(int) gi->s] << '"';
out << ',' << bv->total_time
<< ',' << bv->trans_time << ',' << bv->trans_time
<< ',' << bv->split_time << ',' << bv->split_time
<< ',' << bv->paritize_time; << ',' << bv->paritize_time;
@ -354,13 +285,11 @@ namespace
outf.close(opt_csv); outf.close(opt_csv);
} }
static int int
solve_formula(const spot::formula& f, solve_formula(const spot::formula& f,
const std::vector<std::string>& input_aps, const std::vector<std::string>& input_aps,
const std::vector<std::string>& output_aps) const std::vector<std::string>& output_aps)
{ {
if (opt_csv) // reset benchmark data
gi->bv = spot::synthesis_info::bench_var();
spot::stopwatch sw; spot::stopwatch sw;
if (gi->bv) if (gi->bv)
sw.start(); sw.start();
@ -376,12 +305,6 @@ namespace
if (opt_decompose_ltl) if (opt_decompose_ltl)
{ {
auto subs = split_independant_formulas(f, output_aps); auto subs = split_independant_formulas(f, output_aps);
if (gi->verbose_stream)
{
*gi->verbose_stream << "there are "
<< subs.first.size()
<< " subformulas\n";
}
if (subs.first.size() > 1) if (subs.first.size() > 1)
{ {
sub_form = subs.first; sub_form = subs.first;
@ -424,6 +347,17 @@ namespace
auto sub_o = sub_outs_str.begin(); auto sub_o = sub_outs_str.begin();
std::vector<spot::mealy_like> mealy_machines; std::vector<spot::mealy_like> mealy_machines;
auto print_game = want_game ?
[](const spot::twa_graph_ptr& game)->void
{
if (opt_print_pg)
pg_print(std::cout, game);
else
spot::print_hoa(std::cout, game, opt_print_hoa_args) << '\n';
}
:
[](const spot::twa_graph_ptr&)->void{};
for (; sub_f != sub_form.end(); ++sub_f, ++sub_o) for (; sub_f != sub_form.end(); ++sub_f, ++sub_o)
{ {
spot::mealy_like m_like spot::mealy_like m_like
@ -434,15 +368,14 @@ namespace
}; };
// If we want to print a game, // If we want to print a game,
// we never use the direct approach // we never use the direct approach
if (!want_game && opt_bypass) if (!want_game)
m_like = m_like =
spot::try_create_direct_strategy(*sub_f, *sub_o, *gi, !opt_real); spot::try_create_direct_strategy(*sub_f, *sub_o, *gi);
switch (m_like.success) switch (m_like.success)
{ {
case spot::mealy_like::realizability_code::UNREALIZABLE: case spot::mealy_like::realizability_code::UNREALIZABLE:
{ {
if (show_status)
std::cout << "UNREALIZABLE" << std::endl; std::cout << "UNREALIZABLE" << std::endl;
safe_tot_time(); safe_tot_time();
return 1; return 1;
@ -461,20 +394,13 @@ namespace
assert((spptr->at(arena->get_init_state_number()) == false) assert((spptr->at(arena->get_init_state_number()) == false)
&& "Env needs first turn"); && "Env needs first turn");
} }
if (want_game) print_game(arena);
{
dispatch_print_hoa(arena);
continue;
}
if (!spot::solve_game(arena, *gi)) if (!spot::solve_game(arena, *gi))
{ {
if (show_status)
std::cout << "UNREALIZABLE" << std::endl; std::cout << "UNREALIZABLE" << std::endl;
safe_tot_time(); safe_tot_time();
return 1; return 1;
} }
if (gi->bv)
gi->bv->realizable = true;
// Create the (partial) strategy // Create the (partial) strategy
// only if we need it // only if we need it
if (!opt_real) if (!opt_real)
@ -482,13 +408,14 @@ namespace
spot::mealy_like ml; spot::mealy_like ml;
ml.success = ml.success =
spot::mealy_like::realizability_code::REALIZABLE_REGULAR; spot::mealy_like::realizability_code::REALIZABLE_REGULAR;
// By default this produces a split machine if (opt_print_aiger)
// we do not care about the type,
// machine to aiger can handle it
ml.mealy_like = ml.mealy_like =
spot::solved_game_to_mealy(arena, *gi); spot::solved_game_to_mealy(arena, *gi);
// Keep the machine split for aiger else
// else -> separated ml.mealy_like =
spot::simplify_mealy_here(ml.mealy_like, *gi, spot::solved_game_to_separated_mealy(arena, *gi);
opt_print_aiger);
ml.glob_cond = bddfalse; ml.glob_cond = bddfalse;
mealy_machines.push_back(ml); mealy_machines.push_back(ml);
} }
@ -499,14 +426,54 @@ namespace
// the direct approach yielded a strategy // the direct approach yielded a strategy
// which can now be minimized // which can now be minimized
// We minimize only if we need it // We minimize only if we need it
assert(opt_real || assert(m_like.mealy_like && "Expected success but found no mealy!");
(m_like.mealy_like && "Expected success but found no mealy!"));
if (!opt_real) if (!opt_real)
{ {
// Keep the machine split for aiger spot::stopwatch sw_direct;
// else -> separated sw_direct.start();
spot::simplify_mealy_here(m_like.mealy_like, *gi,
opt_print_aiger); if ((0 < gi->minimize_lvl) && (gi->minimize_lvl < 3))
// Uses reduction or not,
// both work with mealy machines (non-separated)
reduce_mealy_here(m_like.mealy_like, gi->minimize_lvl == 2);
auto delta = sw_direct.stop();
sw_direct.start();
// todo better algo here?
m_like.mealy_like =
split_2step(m_like.mealy_like,
spot::get_synthesis_outputs(m_like.mealy_like),
false);
if (gi->bv)
gi->bv->split_time += sw_direct.stop();
sw_direct.start();
if (gi->minimize_lvl >= 3)
{
sw_direct.start();
// actual minimization, works on split mealy
m_like.mealy_like = minimize_mealy(m_like.mealy_like,
gi->minimize_lvl - 4);
delta = sw_direct.stop();
}
// If our goal is to have an aiger,
// we can use split or separated machines
if (!opt_print_aiger)
// Unsplit to have separated mealy
m_like.mealy_like = unsplit_mealy(m_like.mealy_like);
if (gi->bv)
gi->bv->strat2aut_time += delta;
if (gi->verbose_stream)
*gi->verbose_stream << "final strategy has "
<< m_like.mealy_like->num_states()
<< " states and "
<< m_like.mealy_like->num_edges()
<< " edges\n"
<< "minimization took " << delta
<< " seconds\n";
} }
SPOT_FALLTHROUGH; SPOT_FALLTHROUGH;
} }
@ -527,7 +494,6 @@ namespace
return 0; return 0;
} }
if (show_status)
std::cout << "REALIZABLE" << std::endl; std::cout << "REALIZABLE" << std::endl;
if (opt_real) if (opt_real)
{ {
@ -537,8 +503,8 @@ namespace
// If we reach this line // If we reach this line
// a strategy was found for each subformula // a strategy was found for each subformula
assert(mealy_machines.size() == sub_form.size() assert(mealy_machines.size() == sub_form.size()
&& ("There are subformula for which no mealy like object" && "There are subformula for which no mealy like object"
" has been created.")); "has been created.");
spot::aig_ptr saig = nullptr; spot::aig_ptr saig = nullptr;
spot::twa_graph_ptr tot_strat = nullptr; spot::twa_graph_ptr tot_strat = nullptr;
@ -567,9 +533,6 @@ namespace
<< " latches and " << " latches and "
<< saig->num_gates() << " gates\n"; << saig->num_gates() << " gates\n";
} }
if (opt_dot)
spot::print_dot(std::cout, saig, opt_dot_arg);
else
spot::print_aiger(std::cout, saig) << '\n'; spot::print_aiger(std::cout, saig) << '\n';
} }
else else
@ -582,8 +545,7 @@ namespace
&& "ltlsynt: Cannot handle TGBA as strategy."); && "ltlsynt: Cannot handle TGBA as strategy.");
tot_strat = mealy_machines.front().mealy_like; tot_strat = mealy_machines.front().mealy_like;
for (size_t i = 1; i < mealy_machines.size(); ++i) for (size_t i = 1; i < mealy_machines.size(); ++i)
tot_strat = spot::mealy_product(tot_strat, tot_strat = spot::product(tot_strat, mealy_machines[i].mealy_like);
mealy_machines[i].mealy_like);
printer.print(tot_strat, timer_printer_dummy); printer.print(tot_strat, timer_printer_dummy);
} }
@ -621,27 +583,15 @@ namespace
return 0; return 0;
} }
static void
split_aps(const std::string& arg, std::vector<std::string>& where)
{
std::istringstream aps(arg);
std::string ap;
while (std::getline(aps, ap, ','))
{
ap.erase(remove_if(ap.begin(), ap.end(), isspace), ap.end());
where.push_back(str_tolower(ap));
}
}
class ltl_processor final : public job_processor class ltl_processor final : public job_processor
{ {
private: private:
std::optional<std::vector<std::string>> input_aps_; std::vector<std::string> input_aps_;
std::optional<std::vector<std::string>> output_aps_; std::vector<std::string> output_aps_;
public: public:
ltl_processor(std::optional<std::vector<std::string>> input_aps_, ltl_processor(std::vector<std::string> input_aps_,
std::optional<std::vector<std::string>> output_aps_) std::vector<std::string> output_aps_)
: input_aps_(std::move(input_aps_)), : input_aps_(std::move(input_aps_)),
output_aps_(std::move(output_aps_)) output_aps_(std::move(output_aps_))
{ {
@ -651,13 +601,11 @@ namespace
const char* filename, int linenum) override const char* filename, int linenum) override
{ {
auto unknown_aps = [](spot::formula f, auto unknown_aps = [](spot::formula f,
const std::optional<std::vector<std::string>>& known, const std::vector<std::string>& known,
const std::optional<std::vector<std::string>>& known2 = {}) const std::vector<std::string>* known2 = nullptr)
{ {
std::vector<std::string> unknown; std::vector<std::string> unknown;
std::set<spot::formula> seen; std::set<spot::formula> seen;
// If we don't have --ins and --outs, we must not find an AP.
bool can_have_ap = known.has_value();
f.traverse([&](const spot::formula& s) f.traverse([&](const spot::formula& s)
{ {
if (s.is(spot::op::ap)) if (s.is(spot::op::ap))
@ -665,11 +613,10 @@ namespace
if (!seen.insert(s).second) if (!seen.insert(s).second)
return false; return false;
const std::string& a = s.ap_name(); const std::string& a = s.ap_name();
if (!can_have_ap if (std::find(known.begin(), known.end(), a) == known.end()
|| (std::find(known->begin(), known->end(), a) == known->end() && (!known2
&& (!known2.has_value()
|| std::find(known2->begin(), || std::find(known2->begin(),
known2->end(), a) == known2->end()))) known2->end(), a) == known2->end()))
unknown.push_back(a); unknown.push_back(a);
} }
return false; return false;
@ -679,233 +626,36 @@ namespace
// Decide which atomic propositions are input or output. // Decide which atomic propositions are input or output.
int res; int res;
if (!input_aps_.has_value() && output_aps_.has_value()) if (input_aps_.empty() && !output_aps_.empty())
{ {
res = solve_formula(f, unknown_aps(f, output_aps_), *output_aps_); res = solve_formula(f, unknown_aps(f, output_aps_), output_aps_);
} }
else if (!output_aps_.has_value() && input_aps_.has_value()) else if (output_aps_.empty() && !input_aps_.empty())
{ {
res = solve_formula(f, *input_aps_, unknown_aps(f, input_aps_)); res = solve_formula(f, input_aps_, unknown_aps(f, input_aps_));
} }
else if (!output_aps_.has_value() && !input_aps_.has_value()) else if (output_aps_.empty() && input_aps_.empty())
{ {
for (const std::string& ap: unknown_aps(f, input_aps_, output_aps_)) for (const std::string& ap: unknown_aps(f, input_aps_, &output_aps_))
error_at_line(2, 0, filename, linenum, error_at_line(2, 0, filename, linenum,
"one of --ins or --outs should list '%s'", "one of --ins or --outs should list '%s'",
ap.c_str()); ap.c_str());
res = solve_formula(f, *input_aps_, *output_aps_); res = solve_formula(f, input_aps_, output_aps_);
} }
else else
{ {
for (const std::string& ap: unknown_aps(f, input_aps_, output_aps_)) for (const std::string& ap: unknown_aps(f, input_aps_, &output_aps_))
error_at_line(2, 0, filename, linenum, error_at_line(2, 0, filename, linenum,
"both --ins and --outs are specified, " "both --ins and --outs are specified, "
"but '%s' is unlisted", "but '%s' is unlisted",
ap.c_str()); ap.c_str());
res = solve_formula(f, *input_aps_, *output_aps_); res = solve_formula(f, input_aps_, output_aps_);
} }
if (opt_csv) if (opt_csv)
print_csv(f); print_csv(f);
return res; return res;
} }
int
process_tlsf_file(const char* filename) override
{
static char arg0[] = "syfco";
static char arg1[] = "-f";
static char arg2[] = "ltlxba";
static char arg3[] = "-m";
static char arg4[] = "fully";
char* command[] = { arg0, arg1, arg2, arg3, arg4,
const_cast<char*>(filename), nullptr };
std::string tlsf_string = read_stdout_of_command(command);
// The set of atomic proposition will be temporary set to those
// given by syfco, unless they were forced from the command-line.
bool reset_aps = false;
if (!input_aps_.has_value() && !output_aps_.has_value())
{
reset_aps = true;
static char arg5[] = "--print-output-signals";
char* command[] = { arg0, arg5,
const_cast<char*>(filename), nullptr };
std::string res = read_stdout_of_command(command);
output_aps_.emplace(std::vector<std::string>{});
split_aps(res, *output_aps_);
}
int res = process_string(tlsf_string, filename);
if (reset_aps)
output_aps_.reset();
return res;
}
int process_pgame(spot::twa_graph_ptr arena,
const std::string& location)
{
if (opt_csv) // reset benchmark data
gi->bv = spot::synthesis_info::bench_var();
spot::stopwatch sw_global;
spot::stopwatch sw_local;
if (gi->bv)
{
sw_global.start();
sw_local.start();
}
if (!arena->get_named_prop<bdd>("synthesis-outputs"))
{
std::cerr << location << ": controllable-AP is not specified\n";
return 2;
}
if (!arena->get_named_prop<std::vector<bool>>("state-player"))
arena = spot::split_2step(arena, true);
else
{
// Check if the game is alternating and fix trivial cases
const unsigned N = arena->num_states();
// Can not use get_state_players because we need a non-const version
auto spptr =
arena->get_named_prop<std::vector<bool>>("state-player");
assert(spptr);
const bdd& outs = get_synthesis_outputs(arena);
for (unsigned n = 0; n < N; ++n)
{
const bool p = (*spptr)[n];
for (auto& e : arena->out(n))
{
if (p != (*spptr)[e.dst])
continue; // All good
// Check if the condition is a simply conjunction of input and
// output. If so insert an intermediate state
// This also covers trivial self-loops
bdd cond = e.cond;
bdd i_cond = bdd_exist(cond, outs);
bdd o_cond = bdd_existcomp(cond, outs);
if ((i_cond & o_cond) == cond)
{
unsigned inter = arena->new_state();
spptr->push_back(!p);
e.cond = p ? o_cond : i_cond;
e.dst = inter;
arena->new_edge(inter, e.dst, !p ? o_cond : i_cond);
}
else
throw std::runtime_error("ltlsynt: given parity game is not"
"alternating and not trivially fixable!");
}
}
}
if (gi->bv)
{
gi->bv->split_time += sw_local.stop();
gi->bv->nb_states_arena += arena->num_states();
auto spptr =
arena->get_named_prop<std::vector<bool>>("state-player");
assert(spptr);
gi->bv->nb_states_arena_env +=
std::count(spptr->cbegin(), spptr->cend(), false);
}
if (opt_print_pg || opt_print_hoa)
{
dispatch_print_hoa(arena);
return 0;
}
auto safe_tot_time = [&]() {
if (gi->bv)
gi->bv->total_time = sw_global.stop();
};
if (!spot::solve_game(arena, *gi))
{
if (show_status)
std::cout << "UNREALIZABLE" << std::endl;
safe_tot_time();
return 1;
}
if (gi->bv)
gi->bv->realizable = true;
if (show_status)
std::cout << "REALIZABLE" << std::endl;
if (opt_real)
{
safe_tot_time();
return 0;
}
sw_local.start();
spot::twa_graph_ptr mealy_like =
spot::solved_game_to_mealy(arena, *gi);
// Keep the machine split for aiger otherwise, separate it.
spot::simplify_mealy_here(mealy_like, *gi, opt_print_aiger);
automaton_printer printer;
spot::process_timer timer_printer_dummy;
if (opt_print_aiger)
{
if (gi->bv)
sw_local.start();
spot::aig_ptr saig =
spot::mealy_machine_to_aig(mealy_like, opt_print_aiger);
if (gi->bv)
{
gi->bv->aig_time = sw_local.stop();
gi->bv->nb_latches = saig->num_latches();
gi->bv->nb_gates = saig->num_gates();
}
if (gi->verbose_stream)
{
*gi->verbose_stream << "AIG circuit was created in "
<< gi->bv->aig_time
<< " seconds and has " << saig->num_latches()
<< " latches and "
<< saig->num_gates() << " gates\n";
}
spot::print_aiger(std::cout, saig) << '\n';
}
else
{
printer.print(mealy_like, timer_printer_dummy);
}
safe_tot_time();
return 0;
}
int
process_aut_file(const char* filename) override
{
spot::automaton_stream_parser hp(filename);
int err = 0;
while (!abort_run)
{
spot::parsed_aut_ptr haut = hp.parse(spot::make_bdd_dict());
if (!haut->aut && haut->errors.empty())
break;
if (haut->format_errors(std::cerr))
err = 2;
if (!haut->aut /*|| (err && abort_on_error_)*/)
{
error(2, 0, "failed to read automaton from %s",
haut->filename.c_str());
}
else if (haut->aborted)
{
std::cerr << haut->filename << ':' << haut->loc
<< ": aborted input automaton\n";
err = std::max(err, 2);
}
else
{
std::ostringstream os;
os << haut->filename << ':' << haut->loc;
std::string loc = os.str();
int res = process_pgame(haut->aut, loc);
if (res < 2 && opt_csv)
print_csv(nullptr, loc.c_str());
err = std::max(err, res);
}
}
return err;
}
}; };
} }
@ -919,37 +669,35 @@ parse_opt(int key, char *arg, struct argp_state *)
case OPT_ALGO: case OPT_ALGO:
gi->s = XARGMATCH("--algo", arg, algo_args, algo_types); gi->s = XARGMATCH("--algo", arg, algo_args, algo_types);
break; break;
case OPT_BYPASS:
opt_bypass = XARGMATCH("--bypass", arg, bypass_args, bypass_values);
break;
case OPT_CSV: case OPT_CSV:
opt_csv = arg ? arg : "-"; opt_csv = arg ? arg : "-";
if (not gi->bv)
gi->bv = spot::synthesis_info::bench_var();
break; break;
case OPT_DECOMPOSE: case OPT_DECOMPOSE:
opt_decompose_ltl = XARGMATCH("--decompose", arg, opt_decompose_ltl = XARGMATCH("--decompose", arg,
decompose_args, decompose_values); decompose_args, decompose_values);
break; break;
case OPT_DOT:
opt_dot = true;
automaton_format_opt = opt_dot_arg = arg;
automaton_format = Dot;
break;
case OPT_FROM_PGAME:
jobs.emplace_back(arg, job_type::AUT_FILENAME);
break;
case OPT_HIDE:
show_status = false;
break;
case OPT_INPUT: case OPT_INPUT:
{ {
all_input_aps.emplace(std::vector<std::string>{}); std::istringstream aps(arg);
split_aps(arg, *all_input_aps); std::string ap;
while (std::getline(aps, ap, ','))
{
ap.erase(remove_if(ap.begin(), ap.end(), isspace), ap.end());
all_input_aps.push_back(str_tolower(ap));
}
break; break;
} }
case OPT_OUTPUT: case OPT_OUTPUT:
{ {
all_output_aps.emplace(std::vector<std::string>{}); std::istringstream aps(arg);
split_aps(arg, *all_output_aps); std::string ap;
while (std::getline(aps, ap, ','))
{
ap.erase(remove_if(ap.begin(), ap.end(), isspace), ap.end());
all_output_aps.push_back(str_tolower(ap));
}
break; break;
} }
case OPT_PRINT: case OPT_PRINT:
@ -970,9 +718,6 @@ parse_opt(int key, char *arg, struct argp_state *)
gi->minimize_lvl = XARGMATCH("--simplify", arg, gi->minimize_lvl = XARGMATCH("--simplify", arg,
simplify_args, simplify_values); simplify_args, simplify_values);
break; break;
case OPT_TLSF:
jobs.emplace_back(arg, job_type::TLSF_FILENAME);
break;
case OPT_VERBOSE: case OPT_VERBOSE:
gi->verbose_stream = &std::cerr; gi->verbose_stream = &std::cerr;
if (not gi->bv) if (not gi->bv)
@ -1009,14 +754,12 @@ main(int argc, char **argv)
argp_program_doc, children, nullptr, nullptr }; argp_program_doc, children, nullptr, nullptr };
if (int err = argp_parse(&ap, argc, argv, ARGP_NO_HELP, nullptr, nullptr)) if (int err = argp_parse(&ap, argc, argv, ARGP_NO_HELP, nullptr, nullptr))
exit(err); exit(err);
check_no_formula(); check_no_formula();
// Check if inputs and outputs are distinct // Check if inputs and outputs are distinct
if (all_input_aps.has_value() && all_output_aps.has_value()) for (const std::string& ai : all_input_aps)
for (const std::string& ai : *all_input_aps) if (std::find(all_output_aps.begin(), all_output_aps.end(), ai)
if (std::find(all_output_aps->begin(), all_output_aps->end(), ai) != all_output_aps.end())
!= all_output_aps->end())
error(2, 0, "'%s' appears both in --ins and --outs", ai.c_str()); error(2, 0, "'%s' appears both in --ins and --outs", ai.c_str());
ltl_processor processor(all_input_aps, all_output_aps); ltl_processor processor(all_input_aps, all_output_aps);

View file

@ -1,6 +1,6 @@
// -*- coding: utf-8 -*- // -*- coding: utf-8 -*-
// Copyright (C) 2012-2016, 2018-2020, 2022 Laboratoire de Recherche // Copyright (C) 2012-2016, 2018-2020 Laboratoire de Recherche et
// et Développement de l'Epita (LRDE). // Développement de l'Epita (LRDE).
// //
// This file is part of Spot, a model checking library. // This file is part of Spot, a model checking library.
// //
@ -42,7 +42,7 @@
#include <spot/twaalgos/canonicalize.hh> #include <spot/twaalgos/canonicalize.hh>
static const char argp_program_doc[] = "\ const char argp_program_doc[] = "\
Generate random connected automata.\n\n\ Generate random connected automata.\n\n\
The automata are built over the atomic propositions named by PROPS...\n\ The automata are built over the atomic propositions named by PROPS...\n\
or, if N is a nonnegative number, using N arbitrary names.\n\ or, if N is a nonnegative number, using N arbitrary names.\n\

View file

@ -1,6 +1,6 @@
// -*- coding: utf-8 -*- // -*- coding: utf-8 -*-
// Copyright (C) 2012-2016, 2018-2019, 2022, 2023 Laboratoire de // Copyright (C) 2012-2016, 2018-2019 Laboratoire de Recherche
// Recherche et Développement de l'Epita (LRDE). // et Développement de l'Epita (LRDE).
// //
// This file is part of Spot, a model checking library. // This file is part of Spot, a model checking library.
// //
@ -40,7 +40,7 @@
#include <spot/misc/random.hh> #include <spot/misc/random.hh>
#include <spot/misc/optionmap.hh> #include <spot/misc/optionmap.hh>
static const char argp_program_doc[] = "\ const char argp_program_doc[] ="\
Generate random temporal logic formulas.\n\n\ Generate random temporal logic formulas.\n\n\
The formulas are built over the atomic propositions named by PROPS...\n\ The formulas are built over the atomic propositions named by PROPS...\n\
or, if N is a nonnegative number, using N arbitrary names.\v\ or, if N is a nonnegative number, using N arbitrary names.\v\
@ -65,6 +65,7 @@ enum {
OPT_DUMP_PRIORITIES, OPT_DUMP_PRIORITIES,
OPT_DUPS, OPT_DUPS,
OPT_LTL_PRIORITIES, OPT_LTL_PRIORITIES,
OPT_PSL_PRIORITIES,
OPT_SEED, OPT_SEED,
OPT_SERE_PRIORITIES, OPT_SERE_PRIORITIES,
OPT_TREE_SIZE, OPT_TREE_SIZE,
@ -193,6 +194,7 @@ parse_opt(int key, char* arg, struct argp_state* as)
case OPT_DUMP_PRIORITIES: case OPT_DUMP_PRIORITIES:
opt_dump_priorities = true; opt_dump_priorities = true;
break; break;
// case OPT_PSL_PRIORITIES: break;
case OPT_SERE_PRIORITIES: case OPT_SERE_PRIORITIES:
opt_pS = arg; opt_pS = arg;
break; break;

View file

@ -1,5 +1,5 @@
// -*- coding: utf-8 -*- // -*- coding: utf-8 -*-
// Copyright (C) 2013-2023 Laboratoire de Recherche et Développement // Copyright (C) 2013-2021 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.
@ -24,7 +24,7 @@
#include <argp.h> #include <argp.h>
#include "common_setup.hh" #include "common_setup.hh"
static const char argp_program_doc[] = "\ const char argp_program_doc[] ="\
Common fine-tuning options for programs installed with Spot.\n\ Common fine-tuning options for programs installed with Spot.\n\
\n\ \n\
The argument of -x or --extra-options is a comma-separated list of KEY=INT \ The argument of -x or --extra-options is a comma-separated list of KEY=INT \
@ -47,17 +47,9 @@ depends on the --low, --medium, or --high settings.") },
{ DOC("tls-max-states", { DOC("tls-max-states",
"Maximum number of states of automata involved in automata-based \ "Maximum number of states of automata involved in automata-based \
implication checks for formula simplifications. Defaults to 64.") }, implication checks for formula simplifications. Defaults to 64.") },
{ DOC("tls-max-ops",
"Maximum number of operands in n-ary opertors (or, and) on which \
implication-based simplifications are attempted. Defaults to 16.") },
{ nullptr, 0, nullptr, 0, "Translation options:", 0 }, { nullptr, 0, nullptr, 0, "Translation options:", 0 },
{ DOC("ltl-split", "Set to 0 to disable the translation of automata \ { DOC("ltl-split", "Set to 0 to disable the translation of automata \
as product or sum of subformulas.") }, as product or sum of subformulas.") },
{ DOC("branch-post", "Set to 0 to disable branching-postponement \
(done during translation, may create more states) and delayed-branching \
(almost similar, but done after translation to only remove states). \
Set to 1 to force branching-postponement, and to 2 \
to force delayed-branching. By default delayed-branching is used.") },
{ DOC("comp-susp", "Set to 1 to enable compositional suspension, \ { DOC("comp-susp", "Set to 1 to enable compositional suspension, \
as described in our SPIN'13 paper (see Bibliography below). Set to 2, \ as described in our SPIN'13 paper (see Bibliography below). Set to 2, \
to build only the skeleton TGBA without composing it. Set to 0 (the \ to build only the skeleton TGBA without composing it. Set to 0 (the \
@ -83,9 +75,6 @@ only if it is smaller than the original skeleton. This option is only \
used when comp-susp=1 and default to 1 or 2 depending on whether --small \ used when comp-susp=1 and default to 1 or 2 depending on whether --small \
or --deterministic is specified.") }, or --deterministic is specified.") },
{ nullptr, 0, nullptr, 0, "Postprocessing options:", 0 }, { nullptr, 0, nullptr, 0, "Postprocessing options:", 0 },
{ DOC("acd", "Set to 1 (the default) to use paritize automata using \
the alternatinc cycle decomposition. Set to 0 to use paritization based \
on latest appearance record variants.") },
{ DOC("scc-filter", "Set to 1 (the default) to enable \ { DOC("scc-filter", "Set to 1 (the default) to enable \
SCC-pruning and acceptance simplification at the beginning of \ SCC-pruning and acceptance simplification at the beginning of \
post-processing. Transitions that are outside of accepting SCC are \ post-processing. Transitions that are outside of accepting SCC are \
@ -175,10 +164,6 @@ Set to 1 to use only direct simulation. Set to 2 to use only reverse \
simulation. Set to 3 to iterate both direct and reverse simulations. \ simulation. Set to 3 to iterate both direct and reverse simulations. \
The default is the value of parameter \"simul\" in --high mode, and 0 \ The default is the value of parameter \"simul\" in --high mode, and 0 \
therwise.") }, therwise.") },
{ DOC("merge-states-min", "Number of states above which states are \
merged using a cheap approximation of a bisimulation quotient before \
attempting simulation-based reductions. Defaults to 128. Set to 0 to \
never merge states.") },
{ DOC("simul-max", "Number of states above which simulation-based \ { DOC("simul-max", "Number of states above which simulation-based \
reductions are skipped. Defaults to 4096. Set to 0 to disable. This \ reductions are skipped. Defaults to 4096. Set to 0 to disable. This \
applies to all simulation-based optimization, including thoses of the \ applies to all simulation-based optimization, including thoses of the \

View file

@ -1,6 +1,6 @@
// -*- coding: utf-8 -*- // -*- coding: utf-8 -*-
// Copyright (C) 2013-2018, 2022 Laboratoire de Recherche et // Copyright (C) 2013-2018 Laboratoire de Recherche et Développement
// 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.
// //
@ -24,8 +24,7 @@
#include <argp.h> #include <argp.h>
#include "common_setup.hh" #include "common_setup.hh"
static const char argp_program_doc[] = const char argp_program_doc[] ="Command-line tools installed by Spot.";
"Command-line tools installed by Spot.";
#define DOC(NAME, TXT) NAME, 0, nullptr, OPTION_DOC | OPTION_NO_USAGE, TXT, 0 #define DOC(NAME, TXT) NAME, 0, nullptr, OPTION_DOC | OPTION_NO_USAGE, TXT, 0

View file

@ -501,7 +501,6 @@ BUDDY_API_VAR const BDD bddtrue;
*************************************************************************/ *************************************************************************/
#ifdef CPLUSPLUS #ifdef CPLUSPLUS
#include <iostream> #include <iostream>
#include <memory>
/*=== User BDD class ===================================================*/ /*=== User BDD class ===================================================*/
@ -1093,11 +1092,6 @@ inline bddxfalse bdd_false(void)
{ return bddxfalse(); } { return bddxfalse(); }
template<>
struct std::default_delete<bddPair> {
void operator()(bddPair *p) const { bdd_freepair(p); };
};
/*=== Iostream printing ================================================*/ /*=== Iostream printing ================================================*/
class BUDDY_API bdd_ioformat class BUDDY_API bdd_ioformat

View file

@ -210,6 +210,7 @@ static BddTree *reorder_win2ite(BddTree *t)
{ {
BddTree *this, *first=t; BddTree *this, *first=t;
int lastsize; int lastsize;
int c=1;
if (t == NULL) if (t == NULL)
return t; return t;
@ -245,6 +246,7 @@ static BddTree *reorder_win2ite(BddTree *t)
if (verbose > 1) if (verbose > 1)
printf(" %d nodes\n", reorder_nodenum()); printf(" %d nodes\n", reorder_nodenum());
c++;
} }
while (reorder_nodenum() != lastsize); while (reorder_nodenum() != lastsize);

View file

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Copyright (C) 2008-2023, Laboratoire de Recherche et Développement # Copyright (C) 2008-2022, Laboratoire de Recherche et Développement
# de l'Epita (LRDE). # de l'Epita (LRDE).
# Copyright (C) 2003-2007 Laboratoire d'Informatique de Paris 6 # Copyright (C) 2003-2007 Laboratoire d'Informatique de Paris 6
# (LIP6), département Systèmes Répartis Coopératifs (SRC), Université # (LIP6), département Systèmes Répartis Coopératifs (SRC), Université
@ -21,7 +21,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
AC_PREREQ([2.69]) AC_PREREQ([2.69])
AC_INIT([spot], [2.11.5.dev], [spot@lrde.epita.fr]) AC_INIT([spot], [2.10.4.dev], [spot@lrde.epita.fr])
AC_CONFIG_AUX_DIR([tools]) AC_CONFIG_AUX_DIR([tools])
AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_MACRO_DIR([m4])
AM_INIT_AUTOMAKE([1.11 gnu tar-ustar color-tests parallel-tests]) AM_INIT_AUTOMAKE([1.11 gnu tar-ustar color-tests parallel-tests])
@ -53,15 +53,6 @@ AC_ARG_ENABLE([c++20],
[Compile in C++20 mode.])], [Compile in C++20 mode.])],
[enable_20=$enableval], [enable_20=no]) [enable_20=$enableval], [enable_20=no])
AC_ARG_ENABLE([pthread],
[AS_HELP_STRING([--enable-pthread],
[Allow libspot to use POSIX threads.])],
[enable_pthread=$enableval], [enable_pthread=no])
if test "$enable_pthread" = yes; then
AC_DEFINE([ENABLE_PTHREAD], [1], [Whether Spot is compiled with -pthread.])
AC_SUBST([LIBSPOT_PTHREAD], [-pthread])
fi
AC_ARG_ENABLE([doxygen], AC_ARG_ENABLE([doxygen],
[AS_HELP_STRING([--enable-doxygen], [AS_HELP_STRING([--enable-doxygen],
[enable generation of Doxygen documentation (requires Doxygen)])], [enable generation of Doxygen documentation (requires Doxygen)])],
@ -79,7 +70,6 @@ if test 0 -eq `expr $enable_max_accsets % $default_max_accsets`
then then
AC_DEFINE_UNQUOTED([MAX_ACCSETS], [$enable_max_accsets], AC_DEFINE_UNQUOTED([MAX_ACCSETS], [$enable_max_accsets],
[The maximal number of acceptance sets supported (also known as acceptance marks)]) [The maximal number of acceptance sets supported (also known as acceptance marks)])
AC_SUBST([MAX_ACCSETS], [$enable_max_accsets])
else else
AC_MSG_ERROR([The argument of --enable-max-accsets must be a multiple of $default_max_accsets]) AC_MSG_ERROR([The argument of --enable-max-accsets must be a multiple of $default_max_accsets])
fi fi
@ -160,7 +150,7 @@ AX_CHECK_BUDDY
AC_CHECK_FUNCS([times kill alarm sigaction sched_getcpu]) AC_CHECK_FUNCS([times kill alarm sigaction sched_getcpu])
oLIBS=$LIBS oLIBS=$LIBS
LIBS="$LIBS -pthread" LIBS="$LIBS -lpthread"
AC_CHECK_FUNCS([pthread_setaffinity_np]) AC_CHECK_FUNCS([pthread_setaffinity_np])
LIBS=$oLIBS LIBS=$oLIBS
@ -189,14 +179,9 @@ if test "x${enable_python:-yes}" = xyes; then
AC_MSG_NOTICE([You may configure with --disable-python ]dnl AC_MSG_NOTICE([You may configure with --disable-python ]dnl
[if you do not need Python bindings.]) [if you do not need Python bindings.])
adl_CHECK_PYTHON adl_CHECK_PYTHON
AC_ARG_WITH([pythondir],
[AS_HELP_STRING([--with-pythondir], [override the computed pythondir])],
[pythondir=$withval pyexecdir=$withval], [])
fi fi
adl_ENABLE_DEBUG adl_ENABLE_DEBUG
ad_GCC_OPTIM ad_GCC_OPTIM
adl_NDEBUG adl_NDEBUG
@ -217,7 +202,7 @@ AC_CHECK_PROG([LTL3BA], [ltl3ba], [ltl3ba])
AC_CHECK_PROG([PERL], [perl], [perl]) AC_CHECK_PROG([PERL], [perl], [perl])
AC_CHECK_PROG([SPIN], [spin], [spin]) AC_CHECK_PROG([SPIN], [spin], [spin])
AC_CHECK_PROG([LBTT], [lbtt], [lbtt]) AC_CHECK_PROG([LBTT], [lbtt], [lbtt])
AM_MISSING_PROG([EMACS], [emacs]) AC_CHECK_PROG([EMACS], [emacs], [emacs])
AC_CHECK_PROGS([IPYTHON], [ipython3 ipython], [ipython]) AC_CHECK_PROGS([IPYTHON], [ipython3 ipython], [ipython])
AC_CHECK_PROGS([JUPYTER], [jupyter], [jupyter]) AC_CHECK_PROGS([JUPYTER], [jupyter], [jupyter])
AC_CHECK_PROG([LBTT_TRANSLATE], [lbtt-translate], [lbtt-translate]) AC_CHECK_PROG([LBTT_TRANSLATE], [lbtt-translate], [lbtt-translate])
@ -295,23 +280,3 @@ case $VERSION:$enable_devel in
echo '===================================================================' echo '==================================================================='
;; ;;
esac esac
case $enable_python in
yes)
pd=$pythondir
eval pd=$pd
eval pd=$pd
$PYTHON -c "
import sys
if '$pd' in sys.path:
exit()
else:
print('\nWARNING: Python bindings will be installed in $pd')
print(' however this path is not searched by default by $PYTHON.')
print('\n$PYTHON\'s sys.path contains the following paths:\n',
'\n'.join(sys.path))
print('\nUse --with-pythondir=... if you wish '
'to change this installation path.')
"
;;
esac

2
debian/control vendored
View file

@ -2,7 +2,7 @@ Source: spot
Section: science Section: science
Priority: optional Priority: optional
Maintainer: Alexandre Duret-Lutz <adl@lrde.epita.fr> Maintainer: Alexandre Duret-Lutz <adl@lrde.epita.fr>
Build-Depends: debhelper (>= 12), python3-all-dev, ipython3-notebook | python3-ipykernel, ipython3-notebook | python3-nbconvert, libltdl-dev, dh-python, graphviz, jupyter-nbconvert, doxygen Build-Depends: debhelper (>= 12), python3-all-dev, ipython3-notebook | python3-ipykernel, ipython3-notebook | python3-nbconvert, libltdl-dev, dh-python
Standards-Version: 4.5.1 Standards-Version: 4.5.1
Homepage: http://spot.lrde.epita.fr/ Homepage: http://spot.lrde.epita.fr/

2
debian/copyright vendored
View file

@ -1,6 +1,6 @@
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: spot Upstream-Name: spot
Source: http://www.lrde.epita.fr/dload/spot/ Source: http://spot.lrde.epita.fr/dload/spot/
Files: * Files: *
Copyright: 2003-2007 Laboratoire d'Informatique de Paris 6 (LIP6) Copyright: 2003-2007 Laboratoire d'Informatique de Paris 6 (LIP6)

18
debian/rules vendored
View file

@ -20,16 +20,20 @@ include /usr/share/dpkg/default.mk
%: %:
dh $@ --with=python3 dh $@ --with=python3
# Find the LTO plugin, which we need to pass to ar, nm, and ranlib.
LTOPLUG := $(shell gcc -v 2>&1 | \
sed -n 's:COLLECT_LTO_WRAPPER=\(/.*/\)[^/]*:\1:p')liblto_plugin.so
# ARFLAGS is for Automake # ARFLAGS is for Automake
# AR_FLAGS is for Libtool, (but libtool 2.4.7 will now use ARFLAGS as well) # AR_FLAGS is for Libtool
# The gcc-tools activate the LTO plugin. # These activate the LTO pluggin, but also remove the 'u' option
# from ar, since its now ignored with Debian's default to 'D'.
LTOSETUP = \ LTOSETUP = \
LDFLAGS='-fuse-linker-plugin' \ LDFLAGS='-fuse-linker-plugin' \
NM='gcc-nm' \ NM='nm --plugin $(LTOPLUG)' \
AR='gcc-ar' \ ARFLAGS='cr --plugin $(LTOPLUG)' \
ARFLAGS='cr' \ AR_FLAGS='cr --plugin $(LTOPLUG)' \
AR_FLAGS='cr' \ RANLIB='ranlib --plugin $(LTOPLUG)' \
RANLIB='gcc-ranlib' \
VALGRIND=false VALGRIND=false
GCDADIR := $(shell pwd)/gcda GCDADIR := $(shell pwd)/gcda

View file

@ -1,35 +0,0 @@
# -*- mode: nix; coding: utf-8 -*-
# Copyright (C) 2022 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/>.
{ pkgs ? import <nixpkgs> {} }:
let
version = "@VERSION@";
in
pkgs.stdenv.mkDerivation {
inherit version;
pname = "spot";
buildInputs = [
pkgs.python3
];
src = ./.;
enableParallelBuilding = true;
}

View file

@ -27,9 +27,6 @@
(setenv "SPOT_DOTEXTRA" "node[fontsize=12] fontsize=12 stylesheet=\"spot.css\" edge[arrowhead=vee, arrowsize=.7, fontsize=12]") (setenv "SPOT_DOTEXTRA" "node[fontsize=12] fontsize=12 stylesheet=\"spot.css\" edge[arrowhead=vee, arrowsize=.7, fontsize=12]")
(setq org-babel-temporary-directory "@abs_top_builddir@/doc/org/tmp") (setq org-babel-temporary-directory "@abs_top_builddir@/doc/org/tmp")
(make-directory org-babel-temporary-directory t) (make-directory org-babel-temporary-directory t)
; has to be set globally, not buffer-local
(setq ess-ask-for-ess-directory nil)
(setq ess-startup-directory 'default-directory)
(org-babel-do-load-languages 'org-babel-load-languages (org-babel-do-load-languages 'org-babel-load-languages
`((,(if (version< org-version "8.3") 'sh 'shell) . t) `((,(if (version< org-version "8.3") 'sh 'shell) . t)
(python . t) (python . t)
@ -42,6 +39,7 @@
(org-babel-python-command . "@PYTHON@") (org-babel-python-command . "@PYTHON@")
(org-babel-C++-compiler . "./g++wrap") (org-babel-C++-compiler . "./g++wrap")
(shell-file-name . "@SHELL@") (shell-file-name . "@SHELL@")
(ess-ask-for-ess-directory . nil)
(org-export-html-postamble . nil) (org-export-html-postamble . nil)
(org-html-table-header-tags (org-html-table-header-tags
"<th scope=\"%s\"%s><div><span>" . "</span></div></th>") "<th scope=\"%s\"%s><div><span>" . "</span></div></th>")

View file

@ -249,7 +249,7 @@ EOF
| -:95.1-140.7 | automaton 2 | 2 | 10 | 26 | 26 | 1 | 2 | 6 | 1 | 0 | AF | ok | 0 | 0.0211636 | 2 | 21 | 66 | 84 | 2 | 4 | 0 | 0 | 0 | | -:95.1-140.7 | automaton 2 | 2 | 10 | 26 | 26 | 1 | 2 | 6 | 1 | 0 | AF | ok | 0 | 0.0211636 | 2 | 21 | 66 | 84 | 2 | 4 | 0 | 0 | 0 |
| -:95.1-140.7 | automaton 2 | 2 | 10 | 26 | 26 | 1 | 2 | 6 | 1 | 0 | L2D | ok | 0 | 0.0028508 | 2 | 24 | 74 | 96 | 2 | 4 | 0 | 0 | 0 | | -:95.1-140.7 | automaton 2 | 2 | 10 | 26 | 26 | 1 | 2 | 6 | 1 | 0 | L2D | ok | 0 | 0.0028508 | 2 | 24 | 74 | 96 | 2 | 4 | 0 | 0 | 0 |
* Transformation that preserve or complement languages * Language preserving transformation
By default =autcross= assumes that for a given input the automata By default =autcross= assumes that for a given input the automata
produced by all tools should be equivalent. However it does not produced by all tools should be equivalent. However it does not
@ -261,13 +261,6 @@ automaton, it is worth to pass the =--language-preserved= option to
=autfilt=. Doing so a bit like adding =cat %H>%O= as another tool: it =autfilt=. Doing so a bit like adding =cat %H>%O= as another tool: it
will also ensure that the output is equivalent to the input. will also ensure that the output is equivalent to the input.
Similarly, if the tools being tested implement complementation
algorithm, adding the =--language-complemented= will additionally
compare the outputs using this own complementation algorithm. Using
this option is more efficient than passing =autfilt --complement= as a
tool, since =autcross= can save on complementation by using the input
automaton.
* Detecting problems * Detecting problems
:PROPERTIES: :PROPERTIES:
:CUSTOM_ID: checks :CUSTOM_ID: checks

View file

@ -145,8 +145,7 @@ ltl2tgba --help | sed -n '/ sequences:/,/^$/p' | sed '1d;$d'
(iw) inherently weak. Use uppercase letters to (iw) inherently weak. Use uppercase letters to
negate them. negate them.
%d 1 if the output is deterministic, 0 otherwise %d 1 if the output is deterministic, 0 otherwise
%e, %[LETTER]e number of edges (add one LETTER to select (r) %e number of reachable edges
reachable [default], (u) unreachable, (a) all).
%f the formula, in Spot's syntax %f the formula, in Spot's syntax
%F name of the input file %F name of the input file
%g, %[LETTERS]g acceptance condition (in HOA syntax); add brackets %g, %[LETTERS]g acceptance condition (in HOA syntax); add brackets
@ -171,11 +170,8 @@ ltl2tgba --help | sed -n '/ sequences:/,/^$/p' | sed '1d;$d'
LETTERS to restrict to(u) user time, (s) system LETTERS to restrict to(u) user time, (s) system
time, (p) parent process, or (c) children time, (p) parent process, or (c) children
processes. processes.
%s, %[LETTER]s number of states (add one LETTER to select (r) %s number of reachable states
reachable [default], (u) unreachable, (a) all). %t number of reachable transitions
%t, %[LETTER]t number of transitions (add one LETTER to select
(r) reachable [default], (u) unreachable, (a)
all).
%u, %[e]u number of states (or [e]dges) with universal %u, %[e]u number of states (or [e]dges) with universal
branching branching
%u, %[LETTER]u 1 if the automaton contains some universal %u, %[LETTER]u 1 if the automaton contains some universal

View file

@ -6,22 +6,18 @@
* Generic reference * Generic reference
If you need to cite the Spot project, the latest tool paper about If you need to cite the Spot project in some academic paper, please
it is the following reference: use the following reference:
- *From Spot 2.0 to Spot 2.10: What's new?*, /Alexandre Duret-Lutz/, - *Spot 2.0 — a framework for LTL and ω-automata manipulation*,
/Etienne Renault/, /Maximilien Colange/, /Florian Renkin/, /Alexandre Duret-Lutz/, /Alexandre Lewkowicz/, /Amaury Fauchille/,
/Alexandre Gbaguidi Aisse/, /Philipp Schlehuber-Caissier/, /Thomas /Thibaud Michaud/, /Etienne Renault/, and /Laurent Xu/. In Proc.
Medioni/, /Antoine Martin/, /Jérôme Dubois/, /Clément Gillard/, and of ATVA'16, LNCS 9938, pp. 122--129. Chiba, Japan, Oct. 2016.
Henrich Lauko/. In Proc. of CAV'22, LNCS 13372, pp. 174--187. ([[https://www.lrde.epita.fr/~adl/dl/adl_bib.html#duret.16.atva2][bib]] | [[https://www.lrde.epita.fr/~adl/dl/adl/duret.16.atva2.pdf][pdf]])
Haifa, Israel, Aug. 2022.
([[https://www.lrde.epita.fr/~adl/dl/adl_bib.html#duret.22.cav][bib]] | [[https://www.lrde.epita.fr/~adl/dl/adl/duret.22.cav.pdf][pdf]])
#+begin_note This provides a quick overview of the entire project (the features
Tools evolve while published papers don't. Please always specify of the library, [[file:tools.org][the tools]], the Python bindings), and provides many
the version of Spot (or any other tool) you are using when citing it references detailing more specific aspects.
in a paper. Future versions might have different behaviors.
#+end_note
* Other, more specific, references * Other, more specific, references
@ -80,28 +76,12 @@ be more specific about a particular aspect of Spot.
- *Generic Emptiness Check for Fun and Profit*, - *Generic Emptiness Check for Fun and Profit*,
/Christel Baier/, /František Blahoudek/, /Alexandre Duret-Lutz/, /Christel Baier/, /František Blahoudek/, /Alexandre Duret-Lutz/,
/Joachim Klein/, /David Müller/, and /Jan Strejček/. /Joachim Klein/, /David Müller/, and /Jan Strejček/.
In. Proc. of ATVA'19, LNCS 11781, pp. 445--461, Oct 2019. ([[https://www.lrde.epita.fr/~adl/dl/adl_bib.html#baier.19.atva][bib]] | [[https://www.lrde.epita.fr/~adl/dl/adl/baier.19.atva.pdf][pdf]] | In. Proc. of ATVA'19, LNCS 11781, pp. 11781, Oct 2019. ([[https://www.lrde.epita.fr/~adl/dl/adl_bib.html#baier.19.atva][bib]] | [[https://www.lrde.epita.fr/~adl/dl/adl/baier.19.atva.pdf][pdf]] |
[[https://www.lrde.epita.fr/~adl/dl/adl/baier.19.atva.slides.mefosyloma.pdf][slides1]] | [[https://www.lrde.epita.fr/~adl/dl/adl/baier.19.atva.slides.pdf][slides2]]) [[https://www.lrde.epita.fr/~adl/dl/adl/baier.19.atva.slides.mefosyloma.pdf][slides1]] | [[https://www.lrde.epita.fr/~adl/dl/adl/baier.19.atva.slides.pdf][slides2]])
Presents the generic emptiness-check implemented in Spot. Presents the generic emptiness-check implemented in Spot.
- *Practical Applications of the Alternating Cycle Decomposition*, * Obsolete reference
/Antonio Casares/, /Alexandre Duret-Lutz/, /Klara J. Meyer/, /Florian Renkin/,
and /Salomon Sickert/.
In. Proc. of TACAS'22, LNCS 13244, pp. 99--117, Apr 2022. ([[https://www.lrde.epita.fr/~adl/dl/adl_bib.html#casares.22.tacas][bib]] | [[https://www.lrde.epita.fr/~adl/dl/adl/casares.22.tacas.pdf][pdf]] |
[[https://www.lrde.epita.fr/~adl/dl/adl/casares.22.tacas.slides.pdf][slides1]] | [[https://www.lrde.epita.fr/~adl/dl/adl/casares.22.tacas.slides2.pdf][slides2]])
* Obsolete references
- *Spot 2.0 — a framework for LTL and ω-automata manipulation*,
/Alexandre Duret-Lutz/, /Alexandre Lewkowicz/, /Amaury Fauchille/,
/Thibaud Michaud/, /Etienne Renault/, and /Laurent Xu/. In Proc.
of ATVA'16, LNCS 9938, pp. 122--129. Chiba, Japan, Oct. 2016.
([[https://www.lrde.epita.fr/~adl/dl/adl_bib.html#duret.16.atva2][bib]] | [[https://www.lrde.epita.fr/~adl/dl/adl/duret.16.atva2.pdf][pdf]])
This provides a quick overview of the entire project (the features
of the library, [[file:tools.org][the tools]], the Python bindings), and provides many
references detailing more specific aspects.
- *Spot: an extensible model checking library using transition-based - *Spot: an extensible model checking library using transition-based
generalized Büchi automata*, /Alexandre Duret-Lutz/ and /Denis generalized Büchi automata*, /Alexandre Duret-Lutz/ and /Denis

View file

@ -210,14 +210,11 @@ one library requiring another, you will need to link with the =bddx=
library. This should be as simple as adding =-lbddx= after =-lspot= library. This should be as simple as adding =-lbddx= after =-lspot=
in the first three cases. in the first three cases.
Similarly, if Spot has been configured with =--enable-pthread=, you
will need to add =-pthread= to the compiler flags.
In the fourth case where =libtool= is used to link against In the fourth case where =libtool= is used to link against
=libspot.la= linking against =libbddx.la= should not be necessary because =libspot.la= linking against =libbddx.la= should not be necessary because
Libtool already handles such dependencies. However the version of =libtool= Libtool already handles such dependencies. However the version of =libtool=
distributed with Debian is patched to ignore those dependencies, so in this distributed with Debian is patched to ignore those dependencies, so in this
case you have to list all dependencies. case you 2
* Additional suggestions * Additional suggestions

View file

@ -381,14 +381,13 @@ When /transition-based acceptance/ is used, acceptance sets are now
sets of /edges/ (or set of /transitions/ if you prefer), and runs are sets of /edges/ (or set of /transitions/ if you prefer), and runs are
accepting if the edges they visit satisfy the acceptance condition. accepting if the edges they visit satisfy the acceptance condition.
Here is an example of Transition-based Büchi Automaton Here is an example of Transition-based Generalized Büchi Automaton
(TBA). (TGBA).
#+NAME: tgba-example1 #+NAME: tgba-example1
#+BEGIN_SRC sh #+BEGIN_SRC sh
ltl2tgba 'GF(a & X(a U b))' -d ltl2tgba 'GF(a & X(a U b))' -d
#+END_SRC #+END_SRC
#+BEGIN_SRC dot :file concept-tgba1.svg :var txt=tgba-example1 :exports results #+BEGIN_SRC dot :file concept-tgba1.svg :var txt=tgba-example1 :exports results
$txt $txt
#+END_SRC #+END_SRC
@ -400,13 +399,27 @@ This automaton accept all ω-words that infinitely often match the
pattern $a^+;b$ (that is: a positive number of letters where $a$ is pattern $a^+;b$ (that is: a positive number of letters where $a$ is
true are followed by one letter where $b$ is true). true are followed by one letter where $b$ is true).
Using transition-based acceptance often allows for more compact automata. Using transition-based acceptance allows for more compact automata.
For instance the above automaton would need at least 3 states with The typical example is the LTL formula =GFa= (infinitely often $a$)
that can be represented using a one-state transition-based Büchi
automaton:
#+NAME: tgba-example2
#+BEGIN_SRC sh
ltl2tgba 'GFa' -d
#+END_SRC
#+BEGIN_SRC dot :file concept-tgba2.svg :var txt=tgba-example2 :exports results
$txt
#+END_SRC
#+RESULTS:
[[file:concept-tgba2.svg]]
While the same property require a 2-state Büchi automaton using
state-based acceptance: state-based acceptance:
#+NAME: tgba-example3 #+NAME: tgba-example3
#+BEGIN_SRC sh #+BEGIN_SRC sh
ltl2tgba 'GF(a & X(a U b))' -B -d ltl2tgba 'GFa' -B -d
#+END_SRC #+END_SRC
#+BEGIN_SRC dot :file concept-tba-vs-ba.svg :var txt=tgba-example3 :exports results #+BEGIN_SRC dot :file concept-tba-vs-ba.svg :var txt=tgba-example3 :exports results
$txt $txt
@ -1022,7 +1035,7 @@ layers.
dynamic libraries that [[http://fmt.cs.utwente.nl/tools/ltsmin/][LTSmin]] uses to represent state-spaces. It dynamic libraries that [[http://fmt.cs.utwente.nl/tools/ltsmin/][LTSmin]] uses to represent state-spaces. It
currently supports libraries generated from Promela models using currently supports libraries generated from Promela models using
SpinS or a patched version of DiVinE, but you have to install SpinS or a patched version of DiVinE, but you have to install
those third-party tools first. See [[https://gitlab.lre.epita.fr/spot/spot/blob/next/tests/ltsmin/README][=tests/ltsmin/README=]] those third-party tools first. See [[https://gitlab.lrde.epita.fr/spot/spot/blob/next/tests/ltsmin/README][=tests/ltsmin/README=]]
for details. for details.
- In addition to the C++17 API, we also provide Python bindings for - In addition to the C++17 API, we also provide Python bindings for
=libspotgen=, =libspotltsmin=, =libbddx=, and most of =libspot=. =libspotgen=, =libspotltsmin=, =libbddx=, and most of =libspot=.
@ -1034,8 +1047,8 @@ layers.
distributed with the rest of Spot, their source-code is publicly distributed with the rest of Spot, their source-code is publicly
available (in case you want to contribute or run a local version). available (in case you want to contribute or run a local version).
The [[https://spot-sandbox.lrde.epita.fr/][=spot-sandbox=]] website runs from a Docker container whose The [[https://spot-sandbox.lrde.epita.fr/][=spot-sandbox=]] website runs from a Docker container whose
configuration can be found in [[https://gitlab.lre.epita.fr/spot/sandbox/tree/master=][this repository]]. The client and configuration can be found in [[https://gitlab.lrde.epita.fr/spot/sandbox/tree/master=][this repository]]. The client and
server parts of the [[https://spot.lrde.epita.fr/app/][online LTL translator]] can be found in [[https://gitlab.lre.epita.fr/spot/spot-web-app/][this server parts of the [[https://spot.lrde.epita.fr/app/][online LTL translator]] can be found in [[https://gitlab.lrde.epita.fr/spot/spot-web-app/][this
repository]]. repository]].
* Automaton property flags * Automaton property flags

View file

@ -1,6 +1,6 @@
#!/bin/sh #!/bin/sh
# This is a wrapper around the compiler, to ensure that the code # This is a wrapper around the compiler, to ensure that the code
# examples run from org-mode files are all linked with Spot. # example run from the org-mode file are all linked with Spot.
# #
# Also we save errors to org.errors, so that we can detect issues # Also we save errors to org.errors, so that we can detect issues
# after org-mode has exported everything. Otherwise these errors # after org-mode has exported everything. Otherwise these errors
@ -8,7 +8,7 @@
@top_builddir@/libtool link @CXX@ @CXXFLAGS@ @CPPFLAGS@ -Wall -Werror \ @top_builddir@/libtool link @CXX@ @CXXFLAGS@ @CPPFLAGS@ -Wall -Werror \
-I@abs_top_builddir@ -I@abs_top_srcdir@ -I@abs_top_srcdir@/buddy/src \ -I@abs_top_builddir@ -I@abs_top_srcdir@ -I@abs_top_srcdir@/buddy/src \
"$@" @abs_top_builddir@/spot/libspot.la \ "$@" @abs_top_builddir@/spot/libspot.la \
@abs_top_builddir@/buddy/src/libbddx.la @LIBSPOT_PTHREAD@ 2> errors.$$ @abs_top_builddir@/buddy/src/libbddx.la 2> errors.$$
code=$? code=$?
if test $code -ne 0 && test -s errors.$$; then if test $code -ne 0 && test -s errors.$$; then
cat errors.$$ >>org.errors cat errors.$$ >>org.errors

View file

@ -66,7 +66,7 @@ the HOA format, the output may not be exactly the same as the input.
sets. sets.
This hard-coded limit can be augmented at configure time This hard-coded limit can be augmented at configure time
using option =--enable-max-accsets=N=, but doing so will consume using option `--enable-max-accsets=N`, but doing so will consume
more memory and time. more memory and time.
- Multiple (or missing) initial states are emulated. - Multiple (or missing) initial states are emulated.
@ -76,8 +76,7 @@ the HOA format, the output may not be exactly the same as the input.
is transformed into an equivalent TωA by merging the initial states is transformed into an equivalent TωA by merging the initial states
into a single one. The merged state can either be one of the into a single one. The merged state can either be one of the
original initial states (if one of those has no incoming edge) or a original initial states (if one of those has no incoming edge) or a
new state introduced for that purpose. This "conversion" may change new state introduced for that purpose.
the completeness property of the automaton.
Similarly, when an automaton with no initial state is loaded (this Similarly, when an automaton with no initial state is loaded (this
includes the case where the automaton has no state), a disconnected includes the case where the automaton has no state), a disconnected

View file

@ -25,7 +25,7 @@ checking. It has the following notable features:
weak-DBA, removal of useless SCCs, acceptance-condition weak-DBA, removal of useless SCCs, acceptance-condition
transformations, determinization, [[file:satmin.org][SAT-based minimization of transformations, determinization, [[file:satmin.org][SAT-based minimization of
deterministic automata]], [[https://spot.lrde.epita.fr/ipynb/zlktree.html][Alternating Cycle Decomposition]], etc. deterministic automata]], [[https://spot.lrde.epita.fr/ipynb/zlktree.html][Alternating Cycle Decomposition]], etc.
- Support for [[file:tut40.org][Safety]] and [[https://spot.lrde.epita.fr/ipynb/games.html][parity games]]. - Support for [[file:tut40.org][Safety]] and [[https://spot-dev.lrde.epita.fr/ipynb/games.html][parity games]].
- Applications to [[file:ltlsynt.org][reactive synthesis]] and [[https://spot.lrde.epita.fr/ipynb/atva16-fig2b.html][model checking]]. - Applications to [[file:ltlsynt.org][reactive synthesis]] and [[https://spot.lrde.epita.fr/ipynb/atva16-fig2b.html][model checking]].
- In addition to the C++ interface, most of its algorithms are usable - In addition to the C++ interface, most of its algorithms are usable
via [[file:tools.org][command-line tools]], and via [[file:tut.org][Python bindings]]. via [[file:tools.org][command-line tools]], and via [[file:tut.org][Python bindings]].
@ -37,7 +37,7 @@ checking. It has the following notable features:
* Latest version * Latest version
The latest version is *call_SPOT_VERSION()* and was released on The latest version is *{{{LASTRELEASE}}}* and was released on
*{{{LASTDATE}}}*. Please see the [[file:install.org][download and installation instructions]]. *{{{LASTDATE}}}*. Please see the [[file:install.org][download and installation instructions]].
* Documentation * Documentation

View file

@ -51,6 +51,7 @@
(package-install ess))))) (package-install ess)))))
(require 'ox-publish) (require 'ox-publish)
(require 'org-install)
(require 'hoa-mode) (require 'hoa-mode)
; See https://github.com/emacs-ess/ESS/issues/1052 ; See https://github.com/emacs-ess/ESS/issues/1052
@ -88,9 +89,7 @@
(setq org-babel-C++-compiler "./g++wrap") (setq org-babel-C++-compiler "./g++wrap")
(setq shell-file-name "@SHELL@") (setq shell-file-name "@SHELL@")
(setq ess-ask-for-ess-directory nil) (setq ess-ask-for-ess-directory nil)
; setting ess-startup-directory to 'default-directory is enough with
; newer ESS version (after Fev 2022) but does not work with older ones.
(setq ess-startup-directory "@abs_top_builddir@/doc/org")
(setq org-babel-default-header-args:plantuml (setq org-babel-default-header-args:plantuml
'((:results . "file") '((:results . "file")
(:exports . "results") (:exports . "results")
@ -160,7 +159,7 @@ up.html points to index.html, then the result is:
(setq body res) (setq body res)
(not cmp))) (not cmp)))
(concat "#+TITLE: " title (concat "#+TITLE: " title
"\n#+INCLUDE: setup.org\n#+HTML_LINK_UP: index.html\n\n" "\n#+SETUPFILE: setup.org\n#+HTML_LINK_UP: index.html\n\n"
body))) body)))
(setq org-publish-project-alist (setq org-publish-project-alist
@ -185,49 +184,6 @@ up.html points to index.html, then the result is:
:publishing-function org-publish-attachment) :publishing-function org-publish-attachment)
("spot-all" :components ("spot-html" "spot-static")))) ("spot-all" :components ("spot-html" "spot-static"))))
;;; Org-mode 9.5 is now using <img> to render SVG images.
;;; Unfortunately, this breaks SVG images that use external style
;;; sheets as <img> are expected to be self-contained.
;;;
;;; Since we do use such external style-sheets and never had
;;; any issue with <object type="image/svg+xml"...>, we revert
;;; to the previous behavior.
;;;
;;; The following function is based on org-html--svg-image from
;;; Org-mode 9.4.5, with the addition of the SVG extension test.
(defun spot-svg-output-as-object (source attributes info)
"If source is an SVG file, return an \"object\" embedding svg file
SOURCE with given ATTRIBUTES.
INFO is a plist used as a communication channel. Otherwise return nil.
The special attribute \"fallback\" can be used to specify a
fallback image file to use if the object embedding is not
supported. CSS class \"org-svg\" is assigned as the class of the
object unless a different class is specified with an attribute."
(when (string= "svg" (file-name-extension source))
(let ((fallback (plist-get attributes :fallback))
(attrs (org-html--make-attribute-string
(org-combine-plists
;; Remove fallback attribute, which is not meant to
;; appear directly in the attributes string, and
;; provide a default class if none is set.
'(:class "org-svg") attributes '(:fallback nil)))))
(format "<object type=\"image/svg+xml\" data=\"%s\" %s>\n%s</object>"
source
attrs
(if fallback
(org-html-close-tag
"img" (format "src=\"%s\" %s" fallback attrs) info)
"Sorry, your browser does not support SVG.")))))
;;; Hack org-html--format-image to call the above first.
;;; (The org-html--svg-image function was removed when the formater code
;;; switched to <img> for SVG.)
(unless (fboundp 'org-html--svg-image)
(advice-add 'org-html--format-image :before-until 'spot-svg-output-as-object))
(org-publish-all t) (org-publish-all t)
;;; org-babel-remove-temporary-directory does not correctly remove ;;; org-babel-remove-temporary-directory does not correctly remove
;;; nested directories and we have some files in tmp/.libs/ because of ;;; nested directories and we have some files in tmp/.libs/ because of

View file

@ -9,12 +9,12 @@
:CUSTOM_ID: tar :CUSTOM_ID: tar
:END: :END:
The latest release of Spot is version call_SPOT_VERSION() and was released on {{{LASTDATE}}}: The latest release of Spot is version {{{LASTRELEASE}}}:
- call_TARBALL_LINK() (see also the call_NEWS_LINK()) - {{{LASTTARBALL}}} (see also the {{{LASTNEWS}}})
Past releases can be found [[https://www.lrde.epita.fr/dload/spot/][in the same directory]]. If you are Past releases can be found [[https://www.lrde.epita.fr/dload/spot/][in the same directory]]. If you are
interested in /future/ releases, you can always peek at the [[https://gitlab.lre.epita.fr/spot/spot/-/jobs/artifacts/next/browse?job=make-dist][last interested in /future/ releases, you can always peek at the [[https://gitlab.lrde.epita.fr/spot/spot/-/jobs/artifacts/next/browse?job=debian-stable-gcc][last
successful development build]]. successful development build]].
** Requirements ** Requirements
@ -52,13 +52,10 @@ make
make install make install
#+END_SRC #+END_SRC
Before running =make install=, you might want to run =make check= to
run our test-suite.
Files =INSTALL= and =README= included in the tarball contains more Files =INSTALL= and =README= included in the tarball contains more
explanations about the various options you can use during the explanations about the various options you can use during this
compilation process. Also note that =README= has a section about process. Also note that =README= has a section about troubleshooting
troubleshooting installations. installations.
* Installing the Debian packages * Installing the Debian packages
:PROPERTIES: :PROPERTIES:
@ -91,9 +88,7 @@ apt-get install spot libspot-dev spot-doc python3-spot # Or a subset of those
Note that our Debian repository is signed since that is the new Debian Note that our Debian repository is signed since that is the new Debian
policy, and both of the above command blocks start with a download of policy, and both of the above command blocks start with a download of
our [[https://www.lrde.epita.fr/repo/debian.gpg][GPG key]]. Its fingerprint is =209B 7362 CFD6 FECF B41D 717F 03D9 our [[https://www.lrde.epita.fr/repo/debian.gpg][GPG key]]. Its fingerprint is =209B 7362 CFD6 FECF B41D 717F 03D9
9E74 44F2 A84A=, if you want to verify it. If you have an old copy of 9E74 44F2 A84A=, if you want to verify it.
the GPG key that expired, please download it again: the current
version should be valid until 2032.
The package =spot= contains the [[file:tools.org][command-line tools]]. =libspot-dev= The package =spot= contains the [[file:tools.org][command-line tools]]. =libspot-dev=
contains the header files if you plan to use Spot in a C++17 contains the header files if you plan to use Spot in a C++17
@ -167,11 +162,11 @@ the (working) code that should be part of the next major release.
To clone the git repository, use To clone the git repository, use
#+BEGIN_SRC sh #+BEGIN_SRC sh
git clone https://gitlab.lre.epita.fr/spot/spot.git git clone https://gitlab.lrde.epita.fr/spot/spot.git
#+END_SRC #+END_SRC
This should put you on the =next= branch by default. From there, read This should put you on the =next= branch by default. From there, read
the [[https://gitlab.lre.epita.fr/spot/spot/blob/next/HACKING][HACKING]] file that should be at the top of your cloned repository: the [[https://gitlab.lrde.epita.fr/spot/spot/blob/next/HACKING][HACKING]] file that should be at the top of your cloned repository:
it lists all the tools you should install before attempting to compile it lists all the tools you should install before attempting to compile
the source tree. the source tree.

View file

@ -924,7 +924,7 @@ compare the number of states produced by the two configurations of
=ltl2tgba= for each formula, we just need to plot column =ltl2tgba= for each formula, we just need to plot column
=dt2$state.small= against =dt2$state.deter=. =dt2$state.small= against =dt2$state.deter=.
#+BEGIN_SRC R :results output graphics file :width 5 :height 5 :file ltlcross-r.svg #+BEGIN_SRC R :results output graphics :width 5 :height 5 :file ltlcross-r.svg
library(ggplot2) library(ggplot2)
ggplot(dt2, aes(x=states.small, y=states.deter)) + ggplot(dt2, aes(x=states.small, y=states.deter)) +
geom_abline(colour='white') + geom_point() geom_abline(colour='white') + geom_point()
@ -937,7 +937,7 @@ ggplot(dt2, aes(x=states.small, y=states.deter)) +
We should probably print the formulas for the cases where the two We should probably print the formulas for the cases where the two
sizes differ. sizes differ.
#+BEGIN_SRC R :results output graphics file :width 5 :height 5 :file ltlcross-r2.svg #+BEGIN_SRC R :results output graphics :width 5 :height 5 :file ltlcross-r2.svg
ggplot(dt2, aes(x=states.small, y=states.deter)) + ggplot(dt2, aes(x=states.small, y=states.deter)) +
geom_abline(colour='white') + geom_point() + geom_abline(colour='white') + geom_point() +
geom_text(data=subset(dt2, states.small != states.deter), geom_text(data=subset(dt2, states.small != states.deter),

View file

@ -7,19 +7,19 @@
* Basic usage * Basic usage
This tool synthesizes reactive controllers from LTL/PSL formulas. This tool synthesizes controllers from LTL/PSL formulas.
Consider a set $I$ of /input/ atomic propositions, a set $O$ of output atomic Consider a set $I$ of /input/ atomic propositions, a set $O$ of output atomic
propositions, and a PSL formula \phi over the propositions in $I \cup O$. A propositions, and a PSL formula \phi over the propositions in $I \cup O$. A
*reactive controller* realizing \phi is a function $c: (2^{I})^\star \times 2^I \mapsto =controller= realizing \phi is a function $c: (2^{I})^\star \times 2^I \mapsto
2^O$ such that, for every \omega-word $(u_i)_{i \in N} \in (2^I)^\omega$ over 2^O$ such that, for every \omega-word $(u_i)_{i \in N} \in (2^I)^\omega$ over
the input propositions, the word $(u_i \cup c(u_0 \dots u_{i-1}, u_i))_{i \in the input propositions, the word $(u_i \cup c(u_0 \dots u_{i-1}, u_i))_{i \in
N}$ satisfies \phi. N}$ satisfies \phi.
If a reactive controller exists, then one with finite memory If a controller exists, then one with finite memory exists. Such controllers
exists. Such controllers are easily represented as automata (or more are easily represented as automata (or more specifically as I/O automata or
specifically as Mealy machines). In the automaton representing the transducers). In the automaton representing the controller, the acceptance
controller, the acceptance condition is irrelevant and trivially true. condition is irrelevant and trivially true.
=ltlsynt= has three mandatory options: =ltlsynt= has three mandatory options:
- =--ins=: a comma-separated list of input atomic propositions; - =--ins=: a comma-separated list of input atomic propositions;
@ -27,52 +27,45 @@ controller, the acceptance condition is irrelevant and trivially true.
- =--formula= or =--file=: a specification in LTL or PSL. - =--formula= or =--file=: a specification in LTL or PSL.
One of =--ins= or =--outs= may be omitted, as any atomic proposition not listed One of =--ins= or =--outs= may be omitted, as any atomic proposition not listed
as input can be assumed to be output and vice-versa. as input can be assumed to be an output and vice-versa.
The following example illustrates the synthesis of a controller The following example illustrates the synthesis of a controller acting as an
ensuring that input =i1= and =i2= are both true initially if and only =AND= gate. We have two inputs =a= and =b= and one output =c=, and we want =c=
if eventually output =o1= will go from true to false at some point. to always be the =AND= of the two inputs:
Note that this is an equivalence, not an implication.
#+NAME: example #+NAME: example
#+BEGIN_SRC sh :exports both #+BEGIN_SRC sh :exports both
ltlsynt --ins=i1,i2 -f '(i1 & i2) <-> F(o1 & X(!o1))' ltlsynt --ins=a,b -f 'G (a & b <=> c)'
#+END_SRC #+END_SRC
#+RESULTS: example #+RESULTS: example
#+begin_example #+begin_example
REALIZABLE REALIZABLE
HOA: v1 HOA: v1
States: 3 States: 1
Start: 0 Start: 0
AP: 3 "i1" "i2" "o1" AP: 3 "a" "b" "c"
acc-name: all acc-name: all
Acceptance: 0 t Acceptance: 0 t
properties: trans-labels explicit-labels state-acc deterministic properties: trans-labels explicit-labels state-acc deterministic
controllable-AP: 2
--BODY-- --BODY--
State: 0 State: 0
[0&1&2] 1 [!0&!2 | !1&!2] 0
[!0&2 | !1&2] 2 [0&1&2] 0
State: 1
[!2] 0
State: 2
[2] 2
--END-- --END--
#+end_example #+end_example
The output is composed of two parts: The output is composed of two parts:
- The first one is a single line =REALIZABLE= or =UNREALIZABLE=; the presence of this - the first one is a single line =REALIZABLE= or =UNREALIZABLE;=
line, required by the [[http://http://www.syntcomp.org/][SyntComp competition]], can be disabled with option =--hide-status=. - the second one, only present in the =REALIZABLE= case is an automaton describing the controller.
- The second one, only present in the =REALIZABLE= case, is an automaton describing the controller. In this example, the controller has a single
state, with two loops labeled by =a & b & c= and =(!a | !b) & !c=.
The controller contains the line =controllable-AP: 2=, which means that this automaton
should be interpreted as a Mealy machine where =o0= is part of the output.
Using the =--dot= option, makes it easier to visualize this machine.
#+NAME: exampledot #+NAME: exampledot
#+BEGIN_SRC sh :exports code #+BEGIN_SRC sh :exports none :noweb yes
ltlsynt --ins=i1,i2 -f '(i1 & i2) <-> F(o1 & X(!o1))' --hide-status --dot sed 1d <<EOF | autfilt --dot=.A
<<example()>>
EOF
#+END_SRC #+END_SRC
#+BEGIN_SRC dot :file ltlsyntex.svg :var txt=exampledot :exports results #+BEGIN_SRC dot :file ltlsyntex.svg :var txt=exampledot :exports results
@ -82,6 +75,9 @@ ltlsynt --ins=i1,i2 -f '(i1 & i2) <-> F(o1 & X(!o1))' --hide-status --dot
#+RESULTS: #+RESULTS:
[[file:ltlsyntex.svg]] [[file:ltlsyntex.svg]]
The label =a & b & c= should be understood as: "if the input is =a&b=,
the output should be =c=".
The following example illustrates the case of an unrealizable specification. As The following example illustrates the case of an unrealizable specification. As
=a= is an input proposition, there is no way to guarantee that it will =a= is an input proposition, there is no way to guarantee that it will
eventually hold. eventually hold.
@ -94,68 +90,11 @@ ltlsynt --ins=a -f 'F a'
: UNREALIZABLE : UNREALIZABLE
By default, the controller is output in HOA format, but it can be By default, the controller is output in HOA format, but it can be
output as an And-Inverter-Graph in [[http://fmv.jku.at/aiger/][AIGER format]] using the =--aiger= output as an [[http://fmv.jku.at/aiger/][AIGER]] circuit thanks to the =--aiger= flag. This is the
flag. This is the output format required for the [[http://syntcomp.org/][SYNTCOMP]] competition. output format required for the [[http://syntcomp.org/][SYNTCOMP]] competition.
#+NAME: exampleaig The generation of a controller can be disabled with the flag =--realizability=.
#+BEGIN_SRC sh :exports both In this case, =ltlsynt= output is limited to =REALIZABLE= or =UNREALIZABLE=.
ltlsynt --ins=i1,i2 -f '(i1 & i2) <-> F(o1 & X(!o1))' --aiger
#+END_SRC
#+RESULTS: exampleaig
#+begin_example
REALIZABLE
aag 14 2 2 1 10
2
4
6 14
8 29
7
10 7 9
12 4 10
14 2 12
16 7 8
18 4 16
20 5 7
22 21 19
24 2 23
26 3 7
28 27 25
i0 i1
i1 i2
o0 o1
#+end_example
The above format is not very human friendly. Again, by passing both
=--aiger= and =--dot=, one can display the And-Inverter-Graph representing
the controller:
#+NAME: exampleaigdot
#+BEGIN_SRC sh :exports code
ltlsynt --ins=i1,i2 -f '(i1 & i2) <-> F(o1 & X(!o1))' --hide-status --aiger --dot
#+END_SRC
#+BEGIN_SRC dot :file ltlsyntexaig.svg :var txt=exampleaigdot :exports results
$txt
#+END_SRC
#+RESULTS:
[[file:ltlsyntexaig.svg]]
In the above diagram, round nodes represent AND gates. Small black
circles represent inversions (or negations), colored triangles are
used to represent input signals (at the bottom) and output signals (at
the top), and finally rectangles represent latches. A latch is a one
bit register that delays the signal by one step. Initially, all
latches are assumed to contain =false=, and them emit their value from
the =L0_out= and =L1_out= rectangles at the bottom. Their input value,
to be emitted at the next step, is received via the =L0_in= and =L1_in=
boxes at the top. In =ltlsynt='s encoding, the set of latches is used
to keep track of the current state of the Mealy machine.
The generation of a controller can be disabled with the flag
=--realizability=. In this case, =ltlsynt='s output is limited to
=REALIZABLE= or =UNREALIZABLE=.
* TLSF * TLSF
@ -165,20 +104,14 @@ specification language created for the purpose of this competition.
Fortunately, the SYNTCOMP organizers also provide a tool called Fortunately, the SYNTCOMP organizers also provide a tool called
[[https://github.com/reactive-systems/syfco][=syfco=]] which can translate a TLSF specification to an LTL formula. [[https://github.com/reactive-systems/syfco][=syfco=]] which can translate a TLSF specification to an LTL formula.
The following line shows how a TLSF specification called =FILE= can The following four steps show you how a TLSF specification called =FILE= can
be synthesized using =syfco= and =ltlsynt=: be synthesized using =syfco= and =ltlsynt=:
#+BEGIN_SRC sh :export code #+BEGIN_SRC sh :export code
ltlsynt --tlsf FILE LTL=$(syfco FILE -f ltlxba -m fully)
#+END_SRC IN=$(syfco FILE --print-input-signals)
OUT=$(syfco FILE --print-output-signals)
The above =--tlsf= option will call =syfco= to perform the conversion ltlsynt --formula="$LTL" --ins="$IN" --outs="$OUT"
and extract output signals, as if you had used:
#+BEGIN_SRC sh :export code
LTL=$(syfco -f ltlxba -m fully FILE)
OUT=$(syfco --print-output-signals FILE)
ltlsynt --formula="$LTL" --outs="$OUT"
#+END_SRC #+END_SRC
* Internal details * Internal details
@ -238,18 +171,7 @@ be tried by separating them using commas. For instance
You can also ask =ltlsynt= to print to obtained parity game into You can also ask =ltlsynt= to print to obtained parity game into
[[https://github.com/tcsprojects/pgsolver][PGSolver]] format, with the flag =--print-pg=, or in the HOA format, [[https://github.com/tcsprojects/pgsolver][PGSolver]] format, with the flag =--print-pg=, or in the HOA format,
using =--print-game-hoa=. These flag deactivate the resolution of the using =--print-game-hoa=. These flag deactivate the resolution of the
parity game. Note that if any of those flag is used with =--dot=, the game parity game.
will be printed in the Dot format instead:
#+NAME: examplegamedot
#+BEGIN_SRC sh :exports code
ltlsynt --ins=i1,i2 -f '(i1 & i2) <-> F(o1 & X(!o1))' --print-game-hoa --dot
#+END_SRC
#+BEGIN_SRC dot :file ltlsyntexgame.svg :var txt=examplegamedot :exports results
$txt
#+END_SRC
#+RESULTS:
[[file:ltlsyntexgame.svg]]
For benchmarking purpose, the =--csv= option can be used to record For benchmarking purpose, the =--csv= option can be used to record
intermediate statistics about the resolution. intermediate statistics about the resolution.
@ -272,11 +194,6 @@ Further improvements are described in the following paper:
/Alexandre Duret-Lutz/, and /Adrien Pommellet/. Presented at the /Alexandre Duret-Lutz/, and /Adrien Pommellet/. Presented at the
SYNT'21 workshop. ([[https://www.lrde.epita.fr/~adl/dl/adl/renkin.21.synt.pdf][pdf]] | [[https://www.lrde.epita.fr/~adl/dl/adl_bib.html#renkin.21.synt][bib]]) SYNT'21 workshop. ([[https://www.lrde.epita.fr/~adl/dl/adl/renkin.21.synt.pdf][pdf]] | [[https://www.lrde.epita.fr/~adl/dl/adl_bib.html#renkin.21.synt][bib]])
Simplification of Mealy machines is discussed in:
- *Effective reductions of Mealy machines*, /Florian Renkin/,
/Philipp Schlehuber-Caissier/, /Alexandre Duret-Lutz/, and /Adrien Pommellet/.
Presented at FORTE'22. ([[https://www.lrde.epita.fr/~adl/dl/adl/renkin.22.forte.pdf][pdf]] | [[https://www.lrde.epita.fr/~adl/dl/adl_bib.html#renkin.22.forte][bib]])
# LocalWords: utf ltlsynt AIGER html args mapsto SRC acc aiger TLSF # LocalWords: utf ltlsynt AIGER html args mapsto SRC acc aiger TLSF
# LocalWords: UNREALIZABLE unrealizable SYNTCOMP realizability Proc # LocalWords: UNREALIZABLE unrealizable SYNTCOMP realizability Proc

View file

@ -1,23 +1,11 @@
#+OPTIONS: H:2 num:nil toc:t html-postamble:nil ^:nil #+OPTIONS: H:2 num:nil toc:t html-postamble:nil ^:nil
#+EMAIL: spot@lrde.epita.fr #+EMAIL: spot@lrde.epita.fr
#+HTML_LINK_HOME: index.html #+HTML_LINK_HOME: index.html
#+MACRO: LASTDATE 2023-04-20 #+MACRO: SPOTVERSION 2.10.4
#+MACRO: LASTRELEASE 2.10.4
#+NAME: SPOT_VERSION #+MACRO: LASTTARBALL [[http://www.lrde.epita.fr/dload/spot/spot-2.10.4.tar.gz][=spot-2.10.4.tar.gz=]]
#+BEGIN_SRC python :exports none :results value :wrap org #+MACRO: LASTNEWS [[https://gitlab.lrde.epita.fr/spot/spot/blob/spot-2-10-4/NEWS][summary of the changes]]
return "2.11.5" #+MACRO: LASTDATE 2022-02-01
#+END_SRC
#+NAME: TARBALL_LINK
#+BEGIN_SRC python :exports none :var version=SPOT_VERSION :results output :wrap org
print(f"[[http://www.lrde.epita.fr/dload/spot/spot-{version}.tar.gz][=spot-{version}.tar.gz=]]")
#+END_SRC
#+NAME: NEWS_LINK
#+BEGIN_SRC python :exports none :var version=SPOT_VERSION :results output :wrap org
version = version.replace('.', '-')
print(f"[[https://gitlab.lre.epita.fr/spot/spot/blob/spot-{version}/NEWS][summary of the changes]]")
#+END_SRC
#+ATTR_HTML: :id spotlogo #+ATTR_HTML: :id spotlogo
[[file:spot2.svg]] [[file:spot2.svg]]

View file

@ -16,9 +16,9 @@ h1::before{content:"";position:absolute;z-index:-1;background-color:#ffe35e;left
#table-of-contents #text-table-of-contents{text-align:left} #table-of-contents #text-table-of-contents{text-align:left}
#org-div-home-and-up{text-align:center;font-size:100%} #org-div-home-and-up{text-align:center;font-size:100%}
.outline-2 h2{display:block;width:100%;position:relative} .outline-2 h2{display:block;width:100%;position:relative}
.outline-2 h2::before{content:"";height:100%;width:calc(100% + 2em);position:absolute;z-index:-1;bottom:0em;left:-1em;background:linear-gradient(45deg,#ffe35e 50%,transparent 75%);transform:skew(10deg);border-radius:5px;} .outline-2 h2::before{content:"";height:100%;width:calc(100% + 2em);position:absolute;z-index:-1;bottom:0em;left:-1em;background-color:#ffe35e;background:linear-gradient(45deg,#ffe35e 50%,transparent 75%);transform:skew(10deg);border-radius:5px;}
.outline-3 h3{display:block;width:auto;position:relative} .outline-3 h3{display:block;width:auto;position:relative}
.outline-3 h3::before{content:"";position:absolute;z-index:-1;width:calc(100% + 2em);height:100%;left:-1em;bottom:0em;background:linear-gradient(45deg,#ffe35e 25%,transparent 50%);transform:skew(10deg);border-radius:3px} .outline-3 h3::before{content:"";position:absolute;z-index:-1;width:calc(100% + 2em);height:100%;left:-1em;bottom:0em;;background-color:#ffe35e;background:linear-gradient(45deg,#ffe35e 25%,transparent 50%);transform:skew(10deg);border-radius:3px}
.outline-2 h2:hover::before,.outline-3 h3:hover::before{background-color:#ffe35e} .outline-2 h2:hover::before,.outline-3 h3:hover::before{background-color:#ffe35e}
pre{margin:1.2ex} pre{margin:1.2ex}
pre.src{padding-top:8px;border-left-style:solid;border-color:#00adad;overflow:auto;margin-top:0;margin-bottom:0} pre.src{padding-top:8px;border-left-style:solid;border-color:#00adad;overflow:auto;margin-top:0;margin-bottom:0}
@ -77,13 +77,11 @@ thead tr{background:#ffe35e}
.org-hoa-ap-number{color:#d70079} .org-hoa-ap-number{color:#d70079}
.implem{background:#fff0a6;padding:0.5ex 1ex 0.5ex 1ex;margin:1ex;border-color:#ffe35e;border-style:solid none} .implem{background:#fff0a6;padding:0.5ex 1ex 0.5ex 1ex;margin:1ex;border-color:#ffe35e;border-style:solid none}
.implem::before{background:#ffe35e;content:"Implementation detail";padding:.5ex;position:relative;top:0;left:0;font-weight:bold} .implem::before{background:#ffe35e;content:"Implementation detail";padding:.5ex;position:relative;top:0;left:0;font-weight:bold}
.note{background:#fff0a6;padding:0.5ex 1ex 0.5ex 1ex;margin:1ex;border-color:#ffe35e;border-style:solid none}
.note::before{background:#ffe35e;content:"Note";padding:.5ex;position:relative;top:0;left:0;font-weight:bold}
.caveat{background:#ef99c9;padding:0.5ex 1ex 0.5ex 1ex;margin:1ex;border-color:#d70079;border-style:solid none} .caveat{background:#ef99c9;padding:0.5ex 1ex 0.5ex 1ex;margin:1ex;border-color:#d70079;border-style:solid none}
.caveat::before{background:#d70079;content:"Caveat";padding:.5ex;position:relative;top:0;left:0;font-weight:bold} .caveat::before{background:#d70079;content:"Caveat";padding:.5ex;position:relative;top:0;left:0;font-weight:bold}
.spotlogo{transform-origin:50% 50%;animation-duration:2s;animation-name:animspotlogo} .spotlogo{transform-origin:50% 50%;animation-duration:2s;animation-name:animspotlogo}
g.spotlogobg{transform-origin:50% 50%;animation-duration:2s;animation-name:animspotlogobg} g.spotlogobg{transform-origin:50% 50%;animation-duration:2s;animation-name:animspotlogobg}
g.spotlogover{transform-origin:50% 50%;animation-duration:3s;animation-name:animspotlogover} g#version{transform-origin:50% 50%;animation-duration:3s;animation-name:animspotlogover}
@keyframes animspotlogo{ @keyframes animspotlogo{
0%{transform:rotateY(90deg)} 0%{transform:rotateY(90deg)}
80%{transform:rotateY(0deg)} 80%{transform:rotateY(0deg)}

View file

@ -14,7 +14,7 @@
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,67.83905%,93.728638%);fill-opacity:1;" d="M 29.054688 0.707031 L 0.707031 29.054688 L 29.054688 57.402344 L 43.226562 43.226562 L 43.226562 14.882812 Z M 29.054688 0.707031 "/> <path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,67.83905%,93.728638%);fill-opacity:1;" d="M 29.054688 0.707031 L 0.707031 29.054688 L 29.054688 57.402344 L 43.226562 43.226562 L 43.226562 14.882812 Z M 29.054688 0.707031 "/>
<path style="fill:none;stroke-width:1.41731;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(30.000305%,77.487183%,95.610046%);stroke-opacity:1;stroke-miterlimit:10;" d="M -0.0003125 28.347969 L -28.347969 0.0003125 L -0.0003125 -28.347344 L 14.171563 -14.171563 L 14.171563 14.172187 Z M -0.0003125 28.347969 " transform="matrix(1,0,0,-1,29.055,29.055)"/> <path style="fill:none;stroke-width:1.41731;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(30.000305%,77.487183%,95.610046%);stroke-opacity:1;stroke-miterlimit:10;" d="M -0.0003125 28.347969 L -28.347969 0.0003125 L -0.0003125 -28.347344 L 14.171563 -14.171563 L 14.171563 14.172187 Z M -0.0003125 28.347969 " transform="matrix(1,0,0,-1,29.055,29.055)"/>
</g> </g>
<g class="spotlogover"> <g id="version">
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,94.898987%,0%);fill-opacity:1;" d="M 34.84375 29.054688 C 34.84375 25.855469 32.253906 23.265625 29.054688 23.265625 C 25.855469 23.265625 23.265625 25.855469 23.265625 29.054688 C 23.265625 32.253906 25.855469 34.84375 29.054688 34.84375 C 32.253906 34.84375 34.84375 32.253906 34.84375 29.054688 Z M 34.84375 29.054688 "/> <path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,94.898987%,0%);fill-opacity:1;" d="M 34.84375 29.054688 C 34.84375 25.855469 32.253906 23.265625 29.054688 23.265625 C 25.855469 23.265625 23.265625 25.855469 23.265625 29.054688 C 23.265625 32.253906 25.855469 34.84375 29.054688 34.84375 C 32.253906 34.84375 34.84375 32.253906 34.84375 29.054688 Z M 34.84375 29.054688 "/>
<path style="fill:none;stroke-width:2.83466;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 5.78875 0.0003125 C 5.78875 3.199531 3.198906 5.789375 -0.0003125 5.789375 C -3.199531 5.789375 -5.789375 3.199531 -5.789375 0.0003125 C -5.789375 -3.198906 -3.199531 -5.78875 -0.0003125 -5.78875 C 3.198906 -5.78875 5.78875 -3.198906 5.78875 0.0003125 Z M 5.78875 0.0003125 " transform="matrix(1,0,0,-1,29.055,29.055)"/> <path style="fill:none;stroke-width:2.83466;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 5.78875 0.0003125 C 5.78875 3.199531 3.198906 5.789375 -0.0003125 5.789375 C -3.199531 5.789375 -5.789375 3.199531 -5.789375 0.0003125 C -5.789375 -3.198906 -3.199531 -5.78875 -0.0003125 -5.78875 C 3.198906 -5.78875 5.78875 -3.198906 5.78875 0.0003125 Z M 5.78875 0.0003125 " transform="matrix(1,0,0,-1,29.055,29.055)"/>
<path style="fill:none;stroke-width:5.66934;stroke-linecap:round;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 10.499688 15.965156 C 9.312188 18.754219 7.015313 21.062812 3.945 22.18 C -1.941719 24.320625 -8.445625 21.289375 -10.590156 15.402656 C -11.972969 11.597969 -11.222969 7.340156 -8.621406 4.234687 C -6.465156 1.668281 -3.285469 0.187812 0.0660938 0.187812 C 6.327813 0.187812 11.405938 -4.890313 11.405938 -11.152031 C 11.405938 -17.41375 6.327813 -22.491875 0.0660938 -22.491875 C -6.195625 -22.491875 -11.27375 -17.41375 -11.27375 -11.152031 " transform="matrix(1,0,0,-1,29.055,29.055)"/> <path style="fill:none;stroke-width:5.66934;stroke-linecap:round;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 10.499688 15.965156 C 9.312188 18.754219 7.015313 21.062812 3.945 22.18 C -1.941719 24.320625 -8.445625 21.289375 -10.590156 15.402656 C -11.972969 11.597969 -11.222969 7.340156 -8.621406 4.234687 C -6.465156 1.668281 -3.285469 0.187812 0.0660938 0.187812 C 6.327813 0.187812 11.405938 -4.890313 11.405938 -11.152031 C 11.405938 -17.41375 6.327813 -22.491875 0.0660938 -22.491875 C -6.195625 -22.491875 -11.27375 -17.41375 -11.27375 -11.152031 " transform="matrix(1,0,0,-1,29.055,29.055)"/>

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 6.1 KiB

Before After
Before After

View file

@ -1,12 +1,12 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
#+TITLE: Command-line tools installed by Spot {{{SPOTVERSION}}}
#+DESCRIPTION: List of all the command-line tools installed by Spot {{{SPOTVERSION}}}
#+INCLUDE: setup.org #+INCLUDE: setup.org
#+TITLE: Command-line tools installed by Spot
#+DESCRIPTION: List of all the command-line tools installed by Spot
#+HTML_LINK_UP: index.html #+HTML_LINK_UP: index.html
#+PROPERTY: header-args:sh :results verbatim :exports both #+PROPERTY: header-args:sh :results verbatim :exports both
This document introduces command-line tools that are installed with This document introduces command-line tools that are installed with
Spot call_SPOT_VERSION(). We give some examples to highlight possible the Spot library. We give some examples to highlight possible
use-cases but shall not attempt to cover all features exhaustively use-cases but shall not attempt to cover all features exhaustively
(please check the man pages for further inspiration). (please check the man pages for further inspiration).

View file

@ -89,7 +89,6 @@ real notebooks instead.
automata. automata.
- [[https://spot.lrde.epita.fr/ipynb/atva16-fig2a.html][=atva16-fig2a.ipynb=]] first example from our [[https://www.lrde.epita.fr/~adl/dl/adl/duret.16.atva2.pdf][ATVA'16 tool paper]]. - [[https://spot.lrde.epita.fr/ipynb/atva16-fig2a.html][=atva16-fig2a.ipynb=]] first example from our [[https://www.lrde.epita.fr/~adl/dl/adl/duret.16.atva2.pdf][ATVA'16 tool paper]].
- [[https://spot.lrde.epita.fr/ipynb/atva16-fig2b.html][=atva16-fig2b.ipynb=]] second example from our [[https://www.lrde.epita.fr/~adl/dl/adl/duret.16.atva2.pdf][ATVA'16 tool paper]]. - [[https://spot.lrde.epita.fr/ipynb/atva16-fig2b.html][=atva16-fig2b.ipynb=]] second example from our [[https://www.lrde.epita.fr/~adl/dl/adl/duret.16.atva2.pdf][ATVA'16 tool paper]].
- [[https://spot.lrde.epita.fr/ipynb/cav22-figs.html][=cav22-figs.ipynb=]] figures from our [[https://www.lrde.epita.fr/~adl/dl/adl/duret.22.cav.pdf][CAV'22 tool paper]].
- [[https://spot.lrde.epita.fr/ipynb/alternation.html][=alternation.ipynb=]] examples of alternating automata. - [[https://spot.lrde.epita.fr/ipynb/alternation.html][=alternation.ipynb=]] examples of alternating automata.
- [[https://spot.lrde.epita.fr/ipynb/stutter-inv.html][=stutter-inv.ipynb=]] working with stutter-invariant formulas properties. - [[https://spot.lrde.epita.fr/ipynb/stutter-inv.html][=stutter-inv.ipynb=]] working with stutter-invariant formulas properties.
- [[https://spot.lrde.epita.fr/ipynb/satmin.html][=satmin.ipynb=]] Python interface for [[file:satmin.org][SAT-based minimization of deterministic ω-automata]]. - [[https://spot.lrde.epita.fr/ipynb/satmin.html][=satmin.ipynb=]] Python interface for [[file:satmin.org][SAT-based minimization of deterministic ω-automata]].

View file

@ -81,7 +81,7 @@ simplifications called /trivial identities/. For instance
=formula::F(formula::X(formula::tt()))= will return the same formula =formula::F(formula::X(formula::tt()))= will return the same formula
as =formula::tt()=. These simplifications are those that involve the as =formula::tt()=. These simplifications are those that involve the
true and false constants, impotence (=F(F(e))=F(e)=), involutions true and false constants, impotence (=F(F(e))=F(e)=), involutions
(=Not(Not(e))=e=), associativity (=Not(Not(e)=e=), associativity
(=And({And({e1,e2},e3})=And({e1,e2,e3})=). See [[https://spot.lrde.epita.fr/tl.pdf][tl.pdf]] for a list of (=And({And({e1,e2},e3})=And({e1,e2,e3})=). See [[https://spot.lrde.epita.fr/tl.pdf][tl.pdf]] for a list of
these /trivial identities/. these /trivial identities/.
@ -113,7 +113,7 @@ detail of the top-level operator in the formula.
std::cout << f << '\n'; std::cout << f << '\n';
// kindstr() prints the name of the operator // kindstar() prints the name of the operator
// size() return the number of operands of the operators // size() return the number of operands of the operators
std::cout << f.kindstr() << ", " << f.size() << " children\n"; std::cout << f.kindstr() << ", " << f.size() << " children\n";
// operator[] accesses each operand // operator[] accesses each operand
@ -157,7 +157,7 @@ The Python equivalent is similar:
print(f) print(f)
# kindstr() prints the name of the operator # kindstar() prints the name of the operator
# size() return the number of operands of the operators # size() return the number of operands of the operators
print("{}, {} children".format(f.kindstr(), f.size())) print("{}, {} children".format(f.kindstr(), f.size()))
# [] accesses each operand # [] accesses each operand

View file

@ -139,7 +139,7 @@ automaton. Finally, the output as a never claim is done via the
int main() int main()
{ {
spot::parsed_formula pf = spot::parse_infix_psl("GFa -> GFb"); spot::parsed_formula pf = spot::parse_infix_psl("[]<>a || <>[]b");
if (pf.format_errors(std::cerr)) if (pf.format_errors(std::cerr))
return 1; return 1;
spot::translator trans; spot::translator trans;
@ -158,22 +158,22 @@ never {
T0_init: T0_init:
if if
:: (true) -> goto T0_init :: (true) -> goto T0_init
:: (b) -> goto accept_S1 :: (a) -> goto accept_S1
:: (!(a)) -> goto accept_S2 :: (b) -> goto accept_S2
fi; fi;
accept_S1: accept_S1:
if if
:: (b) -> goto accept_S1 :: (a) -> goto accept_S1
:: (!(b)) -> goto T0_S3 :: (!(a)) -> goto T0_S3
fi; fi;
accept_S2: accept_S2:
if if
:: (!(a)) -> goto accept_S2 :: (b) -> goto accept_S2
fi; fi;
T0_S3: T0_S3:
if if
:: (b) -> goto accept_S1 :: (a) -> goto accept_S1
:: (!(b)) -> goto T0_S3 :: (!(a)) -> goto T0_S3
fi; fi;
} }

View file

@ -144,11 +144,9 @@ states.
We now look at how to create such a game in Python. We now look at how to create such a game in Python.
Essentially, a game in Spot is just an automaton equiped with a [[file:concepts.org::#named-properties][named Essentially, a game in Spot is just an automaton equiped with a
property "state-player"]] that hold a Boolean vector indicating the special property to indicate the owner of each states. So it can be
owner of each state. The game can be created using the usual created using the usual interface:
automaton interface, and the owners are set by calling
=game.set_state_players()= with a vector of Boolean at the very end.
#+NAME: build_game #+NAME: build_game
#+BEGIN_SRC python :exports code #+BEGIN_SRC python :exports code
@ -175,7 +173,7 @@ automaton interface, and the owners are set by calling
todo = [] todo = []
# Create the state (i, j) for a player if it does not exist yet and # Create the state (i, j) for a player if it does not exist yet and
# return the state's number in the game. # returns the state's number in the game.
def get_game_state(player, i, j): def get_game_state(player, i, j):
orig_state = s_orig_states if player else d_orig_states orig_state = s_orig_states if player else d_orig_states
if (i, j) in orig_state: if (i, j) in orig_state:

View file

@ -1,3 +1,4 @@
@InProceedings{ babiak.12.tacas, @InProceedings{ babiak.12.tacas,
author = {Tom{\'a}{\v{s}} Babiak and Mojm{\'i}r author = {Tom{\'a}{\v{s}} Babiak and Mojm{\'i}r
K{\v{r}}et{\'i}nsk{\'y} and Vojt{\v{e}}ch {\v{R}}eh{\'a}k K{\v{r}}et{\'i}nsk{\'y} and Vojt{\v{e}}ch {\v{R}}eh{\'a}k
@ -172,22 +173,6 @@
doi = {10.4230/LIPIcs.ICALP.2021.123} doi = {10.4230/LIPIcs.ICALP.2021.123}
} }
@InProceedings{ casares.22.tacas,
author = {Antonio Casares and Alexandre Duret-Lutz and Klara J.
Meyer and Florian Renkin and Salomon Sickert},
title = {Practical Applications of the {A}lternating {C}ycle
{D}ecomposition},
booktitle = {Proceedings of the 28th International Conference on Tools
and Algorithms for the Construction and Analysis of
Systems},
year = {2022},
series = {Lecture Notes in Computer Science},
month = apr,
volume = {13244},
pages = {99--117},
doi = {10.1007/978-3-030-99527-0_6},
}
@InProceedings{ cerna.03.mfcs, @InProceedings{ cerna.03.mfcs,
author = {Ivana {\v{C}}ern{\'a} and Radek Pel{\'a}nek}, author = {Ivana {\v{C}}ern{\'a} and Radek Pel{\'a}nek},
title = {Relating Hierarchy of Temporal Properties to Model title = {Relating Hierarchy of Temporal Properties to Model
@ -230,11 +215,11 @@
} }
@InProceedings{ cimatti.06.fmcad, @InProceedings{ cimatti.06.fmcad,
author = {Cimatti, Alessandro and Roveri, Marco and Semprini, Simone author = {Cimatti, Alessandro and Roveri, Marco and Semprini, Simone and
and Tonetta, Stefano}, Tonetta, Stefano},
title = {From {PSL} to {NBA}: a Modular Symbolic Encoding}, title = {From {PSL} to {NBA}: a Modular Symbolic Encoding},
booktitle = {Proceedings of the 6th conference on Formal Methods in booktitle = {Proceedings of the 6th conference on Formal Methods in Computer
Computer Aided Design (FMCAD'06)}, Aided Design (FMCAD'06)},
pages = {125--133}, pages = {125--133},
year = {2006}, year = {2006},
publisher = {IEEE Computer Society}, publisher = {IEEE Computer Society},
@ -368,41 +353,6 @@
doi = {10.1504/IJCCBS.2014.059594} doi = {10.1504/IJCCBS.2014.059594}
} }
@InProceedings{ duret.16.atva,
author = {Alexandre Duret-Lutz and Fabrice Kordon and Denis
Poitrenaud and Etienne Renault},
title = {Heuristics for Checking Liveness Properties with Partial
Order Reductions},
booktitle = {Proceedings of the 14th International Symposium on
Automated Technology for Verification and Analysis
(ATVA'16)},
series = {Lecture Notes in Computer Science},
publisher = {Springer},
volume = {9938},
pages = {340--356},
year = {2016},
month = oct,
doi = {10.1007/978-3-319-46520-3_22}
}
@InProceedings{ duret.22.cav,
author = {Alexandre~Duret-Lutz and Etienne Renault and Maximilien
Colange and Florian Renkin and Alexandre Gbaguidi~Aisse and
Philipp Schlehuber-Caissier and Thomas Medioni and Antoine
Martin and J{\'e}r{\^o}me Dubois and Cl{\'e}ment Gillard
and Henrich Lauko},
title = {From {S}pot 2.0 to {S}pot 2.10: What's New?},
booktitle = {Proceedings of the 34th International Conference on
Computer Aided Verification (CAV'22)},
year = 2022,
volume = {13372},
series = {Lecture Notes in Computer Science},
pages = {174--187},
month = aug,
publisher = {Springer},
doi = {10.1007/978-3-031-13188-2_9}
}
@InProceedings{ dwyer.98.fmsp, @InProceedings{ dwyer.98.fmsp,
author = {Matthew B. Dwyer and George S. Avrunin and James C. author = {Matthew B. Dwyer and George S. Avrunin and James C.
Corbett}, Corbett},
@ -908,22 +858,6 @@
doi = {10.1007/978-3-030-59152-6_7} doi = {10.1007/978-3-030-59152-6_7}
} }
@InProceedings{ renkin.22.forte,
author = {Florian Renkin and Philipp Schlehuber-Caissier and
Alexandre Duret-Lutz and Adrien Pommellet},
title = {Effective Reductions of {M}ealy Machines},
year = 2022,
booktitle = {Proceedings of the 42nd International Conference on Formal
Techniques for Distributed Objects, Components, and Systems
(FORTE'22)},
series = {Lecture Notes in Computer Science},
volume = 13273,
pages = {170--187},
month = jun,
publisher = {Springer},
doi = {10.1007/978-3-031-08679-3_8}
}
@InProceedings{ rozier.07.spin, @InProceedings{ rozier.07.spin,
author = {Kristin Y. Rozier and Moshe Y. Vardi}, author = {Kristin Y. Rozier and Moshe Y. Vardi},
title = {LTL Satisfiability Checking}, title = {LTL Satisfiability Checking},
@ -1086,19 +1020,7 @@
publisher = {Elsevier}, publisher = {Elsevier},
editor = {Rance Cleaveland and Hubert Garavel}, editor = {Rance Cleaveland and Hubert Garavel},
year = {2002}, year = {2002},
month = jul, pdf = {adl/duret.16.atva.pdf}, month = jul,
abstract = {Checking liveness properties with partial-order reductions
requires a cycle proviso to ensure that an action cannot be
postponed forever. The proviso forces each cycle to contain
at least one fully expanded state. We present new
heuristics to select which state to expand, hoping to
reduce the size of the resulting graph. The choice of the
state to expand is done when encountering a
\emph{dangerous} edge. Almost all existing provisos expand
the source of this edge, while this paper also explores the
expansion of the destination and the use of SCC-based
information.},
address = {M{\'a}laga, Spain}, address = {M{\'a}laga, Spain},
doi = {10.1016/S1571-0661(04)80409-2} doi = {10.1016/S1571-0661(04)80409-2}
} }

View file

@ -395,7 +395,7 @@ following Boolean operators:
(allowing better compatibility with Wring and VIS) may only used in (allowing better compatibility with Wring and VIS) may only used in
temporal formulas. Boolean expressions that occur inside SERE (see temporal formulas. Boolean expressions that occur inside SERE (see
Section~\ref{sec:sere}) may not use this form because the $\STARALT$ Section~\ref{sec:sere}) may not use this form because the $\STARALT$
symbol is used as the Kleene star.} symbol is used as the Kleen star.}
Additionally, an atomic proposition $a$ can be negated using the Additionally, an atomic proposition $a$ can be negated using the
syntax \samp{$a$=0}, which is equivalent to \samp{$\NOT a$}. Also syntax \samp{$a$=0}, which is equivalent to \samp{$\NOT a$}. Also
@ -600,7 +600,7 @@ the source. It can mean either ``\textit{Sequential Extended Regular
``\textit{Semi-Extended Regular Expression}''~\citep{eisner.08.hvc}. ``\textit{Semi-Extended Regular Expression}''~\citep{eisner.08.hvc}.
In any case, the intent is the same: regular expressions with In any case, the intent is the same: regular expressions with
traditional operations (union `$\OR$', concatenation `$\CONCAT$', traditional operations (union `$\OR$', concatenation `$\CONCAT$',
Kleene star `$\STAR{}$') are extended with operators such as Kleen star `$\STAR{}$') are extended with operators such as
intersection `$\ANDALT$', and fusion `$\FUSION$'. intersection `$\ANDALT$', and fusion `$\FUSION$'.
Any Boolean formula (section~\ref{def:boolform}) is a SERE. SERE can Any Boolean formula (section~\ref{def:boolform}) is a SERE. SERE can
@ -638,7 +638,7 @@ denote arbitrary SERE.
\end{tabular} \end{tabular}
\end{center} \end{center}
\footnotetext{\emph{Non-Length-Matching} intersection.} \footnotetext{\emph{Non-Length-Matching} interesction.}
The character \samp{\$} or the string \samp{inf} can also be used as The character \samp{\$} or the string \samp{inf} can also be used as
value for $\mvar{j}$ in the above operators to denote an unbounded value for $\mvar{j}$ in the above operators to denote an unbounded
@ -668,17 +668,20 @@ $a$ is an atomic proposition.
\sigma\VDash f\FUSION g&\iff \exists k\in\N,\,(\sigma^{0..k} \VDash f)\land(\sigma^{k..} \VDash g)\\ \sigma\VDash f\FUSION g&\iff \exists k\in\N,\,(\sigma^{0..k} \VDash f)\land(\sigma^{k..} \VDash g)\\
\sigma\VDash f\STAR{\mvar{i}..\mvar{j}}& \iff \sigma\VDash f\STAR{\mvar{i}..\mvar{j}}& \iff
\begin{cases} \begin{cases}
\text{either} & \mvar{i}=0 \land\mvar{j}=0\land \sigma=\varepsilon \\ \text{either} & \mvar{i}=0 \land \sigma=\varepsilon \\
\text{or} & \mvar{i}=0 \land \mvar{j}>0 \land \bigl((\sigma = \varepsilon) \lor (\sigma \text{or} & \mvar{i}=0 \land \mvar{j}>0 \land (\exists k\in\N,\,
\VDash f\STAR{\mvar{1}..\mvar{j}})\bigr)\\ (\sigma^{0..k-1}\VDash f) \land (\sigma^{k..}
\VDash f\STAR{\mvar{0}..\mvar{j-1}}))\\
\text{or} & \mvar{i}>0 \land \mvar{j}>0 \land (\exists k\in\N,\, \text{or} & \mvar{i}>0 \land \mvar{j}>0 \land (\exists k\in\N,\,
(\sigma^{0..k-1}\VDash f) \land (\sigma^{k..} (\sigma^{0..k-1}\VDash f) \land (\sigma^{k..}
\VDash f\STAR{\mvar{i-1}..\mvar{j-1}}))\\ \VDash f\STAR{\mvar{i-1}..\mvar{j-1}}))\\
\end{cases}\\ \end{cases}\\
\sigma\VDash f\STAR{\mvar{i}..} & \iff \sigma\VDash f\STAR{\mvar{i}..} & \iff
\begin{cases} \begin{cases}
\text{either} & \mvar{i}=0 \land \bigl((\sigma=\varepsilon)\lor(\sigma \text{either} & \mvar{i}=0 \land \sigma=\varepsilon \\
\VDash f\STAR{\mvar{1}..})\bigr)\\ \text{or} & \mvar{i}=0 \land (\exists k\in\N,\,
(\sigma^{0..k-1}\VDash f) \land (\sigma^{k..}
\VDash f\STAR{\mvar{0}..}))\\
\text{or} & \mvar{i}>0 \land (\exists k\in\N,\, \text{or} & \mvar{i}>0 \land (\exists k\in\N,\,
(\sigma^{0..k-1}\VDash f) \land (\sigma^{k..} (\sigma^{0..k-1}\VDash f) \land (\sigma^{k..}
\VDash f\STAR{\mvar{i-1}..}))\\ \VDash f\STAR{\mvar{i-1}..}))\\
@ -686,22 +689,25 @@ $a$ is an atomic proposition.
\sigma\VDash f\FSTAR{\mvar{i}..\mvar{j}}& \iff \sigma\VDash f\FSTAR{\mvar{i}..\mvar{j}}& \iff
\begin{cases} \begin{cases}
\text{either} & \mvar{i}=0 \land \mvar{j}=0 \land \sigma\VDash\1 \\ \text{either} & \mvar{i}=0 \land \mvar{j}=0 \land \sigma\VDash\1 \\
\text{or} & \mvar{i}=0 \land \mvar{j}>0 \land \bigl((\sigma\VDash\1)\lor(\sigma \text{or} & \mvar{i}=0 \land \mvar{j}>0 \land (\exists k\in\N,\,
\VDash f\FSTAR{\mvar{1}..\mvar{j}})\bigr)\\ (\sigma^{0..k}\VDash f) \land (\sigma^{k..}
\VDash f\FSTAR{\mvar{0}..\mvar{j-1}}))\\
\text{or} & \mvar{i}>0 \land \mvar{j}>0 \land (\exists k\in\N,\, \text{or} & \mvar{i}>0 \land \mvar{j}>0 \land (\exists k\in\N,\,
(\sigma^{0..k}\VDash f) \land (\sigma^{k..} (\sigma^{0..k}\VDash f) \land (\sigma^{k..}
\VDash f\FSTAR{\mvar{i-1}..\mvar{j-1}}))\\ \VDash f\FSTAR{\mvar{i-1}..\mvar{j-1}}))\\
\end{cases}\\ \end{cases}\\
\sigma\VDash f\FSTAR{\mvar{i}..} & \iff \sigma\VDash f\FSTAR{\mvar{i}..} & \iff
\begin{cases} \begin{cases}
\text{either} & \mvar{i}=0 \land \bigl((\sigma\VDash\1) \text{either} & \mvar{i}=0 \land \sigma\VDash\1 \\
\lor(\sigma \VDash f\FSTAR{\mvar{1}..})\bigr)\\ \text{or} & \mvar{i}=0 \land (\exists k\in\N,\,
(\sigma^{0..k}\VDash f) \land (\sigma^{k..}
\VDash f\FSTAR{\mvar{0}..}))\\
\text{or} & \mvar{i}>0 \land (\exists k\in\N,\, \text{or} & \mvar{i}>0 \land (\exists k\in\N,\,
(\sigma^{0..k}\VDash f) \land (\sigma^{k..} (\sigma^{0..k}\VDash f) \land (\sigma^{k..}
\VDash f\FSTAR{\mvar{i-1}..}))\\ \VDash f\FSTAR{\mvar{i-1}..}))\\
\end{cases}\\ \end{cases}\\
\sigma\VDash \FIRSTMATCH\code(f\code) & \iff \sigma\VDash \FIRSTMATCH\code(f\code) & \iff
(\sigma\VDash f)\land (\forall k<|\sigma|,\,\sigma^{0..k-1}\nVDash f) (\sigma\VDash f)\land (\forall k<|\sigma|,\,\sigma^{0..k}\nVDash f)
\end{align*}} \end{align*}}
Notes: Notes:
@ -853,18 +859,10 @@ The following rules are all valid with the two arguments swapped.
\1\OR b &\equiv \1 & \1\OR b &\equiv \1 &
\1 \FUSION f & \equiv f\mathrlap{\text{~if~}\varepsilon\nVDash f}\\ \1 \FUSION f & \equiv f\mathrlap{\text{~if~}\varepsilon\nVDash f}\\
&& &&
\STAR{} \ANDALT f &\equiv f & \STAR{} \AND f &\equiv f &
\STAR{} \OR f &\equiv \mathrlap{\STAR{}} & \STAR{} \OR f &\equiv \1\mathrlap{\STAR{}} &
&& &&
\STAR{} \CONCAT f &\equiv \STAR{}\text{~if~}\varepsilon\VDash f& \\ \STAR{} \CONCAT f &\equiv \STAR{}\mathrlap{\text{~if~}\varepsilon\VDash f}& \\
&&
\PLUS{} \ANDALT f &\equiv f \text{~if~}\varepsilon\nVDash f&
\PLUS{} \OR f &\equiv \begin{cases}
\mathrlap{\STAR{}\text{~if~} \varepsilon\VDash f} \\
\mathrlap{\PLUS{}\text{~if~} \varepsilon\nVDash f} \\
\end{cases} &
&&
&& \\
\eword\AND f &\equiv f & \eword\AND f &\equiv f &
\eword\ANDALT f &\equiv \eword\ANDALT f &\equiv
\begin{cases} \begin{cases}
@ -888,9 +886,7 @@ The following rules are all valid with the two arguments swapped.
f\STAR{\mvar{i}..\mvar{j}}\CONCAT f&\equiv f\STAR{\mvar{i+1}..\mvar{j+1}} & f\STAR{\mvar{i}..\mvar{j}}\CONCAT f&\equiv f\STAR{\mvar{i+1}..\mvar{j+1}} &
f\STAR{\mvar{i}..\mvar{j}}\CONCAT f\STAR{\mvar{k}..\mvar{l}}&\equiv f\STAR{\mvar{i+k}..\mvar{j+l}}\\ f\STAR{\mvar{i}..\mvar{j}}\CONCAT f\STAR{\mvar{k}..\mvar{l}}&\equiv f\STAR{\mvar{i+k}..\mvar{j+l}}\\
f\FSTAR{\mvar{i}..\mvar{j}}\FUSION f&\equiv f\FSTAR{\mvar{i+1}..\mvar{j+1}} & f\FSTAR{\mvar{i}..\mvar{j}}\FUSION f&\equiv f\FSTAR{\mvar{i+1}..\mvar{j+1}} &
f\FSTAR{\mvar{i}..\mvar{j}}\FUSION f\FSTAR{\mvar{k}..\mvar{l}}&\equiv f\FSTAR{\mvar{i+k}..\mvar{j+l}}\\ f\FSTAR{\mvar{i}..\mvar{j}}\FUSION f\FSTAR{\mvar{k}..\mvar{l}}&\equiv f\FSTAR{\mvar{i+k}..\mvar{j+l}}
b\STAR{\mvar{i}..\mvar{j}}\FUSION b &\equiv b\STAR{\mvar{\max(i,1)}..\mvar{j}} &
b\STAR{\mvar{i}..\mvar{j}}\FUSION b\STAR{\mvar{k}..\mvar{l}} &\equiv b\mathrlap{\STAR{\mvar{\max(i,1)+\max(k,1)-1}..\mvar{j+l-1}}}
\end{align*} \end{align*}
\section{SERE-LTL Binding Operators} \section{SERE-LTL Binding Operators}
@ -1073,7 +1069,7 @@ psl2ba, Modella, and NuSMV all have $\U$ and $\R$ as left-associative,
while Goal (hence Büchi store), LTL2AUT, and LTL2Büchi (from while Goal (hence Büchi store), LTL2AUT, and LTL2Büchi (from
JavaPathFinder) have $\U$ and $\R$ as right-associative. Vis and LBTT JavaPathFinder) have $\U$ and $\R$ as right-associative. Vis and LBTT
have these two operators as non-associative (parentheses required). have these two operators as non-associative (parentheses required).
Similarly the tools do not agree on the associativity of $\IMPLIES$ Similarly the tools do not aggree on the associativity of $\IMPLIES$
and $\EQUIV$: some tools handle both operators as left-associative, or and $\EQUIV$: some tools handle both operators as left-associative, or
both right-associative, other have only $\IMPLIES$ as right-associative. both right-associative, other have only $\IMPLIES$ as right-associative.
@ -1433,7 +1429,7 @@ $\NOT$ operator.
\end{align*} \end{align*}
Note that the above rules include the ``unabbreviation'' of operators Note that the above rules include the ``unabbreviation'' of operators
``$\EQUIV$'', ``$\IMPLIES$'', and ``$\XOR$'', corresponding to the ``$\EQUIV$'', ``$\IMPLIES$'', and ``$\XOR$'', correspondings to the
rules \texttt{"ei\^"} of function `\verb=unabbreviate()= as described rules \texttt{"ei\^"} of function `\verb=unabbreviate()= as described
in Section~\ref{sec:unabbrev}. Therefore it is never necessary to in Section~\ref{sec:unabbrev}. Therefore it is never necessary to
apply these abbreviations before or after apply these abbreviations before or after
@ -1930,12 +1926,6 @@ Many of the above rules were collected from the
literature~\cite{somenzi.00.cav,tauriainen.03.tr,babiak.12.tacas} and literature~\cite{somenzi.00.cav,tauriainen.03.tr,babiak.12.tacas} and
sometimes generalized to support operators such as $\M$ and $\W$. sometimes generalized to support operators such as $\M$ and $\W$.
The first six rules, about n-ary operators $\AND$ and $\OR$, are
implemented for $n$ operands by testing each operand against all
other. To prevent the complexity to escalate, this is only performed
with up to 16 operands. That value can be changed in
``\verb|tl_simplifier_options::containment_max_ops|''.
The following rules mix implication-based checks with formulas that The following rules mix implication-based checks with formulas that
are pure eventualities ($e$) or that are purely universal ($u$). are pure eventualities ($e$) or that are purely universal ($u$).
@ -2107,14 +2097,3 @@ $f_1\AND f_2$ & \bor{f_1}{g}{f_2}{g} & & &
%%% TeX-master: t %%% TeX-master: t
%%% coding: utf-8 %%% coding: utf-8
%%% End: %%% End:
% LocalWords: tabu Alexandre Duret Lutz toc subsequence Kripke unary
% LocalWords: LTL GFa INISHED ZX FX cccccrl UTF syntaxes disjunction
% LocalWords: VIS Kleene overline overbar ary cccrl EF sep FB LTLf
% LocalWords: rewritings TSLF NLM iter un SVA PSL SEREs DFA ccccc ba
% LocalWords: SystemVerilog clc ltl psl Modella NuSMV Büchi AUT Vis
% LocalWords: JavaPathFinder LBTT AST subtrees boolean nenoform lbt
% LocalWords: eword nn LBT's automata subformulas ottom unabbreviate
% LocalWords: Unabbreviations ei GRW RW WR unabbreviator simplifier
% LocalWords: tl unabbreviation indeterminism dnf cnf SNF rl iff BDD
% LocalWords: subformula

View file

@ -1,6 +1,6 @@
## -*- coding: utf-8 -*- ## -*- coding: utf-8 -*-
## Copyright (C) 2015-2018, 2022 Laboratoire de Recherche et ## Copyright (C) 2015, 2016, 2017, 2018 Laboratoire de Recherche et Développement
## 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.
## ##
@ -19,7 +19,7 @@
EXTRA_DIST = hoa-mode.el EXTRA_DIST = hoa-mode.el
GIT = https://gitlab.lre.epita.fr/spot/emacs-modes/raw/master/ GIT = https://gitlab.lrde.epita.fr/spot/emacs-modes/raw/master/
.PHONY: update-el .PHONY: update-el
update-el: update-el:

View file

@ -1,10 +1,10 @@
;;; hoa-mode.el --- Major mode for the HOA format -*- lexical-binding: t -*- ;;; hoa-mode.el --- Major mode for the HOA format -*- lexical-binding: t -*-
;; Copyright (C) 2015, 2017, 2019, 2022 Alexandre Duret-Lutz ;; Copyright (C) 2015, 2017, 2019 Alexandre Duret-Lutz
;; Author: Alexandre Duret-Lutz <adl@lrde.epita.fr> ;; Author: Alexandre Duret-Lutz <adl@lrde.epita.fr>
;; Maintainer: Alexandre Duret-Lutz <adl@lrde.epita.fr> ;; Maintainer: Alexandre Duret-Lutz <adl@lrde.epita.fr>
;; URL: https://gitlab.lre.epita.fr/spot/emacs-modes ;; URL: https://gitlab.lrde.epita.fr/spot/emacs-modes
;; Keywords: major-mode, automata, convenience ;; Keywords: major-mode, automata, convenience
;; Created: 2015-11-13 ;; Created: 2015-11-13

43
flake.lock generated
View file

@ -1,43 +0,0 @@
{
"nodes": {
"flake-utils": {
"locked": {
"lastModified": 1642700792,
"narHash": "sha256-XqHrk7hFb+zBvRg6Ghl+AZDq03ov6OshJLiSWOoX5es=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "846b2ae0fc4cc943637d3d1def4454213e203cba",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1673800717,
"narHash": "sha256-SFHraUqLSu5cC6IxTprex/nTsI81ZQAtDvlBvGDWfnA=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "2f9fd351ec37f5d479556cd48be4ca340da59b8f",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-22.11",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs"
}
}
},
"root": "root",
"version": 7
}

211
flake.nix
View file

@ -1,211 +0,0 @@
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-22.11";
flake-utils.url = "github:numtide/flake-utils";
};
outputs = { self, nixpkgs, flake-utils, ... }:
flake-utils.lib.eachSystem
[
"x86_64-linux"
]
(system:
let
pkgs = import nixpkgs { inherit system; };
lib = pkgs.lib;
mkSpotApps = appNames:
pkgs.lib.genAttrs appNames
(name: flake-utils.lib.mkApp {
drv = self.packages.${system}.spot;
name = name;
});
spotPackage =
let
inherit (builtins)
filter
head
isString
match
readFile
split
;
# NOTE: Maintaining the version separately would be a pain, and we
# can't have a flake.nix.in with a @VERSION@ because it would make
# the flake unusable without running autoconf first, defeating some
# of its purpose.
#
# So let's get it the hard way instead :)
extractVersionRegex = ''^AC_INIT\(\[spot], \[([^]]+)], \[spot@lrde\.epita\.fr]\)$'';
getLines = (fileContent:
filter isString (split "\n" fileContent)
);
findVersionLine = (lines:
lib.lists.findFirst
(l: lib.strings.hasPrefix "AC_INIT(" l)
null
lines
);
getVersion = (file:
let
lines = getLines (readFile file);
versionLine = findVersionLine lines;
version = head (match extractVersionRegex versionLine);
in
version
);
in
{
lib,
pkgs,
stdenv,
# FIXME: do we want this flag?
buildOrgDoc ? false,
# Whether to enable Spot's Python 3 bindings
enablePython ? false
}:
stdenv.mkDerivation {
pname = "spot";
version = getVersion ./configure.ac;
src = self;
enableParallelBuilding = true;
# NOTE: Nix enables a lot of hardening flags by default, some of
# these probably harm performance so I've disabled everything
# (haven't benchmarked with vs without these, though).
hardeningDisable = [ "all" ];
# NOTE: mktexpk fails without a HOME set
preBuild = ''
export HOME=$TMPDIR
patchShebangs tools
'' + (if buildOrgDoc then ''
ln -s ${pkgs.plantuml}/lib/plantuml.jar doc/org/plantuml.jar
'' else ''
touch doc/org-stamp
'');
configureFlags = [
"--disable-devel"
"--enable-optimizations"
] ++ lib.optional (!enablePython) [
"--disable-python"
];
nativeBuildInputs = with pkgs; [
autoreconfHook
autoconf
automake
bison
flex
libtool
perl
] ++ lib.optional buildOrgDoc [
graphviz
groff
plantuml
pdf2svg
R
] ++ lib.optional enablePython [
python3
swig4
];
buildInputs = with pkgs; [
# should provide the minimum amount of packages necessary for
# building tl.pdf
(texlive.combine {
inherit (texlive)
scheme-basic
latexmk
booktabs
cm-super
doi
doublestroke
etoolbox
koma-script
mathabx-type1
mathpazo
metafont
microtype
nag
pgf
standalone
stmaryrd
tabulary
todonotes
wasy-type1
wasysym
;
})
];
};
in
{
defaultPackage = self.packages.${system}.spot;
packages = {
# binaries + library only
spot = pkgs.callPackage spotPackage {};
# NOTE: clang build is broken on Nix when linking to stdlib++, using
# libcxx instead. See:
# https://github.com/NixOS/nixpkgs/issues/91285
spotClang = pkgs.callPackage spotPackage {
stdenv = pkgs.llvmPackages.libcxxStdenv;
};
spotWithOrgDoc = pkgs.callPackage spotPackage {
buildOrgDoc = true;
};
spotWithPython = pkgs.python3Packages.toPythonModule (
pkgs.callPackage spotPackage {
enablePython = true;
}
);
spotFull = pkgs.python3Packages.toPythonModule (
pkgs.callPackage spotPackage {
buildOrgDoc = true; enablePython = true;
}
);
};
apps = mkSpotApps [
"autcross"
"autfilt"
"dstar2tgba"
"genaut"
"genltl"
"ltl2tgba"
"ltl2tgta"
"ltlcross"
"ltldo"
"ltlfilt"
"ltlgrind"
"ltlsynt"
"randaut"
"randltl"
];
devShell = pkgs.mkShell {
name = "spot-dev";
inputsFrom = [ self.packages.${system}.spotFull ];
buildInputs = [
pkgs.gdb
(pkgs.python3.withPackages (p: [
p.jupyter
p.ipython # otherwise ipython module isn't found when running ipynb tests
]))
];
};
});
}

View file

@ -1,46 +0,0 @@
# environ.m4 serial 8
dnl Copyright (C) 2001-2004, 2006-2021 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
dnl with or without modifications, as long as this notice is preserved.
AC_DEFUN_ONCE([gl_ENVIRON],
[
AC_REQUIRE([gl_UNISTD_H_DEFAULTS])
dnl Persuade glibc <unistd.h> to declare environ.
AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
AC_CHECK_HEADERS_ONCE([unistd.h])
gt_CHECK_VAR_DECL(
[#if HAVE_UNISTD_H
#include <unistd.h>
#endif
/* mingw, BeOS, Haiku declare environ in <stdlib.h>, not in <unistd.h>. */
#include <stdlib.h>
],
[environ])
if test $gt_cv_var_environ_declaration != yes; then
HAVE_DECL_ENVIRON=0
fi
])
# Check if a variable is properly declared.
# gt_CHECK_VAR_DECL(includes,variable)
AC_DEFUN([gt_CHECK_VAR_DECL],
[
define([gt_cv_var], [gt_cv_var_]$2[_declaration])
AC_CACHE_CHECK([if $2 is properly declared], [gt_cv_var],
[AC_COMPILE_IFELSE(
[AC_LANG_PROGRAM(
[[$1
typedef struct { int foo; } foo_t;
extern foo_t $2;]],
[[$2.foo = 1;]])],
[gt_cv_var=no],
[gt_cv_var=yes])])
if test $gt_cv_var = yes; then
AC_DEFINE([HAVE_]m4_translit($2, [a-z], [A-Z])[_DECL], 1,
[Define if you have the declaration of $2.])
fi
undefine([gt_cv_var])
])

View file

@ -21,14 +21,6 @@ AC_DEFUN([CF_GXX_WARNINGS],
cat > conftest.$ac_ext <<EOF cat > conftest.$ac_ext <<EOF
#line __oline__ "configure" #line __oline__ "configure"
#include <string> #include <string>
#include <regex>
// From GCC bug 106159
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106159
struct left { virtual ~left() {} };
struct right { virtual ~right() {} };
struct both: public left, public right {};
int main(int argc, char *argv[[]]) int main(int argc, char *argv[[]])
{ {
// This string comparison is here to detect superfluous // This string comparison is here to detect superfluous
@ -41,26 +33,19 @@ int main(int argc, char *argv[[]])
std::string a{"foo"}, b{"bar"}; std::string a{"foo"}, b{"bar"};
if (b < a) if (b < a)
return 1; return 1;
// GCC 12 has spurious warnings about ininialized values in regex.
// See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105562
// We need -Wno-maybe-uninitialized in this case.
std::regex r{"a"};
(void)r;
return argv[[argc-1]] == nullptr; return argv[[argc-1]] == nullptr;
} }
EOF EOF
cf_save_CXXFLAGS="$CXXFLAGS" cf_save_CXXFLAGS="$CXXFLAGS"
ac_cv_prog_gxx_warn_flags="-W -Werror" ac_cv_prog_gxx_warn_flags="-W -Wall"
dnl The following list has options of the form OPT:BAD:GOOD
dnl if -OPT fails we try -OPT -BAD. If -OPT succeeds we add -GOOD.
for cf_opt in \ for cf_opt in \
Wall:Wno-maybe-uninitialized:\ Werror \
Wint-to-void-pointer-cast \ Wint-to-void-pointer-cast \
Wzero-as-null-pointer-constant \ Wzero-as-null-pointer-constant \
Wcast-align \ Wcast-align \
Wpointer-arith \ Wpointer-arith \
Wwrite-strings \ Wwrite-strings \
Wcast-qual::DXTSTRINGDEFINES \ Wcast-qual \
Wdocumentation \ Wdocumentation \
Wmissing-declarations \ Wmissing-declarations \
Wnoexcept \ Wnoexcept \
@ -73,25 +58,10 @@ dnl if -OPT fails we try -OPT -BAD. If -OPT succeeds we add -GOOD.
Wsuggest-override \ Wsuggest-override \
Wpedantic Wpedantic
do do
fopt=${cf_opt%%:*} CXXFLAGS="$cf_save_CXXFLAGS $ac_cv_prog_gxx_warn_flags -$cf_opt"
CXXFLAGS="$cf_save_CXXFLAGS $ac_cv_prog_gxx_warn_flags -$fopt"
if AC_TRY_EVAL(ac_compile); then if AC_TRY_EVAL(ac_compile); then
ac_cv_prog_gxx_warn_flags="$ac_cv_prog_gxx_warn_flags -$fopt" ac_cv_prog_gxx_warn_flags="$ac_cv_prog_gxx_warn_flags -$cf_opt"
case $cf_opt in test "$cf_opt" = Wcast-qual && ac_cv_prog_gxx_warn_flags="$ac_cv_prog_gxx_warn_flags -DXTSTRINGDEFINES"
*:*:);;
*:*:*)ac_cv_prog_gxx_warn_flags="$ac_cv_prog_gxx_warn_flags -${cf_opt##*:}";;
esac
else
case $cf_opt in
*::*);;
*:*:*)
sopt=${cf_opt%:*}
sopt=${sopt#*:}
CXXFLAGS="$cf_save_CXXFLAGS $ac_cv_prog_gxx_warn_flags -$fopt -$sopt"
if AC_TRY_EVAL(ac_compile); then
ac_cv_prog_gxx_warn_flags="$ac_cv_prog_gxx_warn_flags -$fopt -$sopt"
fi;;
esac
fi fi
done done
rm -f conftest* rm -f conftest*

View file

@ -1,5 +1,5 @@
# getopt.m4 serial 47 # getopt.m4 serial 47
dnl Copyright (C) 2002-2006, 2008-2020, 2022 Free Software Foundation, Inc. dnl Copyright (C) 2002-2006, 2008-2020 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it, dnl gives unlimited permission to copy and/or distribute it,
dnl with or without modifications, as long as this notice is preserved. dnl with or without modifications, as long as this notice is preserved.
@ -363,9 +363,13 @@ dnl is ambiguous with environment values that contain newlines.
AC_DEFUN([gl_GETOPT_SUBSTITUTE_HEADER], AC_DEFUN([gl_GETOPT_SUBSTITUTE_HEADER],
[ [
# pretend HAVE_SYS_CDEFS_H is always 0 including <sys/defs.h> isn't AC_CHECK_HEADERS_ONCE([sys/cdefs.h])
# really necessary and causes warning on Alpine Linux. if test $ac_cv_header_sys_cdefs_h = yes; then
AC_SUBST([HAVE_SYS_CDEFS_H], [0]) HAVE_SYS_CDEFS_H=1
else
HAVE_SYS_CDEFS_H=0
fi
AC_SUBST([HAVE_SYS_CDEFS_H])
AC_DEFINE([__GETOPT_PREFIX], [[rpl_]], AC_DEFINE([__GETOPT_PREFIX], [[rpl_]],
[Define to rpl_ if the getopt replacement functions and variables [Define to rpl_ if the getopt replacement functions and variables

View file

@ -1,4 +1,4 @@
# Copyright (C) 2002-2020, 2022 Free Software Foundation, Inc. # Copyright (C) 2002-2020 Free Software Foundation, Inc.
# #
# This file is free software; you can redistribute it and/or modify # This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by
@ -57,7 +57,6 @@ gl_MODULES([
argmatch argmatch
argp argp
closeout closeout
environ
error error
isatty isatty
mkstemp mkstemp

View file

@ -1,5 +1,5 @@
# DO NOT EDIT! GENERATED AUTOMATICALLY! # DO NOT EDIT! GENERATED AUTOMATICALLY!
# Copyright (C) 2002-2020, 2022 Free Software Foundation, Inc. # Copyright (C) 2002-2020 Free Software Foundation, Inc.
# #
# This file is free software; you can redistribute it and/or modify # This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by
@ -246,8 +246,6 @@ AC_SUBST([LTALLOCA])
AC_LIBOBJ([lstat]) AC_LIBOBJ([lstat])
gl_PREREQ_LSTAT gl_PREREQ_LSTAT
fi fi
gl_ENVIRON
gl_UNISTD_MODULE_INDICATOR([environ])
gl_SYS_STAT_MODULE_INDICATOR([lstat]) gl_SYS_STAT_MODULE_INDICATOR([lstat])
gl_FUNC_MALLOC_GNU gl_FUNC_MALLOC_GNU
if test $REPLACE_MALLOC = 1; then if test $REPLACE_MALLOC = 1; then

74
m4/ltargz.m4 Normal file
View file

@ -0,0 +1,74 @@
# Portability macros for glibc argz. -*- Autoconf -*-
#
# Copyright (C) 2004-2007, 2011-2015 Free Software Foundation, Inc.
# Written by Gary V. Vaughan <gary@gnu.org>
#
# This file is free software; the Free Software Foundation gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
# serial 1 ltargz.m4
AC_DEFUN([LT_FUNC_ARGZ], [
AC_CHECK_HEADERS([argz.h], [], [], [AC_INCLUDES_DEFAULT])
AC_CHECK_TYPES([error_t],
[],
[AC_DEFINE([error_t], [int],
[Define to a type to use for 'error_t' if it is not otherwise available.])
AC_DEFINE([__error_t_defined], [1], [Define so that glibc/gnulib argp.h
does not typedef error_t.])],
[#if defined(HAVE_ARGZ_H)
# include <argz.h>
#endif])
LT_ARGZ_H=
AC_CHECK_FUNCS([argz_add argz_append argz_count argz_create_sep argz_insert \
argz_next argz_stringify], [], [LT_ARGZ_H=lt__argz.h; AC_LIBOBJ([lt__argz])])
dnl if have system argz functions, allow forced use of
dnl libltdl-supplied implementation (and default to do so
dnl on "known bad" systems). Could use a runtime check, but
dnl (a) detecting malloc issues is notoriously unreliable
dnl (b) only known system that declares argz functions,
dnl provides them, yet they are broken, is cygwin
dnl releases prior to 16-Mar-2007 (1.5.24 and earlier)
dnl So, it's more straightforward simply to special case
dnl this for known bad systems.
AS_IF([test -z "$LT_ARGZ_H"],
[AC_CACHE_CHECK(
[if argz actually works],
[lt_cv_sys_argz_works],
[[case $host_os in #(
*cygwin*)
lt_cv_sys_argz_works=no
if test no != "$cross_compiling"; then
lt_cv_sys_argz_works="guessing no"
else
lt_sed_extract_leading_digits='s/^\([0-9\.]*\).*/\1/'
save_IFS=$IFS
IFS=-.
set x `uname -r | sed -e "$lt_sed_extract_leading_digits"`
IFS=$save_IFS
lt_os_major=${2-0}
lt_os_minor=${3-0}
lt_os_micro=${4-0}
if test 1 -lt "$lt_os_major" \
|| { test 1 -eq "$lt_os_major" \
&& { test 5 -lt "$lt_os_minor" \
|| { test 5 -eq "$lt_os_minor" \
&& test 24 -lt "$lt_os_micro"; }; }; }; then
lt_cv_sys_argz_works=yes
fi
fi
;; #(
*) lt_cv_sys_argz_works=yes ;;
esac]])
AS_IF([test yes = "$lt_cv_sys_argz_works"],
[AC_DEFINE([HAVE_WORKING_ARGZ], 1,
[This value is set to 1 to indicate that the system argz facility works])],
[LT_ARGZ_H=lt__argz.h
AC_LIBOBJ([lt__argz])])])
AC_SUBST([LT_ARGZ_H])
])

View file

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Copyright (C) 2014-2023 Laboratoire de Recherche et Développement de # Copyright (C) 2014-2021 Laboratoire de
# l'Epita (LRDE). # Recherche et Développement de l'Epita (LRDE).
# #
# This file is part of Spot, a model checking library. # This file is part of Spot, a model checking library.
# #
@ -104,22 +104,19 @@ def setup(**kwargs):
os.environ['SPOT_DOTDEFAULT'] = d os.environ['SPOT_DOTDEFAULT'] = d
# Swig versions prior to 4.1.0 export formula.X as formula_X as well, # In version 3.0.2, Swig puts strongly typed enum in the main
# for all operators. Swig 4.1.0 stops doing this, breaking some # namespace without prefixing them. Latter versions fix this. So we
# existing code. # can remove for following hack once 3.0.2 is no longer used in our
if 'formula_ff' not in globals(): # build farm.
if 'op_ff' not in globals():
for i in ('ff', 'tt', 'eword', 'ap', 'Not', 'X', 'F', 'G', for i in ('ff', 'tt', 'eword', 'ap', 'Not', 'X', 'F', 'G',
'Closure', 'NegClosure', 'NegClosureMarked', 'Closure', 'NegClosure', 'NegClosureMarked',
'Xor', 'Implies', 'Equiv', 'U', 'R', 'W', 'M', 'Xor', 'Implies', 'Equiv', 'U', 'R', 'W', 'M',
'EConcat', 'EConcatMarked', 'UConcat', 'Or', 'EConcat', 'EConcatMarked', 'UConcat', 'Or',
'OrRat', 'And', 'AndRat', 'AndNLM', 'Concat', 'OrRat', 'And', 'AndRat', 'AndNLM', 'Concat',
'Fusion', 'Star', 'FStar', 'nested_unop_range', 'Fusion', 'Star', 'FStar'):
'sugar_goto', 'sugar_equal', 'sugar_delay', 'unop', globals()['op_' + i] = globals()[i]
'binop', 'bunop', 'multop', 'first_match', 'unbounded'): del globals()[i]
globals()['formula_' + i] = formula.__dict__[i].__func__
if 'trival_maybe' not in globals():
for i in ('maybe',):
globals()['trival_' + i] = trival.__dict__[i].__func__
# Global BDD dict so that we do not have to create one in user code. # Global BDD dict so that we do not have to create one in user code.
@ -264,12 +261,6 @@ class twa:
ostr = ostringstream() ostr = ostringstream()
print_lbtt(ostr, a, opt) print_lbtt(ostr, a, opt)
return ostr.str() return ostr.str()
if format == 'pg':
if opt is not None:
raise ValueError("print_pg() has no option")
ostr = ostringstream()
print_pg(ostr, a)
return ostr.str()
raise ValueError("unknown string format: " + format) raise ValueError("unknown string format: " + format)
def save(a, filename, format='hoa', opt=None, append=False): def save(a, filename, format='hoa', opt=None, append=False):
@ -502,57 +493,51 @@ class acd:
.acdacc polygon{fill:green;} .acdacc polygon{fill:green;}
''' '''
js = ''' js = '''
function acdremclasses(sel, classes) {{
document.querySelectorAll(sel).forEach(n=>{{n.classList.remove(...classes)}});}}
function acdaddclasses(sel, classes) {{
document.querySelectorAll(sel).forEach(n=>{{n.classList.add(...classes)}});}}
function acdonclick(sel, fn) {{
document.querySelectorAll(sel).forEach(n=>
{{n.addEventListener("click", fn)}});
}}
function acd{num}_clear(){{ function acd{num}_clear(){{
acdremclasses("#acd{num} .node,#acdaut{num} .node,#acdaut{num} .edge", $("#acd{num} .node,#acdaut{num} .node,#acdaut{num} .edge")
["acdhigh", "acdbold", "acdacc", "acdrej"]); .removeClass("acdhigh acdbold acdacc acdrej");
}}; }};
function acd{num}_state(state){{ function acd{num}_state(state){{
acd{num}_clear(); acd{num}_clear();
acdaddclasses("#acd{num} .acdS" + state, ["acdhigh", "acdbold"]); $("#acd{num} .acdS" + state).addClass("acdhigh acdbold");
acdaddclasses("#acdaut{num} #S" + state, ["acdbold"]); $("#acdaut{num} #S" + state).addClass("acdbold");
}}; }};
function acd{num}_edge(edge){{ function acd{num}_edge(edge){{
acd{num}_clear(); acd{num}_clear();
var theedge = document.querySelector('#acdaut{num} #E' + edge); var theedge = $('#acdaut{num} #E' + edge)
theedge.classList.forEach(function(item, index) {{ var classList = theedge.attr('class').split(/\s+/);
$.each(classList, function(index, item) {{
if (item.startsWith('acdN')) {{ if (item.startsWith('acdN')) {{
acdaddclasses("#acd{num} #" + item.substring(3), ["acdhigh", "acdbold"]); $("#acd{num} #" + item.substring(3)).addClass("acdhigh acdbold");
}} }}
}}); }});
theedge.classList.add("acdbold"); theedge.addClass("acdbold");
}}; }};
function acd{num}_node(node, acc){{ function acd{num}_node(node, acc){{
acd{num}_clear(); acd{num}_clear();
acdaddclasses("#acdaut{num} .acdN" + node, $("#acdaut{num} .acdN" + node).addClass(acc
[acc ? "acdacc" : "acdrej", "acdbold"]); ? "acdacc acdbold"
acdaddclasses("#acd{num} #N" + node, ["acdbold", "acdhigh"]); : "acdrej acdbold");
$("#acd{num} #N" + node).addClass("acdbold acdhigh");
}};'''.format(num=num) }};'''.format(num=num)
me = 0 me = 0
for n in range(self.node_count()): for n in range(self.node_count()):
for e in self.edges_of_node(n): for e in self.edges_of_node(n):
me = max(e, me) me = max(e, me)
js += 'acdaddclasses("#acdaut{num} #E{e}", ["acdN{n}"]);\n'\ js += '$("#acdaut{num} #E{e}").addClass("acdN{n}");'\
.format(num=num, e=e, n=n) .format(num=num, e=e, n=n)
for e in range(1, me + 1): for e in range(1, me + 1):
js += 'acdonclick("#acdaut{num} #E{e}",'\ js += '$("#acdaut{num} #E{e}")'\
'function(){{acd{num}_edge({e});}});\n'\ '.click(function(){{acd{num}_edge({e});}});'\
.format(num=num, e=e) .format(num=num, e=e)
for s in range(self.get_aut().num_states()): for s in range(self.get_aut().num_states()):
js += 'acdonclick("#acdaut{num} #S{s}",'\ js += '$("#acdaut{num} #S{s}")'\
'function(){{acd{num}_state({s});}});\n'\ '.click(function(){{acd{num}_state({s});}});'\
.format(num=num, s=s) .format(num=num, s=s)
for n in range(self.node_count()): for n in range(self.node_count()):
v = int(self.node_acceptance(n)) v = int(self.node_acceptance(n))
js += 'acdonclick("#acd{num} #N{n}",'\ js += '$("#acd{num} #N{n}")'\
'function(){{acd{num}_node({n}, {v});}});\n'\ '.click(function(){{acd{num}_node({n}, {v});}});'\
.format(num=num, n=n, v=v) .format(num=num, n=n, v=v)
html = '<style>{}</style><div>{}</div><div>{}</div><script>{}</script>'\ html = '<style>{}</style><div>{}</div><div>{}</div><script>{}</script>'\
.format(style, .format(style,
@ -1307,36 +1292,6 @@ def sat_minimize(aut, acc=None, colored=False,
else: else:
return sm(aut, args, state_based) return sm(aut, args, state_based)
# Adding the inline csv-display option
def minimize_mealy(mm, opt = -1, display_log = False, return_log = False):
from spot.impl import minimize_mealy as minmealy
try:
lvl = int(opt)
opt = synthesis_info()
opt.minimize_lvl = lvl + 4
except (ValueError, TypeError) as _:
pass
if display_log or return_log:
import pandas as pd
with tempfile.NamedTemporaryFile(dir='.', suffix='.minlog') as t:
opt.opt.set_str("satlogcsv", t.name)
resmm = minmealy(mm, opt)
dfrm = pd.read_csv(t.name, dtype=object)
if display_log:
from IPython.display import display
del dfrm['instance']
display(dfrm)
if return_log:
return resmm, dfrm
else:
return resmm
else:
return minmealy(mm, opt)
def parse_word(word, dic=_bdd_dict): def parse_word(word, dic=_bdd_dict):
from spot.impl import parse_word as pw from spot.impl import parse_word as pw
@ -1347,10 +1302,6 @@ def bdd_to_formula(b, dic=_bdd_dict):
from spot.impl import bdd_to_formula as bf from spot.impl import bdd_to_formula as bf
return bf(b, dic) return bf(b, dic)
def bdd_to_cnf_formula(b, dic=_bdd_dict):
from spot.impl import bdd_to_cnf_formula as bf
return bf(b, dic)
def language_containment_checker(dic=_bdd_dict): def language_containment_checker(dic=_bdd_dict):
from spot.impl import language_containment_checker as c from spot.impl import language_containment_checker as c

View file

@ -1,5 +1,5 @@
// -*- coding: utf-8 -*- // -*- coding: utf-8 -*-
// Copyright (C) 2009-2023 Laboratoire de Recherche et Développement // Copyright (C) 2009-2022 Laboratoire de Recherche et Développement
// de l'Epita (LRDE). // de l'Epita (LRDE).
// Copyright (C) 2003-2006 Laboratoire d'Informatique de Paris 6 // Copyright (C) 2003-2006 Laboratoire d'Informatique de Paris 6
// (LIP6), département Systèmes Répartis Coopératifs (SRC), Université // (LIP6), département Systèmes Répartis Coopératifs (SRC), Université
@ -90,9 +90,7 @@
#include <spot/tl/apcollect.hh> #include <spot/tl/apcollect.hh>
#include <spot/tl/contain.hh> #include <spot/tl/contain.hh>
#include <spot/tl/derive.hh>
#include <spot/tl/dot.hh> #include <spot/tl/dot.hh>
#include <spot/tl/expansions.hh>
#include <spot/tl/nenoform.hh> #include <spot/tl/nenoform.hh>
#include <spot/tl/print.hh> #include <spot/tl/print.hh>
#include <spot/tl/simplify.hh> #include <spot/tl/simplify.hh>
@ -116,14 +114,13 @@
#include <spot/twaalgos/aiger.hh> #include <spot/twaalgos/aiger.hh>
#include <spot/twaalgos/alternation.hh> #include <spot/twaalgos/alternation.hh>
#include <spot/twaalgos/cleanacc.hh> #include <spot/twaalgos/cleanacc.hh>
#include <spot/twaalgos/degen.hh>
#include <spot/twaalgos/dot.hh>
#include <spot/twaalgos/dualize.hh>
#include <spot/twaalgos/cobuchi.hh> #include <spot/twaalgos/cobuchi.hh>
#include <spot/twaalgos/copy.hh> #include <spot/twaalgos/copy.hh>
#include <spot/twaalgos/complete.hh> #include <spot/twaalgos/complete.hh>
#include <spot/twaalgos/complement.hh> #include <spot/twaalgos/complement.hh>
#include <spot/twaalgos/dbranch.hh>
#include <spot/twaalgos/degen.hh>
#include <spot/twaalgos/dot.hh>
#include <spot/twaalgos/dualize.hh>
#include <spot/twaalgos/emptiness.hh> #include <spot/twaalgos/emptiness.hh>
#include <spot/twaalgos/gtec/gtec.hh> #include <spot/twaalgos/gtec/gtec.hh>
#include <spot/twaalgos/genem.hh> #include <spot/twaalgos/genem.hh>
@ -163,7 +160,6 @@
#include <spot/twaalgos/stutter.hh> #include <spot/twaalgos/stutter.hh>
#include <spot/twaalgos/synthesis.hh> #include <spot/twaalgos/synthesis.hh>
#include <spot/twaalgos/translate.hh> #include <spot/twaalgos/translate.hh>
#include <spot/twaalgos/translate_aa.hh>
#include <spot/twaalgos/toweak.hh> #include <spot/twaalgos/toweak.hh>
#include <spot/twaalgos/hoa.hh> #include <spot/twaalgos/hoa.hh>
#include <spot/twaalgos/dtwasat.hh> #include <spot/twaalgos/dtwasat.hh>
@ -490,7 +486,6 @@ static void handle_any_exception()
} }
} }
%implicitconv spot::parallel_policy;
%include <spot/misc/common.hh> %include <spot/misc/common.hh>
%include <spot/misc/version.hh> %include <spot/misc/version.hh>
%include <spot/misc/minato.hh> %include <spot/misc/minato.hh>
@ -523,12 +518,9 @@ namespace std {
%template(vectorbdd) vector<bdd>; %template(vectorbdd) vector<bdd>;
%template(aliasvector) vector<pair<string, bdd>>; %template(aliasvector) vector<pair<string, bdd>>;
%template(vectorstring) vector<string>; %template(vectorstring) vector<string>;
%template(vectorint) vector<int>;
%template(pair_formula_vectorstring) pair<spot::formula, vector<string>>; %template(pair_formula_vectorstring) pair<spot::formula, vector<string>>;
%template(atomic_prop_set) set<spot::formula>; %template(atomic_prop_set) set<spot::formula>;
%template(relabeling_map) map<spot::formula, spot::formula>; %template(relabeling_map) map<spot::formula, spot::formula>;
%template(pair_formula) pair<spot::formula, spot::formula>;
%template(vector_pair_formula) vector<pair<spot::formula, spot::formula>>;
} }
%include <spot/tl/environment.hh> %include <spot/tl/environment.hh>
@ -541,8 +533,6 @@ namespace std {
%include <spot/twa/bdddict.hh> %include <spot/twa/bdddict.hh>
%include <spot/twa/bddprint.hh> %include <spot/twa/bddprint.hh>
%include <spot/twa/formula2bdd.hh> %include <spot/twa/formula2bdd.hh>
%template(formula_to_bdd) spot::formula_to_bdd<spot::twa_graph>;
%include <spot/twa/fwd.hh> %include <spot/twa/fwd.hh>
/* These operators may raise exceptions, and we do not /* These operators may raise exceptions, and we do not
want Swig4 to convert those exceptions to NotImplemented. */ want Swig4 to convert those exceptions to NotImplemented. */
@ -559,27 +549,6 @@ namespace std {
} }
%apply std::vector<unsigned> &OUTPUT {std::vector<unsigned>& pairs} %apply std::vector<unsigned> &OUTPUT {std::vector<unsigned>& pairs}
%apply std::vector<spot::acc_cond::rs_pair> &OUTPUT {std::vector<spot::acc_cond::rs_pair>& pairs} %apply std::vector<spot::acc_cond::rs_pair> &OUTPUT {std::vector<spot::acc_cond::rs_pair>& pairs}
// Must occur before the twa declaration
%typemap(out) SWIGTYPE spot::acc_cond::fin_unit_one_split %{
{
auto& v = static_cast<const std::tuple<int, spot::acc_cond, spot::acc_cond>>($1);
$result = PyTuple_Pack(3,
swig::from(std::get<0>(v)),
swig::from(std::get<1>(v)),
swig::from(std::get<2>(v)));
}
%}
// Must occur before the twa declaration
%typemap(out) SWIGTYPE spot::acc_cond::fin_unit_one_split_improved %{
{
auto& v = static_cast<const std::tuple<int, spot::acc_cond, spot::acc_cond>>($1);
$result = PyTuple_Pack(3,
swig::from(std::get<0>(v)),
swig::from(std::get<1>(v)),
swig::from(std::get<2>(v)));
}
%}
%include <spot/twa/acc.hh> %include <spot/twa/acc.hh>
%template(pair_bool_mark) std::pair<bool, spot::acc_cond::mark_t>; %template(pair_bool_mark) std::pair<bool, spot::acc_cond::mark_t>;
@ -608,8 +577,6 @@ namespace std {
%include <spot/tl/apcollect.hh> %include <spot/tl/apcollect.hh>
%include <spot/tl/contain.hh> %include <spot/tl/contain.hh>
%include <spot/tl/derive.hh>
%include <spot/tl/expansions.hh>
%include <spot/tl/dot.hh> %include <spot/tl/dot.hh>
%include <spot/tl/nenoform.hh> %include <spot/tl/nenoform.hh>
%include <spot/tl/sonf.hh> %include <spot/tl/sonf.hh>
@ -697,14 +664,11 @@ def state_is_accepting(self, src) -> "bool":
%include <spot/twaalgos/aiger.hh> %include <spot/twaalgos/aiger.hh>
%include <spot/twaalgos/alternation.hh> %include <spot/twaalgos/alternation.hh>
%include <spot/twaalgos/cleanacc.hh> %include <spot/twaalgos/cleanacc.hh>
%include <spot/twaalgos/degen.hh>
%include <spot/twaalgos/dot.hh>
%include <spot/twaalgos/cobuchi.hh> %include <spot/twaalgos/cobuchi.hh>
%include <spot/twaalgos/copy.hh> %include <spot/twaalgos/copy.hh>
%include <spot/twaalgos/complete.hh> %include <spot/twaalgos/complete.hh>
%include <spot/twaalgos/dbranch.hh>
%include <spot/twaalgos/degen.hh>
%include <spot/twaalgos/determinize.hh>
%include <spot/twaalgos/dot.hh>
%include <spot/twaalgos/dualize.hh>
%feature("flatnested") spot::twa_run::step; %feature("flatnested") spot::twa_run::step;
%include <spot/twaalgos/emptiness.hh> %include <spot/twaalgos/emptiness.hh>
%template(list_step) std::list<spot::twa_run::step>; %template(list_step) std::list<spot::twa_run::step>;
@ -716,6 +680,8 @@ def state_is_accepting(self, src) -> "bool":
%include <spot/twaalgos/gfguarantee.hh> %include <spot/twaalgos/gfguarantee.hh>
%include <spot/twaalgos/compsusp.hh> %include <spot/twaalgos/compsusp.hh>
%include <spot/twaalgos/contains.hh> %include <spot/twaalgos/contains.hh>
%include <spot/twaalgos/determinize.hh>
%include <spot/twaalgos/dualize.hh>
%include <spot/twaalgos/langmap.hh> %include <spot/twaalgos/langmap.hh>
%include <spot/twaalgos/magic.hh> %include <spot/twaalgos/magic.hh>
%include <spot/twaalgos/minimize.hh> %include <spot/twaalgos/minimize.hh>
@ -762,7 +728,6 @@ def state_is_accepting(self, src) -> "bool":
%include <spot/twaalgos/stutter.hh> %include <spot/twaalgos/stutter.hh>
%include <spot/twaalgos/synthesis.hh> %include <spot/twaalgos/synthesis.hh>
%include <spot/twaalgos/translate.hh> %include <spot/twaalgos/translate.hh>
%include <spot/twaalgos/translate_aa.hh>
%include <spot/twaalgos/toweak.hh> %include <spot/twaalgos/toweak.hh>
%include <spot/twaalgos/hoa.hh> %include <spot/twaalgos/hoa.hh>
%include <spot/twaalgos/dtwasat.hh> %include <spot/twaalgos/dtwasat.hh>

View file

@ -71,16 +71,16 @@ logic (LTL & PSL).
%files -n libspot %files -n libspot
%{_libdir}/libbddx.a %{_libdir}/libbddx.a
%exclude %{_libdir}/libbddx.la %{_libdir}/libbddx.la
%{_libdir}/libbddx.so* %{_libdir}/libbddx.so*
%{_libdir}/libspot.a %{_libdir}/libspot.a
%exclude %{_libdir}/libspot.la %{_libdir}/libspot.la
%{_libdir}/libspot.so* %{_libdir}/libspot.so*
%{_libdir}/libspotgen.a %{_libdir}/libspotgen.a
%exclude %{_libdir}/libspotgen.la %{_libdir}/libspotgen.la
%{_libdir}/libspotgen.so* %{_libdir}/libspotgen.so*
%{_libdir}/libspotltsmin.a %{_libdir}/libspotltsmin.a
%exclude %{_libdir}/libspotltsmin.la %{_libdir}/libspotltsmin.la
%{_libdir}/libspotltsmin.so* %{_libdir}/libspotltsmin.so*
%license COPYING %license COPYING
%doc AUTHORS COPYING NEWS README THANKS %doc AUTHORS COPYING NEWS README THANKS
@ -121,7 +121,7 @@ temporal logic (LTL & PSL).
%dir %{python3_sitearch}/spot %dir %{python3_sitearch}/spot
%{python3_sitearch}/spot/* %{python3_sitearch}/spot/*
%{python3_sitearch}/_buddy.*.a %{python3_sitearch}/_buddy.*.a
%exclude %{python3_sitearch}/_buddy.*.la %{python3_sitearch}/_buddy.*.la
%{python3_sitearch}/_buddy.*.so %{python3_sitearch}/_buddy.*.so
%license COPYING %license COPYING
%doc AUTHORS COPYING NEWS README THANKS %doc AUTHORS COPYING NEWS README THANKS

View file

@ -1,5 +1,5 @@
## -*- coding: utf-8 -*- ## -*- coding: utf-8 -*-
## Copyright (C) 2009, 2010, 2012, 2013, 2014, 2015, 2016, 2017, 2020, 2022 ## Copyright (C) 2009, 2010, 2012, 2013, 2014, 2015, 2016, 2017, 2020
## Laboratoire de Recherche et Développement de l'Epita (LRDE). ## Laboratoire de Recherche et Développement de l'Epita (LRDE).
## Copyright (C) 2003, 2004 Laboratoire d'Informatique de Paris 6 (LIP6), ## Copyright (C) 2003, 2004 Laboratoire d'Informatique de Paris 6 (LIP6),
## département Systèmes Répartis Coopératifs (SRC), Université Pierre ## département Systèmes Répartis Coopératifs (SRC), Université Pierre
@ -35,7 +35,7 @@ SUBDIRS = misc priv tl graph twa twacube twaalgos ta taalgos kripke \
lib_LTLIBRARIES = libspot.la lib_LTLIBRARIES = libspot.la
libspot_la_SOURCES = libspot_la_SOURCES =
libspot_la_LDFLAGS = $(BUDDY_LDFLAGS) -no-undefined @LIBSPOT_PTHREAD@ $(SYMBOLIC_LDFLAGS) libspot_la_LDFLAGS = $(BUDDY_LDFLAGS) -no-undefined $(SYMBOLIC_LDFLAGS)
libspot_la_LIBADD = \ libspot_la_LIBADD = \
kripke/libkripke.la \ kripke/libkripke.la \
misc/libmisc.la \ misc/libmisc.la \
@ -68,7 +68,6 @@ libspot.pc: $(srcdir)/libspot.pc.in Makefile
-e 's![@]includedir[@]!$(includedir)!g' \ -e 's![@]includedir[@]!$(includedir)!g' \
-e 's![@]libdir[@]!$(libdir)!g' \ -e 's![@]libdir[@]!$(libdir)!g' \
-e 's![@]PACKAGE_VERSION[@]!$(PACKAGE_VERSION)!g' \ -e 's![@]PACKAGE_VERSION[@]!$(PACKAGE_VERSION)!g' \
-e 's![@]LIBSPOT_PTHREAD[@]!$(LIBSPOT_PTHREAD)!g' \
$(srcdir)/libspot.pc.in > $@.tmp && mv $@.tmp $@ $(srcdir)/libspot.pc.in > $@.tmp && mv $@.tmp $@
CLEANFILES = libspot.pc CLEANFILES = libspot.pc

View file

@ -583,7 +583,7 @@ struct _ConcurrentHashSet : HashSetBase< Cell >
return begin() + size(); return begin() + size();
} }
Row() noexcept : _data( nullptr ), _size( 0 ) {} Row() : _data( nullptr ), _size( 0 ) {}
~Row() { free(); } ~Row() { free(); }
}; };

View file

@ -1,5 +1,5 @@
// -*- coding: utf-8 -*- // -*- coding: utf-8 -*-
// Copyright (C) 2017-2019, 2021-2022 Laboratoire de Recherche et // Copyright (C) 2017-2019, 2021 Laboratoire de Recherche et
// Developpement de l'EPITA (LRDE). // Developpement de l'EPITA (LRDE).
// //
// This file is part of Spot, a model checking library. // This file is part of Spot, a model checking library.
@ -220,48 +220,13 @@ namespace spot
return aut; return aut;
} }
static twa_graph_ptr
cyclist_trace_or_proof(unsigned n, bool trace, bdd_dict_ptr dict)
{
auto aut = make_twa_graph(dict);
acc_cond::mark_t m = aut->set_buchi();
aut->new_states(n + 2);
aut->set_init_state(0);
if (trace)
m = {};
aut->prop_state_acc(true);
// How many AP to we need to represent n letters
unsigned nap = ulog2(n + 1);
std::vector<int> apvars(nap);
for (unsigned a = 0; a < nap; ++a)
apvars[a] = aut->register_ap("p" + std::to_string(a));
if (trace)
aut->new_edge(0, 0, bddtrue); // the only non-deterministic edge
else
aut->prop_universal(true);
bdd zero = bdd_ibuildcube(0, nap, apvars.data());
aut->new_edge(0, 1, zero, m);
for (unsigned letter = 1; letter <= n; ++letter)
{
bdd cond = bdd_ibuildcube(letter, nap, apvars.data());
aut->new_acc_edge(1, letter + 1, cond);
aut->new_edge(letter + 1, 1, zero, m);
}
return aut;
}
twa_graph_ptr aut_pattern(aut_pattern_id pattern, int n, bdd_dict_ptr dict) twa_graph_ptr aut_pattern(aut_pattern_id pattern, int n, bdd_dict_ptr dict)
{ {
if (n < 0) if (n < 0)
{ {
std::ostringstream err; std::ostringstream err;
err << "pattern argument for " << aut_pattern_name(pattern) err << "pattern argument for " << aut_pattern_name(pattern)
<< " should be non-negative"; << " should be positive";
throw std::runtime_error(err.str()); throw std::runtime_error(err.str());
} }
@ -276,10 +241,6 @@ namespace spot
return l_dsa(n, dict); return l_dsa(n, dict);
case AUT_M_NBA: case AUT_M_NBA:
return m_nba(n, dict); return m_nba(n, dict);
case AUT_CYCLIST_TRACE_NBA:
return cyclist_trace_or_proof(n, true, dict);
case AUT_CYCLIST_PROOF_DBA:
return cyclist_trace_or_proof(n, false, dict);
case AUT_END: case AUT_END:
break; break;
} }
@ -294,8 +255,6 @@ namespace spot
"l-nba", "l-nba",
"l-dsa", "l-dsa",
"m-nba", "m-nba",
"cyclist-trace-nba",
"cyclist-proof-dba",
}; };
// Make sure we do not forget to update the above table every // Make sure we do not forget to update the above table every
// time a new pattern is added. // time a new pattern is added.

View file

@ -1,5 +1,5 @@
// -*- coding: utf-8 -*- // -*- coding: utf-8 -*-
// Copyright (C) 2017, 2019, 2022 Laboratoire de Recherche et Developpement de // Copyright (C) 2017, 2019 Laboratoire de Recherche et Developpement de
// l'EPITA (LRDE). // l'EPITA (LRDE).
// //
// This file is part of Spot, a model checking library. // This file is part of Spot, a model checking library.
@ -79,24 +79,6 @@ namespace spot
/// propositions to encode the $n+1$ letters used in the /// propositions to encode the $n+1$ letters used in the
/// original alphabet. /// original alphabet.
AUT_M_NBA, AUT_M_NBA,
/// \brief An NBA with (n+2) states derived from a Cyclic test
/// case.
///
/// This familly of automata is derived from a couple of
/// examples supplied by Reuben Rowe. The task is to
/// check that the automaton generated with AUT_CYCLIST_TRACE_NBA
/// for a given n contain the automaton generated with
/// AUT_CYCLIST_PROOF_DBA for the same n.
AUT_CYCLIST_TRACE_NBA,
/// \brief A DBA with (n+2) states derived from a Cyclic test
/// case.
///
/// This familly of automata is derived from a couple of
/// examples supplied by Reuben Rowe. The task is to
/// check that the automaton generated with AUT_CYCLIST_TRACE_NBA
/// for a given n contain the automaton generated with
/// AUT_CYCLIST_PROOF_DBA for the same n.
AUT_CYCLIST_PROOF_DBA,
AUT_END AUT_END
}; };

View file

@ -1,5 +1,5 @@
// -*- coding: utf-8 -*- // -*- coding: utf-8 -*-
// Copyright (C) 2012-2019, 2022 Laboratoire de Recherche et Developpement // Copyright (C) 2012-2019 Laboratoire de Recherche et Developpement
// 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.
@ -1198,13 +1198,13 @@ namespace spot
} }
static formula static formula
pps_arbiter(std::string r_, std::string g_, unsigned n, bool strict_) pps_arbiter(std::string r_, std::string g_, int n, bool strict_)
{ {
formula* r = new formula[n]; formula* r = new formula[n];
formula* g = new formula[n]; formula* g = new formula[n];
std::vector<formula> res; std::vector<formula> res;
for (unsigned i = 0; i < n; ++i) for (int i = 0; i < n; ++i)
{ {
r[i] = formula::ap(r_ + std::to_string(i + 1)); r[i] = formula::ap(r_ + std::to_string(i + 1));
g[i] = formula::ap(g_ + std::to_string(i + 1)); g[i] = formula::ap(g_ + std::to_string(i + 1));
@ -1218,17 +1218,17 @@ namespace spot
formula phi_s; formula phi_s;
{ {
std::vector<formula> res; std::vector<formula> res;
for (unsigned i = 0; i < n; ++i) for (int i = 0; i < n; ++i)
res.push_back(formula::Not(r[i])); res.push_back(formula::Not(r[i]));
theta_e = formula::And(res); theta_e = formula::And(res);
res.clear(); res.clear();
for (unsigned i = 0; i < n; ++i) for (int i = 0; i < n; ++i)
res.push_back(formula::Not(g[i])); res.push_back(formula::Not(g[i]));
theta_s = formula::And(res); theta_s = formula::And(res);
res.clear(); res.clear();
for (unsigned i = 0; i < n; ++i) for (int i = 0; i < n; ++i)
{ {
formula left = formula::Xor(r[i], g[i]); formula left = formula::Xor(r[i], g[i]);
formula right = formula::Equiv(r[i], formula::X(r[i])); formula right = formula::Equiv(r[i], formula::X(r[i]));
@ -1237,9 +1237,9 @@ namespace spot
psi_e = formula::And(res); psi_e = formula::And(res);
res.clear(); res.clear();
for (unsigned i = 0; i < n; ++i) for (int i = 0; i < n; ++i)
{ {
for (unsigned j = 0; j < i; ++j) for (int j = 0; j < i; ++j)
res.push_back(formula::Not(formula::And({g[i], g[j]}))); res.push_back(formula::Not(formula::And({g[i], g[j]})));
formula left = formula::Equiv(r[i], g[i]); formula left = formula::Equiv(r[i], g[i]);
formula right = formula::Equiv(g[i], formula::X(g[i])); formula right = formula::Equiv(g[i], formula::X(g[i]));
@ -1248,7 +1248,7 @@ namespace spot
psi_s = formula::And(res); psi_s = formula::And(res);
res.clear(); res.clear();
for (unsigned i = 0; i < n; ++i) for (int i = 0; i < n; ++i)
{ {
formula f = formula::Not(formula::And({r[i], g[i]})); formula f = formula::Not(formula::And({r[i], g[i]}));
res.push_back(formula::G(formula::F(f))); res.push_back(formula::G(formula::F(f)));
@ -1256,7 +1256,7 @@ namespace spot
phi_e = formula::And(res); phi_e = formula::And(res);
res.clear(); res.clear();
for (unsigned i = 0; i < n; ++i) for (int i = 0; i < n; ++i)
{ {
res.push_back(formula::G(formula::F(formula::Equiv(r[i], g[i])))); res.push_back(formula::G(formula::F(formula::Equiv(r[i], g[i]))));
} }
@ -1267,9 +1267,9 @@ namespace spot
if (!strict_) if (!strict_)
{ {
formula left = formula::And({formula::G(psi_e), phi_e});
formula imp = formula imp =
formula::Implies(left, formula::And({formula::G(psi_s), phi_s})); formula::Implies(formula::And({formula::G(psi_e), phi_e}),
formula::And({formula::G(psi_s), phi_s}));
return formula::Implies(theta_e, formula::And({theta_s, imp})); return formula::Implies(theta_e, formula::And({theta_s, imp}));
} }
else else
@ -1281,21 +1281,6 @@ namespace spot
} }
} }
// G[0..n]((a S b) -> c) rewritten using future operators,
// from Edmond Irani Liu (EIL). GSI stands for "Globally Since Implies."
static formula eil_gsi(int n, std::string a, std::string b, std::string c)
{
formula fa = formula::ap(a);
formula fb = formula::ap(b);
formula res = fb;
for (int i = 1; i <= n; ++i)
{
formula tmp = formula::And({formula::strong_X(i, fa), res});
res = formula::Or({formula::strong_X(i, fb), tmp});
}
return formula::Implies(res, formula::strong_X(n, formula::ap(c)));
}
formula ltl_pattern(ltl_pattern_id pattern, int n, int m) formula ltl_pattern(ltl_pattern_id pattern, int n, int m)
{ {
if (n < 0) if (n < 0)
@ -1332,8 +1317,6 @@ namespace spot
return dac_pattern(n); return dac_pattern(n);
case LTL_EH_PATTERNS: case LTL_EH_PATTERNS:
return eh_pattern(n); return eh_pattern(n);
case LTL_EIL_GSI:
return eil_gsi(n, "a", "b", "c");
case LTL_FXG_OR: case LTL_FXG_OR:
return FXG_or_n("p", n); return FXG_or_n("p", n);
case LTL_GF_EQUIV: case LTL_GF_EQUIV:
@ -1435,7 +1418,6 @@ namespace spot
"ccj-beta-prime", "ccj-beta-prime",
"dac-patterns", "dac-patterns",
"eh-patterns", "eh-patterns",
"eil-gsi",
"fxg-or", "fxg-or",
"gf-equiv", "gf-equiv",
"gf-equiv-xn", "gf-equiv-xn",
@ -1503,7 +1485,6 @@ namespace spot
return 55; return 55;
case LTL_EH_PATTERNS: case LTL_EH_PATTERNS:
return 12; return 12;
case LTL_EIL_GSI:
case LTL_FXG_OR: case LTL_FXG_OR:
case LTL_GF_EQUIV: case LTL_GF_EQUIV:
case LTL_GF_EQUIV_XN: case LTL_GF_EQUIV_XN:
@ -1573,7 +1554,6 @@ namespace spot
case LTL_CCJ_BETA_PRIME: case LTL_CCJ_BETA_PRIME:
case LTL_DAC_PATTERNS: case LTL_DAC_PATTERNS:
case LTL_EH_PATTERNS: case LTL_EH_PATTERNS:
case LTL_EIL_GSI:
case LTL_FXG_OR: case LTL_FXG_OR:
case LTL_GF_EQUIV: case LTL_GF_EQUIV:
case LTL_GF_EQUIV_XN: case LTL_GF_EQUIV_XN:

View file

@ -1,6 +1,6 @@
// -*- coding: utf-8 -*- // -*- coding: utf-8 -*-
// Copyright (C) 2017-2019, 2022 Laboratoire de Recherche et // Copyright (C) 2017, 2018, 2019 Laboratoire de Recherche et Developpement de
// Developpement de l'EPITA (LRDE). // l'EPITA (LRDE).
// //
// This file is part of Spot, a model checking library. // This file is part of Spot, a model checking library.
// //
@ -56,8 +56,6 @@ namespace spot
/// 12 formulas from Etessami and Holzmann. /// 12 formulas from Etessami and Holzmann.
/// \cite etessami.00.concur /// \cite etessami.00.concur
LTL_EH_PATTERNS, LTL_EH_PATTERNS,
/// Familly sent by Edmond Irani Liu
LTL_EIL_GSI,
/// `F(p0 | XG(p1 | XG(p2 | ... XG(pn))))` /// `F(p0 | XG(p1 | XG(p2 | ... XG(pn))))`
LTL_FXG_OR, LTL_FXG_OR,
/// `(GFa1 & GFa2 & ... & GFan) <-> GFz` /// `(GFa1 & GFa2 & ... & GFan) <-> GFz`

View file

@ -1,5 +1,5 @@
// -*- coding: utf-8 -*- // -*- coding: utf-8 -*-
// Copyright (C) 2014-2018, 2020-2022 Laboratoire de Recherche et // Copyright (C) 2014-2018, 2020, 2021 Laboratoire de Recherche et
// Développement de l'Epita. // Développement de l'Epita.
// //
// This file is part of Spot, a model checking library. // This file is part of Spot, a model checking library.
@ -20,7 +20,6 @@
#pragma once #pragma once
#include <spot/misc/common.hh> #include <spot/misc/common.hh>
#include <spot/misc/_config.h>
#include <vector> #include <vector>
#include <type_traits> #include <type_traits>
#include <tuple> #include <tuple>
@ -29,9 +28,6 @@
#include <algorithm> #include <algorithm>
#include <map> #include <map>
#include <iostream> #include <iostream>
#ifdef SPOT_ENABLE_PTHREAD
# include <thread>
#endif // SPOT_ENABLE_PTHREAD
namespace spot namespace spot
{ {
@ -557,11 +553,10 @@ namespace spot
{ {
std::map<std::vector<unsigned>, unsigned> uniq_; std::map<std::vector<unsigned>, unsigned> uniq_;
G& g_; G& g_;
unsigned acc_sink_;
public: public:
univ_dest_mapper(G& graph, unsigned sink = -1u) univ_dest_mapper(G& graph)
: g_(graph), acc_sink_(sink) : g_(graph)
{ {
} }
@ -571,9 +566,6 @@ namespace spot
std::vector<unsigned> tmp(begin, end); std::vector<unsigned> tmp(begin, end);
std::sort(tmp.begin(), tmp.end()); std::sort(tmp.begin(), tmp.end());
tmp.erase(std::unique(tmp.begin(), tmp.end()), tmp.end()); tmp.erase(std::unique(tmp.begin(), tmp.end()), tmp.end());
if (acc_sink_ != -1u && tmp.size() > 1)
tmp.erase(std::remove(tmp.begin(), tmp.end(), acc_sink_),
tmp.end());
auto p = uniq_.emplace(tmp, 0); auto p = uniq_.emplace(tmp, 0);
if (p.second) if (p.second)
p.first->second = g_.new_univ_dests(tmp.begin(), tmp.end()); p.first->second = g_.new_univ_dests(tmp.begin(), tmp.end());
@ -808,23 +800,8 @@ namespace spot
return *dst_begin; return *dst_begin;
SPOT_ASSERT(sz > 1); SPOT_ASSERT(sz > 1);
unsigned d = dests_.size(); unsigned d = dests_.size();
if (!dests_.empty()
&& &*dst_begin >= &dests_.front()
&& &*dst_begin <= &dests_.back()
&& (dests_.capacity() - dests_.size()) < (sz + 1))
{
// If dst_begin...dst_end points into dests_ and dests_ risk
// being reallocated, we have to savea the destination
// states before we lose them.
std::vector<unsigned> tmp(dst_begin, dst_end);
dests_.emplace_back(sz);
dests_.insert(dests_.end(), tmp.begin(), tmp.end());
}
else
{
dests_.emplace_back(sz); dests_.emplace_back(sz);
dests_.insert(dests_.end(), dst_begin, dst_end); dests_.insert(dests_.end(), dst_begin, dst_end);
}
return ~d; return ~d;
} }
@ -1249,78 +1226,6 @@ namespace spot
std::stable_sort(edges_.begin() + 1, edges_.end(), p); std::stable_sort(edges_.begin() + 1, edges_.end(), p);
} }
/// \brief Sort all edges by src first, then, within edges of the same
/// source use the predicate
///
/// This will invalidate all iterators, and also destroy edge
/// chains. Call chain_edges_() immediately afterwards unless you
/// know what you are doing.
/// \note: for performance this will work in parallel (if enabled)
/// and make a temporary copy of the edges (needs more ram)
/// \pre This needs the edge_vector to be in a coherent state when called
template<class Predicate = std::less<edge_storage_t>>
void sort_edges_srcfirst_(Predicate p = Predicate(),
parallel_policy ppolicy = parallel_policy())
{
SPOT_ASSERT(!edges_.empty());
const unsigned ns = num_states();
std::vector<unsigned> idx_list(ns+1);
edge_vector_t new_edges;
new_edges.reserve(edges_.size());
new_edges.resize(1);
// This causes edge 0 to be considered as dead.
new_edges[0].next_succ = 0;
// Copy all edges so that they are sorted by src
for (unsigned s = 0; s < ns; ++s)
{
idx_list[s] = new_edges.size();
for (const auto& e : out(s))
new_edges.push_back(e);
}
idx_list[ns] = new_edges.size();
// New edge sorted by source
// If we have few edge or only one threads
// Benchmark few?
auto bne = new_edges.begin();
#ifndef SPOT_ENABLE_PTHREAD
(void) ppolicy;
#else
unsigned nthreads = ppolicy.nthreads();
if (nthreads <= 1)
#endif
{
for (unsigned s = 0u; s < ns; ++s)
std::stable_sort(bne + idx_list[s],
bne + idx_list[s+1], p);
}
#ifdef SPOT_ENABLE_PTHREAD
else
{
static std::vector<std::thread> tv;
SPOT_ASSERT(tv.empty());
tv.resize(nthreads);
// FIXME: Due to the way these thread advance into the state
// vector, they access very close memory location. It would
// seems more cache friendly to have threads work on blocks
// of continuous states.
for (unsigned id = 0; id < nthreads; ++id)
tv[id] = std::thread(
[bne, id, ns, &idx_list, p, nthreads]()
{
for (unsigned s = id; s < ns; s += nthreads)
std::stable_sort(bne + idx_list[s],
bne + idx_list[s+1], p);
return;
});
for (auto& t : tv)
t.join();
tv.clear();
}
#endif
std::swap(edges_, new_edges);
// Like after normal sort_edges, they need to be chained before usage
}
/// \brief Sort edges of the given states /// \brief Sort edges of the given states
/// ///
/// \tparam Predicate : Comparison type /// \tparam Predicate : Comparison type
@ -1338,19 +1243,14 @@ namespace spot
//dump_storage(std::cerr); //dump_storage(std::cerr);
auto pi = [&](unsigned t1, unsigned t2) auto pi = [&](unsigned t1, unsigned t2)
{return p(edges_[t1], edges_[t2]); }; {return p(edges_[t1], edges_[t2]); };
// Sort the outgoing edges of each selected state according
// to predicate p. Do that in place.
std::vector<unsigned> sort_idx_; std::vector<unsigned> sort_idx_;
unsigned ns = num_states(); for (unsigned i = 0; i < num_states(); ++i)
for (unsigned i = 0; i < ns; ++i)
{ {
if (to_sort_ptr && !(*to_sort_ptr)[i]) if (to_sort_ptr && !(*to_sort_ptr)[i])
continue; continue;
unsigned t = states_[i].succ;
if (t == 0)
continue;
sort_idx_.clear(); sort_idx_.clear();
unsigned t = states_[i].succ;
do do
{ {
sort_idx_.push_back(t); sort_idx_.push_back(t);

View file

@ -8,5 +8,5 @@ Description: A library of LTL and omega-automata algorithms for model checking
URL: https://spot.lrde.epita.fr/ URL: https://spot.lrde.epita.fr/
Version: @PACKAGE_VERSION@ Version: @PACKAGE_VERSION@
Cflags: -I${includedir} Cflags: -I${includedir}
Libs: -L${libdir} -lspot @LIBSPOT_PTHREAD@ Libs: -L${libdir} -lspot
Requires: libbddx Requires: libbddx

View file

@ -1,6 +1,6 @@
// -*- coding: utf-8 -*- // -*- coding: utf-8 -*-
// Copyright (C) 2017, 2018, 2020, 2022 Laboratoire de Recherche et // Copyright (C) 2017, 2018, 2020 Laboratoire de Recherche et Développement de
// Développement de l'Epita (LRDE) // l'Epita (LRDE)
// //
// This file is part of Spot, a model checking library. // This file is part of Spot, a model checking library.
// //
@ -400,10 +400,10 @@ namespace spot
} }
} }
// FIXME: I think we only need visible aps. E.g., if the system has // FIXME I think we only need visbles aps, i.e. if the system has
// variables P_0.var1 and P_0.var2 but the property automaton only // following variables, i.e. P_0.var1 and P_0.var2 but the property
// mentions P_0.var2, we do not need to capture (in the resulting // automaton only mention P_0.var2, we do not need to capture (in
// cube) any atomic proposition for P_0.var1 // the resulting cube) any atomic proposition for P_0.var1
void void
kripkecube<cspins_state, kripkecube<cspins_state,
cspins_iterator>::match_aps(std::vector<std::string>& aps, cspins_iterator>::match_aps(std::vector<std::string>& aps,

View file

@ -1,5 +1,5 @@
// -*- coding: utf-8 -*- // -*- coding: utf-8 -*-
// Copyright (C) 2015-2020, 2022 Laboratoire de Recherche et // Copyright (C) 2015, 2016, 2017, 2018, 2019, 2020 Laboratoire de Recherche et
// Developpement de l'Epita // Developpement de l'Epita
// //
// This file is part of Spot, a model checking library. // This file is part of Spot, a model checking library.
@ -127,7 +127,7 @@ namespace spot
bool b = it.isnew(); bool b = it.isnew();
// Insertion failed, delete element // Insertion failed, delete element
// FIXME: Should we add a local cache to avoid useless allocations? // FIXME Should we add a local cache to avoid useless allocations?
if (!b) if (!b)
p_.deallocate(v); p_.deallocate(v);
else else

View file

@ -1,5 +1,5 @@
// -*- coding: utf-8 -*- // -*- coding: utf-8 -*-
// Copyright (C) 2015-2020, 2022 Laboratoire de Recherche et // Copyright (C) 2015, 2016, 2017, 2018, 2019, 2020 Laboratoire de Recherche et
// Developpement de l'Epita // Developpement de l'Epita
// //
// This file is part of Spot, a model checking library. // This file is part of Spot, a model checking library.
@ -251,7 +251,7 @@ namespace spot
uf_element* q; uf_element* q;
uf_element* r; uf_element* r;
do while (true)
{ {
a_root = find(a); a_root = find(a);
b_root = find(b); b_root = find(b);
@ -261,24 +261,28 @@ namespace spot
// Update acceptance condition // Update acceptance condition
{ {
std::lock_guard<std::mutex> rlock(a_root->acc_mutex_); std::lock_guard<std::mutex> rlock(a_root->acc_mutex_);
a_root->acc |= acc;
acc |= a_root->acc; acc |= a_root->acc;
a_root->acc = acc;
} }
while (a_root->parent.load() != a_root) while (a_root->parent.load() != a_root)
{ {
a_root = find(a_root); a_root = find(a_root);
std::lock_guard<std::mutex> rlock(a_root->acc_mutex_); std::lock_guard<std::mutex> rlock(a_root->acc_mutex_);
a_root->acc |= acc;
acc |= a_root->acc; acc |= a_root->acc;
a_root->acc = acc;
} }
return acc; return acc;
} }
r = std::max(a_root, b_root); r = std::max(a_root, b_root);
q = std::min(a_root, b_root); q = std::min(a_root, b_root);
if (!lock_root(q))
continue;
break;
} }
while (!lock_root(q));
uf_element* a_list = lock_list(a); uf_element* a_list = lock_list(a);
if (a_list == nullptr) if (a_list == nullptr)
@ -325,8 +329,9 @@ namespace spot
{ {
std::lock_guard<std::mutex> rlock(r->acc_mutex_); std::lock_guard<std::mutex> rlock(r->acc_mutex_);
std::lock_guard<std::mutex> qlock(q->acc_mutex_); std::lock_guard<std::mutex> qlock(q->acc_mutex_);
acc |= r->acc | q->acc; q->acc |= acc;
r->acc = q->acc = acc; r->acc |= q->acc;
acc |= r->acc;
} }
while (r->parent.load() != r) while (r->parent.load() != r)
@ -334,8 +339,8 @@ namespace spot
r = find(r); r = find(r);
std::lock_guard<std::mutex> rlock(r->acc_mutex_); std::lock_guard<std::mutex> rlock(r->acc_mutex_);
std::lock_guard<std::mutex> qlock(q->acc_mutex_); std::lock_guard<std::mutex> qlock(q->acc_mutex_);
acc |= r->acc | q->acc; r->acc |= q->acc;
r->acc = acc; acc |= r->acc;
} }
unlock_list(a_list); unlock_list(a_list);
@ -355,7 +360,9 @@ namespace spot
a_status = a->list_status_.load(); a_status = a->list_status_.load();
if (a_status == list_status::BUSY) if (a_status == list_status::BUSY)
{
return a; return a;
}
if (a_status == list_status::DONE) if (a_status == list_status::DONE)
break; break;
@ -400,7 +407,9 @@ namespace spot
b_status = b->list_status_.load(); b_status = b->list_status_.load();
if (b_status == list_status::BUSY) if (b_status == list_status::BUSY)
{
return b; return b;
}
if (b_status == list_status::DONE) if (b_status == list_status::DONE)
break; break;
@ -547,8 +556,8 @@ namespace spot
{ {
auto root = uf_.find(w.second); auto root = uf_.find(w.second);
std::lock_guard<std::mutex> lock(root->acc_mutex_); std::lock_guard<std::mutex> lock(w.second->acc_mutex_);
scc_acc = root->acc; scc_acc = w.second->acc;
} }
// cycle found in SCC and it contains acceptance condition // cycle found in SCC and it contains acceptance condition

View file

@ -1,5 +1,5 @@
// -*- coding: utf-8 -*- // -*- coding: utf-8 -*-
// Copyright (C) 2015-2020, 2022 Laboratoire de Recherche et // Copyright (C) 2015, 2016, 2017, 2018, 2019, 2020 Laboratoire de Recherche et
// Developpement de l'Epita // Developpement de l'Epita
// //
// This file is part of Spot, a model checking library. // This file is part of Spot, a model checking library.
@ -191,7 +191,9 @@ namespace spot
{ {
// Try to insert the new state in the shared map. // Try to insert the new state in the shared map.
auto it = map_.insert(s); auto it = map_.insert(s);
SPOT_ASSERT(!it.isnew()); // should never be new in a red DFS bool b = it.isnew();
SPOT_ASSERT(!b); // should never be new in a red DFS
bool red = ((*it)).colors->red.load(); bool red = ((*it)).colors->red.load();
bool cyan = ((*it)).colors->l[tid_].cyan; bool cyan = ((*it)).colors->l[tid_].cyan;
bool in_Rp = ((*it)).colors->l[tid_].is_in_Rp; bool in_Rp = ((*it)).colors->l[tid_].is_in_Rp;

View file

@ -1,5 +1,5 @@
// -*- coding: utf-8 -*- // -*- coding: utf-8 -*-
// Copyright (C) 2015-2016, 2018-, 20222022 Laboratoire de Recherche et // Copyright (C) 2015-2016, 2018-2021 Laboratoire de Recherche et
// Developpement de l'Epita // Developpement de l'Epita
// //
// This file is part of Spot, a model checking library. // This file is part of Spot, a model checking library.
@ -32,9 +32,9 @@ namespace spot
{ {
/// \brief This class implements the sequential emptiness check as /// \brief This class implements the sequential emptiness check as
/// presented in "Three SCC-based Emptiness Checks for Generalized /// presented in "Three SCC-based Emptiness Checks for Generalized
/// Büchi Automata" (Renault et al, LPAR 2013). Among the three /// B\¨uchi Automata" (Renault et al, LPAR 2013). Among the three
/// emptiness checks that have been proposed, we opted to implement /// emptiness check that has been proposed we opted to implement
/// yGabow's one. /// the Gabow's one.
template<typename State, typename SuccIterator, template<typename State, typename SuccIterator,
typename StateHash, typename StateEqual> typename StateHash, typename StateEqual>
class SPOT_API lpar13 class SPOT_API lpar13
@ -62,8 +62,8 @@ namespace spot
size_t size_t
operator()(const product_state that) const noexcept operator()(const product_state that) const noexcept
{ {
// FIXME: wang32_hash(that.st_prop) could have been // FIXME! wang32_hash(that.st_prop) could have
// pre-calculated! // been pre-calculated!
StateHash hasher; StateHash hasher;
return wang32_hash(that.st_prop) ^ hasher(that.st_kripke); return wang32_hash(that.st_prop) ^ hasher(that.st_kripke);
} }
@ -135,7 +135,7 @@ namespace spot
map[newtop]))) map[newtop])))
{ {
sys_.recycle(todo.back().it_kripke, tid_); sys_.recycle(todo.back().it_kripke, tid_);
// FIXME: a local storage for twacube iterator? // FIXME a local storage for twacube iterator?
todo.pop_back(); todo.pop_back();
if (SPOT_UNLIKELY(found_)) if (SPOT_UNLIKELY(found_))
{ {
@ -346,7 +346,7 @@ namespace spot
ctrx_element* current = front; ctrx_element* current = front;
while (current != nullptr) while (current != nullptr)
{ {
// FIXME: also display acc? // FIXME also display acc?
res = res + " " + res = res + " " +
std::to_string(current->prod_st->st_prop) + std::to_string(current->prod_st->st_prop) +
+ "*" + + "*" +

View file

@ -1,5 +1,5 @@
## -*- coding: utf-8 -*- ## -*- coding: utf-8 -*-
## Copyright (C) 2011-2014, 2016-2018, 2020-2022 Laboratoire de ## Copyright (C) 2011-2014, 2016-2018, 2020-2021 Laboratoire de
## Recherche et Développement de l'Epita (LRDE). ## Recherche et Développement de l'Epita (LRDE).
## Copyright (C) 2003, 2004, 2005, 2006 Laboratoire d'Informatique de ## Copyright (C) 2003, 2004, 2005, 2006 Laboratoire d'Informatique de
## Paris 6 (LIP6), département Systèmes Répartis Coopératifs (SRC), ## Paris 6 (LIP6), département Systèmes Répartis Coopératifs (SRC),

View file

@ -1,5 +1,5 @@
// -*- coding: utf-8 -*- // -*- coding: utf-8 -*-
// Copyright (C) 2013-2021, 2023 Laboratoire de Recherche et Développement // Copyright (C) 2013-2021 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.
@ -111,22 +111,22 @@ namespace spot
return; return;
if (storage_ == &local_storage_) if (storage_ == &local_storage_)
{ {
block_t* new_storage = static_cast<block_t*> block_t* new_storage_ = static_cast<block_t*>
(malloc(new_block_count * sizeof(block_t))); (malloc(new_block_count * sizeof(block_t)));
if (SPOT_UNLIKELY(!new_storage))
throw std::bad_alloc();
for (size_t i = 0; i < block_count_; ++i) for (size_t i = 0; i < block_count_; ++i)
new_storage[i] = storage_[i]; new_storage_[i] = storage_[i];
storage_ = new_storage; storage_ = new_storage_;
} }
else else
{ {
block_t* new_storage = static_cast<block_t*> auto old = storage_;
(realloc(storage_, new_block_count * sizeof(block_t))); storage_ = static_cast<block_t*>
if (SPOT_UNLIKELY(!new_storage)) (realloc(old, new_block_count * sizeof(block_t)));
// storage_, untouched, will be freed by the destructor. if (!storage_)
{
free(old);
throw std::bad_alloc(); throw std::bad_alloc();
storage_ = new_storage; }
} }
block_count_ = new_block_count; block_count_ = new_block_count;
} }
@ -134,8 +134,8 @@ namespace spot
private: private:
void grow() void grow()
{ {
size_t new_block_count = (block_count_ + 1) * 7 / 5; size_t new_block_count_ = (block_count_ + 1) * 7 / 5;
reserve_blocks(new_block_count); reserve_blocks(new_block_count_);
} }
public: public:

View file

@ -1,5 +1,5 @@
// -*- coding: utf-8 -*- // -*- coding: utf-8 -*-
// Copyright (C) 2013-2022 Laboratoire de Recherche et Développement // Copyright (C) 2013-2021 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.
@ -145,27 +145,6 @@ namespace spot
{ {
} }
}; };
/// \brief This class is used to tell parallel algorithms what
/// resources they may use.
///
/// Currently, this simply stores an integer indicating the number
/// of threads that the algorithm may create, but in the future it
/// will probably do more.
class SPOT_API parallel_policy
{
unsigned nthreads_;
public:
parallel_policy(unsigned nthreads = 1) : nthreads_(nthreads)
{
}
unsigned nthreads() const
{
return nthreads_;
}
};
} }
// This is a workaround for the issue described in GNU GCC bug 89303. // This is a workaround for the issue described in GNU GCC bug 89303.

Some files were not shown because too many files have changed in this diff Show more