From 6668dbfbfb4b0ba1b1e835539c4f4c67d2873716 Mon Sep 17 00:00:00 2001 From: Lars Kuhtz Date: Sat, 4 Feb 2012 17:46:48 -0800 Subject: [PATCH] Import files from release clone of old MoCS repository --- .hg_archival.txt | 5 + .hgignore | 45 ++ .hgsigs | 3 + .hgtags | 3 + LICENSE | 11 + Makefile | 46 ++ Makefile.post | 64 ++ Makefile.pre | 64 ++ README | 88 +++ add-copyright-notice | 357 ++++++++++++ c-bindings/Makefile | 32 + c-bindings/aa.h | 144 +++++ c-bindings/aa_c.cc | 298 ++++++++++ c-bindings/context.h | 55 ++ c-bindings/context_c.cc | 35 ++ c-bindings/expr.h | 67 +++ c-bindings/expr_c.cc | 128 ++++ c-bindings/sm.h | 47 ++ c-bindings/sm_c.cc | 54 ++ config.make | 31 + formulas/12-formulas.txt | 48 ++ formulas/Makefile | 143 +++++ formulas/bounded-request.tltl | 17 + formulas/cir-size.sh | 40 ++ formulas/fair-bounded-request-gen.sh | 25 + formulas/gen12f.sh | 22 + formulas/markey.ltl | 21 + formulas/plot.sh | 33 ++ formulas/plot12.sh | 34 ++ formulas/run12.sh | 20 + formulas/runall12.sh | 24 + formulas/set-bounds.sh | 32 + formulas/vardi.static.ltl | 26 + formulas/vardi.tltl | 26 + formulas/vardigen.sh | 33 ++ formulas/waitfor.tltl | 19 + formulas/waitfor_tree.tltl | 17 + haskell-bindings/CAut.hs | 258 +++++++++ haskell-bindings/CExpr.hs | 150 +++++ haskell-bindings/CStateMachine.hs | 62 ++ haskell-bindings/Makefile | 25 + haskell-frontend/Main.hs | 261 +++++++++ haskell-frontend/Main2.hs | 162 ++++++ haskell-frontend/Makefile | 27 + haskell-frontend/Ordinal.hs | 65 +++ haskell-frontend/PSL.hs | 138 +++++ haskell-frontend/PSLFragment.hs | 87 +++ haskell-frontend/PSLLexer.hs | 100 ++++ haskell-frontend/Propositional.hs | 134 +++++ haskell-frontend/Regular.hs | 133 +++++ haskell-frontend/T2Automaton.hs | 224 +++++++ haskell-frontend/Temporal.hs | 627 ++++++++++++++++++++ haskell-frontend/ToString.hs | 58 ++ libaaut/Makefile | 27 + libaaut/aa.hh | 167 ++++++ libaaut/aa.tcc | 837 +++++++++++++++++++++++++++ libaaut/config.h | 44 ++ libaaut/expr.cc | 239 ++++++++ libaaut/expr.hh | 263 +++++++++ libaaut/expr.tcc | 515 ++++++++++++++++ libaaut/expr_util.hh | 437 ++++++++++++++ libaaut/state-machine.cc | 141 +++++ libaaut/state-machine.hh | 50 ++ libaaut/subsetconstruction.tcc | 278 +++++++++ libaaut/util.hh | 157 +++++ libaaut/vhdl.cc | 799 +++++++++++++++++++++++++ libaaut/vhdl.hh | 138 +++++ test/Makefile | 27 + test/Rollout.hs | 59 ++ test/RolloutStat.hs | 60 ++ test/SuffixRolloutStat.hs | 65 +++ test/auttest.cc | 84 +++ test/ctest.c | 27 + test/exprtest.cc | 79 +++ test/formulas/f0.psl | 1 + test/funcs.sh | 18 + vhdl/countdown.vhdl | 50 ++ vhdl/countdown_tb.vhdl | 55 ++ vhdl/d.vhdl | 39 ++ vhdl/d_tb.vhdl | 56 ++ vhdl/monitor_tb.vhdl | 70 +++ vhdl/pipeline.vhdl | 52 ++ vhdl/pipeline_tb.vhdl | 53 ++ vhdl/ptsm_tb.vhdl | 60 ++ 84 files changed, 9615 insertions(+) create mode 100644 .hg_archival.txt create mode 100644 .hgignore create mode 100644 .hgsigs create mode 100644 .hgtags create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 Makefile.post create mode 100644 Makefile.pre create mode 100644 README create mode 100755 add-copyright-notice create mode 100644 c-bindings/Makefile create mode 100644 c-bindings/aa.h create mode 100644 c-bindings/aa_c.cc create mode 100644 c-bindings/context.h create mode 100644 c-bindings/context_c.cc create mode 100644 c-bindings/expr.h create mode 100644 c-bindings/expr_c.cc create mode 100644 c-bindings/sm.h create mode 100644 c-bindings/sm_c.cc create mode 100644 config.make create mode 100644 formulas/12-formulas.txt create mode 100644 formulas/Makefile create mode 100644 formulas/bounded-request.tltl create mode 100755 formulas/cir-size.sh create mode 100755 formulas/fair-bounded-request-gen.sh create mode 100755 formulas/gen12f.sh create mode 100644 formulas/markey.ltl create mode 100755 formulas/plot.sh create mode 100755 formulas/plot12.sh create mode 100755 formulas/run12.sh create mode 100755 formulas/runall12.sh create mode 100755 formulas/set-bounds.sh create mode 100644 formulas/vardi.static.ltl create mode 100644 formulas/vardi.tltl create mode 100755 formulas/vardigen.sh create mode 100644 formulas/waitfor.tltl create mode 100644 formulas/waitfor_tree.tltl create mode 100644 haskell-bindings/CAut.hs create mode 100644 haskell-bindings/CExpr.hs create mode 100644 haskell-bindings/CStateMachine.hs create mode 100644 haskell-bindings/Makefile create mode 100644 haskell-frontend/Main.hs create mode 100644 haskell-frontend/Main2.hs create mode 100644 haskell-frontend/Makefile create mode 100644 haskell-frontend/Ordinal.hs create mode 100644 haskell-frontend/PSL.hs create mode 100644 haskell-frontend/PSLFragment.hs create mode 100644 haskell-frontend/PSLLexer.hs create mode 100644 haskell-frontend/Propositional.hs create mode 100644 haskell-frontend/Regular.hs create mode 100644 haskell-frontend/T2Automaton.hs create mode 100644 haskell-frontend/Temporal.hs create mode 100644 haskell-frontend/ToString.hs create mode 100644 libaaut/Makefile create mode 100644 libaaut/aa.hh create mode 100644 libaaut/aa.tcc create mode 100644 libaaut/config.h create mode 100644 libaaut/expr.cc create mode 100644 libaaut/expr.hh create mode 100644 libaaut/expr.tcc create mode 100644 libaaut/expr_util.hh create mode 100644 libaaut/state-machine.cc create mode 100644 libaaut/state-machine.hh create mode 100644 libaaut/subsetconstruction.tcc create mode 100644 libaaut/util.hh create mode 100644 libaaut/vhdl.cc create mode 100644 libaaut/vhdl.hh create mode 100644 test/Makefile create mode 100644 test/Rollout.hs create mode 100644 test/RolloutStat.hs create mode 100644 test/SuffixRolloutStat.hs create mode 100644 test/auttest.cc create mode 100644 test/ctest.c create mode 100644 test/exprtest.cc create mode 100644 test/formulas/f0.psl create mode 100644 test/funcs.sh create mode 100644 vhdl/countdown.vhdl create mode 100644 vhdl/countdown_tb.vhdl create mode 100644 vhdl/d.vhdl create mode 100644 vhdl/d_tb.vhdl create mode 100644 vhdl/monitor_tb.vhdl create mode 100644 vhdl/pipeline.vhdl create mode 100644 vhdl/pipeline_tb.vhdl create mode 100644 vhdl/ptsm_tb.vhdl diff --git a/.hg_archival.txt b/.hg_archival.txt new file mode 100644 index 0000000..da8a45f --- /dev/null +++ b/.hg_archival.txt @@ -0,0 +1,5 @@ +repo: 41eccac6fdd052fca3d42e4d6a7ab8aef775f0f8 +node: e85c0b6a03386649fea9c96f250ddd57e4bb38b4 +branch: default +latesttag: 0.1 +latesttagdistance: 16 diff --git a/.hgignore b/.hgignore new file mode 100644 index 0000000..bbee008 --- /dev/null +++ b/.hgignore @@ -0,0 +1,45 @@ +# *** MOCS-COPYRIGHT-NOTICE-BEGIN *** +# +# This copyright notice is auto-generated by ./add-copyright-notice. +# Additional copyright notices must be added below the last line of this notice. +# +# MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): ".hgignore". +# The content of this file is copyright of Saarland University - +# Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . +# +# This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). +# +# License: three-clause BSD style license. +# The license text can be found in the file LICENSE. +# +# *** MOCS-COPYRIGHT-NOTICE-END *** + +syntax: glob +doc/*.pdf +doc/*.log +doc/*.aux +test/SuffixRolloutStat +test/RolloutStat +test/Rollout +*.a +*.orig +*.o +vardi*.vhdl +*.dot +*.ps +main +exprtest +auttest +*.hi +haskell-frontend/Main +haskell-frontend/Main2 +libaaut.a +haskell-docs** +haskell-docs/src/** +formulas/all.data +libaaut/tags +test/aut +test/rollout +test/ctest +formulas/xst +glob:mocs-*.tar.bz2 diff --git a/.hgsigs b/.hgsigs new file mode 100644 index 0000000..8208d57 --- /dev/null +++ b/.hgsigs @@ -0,0 +1,3 @@ +6e9c9bdde7b44ad586a0073c421bed726bdfc3a8 0 iEYEABECAAYFAknQoIQACgkQLJDCN6UpI1eRgQCgielKdQHKO8v+/Zgb+WvocpRKk+cAoN/zRwSz9g4n2bHvcRayhxmGl6Fl +6c65569c9d2536062bd157597bf91f3fb004c3ce 0 iEYEABECAAYFAktFoQIACgkQLJDCN6UpI1f74wCggG6gL5PmIMMiJ1myWf1Dt62ZzkAAoLfCDApmKDHeY+z4VwGZri+MJBIP +fc3fbc520e5e8e7b791ab6e756d3c67a6d6045a0 0 iEYEABECAAYFAkuRA7IACgkQLJDCN6UpI1c9OACeL/NElMUofvlBtHNKhaIyVX9sgXoAoLBd5rkwR7PCt07RWnmqtybLgEfU diff --git a/.hgtags b/.hgtags new file mode 100644 index 0000000..0df1203 --- /dev/null +++ b/.hgtags @@ -0,0 +1,3 @@ +6e9c9bdde7b44ad586a0073c421bed726bdfc3a8 used for experimental results in rv 2009 +6c65569c9d2536062bd157597bf91f3fb004c3ce ready for relesae +3cbf52141620d3d929eb346b721739bd71f43c3d 0.1 diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..2cac7d7 --- /dev/null +++ b/LICENSE @@ -0,0 +1,11 @@ +Copyright (c) 2009, Saarland University +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * Neither the name of the Saarland University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..387377d --- /dev/null +++ b/Makefile @@ -0,0 +1,46 @@ +# *** MOCS-COPYRIGHT-NOTICE-BEGIN *** +# +# This copyright notice is auto-generated by ./add-copyright-notice. +# Additional copyright notices must be added below the last line of this notice. +# +# MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "Makefile". +# The content of this file is copyright of Saarland University - +# Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . +# +# This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). +# +# License: three-clause BSD style license. +# The license text can be found in the file LICENSE. +# +# *** MOCS-COPYRIGHT-NOTICE-END *** + +ROOT=. + +include $(ROOT)/Makefile.pre + +.PHONY: archive brelease hsdoc all + +MODULEDEPS=libaaut c-bindings haskell-bindings test haskell-frontend # cppfrontend + +MODULEDEPSTARGET=$(MAKECMDGOALS) + +HSSOURCES:=$(wildcard haskell-bindings/*.hs haskell-frontend/*.hs test/*.hs) +hsdoc: $(HSSOURCES) + mkdir -p haskell-docs/src + HsColour -print-css > haskell-docs/src/hscolour.css + for i in $^ ; do echo haskell-docs/src/`basename $$i .hs`.html; HsColour -css -anchor $$i > haskell-docs/src/`basename $$i .hs`.html ; done + haddock --html --title="psl-monitor-synth" --odir=haskell-docs \ + --source-module='src/%M.html' --source-entity='src/%M.html#%N' $^ + +archive: + hg archive -p mocs -t tbz2 mocs.tar.bz2 -X '\.hg[a-z]*' -X 'add-copyright-notice' + +brelease: MODULEDEPSTARGET= +brelease: haskell-frontend + mkdir -p mocs + cp LICENSE README haskell-frontend/Main mocs + mv mocs/Main mocs/MoCS + tar czf "mocs-$(VERSION)-$(shell hg id -i).tar.gz" mocs + rm -rf mocs + +include $(ROOT)/Makefile.post diff --git a/Makefile.post b/Makefile.post new file mode 100644 index 0000000..9da6333 --- /dev/null +++ b/Makefile.post @@ -0,0 +1,64 @@ +# *** MOCS-COPYRIGHT-NOTICE-BEGIN *** +# +# This copyright notice is auto-generated by ./add-copyright-notice. +# Additional copyright notices must be added below the last line of this notice. +# +# MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "Makefile.post". +# The content of this file is copyright of Saarland University - +# Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . +# +# This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). +# +# License: three-clause BSD style license. +# The license text can be found in the file LICENSE. +# +# *** MOCS-COPYRIGHT-NOTICE-END *** + +TARGETS=$(CCBINTARGETS) $(CBINTARGETS) $(LIBTARGETS) $(HSTARGETS) + +all: $(MODULEDEPS) $(TARGETS) $(HSMODULETARGETS) + +ifneq ($(ROOT),.) +clean: + rm -f $(HIS) $(OBJS) $(TARGETS) +else +clean: all +endif + +.PHONY: all clean $(MODULEDEPS) + +# Rules: + +$(MODULEDEPS): % : + $(MAKE) -C $(ROOT)/$@ $(MODULEDEPSTARGET) + +$(HSTARGETS): % : %.hs force + $(GHC) $(HSOPT) $(HSARGS) --make -o $@ $(CINCS) $(HSINCS) $(LIBPATH) $< $(LIBS) + +$(HSMODULETARGETS) : % : %.hs + $(GHC) $(HSARGS) $(HSOPT) $(CINCS) -c $< + + +$(CBINTARGETS): % : %.o + $(CC) $(COPT) $(CDEBUG) $(CINCS) $(LIBPATH) -o $@ $^ $(LIBS) + +$(CCBINTARGETS): % : %.o + $(CPP) $(COPT) $(CDEBUG) $(CINCS) $(LIBPATH) -o $@ $^ $(LIBS) + +.c.o: + $(CC) -c $(COPT) $(CDEBUG) $(CINCS) -o $@ $< + +.cc.o: + $(CPP) -c $(COPT) $(CDEBUG) $(CINCS) -o $@ $< + +%.a: $(OBJS) + ar r $@ $^ + +# Special targets +force: ; + +MoCSVersion.hs: + echo -e "module MoCSVersion where\n mocsVersion = \"$(VERSION)\"\n mocsRevision = \"$(REVISION)\"" > MoCSVersion.hs + + .INTERMEDIATE: MoCSVersion.hs + diff --git a/Makefile.pre b/Makefile.pre new file mode 100644 index 0000000..58a8821 --- /dev/null +++ b/Makefile.pre @@ -0,0 +1,64 @@ +# *** MOCS-COPYRIGHT-NOTICE-BEGIN *** +# +# This copyright notice is auto-generated by ./add-copyright-notice. +# Additional copyright notices must be added below the last line of this notice. +# +# MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "Makefile.pre". +# The content of this file is copyright of Saarland University - +# Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . +# +# This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). +# +# License: three-clause BSD style license. +# The license text can be found in the file LICENSE. +# +# *** MOCS-COPYRIGHT-NOTICE-END *** + +SHELL = /bin/bash + +include $(ROOT)/config.make + +.SUFFIXES: +.SUFFIXES: .c .o .a .cc .hh .tcc .hs .vhdl .h + +.DEFAULT_GOAL := all + +# Tools +CC:=gcc +CPP:=g++ +GHC:=ghc + +# Generic file lists +CCSRCS=$(wildcard *.cc) +HEADER=$(wildcard *.hh) $(wildcard *.h) +THEADER=$(wildcard *.tcc) +HSSRCS=$(wildcard *.hs) + +OBJS=$(CCSRCS:.cc=.o) $(HSSRCS:.hs=.o) +HIS=$(HSSRCS:.hs=.hi) + +# C-Icludes +CINCS=-I$(ROOT)/c-bindings -I$(ROOT)/libaaut + +# HS-includes +HSINCS=-i$(ROOT)/haskell-bindings -i$(ROOT)/haskell-frontend + +# library pathes +LIBPATH=-L$(ROOT)/libaaut -L$(ROOT)/c-bindings +LIBS=-laautc -laaut -lstdc++ + +# vpathes +vpath %.hs $(ROOT)/haskell-bindings:$(ROOT)/haskell-frontend:test + +vpath %._c.cc $(ROOT)/c-bindings +vpath %.h $(ROOT)/c-bindings +vpath %.hh $(ROOT)/libaaut +vpath %.cc $(ROOT)/libaaut:$(ROOT)/test +vpath %.c $(ROOT)/test + +vpath libaaut.a $(ROOT)/libaaut +vpath libaautc.a $(ROOT)/c-bindings + +vpath %.vhdl $(ROOT)/vhdl + +vpath %.hs $(ROOT)/haskell-bindings:$(ROOT)/haskell-frontend:$(ROOT)/test diff --git a/README b/README new file mode 100644 index 0000000..dfe4051 --- /dev/null +++ b/README @@ -0,0 +1,88 @@ +*** MOCS-COPYRIGHT-NOTICE-BEGIN *** + +This copyright notice is auto-generated by ./add-copyright-notice. +Additional copyright notices must be added below the last line of this notice. + +MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "README". +The content of this file is copyright of Saarland University - +Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . + +This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). + +License: three-clause BSD style license. +The license text can be found in the file LICENSE. + +*** MOCS-COPYRIGHT-NOTICE-END *** + +== OVERVIEW == + +MoCS -- Monitor Circuits Synthesis for PSL specifications + +MoCS synthesies monitor circuits from linear time temporal logic +specifications. The input logic is similar to PSL by allowing nesting of +regular expressions within temporal modalities. The output of MoCS is a +synthesizable VHDL description of the monitor circuit. The resulting monitors +implement truncated path semantics. On sequentially reading an input trace a +monitor outputs at each input position whether the current prefix of the trace +satisfies the monitored property. MoCS is particularly careful about generating +small monitors form specifications containing sub-properties of bounded +temporal scope. + +Reference: Bernd Finkbeiner and Lars Kuhtz. Monitor Circuits for LTL with +Bounded and Unbounded Future. Proceedings of RV 09, LNCS 5779, 2009. + +Author: Lars Kuhtz + +IMPORTANT NOTE: + +Please note that MoCS is still prototypic phase. Not all operators are +supported in all contexts yet. This is not due to limitations of the approach +but to missing bits in the implementation. If you rely on such a missing bit +please let us know. Simliar statement holds for the technical quality of the +generated VHDL Model. + +== INSTALLATION FROM SOURCE == + +1. Edit the file config.make + +2. To build everything run: + + make all + +== USAGE == + +MoCS [--ouput FILE] FILE +MoCS [--output FILE] --formula STRING +MoCS [--output FILE]" +MoCS --help +MoCS --version + +Syntax for a formulas: + +-------------------------------------------------------------------------------- +Formula ::= '(' Formula ')' | RegEx | '\strong' Regex + | PrefixOp Formula | BPrefixOp BoundExpr Formula + | Formula BinaryOp Formula | Formula BBinaryOp BoundExpr Formula + | Formula '\abort' Prop | RegEx '\simplies' Formula + +PrefixOp ::= '\not' | '\N' | '\wN' | '\G' | '\F' +BPreifxOp ::= '\BN' | '\wBN' | '\BG' | '\BF' | '\sBG' | '\wBF' + +BinaryOp ::= '\and' | '\or' | '\implies' | '\equiv' | '\U' | '\W' | '\R' | '\sR' +BBinaryOp ::= '\BU' | '\BR' | '\BW' | '\SBR' + +Prop ::= '(' Prop ')' | Var | 'true' | 'false' | '-' Prop + | Prop '+' Prop | Prop '^' Prop + +RegEx ::= '(' RegEx ')' | Prop | 'epsilon' + | RegEx '&&' RegEx | RegEx '|' RegEx | RegEx ':' RegEx | RegEx ';' RegEx + | RegEx '*' | RegEx '[' Ordinal ']' + +Var ::= "[_a-zA-Z][_a-zA-Z0-9]*" + +BoundExpr ::= '(' BoundExpr ')' | Ordinal + | BoundExpr '*' BoundExpr | '-' BoundExpr | BoundExpr '++' + +Ordinal ::= [0-9]+ | 'infty'" +-------------------------------------------------------------------------------- + diff --git a/add-copyright-notice b/add-copyright-notice new file mode 100755 index 0000000..42dcf45 --- /dev/null +++ b/add-copyright-notice @@ -0,0 +1,357 @@ +#!/bin/bash + +# *** MOCS-COPYRIGHT-NOTICE-BEGIN *** +# +# This copyright notice is auto-generated by ./add-copyright-notice. +# Additional copyright notices must be added below the last line of this notice. +# +# MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "add-copyright-notice". +# The content of this file is copyright of Saarland University - +# Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . +# +# This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). +# +# License: three-clause BSD style license. +# The license text can be found in the file LICENSE. +# +# *** MOCS-COPYRIGHT-NOTICE-END *** + +# TODO: Move comment-syntax definitions into Configuration section + +# Usage: See usagestring variable defined below. +# +# Check the pattern below in order to make sure that they match +# the files in your project. +# +# WARNING WARNING WARNING: +# make a backup first (or better: run on a clean working copy). +# Things _will not_ work on the first try! + +# NOTE: If you edit this file make sure that the string "copy-right" without +# the hyphen does not occur neither literaly nor with any character converted +# to upper case. Use the variables $COPYR or $CCOPYR instead: + +COPYR="copy""right" +CCOPYR="Copy""right" + +################################################################################ +# Configuration Section +################################################################################ +# General Configuration Settings + +skip_unknown=true + +# please fill out or specify on the command line +tool=MoCS +url=https://lewis.cs.uni-saarland.de/tools/mocs/ +year=2009 + +# copyrholder= +copyrholder="Saarland University" +# holderaddr= +holderaddr="Reactive Systems Group, Lars Kuhtz " + +# choose a license by uncommenting one of the following lines +# license="binaryrestricted" +# license="gpl3" +license="bsd3" +# license="bsd2" + +################################################################################ +# Check dependencies +declare -A testarray || { + echo "ERROR: in order to run this program you need a version of Bash that supports associative arrays (e.g. Bash version 4.0)." >&2 ; + exit 1; +} + +[ `hg version | head -n 1 | sed -n -e 's/^.*(version \([0-9]\{1,2\}\).*$/\1/p'` -ge '2' ] || { + echo "ERROR: in order to run this program you need mercurial (hg) of version at least 2.0." >&2 ; + exit 1; +} + +sed --version 2>&1 | head -n 1 | grep -q '^GNU' || { + echo "Error: in order to run this program you need the GNU version of sed." >&2 ; + exit 1; +} + +################################################################################ +# Patterns (edit according to the needs of your project) + +# Blacklist for files that do not deserve a copy-right notice +BL='(^doxyconfig$)|(docbooksrc/.*\.(pl|dsl|xsl|dtd|cfg)$)|(test/.*/output/.*$)|(^.hgempty$)|(^\.hgsigs$)|(^\.hgtags)|(^dist/.*)|(TODO)|(LICENSE)|(^results/.*)' + +# Files that contain the term copy-right (without hyphen, either upper or lower case) and have not a third party copy-right. +THIRDPARTYBL='(^.*\.cabal$)' + +# patterns to match on file name +CC='(\.cxx|\.txx|\.hxx|\.h|\.c|\.c0|\.hpp|\.cc|\.tcc|\.hh)$' +TEX='(\.tex)$' +SHELL='((\.sh|\.pl)$)|(/?Makefile)' +XML='(\.xml|\.xsl|\.html|\.xsd|\.docbook)$' +PYTHON='(\.py)$' +VD='(\.vd|\.abs|\.cfg)$' +LTL='(\.ltl|\.tltl)$' +DSL='\.dsl$' +PRED='\.pred$' +TXT='(\.txt$)|(test/.*/.*\.log$)' +HS='(\.hs)$' +VHDL='(\.vhdl)$' +CABAL='(\.cabal)$' +CSS='(\.css)$' + +# patterns to match on result of file -b +F_SHELL='^Bourne.*shell' +F_CC='^ASCII C program text' +F_BINARY='^ELF.* executable' + +# explicit mapping for files that do not match a pattern +declare -A extra +extra=( + [.hgignore]='SHELL' + [.config/functions]='SHELL' + [add-$COPYR-notice]='SHELL' + [configure]='SHELL' + [config.make]='SHELL' + [README]='TXT' + [INSTALL]='TXT' + [TODO]='TXT' + [formulas/12-formulas.txt]='LTL' + [Setup.lhs]='HS' +) + +################################################################################ +# End of Configuration Section +################################################################################ +# Main Loop + +# command line takes precedence +# FIXME use options here. +# Provide the possiblity to specify only some of the parameters. +if [ $# -ge 3 ] ; then + tool=$1; shift + url=$1; shift + year=$1; shift +fi + +usagestring="Usage: $0 [ ] []" + +# check for correct number of arguments (0, 1, 3, or 4) +if [[ $# -gt 1 ]] ; then + echo "ERROR: illegal number of parameters" + echo "$usagestring" + exit 1 +fi + +# check if everything we need was specified +if [[ -z "$tool" || -z "$url" || -z "$year" ]] ; then + echo "ERROR: please specify and " + echo " either by editing $0 or on the command line." + echo "$usagestring" + exit 1 +fi + +# we need to prevent word-spliting to be save on file names with spaces. +IFS=' +' + +# Get the list of files to work on (newline separated array!) +if [ -n "$1" ] ; then + echo "Run on single file: $1" + files=( $1 ) +else + echo "Run on all project files (listed by 'hg manifest')." + files=( `hg manifest` ) + echo "Number of files: ${#files[@]}." +fi + +# Define some invariant variables +function upper() { echo $@ | tr [a-z] [A-Z]; } +utool=`upper $tool` +NOTEB="$utool-COPY""RIGHT-NOTICE""-BEGIN" # split it in order to avoid matching when running on it self +NOTEE="$utool-COPY""RIGHT-NOTICE""-END" + +# Loop on files +for file in "${files[@]}" ; do + +################################################################################ +# sanity checkes for file + +if [ ! -f "$file" ] ; then + echo "ERROR: $file is not a regular file" + continue +fi + +if [ ! -w "$file" ] ; then + echo "ERROR: $file can not be written" + continue +fi + +################################################################################ +# Blacklisting and detection of 3. party copy-right + +# Check for 3. party copy-right notice +# FIXME: we definitely want something more sofisticated here +if [[ ! "$file" =~ $THIRDPARTYBL ]] && grep -q -i -e "$COPYR" "$file" && ! grep -q -i -e "$NOTEB" "$file" ; then + echo "$file: third party $COPYR" + continue +fi + +# check blacklist +if [[ "$file" =~ $BL ]] ; then + echo "$file: blacklisted" + continue +fi + +################################################################################ +# detect comment style + +# give file a try +type=`file -b "$file"` + +# techincal stuff +function check() +{ + p=${!1} + qvar="F_$1" + q=${!qvar} + [[ "${extra[$file]}" == "$1" || -z "${extra[$file]}" && ( -n "$p" && "$file" =~ $p ) || ( -n "$q" && "$type" =~ $q ) ]] +} + +CS='' +C='' +CE='' +function use() +{ + echo "$file: type $1" + CS=$2 + C=$3 + CE=$4 +} + +# comment syntax for the file types: comment start (CC), comment line start (C), comment end (CE) +if check 'CC' ; then use 'CC' '/* ' ' * ' '*/'; +elif check 'CSS' ; then use 'CSS' '/* ' ' * ' '*/'; +elif check 'TEX' ; then use 'TEX' '% ' '% ' ''; +elif check 'SHELL' ; then use 'SHELL' '# ' '# ' ''; +elif check 'XML' ; then use 'XML' ''; +elif check 'PYTHON' ; then use 'PYTHON' '# ' '# ' ''; +elif check 'VD' ; then use 'VD' '// ' '// ' ''; +elif check 'PRED' ; then use 'PRED' '// ' '// ' ''; +elif check 'DSL' ; then use 'DSL' '; ' '; ' ''; +elif check 'TXT' ; then use 'TXT' '' '' ''; +elif check 'HS' ; then use 'HS' '{- ' ' - ' '-}'; +elif check 'LTL' ; then use 'LTL' '-- ' '-- ' ''; +elif check 'VHDL' ; then use 'VHDL' '-- ' '-- ' ''; +elif check 'CABAL' ; then use 'CABAL' '-- ' '-- ' ''; +elif check 'BINARY'; then + echo "$file: type binary" + continue +else + echo "$file: type unknown" + [ -n "$skip_unknown" ] && continue + CS=''; C=''; CE='' +fi + +################################################################################ +# copy-right notice + +# the copy-right notice formated to be used with sed (binaryrestricted version) +restrictedtext="\ +${CS}*** $NOTEB ***\\ +${C}\\ +${C}This $COPYR notice is auto-generated by $0.\\ +${C}Additional $COPYR notices must be added below the last line of this notice.\\ +${C}\\ +${C}$tool ($url): \\\"$file\\\".\\ +${C}The content of this file is $COPYR of $copyrholder -\\ +${C}$CCOPYR (C) $year $copyrholder, $holderaddr.\\ +${C}All rights reserved.\\ +${C}\\ +${C}License information can be found in the file LICENSE.\\ +${C}\\ +${C}*** $NOTEE *** $CE\\ + +" + +# the copy-right notice formated to be used with sed (BSD2 version) +bsd2text="\ +${CS}*** $NOTEB ***\\ +${C}\\ +${C}This $COPYR notice is auto-generated by $0.\\ +${C}Additional $COPYR notices must be added below the last line of this notice.\\ +${C}\\ +${C}$tool ($url): \\\"$file\\\".\\ +${C}The content of this file is $COPYR of $copyrholder -\\ +${C}$CCOPYR (C) $year $copyrholder, $holderaddr.\\ +${C}\\ +${C}This file is part of $tool ($url).\\ +${C}\\ +${C}License: two-clause BSD style license.\\ +${C}The license text can be found in the file LICENSE.\\ +${C}\\ +${C}*** $NOTEE *** $CE\\ + +" + +# the copy-right notice formated to be used with sed (BSD3 version) +bsd3text="\ +${CS}*** $NOTEB ***\\ +${C}\\ +${C}This $COPYR notice is auto-generated by $0.\\ +${C}Additional $COPYR notices must be added below the last line of this notice.\\ +${C}\\ +${C}$tool ($url): \\\"$file\\\".\\ +${C}The content of this file is $COPYR of $copyrholder -\\ +${C}$CCOPYR (C) $year $copyrholder, $holderaddr.\\ +${C}\\ +${C}This file is part of $tool ($url).\\ +${C}\\ +${C}License: three-clause BSD style license.\\ +${C}The license text can be found in the file LICENSE.\\ +${C}\\ +${C}*** $NOTEE *** $CE\\ + +" + +case "$license" in +binaryrestricted) text="$restrictedtext";; +gpl3) text="$gpl3text";; +bsd2) text="$bsd2text";; +bsd3) text="$bsd3text";; +*) echo "unknown LICENSE type" && exit 1;; +esac + + +################################################################################ +# insert notice + +# Check for existing copy-right notice +if grep -q -i -e "$NOTEB" "$file" ; then + echo "$file: replace $COPYR" + sed -i -e "/$NOTEB/a $text + /$NOTEB/,/$NOTEE/d" "$file" +else + + fl=`head -n 1 "$file"` + xml_pat='^ *<\?(xml|XML).*\?> *$' + shell_pat='^ *#\!' + if [[ ("$fl" =~ $xml_pat) || ("$fl" =~ $shell_pat) ]] ; then + echo "$file: new $COPYR (first line preserved)" + sed -i -e "1{a \\ + +a $text}" "$file" + else + echo "$file: new $COPYR" + sed -i -e "1{x;i $text ;G}" "$file" + fi +fi + +# Make sure there is exactly one blank line after the notice +sed -i -n -e "/$NOTEE/{p;: lab; n;s/^\\s*$/&/;t lab;i \\ + +};p" "$file" + +# trim trailing white space in copy-right notice +sed -i -e "/$NOTEB/,/$NOTEE/s/\\s*$//" "$file" + +done diff --git a/c-bindings/Makefile b/c-bindings/Makefile new file mode 100644 index 0000000..c3f526b --- /dev/null +++ b/c-bindings/Makefile @@ -0,0 +1,32 @@ +# *** MOCS-COPYRIGHT-NOTICE-BEGIN *** +# +# This copyright notice is auto-generated by ./add-copyright-notice. +# Additional copyright notices must be added below the last line of this notice. +# +# MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "c-bindings/Makefile". +# The content of this file is copyright of Saarland University - +# Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . +# +# This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). +# +# License: three-clause BSD style license. +# The license text can be found in the file LICENSE. +# +# *** MOCS-COPYRIGHT-NOTICE-END *** + +ROOT=.. + +include $(ROOT)/Makefile.pre + +MODULEDEPS=libaaut +LIBTARGETS=libaautc.a + +LIBAAUTSCRS=$(wildcard $(ROOT)/libaaut/*.hh) $(wildcard $(ROOT)/libaaut/*.tcc) $(wildcard $(ROOT)/libaaut/*.cc) $(ROOT)/libaaut/config.h + +# deps +aa_c.o : aa_c.cc aa.h expr.h context.h $(LIBAAUTSCRS) +expr_c.o: expr_c.cc expr.h context.h $(LIBAAUTSCRS) +context_c.o: context_c.cc context.h $(LIBAAUTSCRS) +sm_c.o: sm_c.cc aa.h expr.h context.h $(LIBAAUTSCRS) + +include $(ROOT)/Makefile.post diff --git a/c-bindings/aa.h b/c-bindings/aa.h new file mode 100644 index 0000000..d2ee9a7 --- /dev/null +++ b/c-bindings/aa.h @@ -0,0 +1,144 @@ +/* *** MOCS-COPYRIGHT-NOTICE-BEGIN *** + * + * This copyright notice is auto-generated by ./add-copyright-notice. + * Additional copyright notices must be added below the last line of this notice. + * + * MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "c-bindings/aa.h". + * The content of this file is copyright of Saarland University - + * Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . + * + * This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). + * + * License: three-clause BSD style license. + * The license text can be found in the file LICENSE. + * + * *** MOCS-COPYRIGHT-NOTICE-END *** */ + +#ifndef _AA_H_ +#define _AA_H_ + +#include "context.h" +#include "expr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// incomplete. Pure pointer-interface. +struct automaton_t; +typedef struct automaton_t* automaton_ptr; + +// constructors/ destructors +void free_automaton(automaton_ptr a); + +// Get Context +context_ptr get_aut_context(automaton_ptr a); + +// SImplies +// precondition: a is nondeterministic +automaton_ptr simplies_aut(const automaton_ptr a, const automaton_ptr b); + +// Abort +automaton_ptr abort_aut(const automaton_ptr a, const automaton_ptr b); + +// Concatenation +// precondition: a is nondeterministic +automaton_ptr conc_aut(const automaton_ptr a, const automaton_ptr b); + +// Overlapping Concatenation +// precondition: a is nondeterministic +automaton_ptr oconc_aut(const automaton_ptr a, const automaton_ptr b); + +// Kleene-Closure +// precondition: a is nondeterministic +automaton_ptr kleene_aut(const automaton_ptr a); + +// Union +automaton_ptr union_aut(const automaton_ptr a, const automaton_ptr b); + +// Empty +automaton_ptr empty_aut(context_ptr c); + +// Proposition +automaton_ptr prop_aut(context_ptr c, const c_prop_t p, int dim); + +// Negated Proposition +automaton_ptr nprop_aut(context_ptr c, const c_prop_t p, int dim); + +// Constant +automaton_ptr const_aut(context_ptr c, int p); + +// Conjunction +automaton_ptr and_aut(const automaton_ptr a, const automaton_ptr b); + +// Disjunction +automaton_ptr or_aut(const automaton_ptr a, const automaton_ptr b); + +// Negation (dualization) +automaton_ptr dual_aut(const automaton_ptr a); + +// Implication +automaton_ptr implies_aut(const automaton_ptr a, const automaton_ptr b); + +// Next +automaton_ptr next_aut(const automaton_ptr a); +automaton_ptr bnext_aut(int i, const automaton_ptr a); + +automaton_ptr wnext_aut(const automaton_ptr a); +automaton_ptr bwnext_aut(int i, const automaton_ptr a); + +// Globally +automaton_ptr g_aut(const automaton_ptr a); +automaton_ptr bg_aut(int i, const automaton_ptr a); +automaton_ptr strong_bg_aut(int i, const automaton_ptr a); + +// Eventually +automaton_ptr f_aut(const automaton_ptr a); +automaton_ptr bf_aut(int i, const automaton_ptr a); +automaton_ptr weak_bf_aut(int i, const automaton_ptr a); + +// Until +automaton_ptr until_aut(const automaton_ptr a,const automaton_ptr b); +automaton_ptr buntil_aut(int i, const automaton_ptr a,const automaton_ptr b); + +automaton_ptr waitfor_aut(const automaton_ptr a,const automaton_ptr b); +automaton_ptr bwaitfor_aut(int i, const automaton_ptr a,const automaton_ptr b); + +// Release +automaton_ptr release_aut(const automaton_ptr a,const automaton_ptr b); +automaton_ptr brelease_aut(int i, const automaton_ptr a,const automaton_ptr b); + +automaton_ptr strong_release_aut(const automaton_ptr a,const automaton_ptr b); +automaton_ptr strong_brelease_aut(int i, const automaton_ptr a,const automaton_ptr b); + +// make weak +automaton_ptr weak_aut(const automaton_ptr a); + +// Universalization +automaton_ptr universal_aut(const automaton_ptr a); + +// Rollout +// returns null-terminated array of expression_ptr +expr_ptr* aut_suffix_rollout(const automaton_ptr a, int b); + +// prefix-rollout (the expression is build within a new context) +expr_ptr aut_prefix_rollout(const automaton_ptr a, int b); + +// TODO move this into vhdl.h +void vhdl_build_monitor(const char* file_name, + int b, + int pc, + int sc, + expr_ptr po, // prefix automaton output expr + automaton_ptr pa, // prefix automaton + expr_ptr**); // array of array of suffix output expr + +// pretty-printing +void automaton2dot(const char* file_name, const automaton_ptr a, const char* name); + +#ifdef __cplusplus +} +#endif + +#endif // _AA_H_ + diff --git a/c-bindings/aa_c.cc b/c-bindings/aa_c.cc new file mode 100644 index 0000000..c875087 --- /dev/null +++ b/c-bindings/aa_c.cc @@ -0,0 +1,298 @@ +/* *** MOCS-COPYRIGHT-NOTICE-BEGIN *** + * + * This copyright notice is auto-generated by ./add-copyright-notice. + * Additional copyright notices must be added below the last line of this notice. + * + * MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "c-bindings/aa_c.cc". + * The content of this file is copyright of Saarland University - + * Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . + * + * This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). + * + * License: three-clause BSD style license. + * The license text can be found in the file LICENSE. + * + * *** MOCS-COPYRIGHT-NOTICE-END *** */ + +#include + +#include "aa.hh" +#include "vhdl.hh" + +#include "aa.h" + +namespace +{ + std::vector mk_cpp_prop(const c_prop_t p, long dim) + { + std::vector ret(dim); + for (int i = 0; i < dim; ++i) ret[i] = p[i]; + return ret; + } + +}; + +using namespace c::context; + +// constructors/ destructors +void free_automaton(automaton_ptr a) +{ + delete a; +} + +// Get Context +context_ptr get_aut_context(automaton_ptr a) +{ + return new context_t(a->init->efac()); +} + +// SImplies +automaton_ptr simplies_aut(const automaton_ptr a, const automaton_ptr b) +{ + return new automaton_t(simplies_aut(*a,*b)); +} + +// Abort +automaton_ptr abort_aut(const automaton_ptr a, const automaton_ptr b) +{ + return new automaton_t(abort_aut(*a,*b)); +} + +// Concatenation +automaton_ptr conc_aut(const automaton_ptr a, const automaton_ptr b) +{ + return new automaton_t(conc_aut(*a,*b)); +} + +// Overlapping Concatenation +automaton_ptr oconc_aut(const automaton_ptr a, const automaton_ptr b) +{ + return new automaton_t(oconc_aut(*a,*b)); +} + +// Kleene-Closure +automaton_ptr kleene_aut(const automaton_ptr a) +{ + return new automaton_t(kleene_aut(*a)); +} + +// Union +automaton_ptr union_aut(const automaton_ptr a, const automaton_ptr b) +{ + return new automaton_t(union_aut(*a,*b)); +} + +// Empty +automaton_ptr empty_aut(context_ptr c) +{ + return new automaton_t(empty_aut(c->impl)); +} + +// Proposition +automaton_ptr prop_aut(context_ptr c, const c_prop_t p, int dim) +{ + return new automaton_t(prop_aut(c->impl, mk_cpp_prop(p,dim))); +} + +// Negated Proposition +automaton_ptr nprop_aut(context_ptr c, const c_prop_t p, int dim) +{ + return new automaton_t(nprop_aut(c->impl, mk_cpp_prop(p,dim))); +} + +// Constant +automaton_ptr const_aut(context_ptr c, int p) +{ + return new automaton_t(const_aut(c->impl,(bool) p)); +} + +// Conjunction +automaton_ptr and_aut(const automaton_ptr a, const automaton_ptr b) +{ + return new automaton_t(*a && *b); +} + +// Disjunction +automaton_ptr or_aut(const automaton_ptr a, const automaton_ptr b) +{ + return new automaton_t(*a || *b); +} + +// Negation (dualization) +automaton_ptr dual_aut(const automaton_ptr a) +{ + return new automaton_t(~ *a); +} + +// Implication +automaton_ptr implies_aut(const automaton_ptr a, const automaton_ptr b) +{ + return new automaton_t(*a >> *b); +} + + +// Next +automaton_ptr next_aut(const automaton_ptr a) +{ + return new automaton_t(next_aut(*a)); +} + +automaton_ptr bnext_aut(int i, const automaton_ptr a) +{ + return new automaton_t(next_aut(i,*a)); +} + +automaton_ptr wnext_aut(const automaton_ptr a) +{ + return new automaton_t(wnext_aut(*a)); +} + +automaton_ptr bwnext_aut(int i, const automaton_ptr a) +{ + return new automaton_t(wnext_aut(i,*a)); +} + + +// Globally +automaton_ptr g_aut(const automaton_ptr a) +{ + return new automaton_t(g_aut(*a)); +} +automaton_ptr bg_aut(int i, const automaton_ptr a) +{ + return new automaton_t(g_aut(i,*a)); +} +automaton_ptr strong_bg_aut(int i, const automaton_ptr a) +{ + return new automaton_t(strong_g_aut(i,*a)); +} + +// Eventually +automaton_ptr f_aut(const automaton_ptr a) +{ + return new automaton_t(f_aut(*a)); +} +automaton_ptr bf_aut(int i, const automaton_ptr a) +{ + return new automaton_t(f_aut(i,*a)); +} +automaton_ptr weak_bf_aut(int i, const automaton_ptr a) +{ + return new automaton_t(weak_f_aut(i,*a)); +} + +// Until +automaton_ptr until_aut(const automaton_ptr a,const automaton_ptr b) +{ + return new automaton_t(until_aut(*a,*b)); +} + +automaton_ptr buntil_aut(int i, const automaton_ptr a,const automaton_ptr b) +{ + return new automaton_t(until_aut(i,*a,*b)); +} + +automaton_ptr waitfor_aut(const automaton_ptr a,const automaton_ptr b) +{ + return new automaton_t(waitfor_aut(*a,*b)); +} + +automaton_ptr bwaitfor_aut(int i, const automaton_ptr a,const automaton_ptr b) +{ + return new automaton_t(waitfor_aut(i,*a,*b)); +} + + +// Release +automaton_ptr release_aut(const automaton_ptr a,const automaton_ptr b) +{ + return new automaton_t(release_aut(*a,*b)); +} + +automaton_ptr brelease_aut(int i, const automaton_ptr a,const automaton_ptr b) +{ + return new automaton_t(release_aut(i,*a,*b)); +} + +automaton_ptr strong_release_aut(const automaton_ptr a,const automaton_ptr b) +{ + return new automaton_t(strong_release_aut(*a,*b)); +} + +automaton_ptr strong_brelease_aut(int i, const automaton_ptr a,const automaton_ptr b) +{ + return new automaton_t(strong_release_aut(i,*a,*b)); +} + +// make weak +automaton_ptr weak_aut(const automaton_ptr a) +{ + return new automaton_t(weak_aut(*a)); +} + +// Universalization +automaton_ptr universal_aut(const automaton_ptr a) +{ + return new automaton_t(universal_aut(*a)); +} + +// Rollout +//template +//context_t suffix_rollout(const automaton_t&, int, std::back_insert_iterator); +// returns null-terminated array of expression_ptr +expr_ptr* aut_suffix_rollout(const automaton_ptr a, int b) +{ + std::list l; + suffix_rollout(*a,b,std::back_inserter(l)); + expr_ptr* res = (expr_ptr*) malloc((sizeof(expr_ptr) * (l.size() + 1))); + int i = 0; + foreach(const expr_t& e, l) { + res[i++] = new expr_t(e); + } + res[i] = 0; + return res; +} + + +expr_ptr aut_prefix_rollout(const automaton_ptr a, int b) +{ + return new expr_t(prefix_rollout(*a,b).first); +} + +// pretty-printing +void automaton2dot(const char* file_name, const automaton_ptr a, const char* name) +{ + std::ofstream file(file_name); + if (file) { + automaton2dot(file,*a,name); + } else { + std::cerr << "Error: Failed to open file for writing." << std::endl; + } +} + + +void vhdl_build_monitor(const char* file_name, + int b, + int pc, + int sc, + expr_ptr po, // prefix automaton output expr + automaton_ptr pa, // prefix automaton + expr_ptr** so) // array of array of suffix output expr +{ + std::ofstream file(file_name); + if (file) { + std::list > ll; + while(*so) { + std::list l; + expr_ptr* e = *so++; + while (*e) { + l.push_back(**e++); + } + ll.push_back(l); + } + vhdl::monitor(file,b,pc,sc,*po,*pa,ll); + } else { + std::cerr << "Error: Failed to open file " << file_name << " for writing." << std::endl; + } +} + diff --git a/c-bindings/context.h b/c-bindings/context.h new file mode 100644 index 0000000..7d004c2 --- /dev/null +++ b/c-bindings/context.h @@ -0,0 +1,55 @@ +/* *** MOCS-COPYRIGHT-NOTICE-BEGIN *** + * + * This copyright notice is auto-generated by ./add-copyright-notice. + * Additional copyright notices must be added below the last line of this notice. + * + * MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "c-bindings/context.h". + * The content of this file is copyright of Saarland University - + * Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . + * + * This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). + * + * License: three-clause BSD style license. + * The license text can be found in the file LICENSE. + * + * *** MOCS-COPYRIGHT-NOTICE-END *** */ + +#ifndef _CONTEXT_H_ +#define _CONTEXT_H_ + +#ifdef __cplusplus +#include "expr.hh" +namespace c { namespace context +{ + struct context_t + { + context_t(efac_ptr e) : impl(e) {} + efac_ptr impl; + }; + +}; }; +#else +struct context_t; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus +typedef struct c::context::context_t* context_ptr; +#else +typedef struct context_t* context_ptr; +#endif + +// constructors/ destructors +context_ptr new_context(); +void free_context(context_ptr); + +int context_size(const context_ptr); + +#ifdef __cplusplus +} +#endif + +#endif // _CONTEXT_H_ diff --git a/c-bindings/context_c.cc b/c-bindings/context_c.cc new file mode 100644 index 0000000..96a92ea --- /dev/null +++ b/c-bindings/context_c.cc @@ -0,0 +1,35 @@ +/* *** MOCS-COPYRIGHT-NOTICE-BEGIN *** + * + * This copyright notice is auto-generated by ./add-copyright-notice. + * Additional copyright notices must be added below the last line of this notice. + * + * MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "c-bindings/context_c.cc". + * The content of this file is copyright of Saarland University - + * Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . + * + * This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). + * + * License: three-clause BSD style license. + * The license text can be found in the file LICENSE. + * + * *** MOCS-COPYRIGHT-NOTICE-END *** */ + +#include "context.h" + +using namespace c::context; + +// constructors/ destructors +context_ptr new_context() +{ + return new context_t(efac::newEfac()); +} + +void free_context(context_ptr e) +{ + delete e; +} + +int context_size(const context_ptr e) +{ + return e->impl->size(); +} diff --git a/c-bindings/expr.h b/c-bindings/expr.h new file mode 100644 index 0000000..d45b482 --- /dev/null +++ b/c-bindings/expr.h @@ -0,0 +1,67 @@ +/* *** MOCS-COPYRIGHT-NOTICE-BEGIN *** + * + * This copyright notice is auto-generated by ./add-copyright-notice. + * Additional copyright notices must be added below the last line of this notice. + * + * MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "c-bindings/expr.h". + * The content of this file is copyright of Saarland University - + * Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . + * + * This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). + * + * License: three-clause BSD style license. + * The license text can be found in the file LICENSE. + * + * *** MOCS-COPYRIGHT-NOTICE-END *** */ + +#ifndef _EXPR_H_ +#define _EXPR_H_ + +#include "context.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef long* c_prop_t; // should be an array/ vector + +// incomplete. Pure pointer-interface. +struct expr_t; +typedef struct expr_t* expr_ptr; + +// constructors/ destructors +// expr_ptr expr_new(); +void expr_free(expr_ptr); + +// copy expression into traget_context +expr_ptr copy(const expr_ptr, context_ptr target_context); + +// printing +void expr_expr2dot(const char* file_name, const expr_ptr, const char* name); +char* expr_exprs2dot(const char* file_name, const expr_ptr*,int dim, const char* name); +char* expr_exprs2dot_(const char* file_name, const expr_ptr*, const char* name); // null-terminated +char* expr_to_string(const expr_ptr); + +// comparing +int expr_eq(const expr_ptr, const expr_ptr); + +// querying +int expr_is_false(const expr_ptr); +int expr_is_true(const expr_ptr); +context_ptr expr_get_context(const expr_ptr); +//expr_ptr* expr_get_childreen(const expr_ptr); // returns null-terminated array +// TODO query type and content + +int expr_size(const expr_ptr); +int exprs_size(const expr_ptr*); // null-terminated + +// manipulation +expr_ptr expr_and(const expr_ptr,const expr_ptr); +expr_ptr expr_or(const expr_ptr,const expr_ptr); +// TODO missing generators (from efac) + +#ifdef __cplusplus +} +#endif + +#endif // _EXPR_H_ diff --git a/c-bindings/expr_c.cc b/c-bindings/expr_c.cc new file mode 100644 index 0000000..187abb3 --- /dev/null +++ b/c-bindings/expr_c.cc @@ -0,0 +1,128 @@ +/* *** MOCS-COPYRIGHT-NOTICE-BEGIN *** + * + * This copyright notice is auto-generated by ./add-copyright-notice. + * Additional copyright notices must be added below the last line of this notice. + * + * MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "c-bindings/expr_c.cc". + * The content of this file is copyright of Saarland University - + * Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . + * + * This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). + * + * License: three-clause BSD style license. + * The license text can be found in the file LICENSE. + * + * *** MOCS-COPYRIGHT-NOTICE-END *** */ + +#include "expr.h" + +#include "expr.hh" + +#include +#include + + +// constructors/ destructors +// expr_ptr expr_new(); +void expr_free(expr_ptr e) +{ + delete e; +} + +// printing +void expr_expr2dot(const char* file_name, const expr_ptr e, const char* name) +{ + std::ofstream file(file_name); + if (file) { + expr2dot(file,*e,name); + } else { + std::cerr << "Error: Failed to open file for writing." << std::endl; + } +} + +char* expr_exprs2dot(const char* file_name, const expr_ptr* e,int dim, const char* name) +{ + std::ofstream file(file_name); + if (file) { + std::list l; + const expr_ptr* ptr = e; + for(int i = 0; i++; i < dim) { + l.push_back(**e++); + } + exprs2dot(file,l,name); + } else { + std::cerr << "Error: Failed to open file for writing." << std::endl; + } +} + +char* expr_exprs2dot_(const char* file_name, const expr_ptr* e, const char* name) // null-terminated +{ + std::ofstream file(file_name); + if (file) { + std::list l; + const expr_ptr* ptr = e; + while (*e) { + l.push_back(**e++); + } + exprs2dot(file,l,name); + } else { + std::cerr << "Error: Failed to open file for writing." << std::endl; + } +} + +char* expr_to_string(const expr_ptr e) +{ + std::ostringstream s; + s << *e; + char* ret = (char*) malloc(sizeof(char) * (s.str().size() + 1)); + return strcpy(ret,s.str().c_str()); +} + +// copy +expr_ptr copy(const expr_ptr e, context_ptr target_context) +{ + return new expr_t(target_context->impl->copy(*e)); +} + +// comparing +int expr_eq(const expr_ptr e0, const expr_ptr e1) { return *e0 == *e1; } + +// querying +int expr_is_false(const expr_ptr e) { return e->is_false(); } +int expr_is_true(const expr_ptr e) { return e->is_true(); } + +context_ptr expr_get_context(expr_ptr e) +{ + return new c::context::context_t(e->efac()); +} + +//expr_ptr* expr_get_childreen(const expr_ptr); // returns null-terminated array +// TODO query type and content + +int expr_size(const expr_ptr e) +{ + return e->size(); +} + +int exprs_size(const expr_ptr* e) // null-terminated +{ + std::list l; + const expr_ptr* ptr = e; + while (e) { + l.push_back(**e++); + } + return size(l); +} + +// manipulation +expr_ptr expr_and(const expr_ptr e0,const expr_ptr e1) +{ + return new expr_t(*e0 && *e1); +} + +expr_ptr expr_or(const expr_ptr e0,const expr_ptr e1) +{ + return new expr_t(*e0 || *e1); +} + +// TODO missing generators (from efac) diff --git a/c-bindings/sm.h b/c-bindings/sm.h new file mode 100644 index 0000000..065fe7e --- /dev/null +++ b/c-bindings/sm.h @@ -0,0 +1,47 @@ +/* *** MOCS-COPYRIGHT-NOTICE-BEGIN *** + * + * This copyright notice is auto-generated by ./add-copyright-notice. + * Additional copyright notices must be added below the last line of this notice. + * + * MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "c-bindings/sm.h". + * The content of this file is copyright of Saarland University - + * Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . + * + * This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). + * + * License: three-clause BSD style license. + * The license text can be found in the file LICENSE. + * + * *** MOCS-COPYRIGHT-NOTICE-END *** */ + +#ifndef _SM_H_ +#define _SM_H_ + +#include "context.h" +#include "expr.h" +#include "aa.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// incomplete. Pure pointer-interface. +struct state_machine_t; +typedef struct state_machine_t* state_machine_ptr; + +// constructors/ destructors +state_machine_ptr mk_state_machine(automaton_ptr a); +void free_state_machine(state_machine_ptr a); + +// Get Context +context_ptr get_sm_context(state_machine_ptr a); + +// pretty-printing +void state_machine2dot(const char* file_name, const state_machine_ptr a, const char* name); + +#ifdef __cplusplus +} +#endif + +#endif // _SM_H_ + diff --git a/c-bindings/sm_c.cc b/c-bindings/sm_c.cc new file mode 100644 index 0000000..331142e --- /dev/null +++ b/c-bindings/sm_c.cc @@ -0,0 +1,54 @@ +/* *** MOCS-COPYRIGHT-NOTICE-BEGIN *** + * + * This copyright notice is auto-generated by ./add-copyright-notice. + * Additional copyright notices must be added below the last line of this notice. + * + * MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "c-bindings/sm_c.cc". + * The content of this file is copyright of Saarland University - + * Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . + * + * This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). + * + * License: three-clause BSD style license. + * The license text can be found in the file LICENSE. + * + * *** MOCS-COPYRIGHT-NOTICE-END *** */ + +#include + +#include "aa.hh" +#include "vhdl.hh" +#include "state-machine.hh" + +#include "sm.h" + +using namespace c::context; + +// constructors/ destructors +void free_state_machine(state_machine_ptr a) +{ + delete a; +} + +// Get Context +context_ptr get_sm_context(state_machine_ptr a) +{ + return new context_t(a->init->efac()); +} + +state_machine_ptr mk_state_machine(automaton_ptr a) +{ + return new state_machine_t(*a); +} + +// pretty-printing +void state_machine2dot(const char* file_name, const state_machine_ptr a, const char* name) +{ + std::ofstream file(file_name); + if (file) { + state_machine2dot(file,*a,name); + } else { + std::cerr << "Error: Failed to open file for writing." << std::endl; + } +} + diff --git a/config.make b/config.make new file mode 100644 index 0000000..d807ec6 --- /dev/null +++ b/config.make @@ -0,0 +1,31 @@ +# *** MOCS-COPYRIGHT-NOTICE-BEGIN *** +# +# This copyright notice is auto-generated by ./add-copyright-notice. +# Additional copyright notices must be added below the last line of this notice. +# +# MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "config.make". +# The content of this file is copyright of Saarland University - +# Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . +# +# This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). +# +# License: three-clause BSD style license. +# The license text can be found in the file LICENSE. +# +# *** MOCS-COPYRIGHT-NOTICE-END *** + +VERSION="0.1" +REVISION := $(shell hg id) + +# Optimization +HSOPT:=-O2 +#HSOPT:=-O2 -hide-package mtl -W # use this in case of conflicts +COPT:=-O2 + +# Debugging +#CDEBUG:=-ggdb + +# temporary hack: +XILINX:=/home/kuhtz/misc/xilinx-on-paul/Xilinx/10.1 +XST:=$(XILINX)/ISE/bin/lin/xst + diff --git a/formulas/12-formulas.txt b/formulas/12-formulas.txt new file mode 100644 index 0000000..99335ca --- /dev/null +++ b/formulas/12-formulas.txt @@ -0,0 +1,48 @@ +-- *** MOCS-COPYRIGHT-NOTICE-BEGIN *** +-- +-- This copyright notice is auto-generated by ./add-copyright-notice. +-- Additional copyright notices must be added below the last line of this notice. +-- +-- MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "formulas/12-formulas.txt". +-- The content of this file is copyright of Saarland University - +-- Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . +-- +-- This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). +-- +-- License: three-clause BSD style license. +-- The license text can be found in the file LICENSE. +-- +-- *** MOCS-COPYRIGHT-NOTICE-END *** + +-- from EtessamiHolzmann00 + +-- 1. p \U (q \and \G r) +-- 2. p \U (q \and \N(r \U s)) +-- 3. p \U (q \and \N(r \and (\F (s \and \N(\F (t \and \N(\F (u \and \N \F v)))))))) +-- 4. \F (p \and \N \G q) +-- 5. \F (p \and \N(q \and \N(\F r))) +-- 6. \F (q \and \N(p \U r)) +-- 7. (\F \G q) \or (\F \G p) +-- 8. \G ((\not p) \or (q \U r)) +-- 9. \F (p \and \N \F (q \and \N \F (r \and \N \F s))) +-- 10. \G \F p \and \G \F q \and \G \F r \and \G \F s \and \G \F t +-- 11. (p \U q \U r) \or (q \U r \U p) \or (r \U p \U q) +-- 12. \G ((\not p) \or (q \U ( \G r \or \G s))) + +-- Bounded version +-- \b: big +-- \m: medium +-- \s: small +1. p \BU \b (q \and (\BG \b r)) +2. p \U (q \and (\N (r \BU \m s))) +3. p \U (q \and (\N (r \and (\BF \m (s \and (\N (\BF \m (t \and (\N (\BF \m (u \and (\N (\BF \m v))))))))))))) +4. \BF \b (p \and (\N (\BG \m q))) +5. \F (p \and (\N(q \and (\N(\BF \s r))))) +6. \F (q \and (\N(p \BU \m r))) +7. (\F (\BG \b q)) \or (\F (\BG \b p)) +8. \G ((\not p) \or (q \BU \s r)) +9. \F (p \and (\N (\BF \s (q \and (\N (\BF \s (r \and (\N (\BF \s s))))))))) +10. (\G (\BF \m p)) \and (\G (\BF \m q)) \and (\G (\BF \m r)) \and (\G (\BF \m s)) \and (\G (\BF \m t)) +11. (p \BU \m q \BU \m r) \or (q \BU \m r \BU \m p) \or (r \BU \m p \BU \m q) +12. \G ((\not p) \or (q \BU \s ( (\BG \b r) \or (\BG \b s)))) + diff --git a/formulas/Makefile b/formulas/Makefile new file mode 100644 index 0000000..1b308a3 --- /dev/null +++ b/formulas/Makefile @@ -0,0 +1,143 @@ +# *** MOCS-COPYRIGHT-NOTICE-BEGIN *** +# +# This copyright notice is auto-generated by ./add-copyright-notice. +# Additional copyright notices must be added below the last line of this notice. +# +# MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "formulas/Makefile". +# The content of this file is copyright of Saarland University - +# Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . +# +# This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). +# +# License: three-clause BSD style license. +# The license text can be found in the file LICENSE. +# +# *** MOCS-COPYRIGHT-NOTICE-END *** + +include ../config.make + +M:=40 + +Main:=Main + +export PATH:=${PATH}:. +SHELL:=/bin/bash + +Xs:=$(shell echo {1..$M}) + +.PHONY: all clean +all: + @echo "just doing nothing" + +clean: + rm -rf *.dat + +help: + @echo "all: does nothing" + @echo "clean: remove all dat files" + @echo "xst/.srp: synthesis " + @echo ".dat: gnuplot data for " + @echo ".vhdl: vhdl monitor code for " + @echo ".ltl: instantiate ltl formula from .tltl" + @echo "vardi.vdat: gnuplot data for vardis formula over number of variables" + @echo "fair-bounded-request.vdat: gnuplot data for vardis formula over number of variables" + +# takes the current x value +define X +%.$(1).ltl: %.tltl + cat $$< | ./set-bounds.sh "$$$$((3*$(1)))" "$$$$((2*$(1)))" "$$$$(($(1)))" > $$@ +# cat $$< | ./set-bounds.sh "(infty)" "(infty)" "(infty)" > $$@ + +%.$(1).tdat: %.$(1).vhdl + echo -n "$(1) " > $$@ + ./cir-size.sh $$< | cut -d ' ' -f 3,5,7 | sed 's/,//g' >> $$@ +endef +$(foreach i, $(Xs), $(eval $(call X,$(i)))) + + +%.vhdl: %.ltl + ../haskell-frontend/$(Main) $@ < $< + +%.dat: $(foreach i, $(Xs), %.$(i).tdat) + echo "% M=$(M)" > $@ + cat $^ >> $@ + +%.mdat: %.$(M).tdat + cp $< $@ + +# ############################################################################## +# synthesize + +XSTDIR:=xst +VHDLDIR:=../../vhdl + +$(XSTDIR)/%.srp: $(XSTDIR)/%.xst.src $(XSTDIR)/%.prj %.vhdl MKXSTDIR + (cd $(XSTDIR); $(XST) -ifn $*.xst.src -ofn $*.srp) + +MKXSTDIR: + mkdir -p $(XSTDIR) + +$(XSTDIR)/%.xst.src: MKXSTDIR + echo -e "run -ifn $*.prj -top monitor -ifmt MIXED -opt_mode SPEED -opt_level 1 -ofn $*.ngc -p xc5vlx50 -tmpdir tmp\n" > $@ + +$(XSTDIR)/%.prj: %.vhdl MKXSTDIR + echo -e " vhdl work \"../$<\"\nvhdl work \"$(VHDLDIR)/pipeline.vhdl\"\nvhdl work \"$(VHDLDIR)/d.vhdl\"\nvhdl work \"$(VHDLDIR)/countdown.vhdl\"\n" > $@ + +# ############################################################################## +# Twelf formulas: +# stems are f1, f2, f3, ..., f12 + +TWELF:=$(shell echo {1..12}) +TWELF_FORMULAS:=$(TWELF:%=f%) + +# ranges over twelf +define T +.INTERMEDIATE: f$(1).tltl +f$(1).tltl: %$(1).tltl: 12-formulas.txt + grep "^$(1)\. " $$< | sed -e 's/^.*\. //' > $$@; +endef +$(foreach i, $(TWELF), $(eval $(call T,$(i)))) + +.INTERMEDIATE: $(TWELF:%=f%.dat) +twelf.dat : $(foreach i,$(TWELF), f$(i).dat) + rm -f $@ + for i in $^ ; do cat $$i >> $@; echo -e "\n" >> $@; done + +.INTERMEDIATE: $(TWELF:%=f%.mdat) +twelf.mdat: $(foreach i, $(TWELF), f$(i).mdat) + rm -f $@ + for i in $^ ; do cat $$i >> $@; done + +# ############################################################################## +# Parameterized formulas + +#parameter +V:=60 +Vs:=$(shell echo {1..$(V)}) + +# Value for the bound +vX:=100 +$(eval $(call X,$(vX))) + +# Generate data ranging over Vs +%.vdat: $(foreach i, $(Vs), %.$(i).$(vX).tdat) + echo "% vX=$(vX), V=$(V)" > $@ + cat $^ > $@ + +# $1 generator +# $2 stem +# $3 parameter of generator +define Generate +.INTERMEDIATE: $(2).$(3).tltl +$(2).$(3).tltl: $(1) + $(1) $(3) > $$@ + +.INTERMEDIATE: $(2).$(3).$(vX).tdat +$(2).$(3).$(vX).tdat: $(2).$(3).$(vX).vhdl + echo -n "$(3) " > $$@ + ./cir-size.sh $$< | cut -d ' ' -f 3,5,7 | sed 's/,//g' >> $$@ +endef +$(foreach i, $(Vs), $(eval $(call Generate,vardigen.sh,vardi,$(i)))) +$(foreach i, $(Vs), $(eval $(call Generate,fair-bounded-request-gen.sh,fair-bounded-request,$(i)))) + + diff --git a/formulas/bounded-request.tltl b/formulas/bounded-request.tltl new file mode 100644 index 0000000..907aeea --- /dev/null +++ b/formulas/bounded-request.tltl @@ -0,0 +1,17 @@ +-- *** MOCS-COPYRIGHT-NOTICE-BEGIN *** +-- +-- This copyright notice is auto-generated by ./add-copyright-notice. +-- Additional copyright notices must be added below the last line of this notice. +-- +-- MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "formulas/bounded-request.tltl". +-- The content of this file is copyright of Saarland University - +-- Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . +-- +-- This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). +-- +-- License: three-clause BSD style license. +-- The license text can be found in the file LICENSE. +-- +-- *** MOCS-COPYRIGHT-NOTICE-END *** + +\G ( (\not a) \or (\wBF \m b)) diff --git a/formulas/cir-size.sh b/formulas/cir-size.sh new file mode 100755 index 0000000..d4748f4 --- /dev/null +++ b/formulas/cir-size.sh @@ -0,0 +1,40 @@ +#!/bin/bash + +# *** MOCS-COPYRIGHT-NOTICE-BEGIN *** +# +# This copyright notice is auto-generated by ./add-copyright-notice. +# Additional copyright notices must be added below the last line of this notice. +# +# MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "formulas/cir-size.sh". +# The content of this file is copyright of Saarland University - +# Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . +# +# This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). +# +# License: three-clause BSD style license. +# The license text can be found in the file LICENSE. +# +# *** MOCS-COPYRIGHT-NOTICE-END *** + +if [[ $# -lt 1 ]] ; then + echo "Usage: $0 [-n|-l|-f|-s] " + exit 1 +elif [[ $# = 1 ]] ; then + OPT="" + ARG=$1 +else + OPT=$1 + ARG=$2 +fi + +S=`grep '^ *\ \+\<\w\+\> : \; *$' $ARG | wc -l` +LG=`grep '^ *\<\w\+\> <= \<\w\+\> \<\(and\|or\)\> \<\w\+\> *; *$' $ARG | wc -l` +D=`grep 'entity work.dff' $ARG | wc -l` + +case $OPT in +-n) echo "$LG $D $S";; +-l) echo "$LG";; +-f) echo "$D";; +-s) echo "$S";; +*) echo "logic gates: $LG, flip-flops: $D, signals: $S";; +esac diff --git a/formulas/fair-bounded-request-gen.sh b/formulas/fair-bounded-request-gen.sh new file mode 100755 index 0000000..50294a2 --- /dev/null +++ b/formulas/fair-bounded-request-gen.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +# *** MOCS-COPYRIGHT-NOTICE-BEGIN *** +# +# This copyright notice is auto-generated by ./add-copyright-notice. +# Additional copyright notices must be added below the last line of this notice. +# +# MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "formulas/fair-bounded-request-gen.sh". +# The content of this file is copyright of Saarland University - +# Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . +# +# This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). +# +# License: three-clause BSD style license. +# The license text can be found in the file LICENSE. +# +# *** MOCS-COPYRIGHT-NOTICE-END *** + +echo "-- Taken from GastinOddoux2001" +echo "\G ( ( true " +for ((i=0; i<$1; ++i)) do + echo "\and (\G (\wBF \b f$i))" +done +echo ") \implies (a \implies (\wBF \s b)))" + diff --git a/formulas/gen12f.sh b/formulas/gen12f.sh new file mode 100755 index 0000000..6276b01 --- /dev/null +++ b/formulas/gen12f.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +# *** MOCS-COPYRIGHT-NOTICE-BEGIN *** +# +# This copyright notice is auto-generated by ./add-copyright-notice. +# Additional copyright notices must be added below the last line of this notice. +# +# MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "formulas/gen12f.sh". +# The content of this file is copyright of Saarland University - +# Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . +# +# This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). +# +# License: three-clause BSD style license. +# The license text can be found in the file LICENSE. +# +# *** MOCS-COPYRIGHT-NOTICE-END *** + +for ((i=1; i<=12; ++i)) ; do + #echo $i; + grep "^$i\. " 12-formulas.txt | sed -e 's/^.*\. //' > f$i.tltl; +done diff --git a/formulas/markey.ltl b/formulas/markey.ltl new file mode 100644 index 0000000..3afe17e --- /dev/null +++ b/formulas/markey.ltl @@ -0,0 +1,21 @@ +-- *** MOCS-COPYRIGHT-NOTICE-BEGIN *** +-- +-- This copyright notice is auto-generated by ./add-copyright-notice. +-- Additional copyright notices must be added below the last line of this notice. +-- +-- MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "formulas/markey.ltl". +-- The content of this file is copyright of Saarland University - +-- Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . +-- +-- This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). +-- +-- License: three-clause BSD style license. +-- The license text can be found in the file LICENSE. +-- +-- *** MOCS-COPYRIGHT-NOTICE-END *** + +-- NOTE: we do not support past operators, yet! +{- +G{[(p1 <=> F-1G-1 p1) & ... & (pn <=> F-1G-1 pn)] => + (p0 <=> F-1G-1 p0)} +-} diff --git a/formulas/plot.sh b/formulas/plot.sh new file mode 100755 index 0000000..261fdf2 --- /dev/null +++ b/formulas/plot.sh @@ -0,0 +1,33 @@ +#!/bin/bash + +# *** MOCS-COPYRIGHT-NOTICE-BEGIN *** +# +# This copyright notice is auto-generated by ./add-copyright-notice. +# Additional copyright notices must be added below the last line of this notice. +# +# MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "formulas/plot.sh". +# The content of this file is copyright of Saarland University - +# Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . +# +# This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). +# +# License: three-clause BSD style license. +# The license text can be found in the file LICENSE. +# +# *** MOCS-COPYRIGHT-NOTICE-END *** + +FILE=$1 +LABEL=$2 +Xlabel=$3 + +gnuplot <. +# +# This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). +# +# License: three-clause BSD style license. +# The license text can be found in the file LICENSE. +# +# *** MOCS-COPYRIGHT-NOTICE-END *** + +for ((i=1;i<=$1;++i)) ; do + ./runall12.sh $(($i*3)) $(($i*2)) $(($i*1)) | + cut -d ' ' -f '5' | + sed 's/:\|,//g' | + gawk -v i=$i 'BEGIN {x=""}; {x=x " " $1}; END {print i x}' ; +done > tmp +rm -f data +for ((i=2;i<=13;++i)) ; do + cat tmp | + cut -d ' ' -f "1,$i" >> data ; + echo -e "\n" >> data; +done + + +gnuplot -persist <(echo "plot 'data', x**3, x**3.3") + diff --git a/formulas/run12.sh b/formulas/run12.sh new file mode 100755 index 0000000..c199940 --- /dev/null +++ b/formulas/run12.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +# *** MOCS-COPYRIGHT-NOTICE-BEGIN *** +# +# This copyright notice is auto-generated by ./add-copyright-notice. +# Additional copyright notices must be added below the last line of this notice. +# +# MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "formulas/run12.sh". +# The content of this file is copyright of Saarland University - +# Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . +# +# This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). +# +# License: three-clause BSD style license. +# The license text can be found in the file LICENSE. +# +# *** MOCS-COPYRIGHT-NOTICE-END *** + +cat f$1.ltl | ./set-bounds.sh $2 $3 $4 | ../haskell-frontend/Main f$1.vhdl && ./cir-size.sh f$1.vhdl + diff --git a/formulas/runall12.sh b/formulas/runall12.sh new file mode 100755 index 0000000..c28c43b --- /dev/null +++ b/formulas/runall12.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +# *** MOCS-COPYRIGHT-NOTICE-BEGIN *** +# +# This copyright notice is auto-generated by ./add-copyright-notice. +# Additional copyright notices must be added below the last line of this notice. +# +# MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "formulas/runall12.sh". +# The content of this file is copyright of Saarland University - +# Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . +# +# This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). +# +# License: three-clause BSD style license. +# The license text can be found in the file LICENSE. +# +# *** MOCS-COPYRIGHT-NOTICE-END *** + +./gen12f.sh +for ((i=1; i<=12; i++)) ; do + echo -n "run $i: " + ./run12.sh $i $1 $2 $3 +done + diff --git a/formulas/set-bounds.sh b/formulas/set-bounds.sh new file mode 100755 index 0000000..b56f64d --- /dev/null +++ b/formulas/set-bounds.sh @@ -0,0 +1,32 @@ +#!/bin/bash + +# *** MOCS-COPYRIGHT-NOTICE-BEGIN *** +# +# This copyright notice is auto-generated by ./add-copyright-notice. +# Additional copyright notices must be added below the last line of this notice. +# +# MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "formulas/set-bounds.sh". +# The content of this file is copyright of Saarland University - +# Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . +# +# This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). +# +# License: three-clause BSD style license. +# The license text can be found in the file LICENSE. +# +# *** MOCS-COPYRIGHT-NOTICE-END *** + +if [[ $# = 0 ]] ; then + sed -e "s/\\\\b/(infty)/g; s/\\\\m/(infty)/g; s/\\\\s/(infty)/g" +elif [[ $# = 1 ]] ; then + sed -e "s/\\\\b/(3*$1)/g; s/\\\\m/(2*$1)/g; s/\\\\s/$1/g" +elif [[ $# = 3 ]] ; then + sed -e "s/\\\\b/$1/g; s/\\\\m/$2/g; s/\\\\s/$3/g" +else + echo "Error: wrong number of arguments" 1>&2 + echo "Usage: $0 (set bounds to infty)" 1>&2 + echo " $0 n (set bounds to 3*n, 2*n, n, respectively)" 1>&2 + echo " $0 n0 n1 n2 (set bounds to n0, n1, n2 respectively)" 1>&2 + exit 1 +fi + diff --git a/formulas/vardi.static.ltl b/formulas/vardi.static.ltl new file mode 100644 index 0000000..f3f3f51 --- /dev/null +++ b/formulas/vardi.static.ltl @@ -0,0 +1,26 @@ +-- *** MOCS-COPYRIGHT-NOTICE-BEGIN *** +-- +-- This copyright notice is auto-generated by ./add-copyright-notice. +-- Additional copyright notices must be added below the last line of this notice. +-- +-- MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "formulas/vardi.static.ltl". +-- The content of this file is copyright of Saarland University - +-- Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . +-- +-- This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). +-- +-- License: three-clause BSD style license. +-- The license text can be found in the file LICENSE. +-- +-- *** MOCS-COPYRIGHT-NOTICE-END *** + +\G ( (\not (\BN 100 (x \and (\N (\BG 99 \not x))))) \or + (\BF 99 ( + (\not i1 \or (\BF 100 (i1 \and (x \and (\N (\BG 99 \not x)))))) + \and (\not i2 \or (\BF 100 (i2 \and (x \and (\N (\BG 99 \not x)))))) + \and (\not i3 \or (\BF 100 (i3 \and (x \and (\N (\BG 99 \not x)))))) + \and (\not i4 \or (\BF 100 (i4 \and (x \and (\N (\BG 99 \not x)))))) + \and (\not i5 \or (\BF 100 (i5 \and (x \and (\N (\BG 99 \not x)))))) + )) + ) + diff --git a/formulas/vardi.tltl b/formulas/vardi.tltl new file mode 100644 index 0000000..0603863 --- /dev/null +++ b/formulas/vardi.tltl @@ -0,0 +1,26 @@ +-- *** MOCS-COPYRIGHT-NOTICE-BEGIN *** +-- +-- This copyright notice is auto-generated by ./add-copyright-notice. +-- Additional copyright notices must be added below the last line of this notice. +-- +-- MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "formulas/vardi.tltl". +-- The content of this file is copyright of Saarland University - +-- Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . +-- +-- This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). +-- +-- License: three-clause BSD style license. +-- The license text can be found in the file LICENSE. +-- +-- *** MOCS-COPYRIGHT-NOTICE-END *** + +\G ( (\not (\BN (\s) (x \and (\N (\BG (\s - 1) \not x))))) \or + (\BF (\s - 1) ( + (\not i1 \or (\BF (\s) (i1 \and (x \and (\N (\BG (\s - 1) \not x)))))) + \and (\not i2 \or (\BF (\s) (i2 \and (x \and (\N (\BG (\s - 1) \not x)))))) + \and (\not i3 \or (\BF (\s) (i3 \and (x \and (\N (\BG (\s - 1) \not x)))))) + \and (\not i4 \or (\BF (\s) (i4 \and (x \and (\N (\BG (\s - 1) \not x)))))) + \and (\not i5 \or (\BF (\s) (i5 \and (x \and (\N (\BG (\s - 1) \not x)))))) + )) + ) + diff --git a/formulas/vardigen.sh b/formulas/vardigen.sh new file mode 100755 index 0000000..a7d374e --- /dev/null +++ b/formulas/vardigen.sh @@ -0,0 +1,33 @@ +#!/bin/bash + +# *** MOCS-COPYRIGHT-NOTICE-BEGIN *** +# +# This copyright notice is auto-generated by ./add-copyright-notice. +# Additional copyright notices must be added below the last line of this notice. +# +# MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "formulas/vardigen.sh". +# The content of this file is copyright of Saarland University - +# Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . +# +# This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). +# +# License: three-clause BSD style license. +# The license text can be found in the file LICENSE. +# +# *** MOCS-COPYRIGHT-NOTICE-END *** + +#echo "\G ( (\not (\BN (\s) (x \and (\N (\BG (\s - 1) \not x))))) \or" +#echo " (\BF (\s - 1) (" +#echo " (\not i1 \or (\BF (\s) (i1 \and (x \and (\N (\BG (\s - 1) \not x))))))" +#for ((i=0; i<=$1; ++i)) do +# echo " \and (\not i$i \or (\BF (\s) (i$i \and (x \and (\N (\BG (\s - 1) \not x))))))" +#done +#echo " ))" +#echo " )" + +echo "\F ( \not x " +for ((i=0; i<=$1; ++i)) do + echo "\and (i$i \equiv \BF (\s) (i$i \and x) )" +done +echo ") \and \G (x \implies \N \G \not x) \and \F x" + diff --git a/formulas/waitfor.tltl b/formulas/waitfor.tltl new file mode 100644 index 0000000..7bb214a --- /dev/null +++ b/formulas/waitfor.tltl @@ -0,0 +1,19 @@ +-- *** MOCS-COPYRIGHT-NOTICE-BEGIN *** +-- +-- This copyright notice is auto-generated by ./add-copyright-notice. +-- Additional copyright notices must be added below the last line of this notice. +-- +-- MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "formulas/waitfor.tltl". +-- The content of this file is copyright of Saarland University - +-- Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . +-- +-- This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). +-- +-- License: three-clause BSD style license. +-- The license text can be found in the file LICENSE. +-- +-- *** MOCS-COPYRIGHT-NOTICE-END *** + +-- GastinOddoux01 state that these kind of thing (without bounds) occour in practice +(a \W (b \BW \s (c \BW \b (d \BW \s (e \BW \b f))))) + diff --git a/formulas/waitfor_tree.tltl b/formulas/waitfor_tree.tltl new file mode 100644 index 0000000..1d4791c --- /dev/null +++ b/formulas/waitfor_tree.tltl @@ -0,0 +1,17 @@ +-- *** MOCS-COPYRIGHT-NOTICE-BEGIN *** +-- +-- This copyright notice is auto-generated by ./add-copyright-notice. +-- Additional copyright notices must be added below the last line of this notice. +-- +-- MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "formulas/waitfor_tree.tltl". +-- The content of this file is copyright of Saarland University - +-- Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . +-- +-- This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). +-- +-- License: three-clause BSD style license. +-- The license text can be found in the file LICENSE. +-- +-- *** MOCS-COPYRIGHT-NOTICE-END *** + +( ((a \BW \b b) \W (c \BW \m d) ) \W ( (e \BW \s f) \W (g \BW \b h) ) ) diff --git a/haskell-bindings/CAut.hs b/haskell-bindings/CAut.hs new file mode 100644 index 0000000..349683c --- /dev/null +++ b/haskell-bindings/CAut.hs @@ -0,0 +1,258 @@ +{- *** MOCS-COPYRIGHT-NOTICE-BEGIN *** + - + - This copyright notice is auto-generated by ./add-copyright-notice. + - Additional copyright notices must be added below the last line of this notice. + - + - MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "haskell-bindings/CAut.hs". + - The content of this file is copyright of Saarland University - + - Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . + - + - This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). + - + - License: three-clause BSD style license. + - The license text can be found in the file LICENSE. + - + - *** MOCS-COPYRIGHT-NOTICE-END *** -} + +{-# LANGUAGE ForeignFunctionInterface #-} +module CAut where + +import Foreign +import ForeignPtr +import Foreign.C.Types +import Foreign.C.String +import Foreign.Marshal.Array + +import CExpr + +-- -------------------------------------------------------------------------- -- +-- Automaton Context +type CAutCtx = CExprCtx +type AutCtxPtr = ExprCtxPtr +newAutCtx = newExprCtx +mkAutCtx = mkExprCtx + +-- -------------------------------------------------------------------------- -- +-- Automaton +data CAut = CAut +foreign import ccall "aa.h &free_automaton" free_automaton :: FunPtr (Ptr CAut -> IO ()) + +foreign import ccall "aa.h simplies_aut" simplies_aut :: (Ptr CAut) -> (Ptr CAut) -> IO (Ptr CAut) +foreign import ccall "aa.h abort_aut" abort_aut :: (Ptr CAut) -> (Ptr CAut) -> IO (Ptr CAut) + +foreign import ccall "aa.h conc_aut" conc_aut :: (Ptr CAut) -> (Ptr CAut) -> IO (Ptr CAut) +foreign import ccall "aa.h oconc_aut" oconc_aut :: (Ptr CAut) -> (Ptr CAut) -> IO (Ptr CAut) +foreign import ccall "aa.h kleene_aut" kleene_aut :: (Ptr CAut) -> IO (Ptr CAut) +foreign import ccall "aa.h union_aut" union_aut :: (Ptr CAut) -> (Ptr CAut) -> IO (Ptr CAut) +foreign import ccall "aa.h empty_aut" empty_aut :: (Ptr CAutCtx) -> IO (Ptr CAut) + +foreign import ccall "aa.h const_aut" const_aut :: (Ptr CAutCtx) -> CInt -> IO (Ptr CAut) +foreign import ccall "aa.h prop_aut" prop_aut :: (Ptr CAutCtx) -> (Ptr CLong) -> CSize -> IO (Ptr CAut) +foreign import ccall "aa.h nprop_aut" nprop_aut :: (Ptr CAutCtx) -> (Ptr CLong) -> CSize -> IO (Ptr CAut) + +foreign import ccall "aa.h and_aut" and_aut :: (Ptr CAut) -> (Ptr CAut) -> IO (Ptr CAut) +foreign import ccall "aa.h or_aut" or_aut :: (Ptr CAut) -> (Ptr CAut) -> IO (Ptr CAut) +foreign import ccall "aa.h implies_aut" implies_aut :: (Ptr CAut) -> (Ptr CAut) -> IO (Ptr CAut) + +foreign import ccall "aa.h dual_aut" dual_aut :: (Ptr CAut) -> IO (Ptr CAut) + +foreign import ccall "aa.h next_aut" next_aut :: (Ptr CAut) -> IO (Ptr CAut) +foreign import ccall "aa.h bnext_aut" bnext_aut :: CInt -> (Ptr CAut) -> IO (Ptr CAut) +foreign import ccall "aa.h wnext_aut" wnext_aut :: (Ptr CAut) -> IO (Ptr CAut) +foreign import ccall "aa.h bwnext_aut" bwnext_aut :: CInt -> (Ptr CAut) -> IO (Ptr CAut) + +foreign import ccall "aa.h g_aut" g_aut :: (Ptr CAut) -> IO (Ptr CAut) +foreign import ccall "aa.h bg_aut" bg_aut :: CInt -> (Ptr CAut) -> IO (Ptr CAut) +foreign import ccall "aa.h strong_bg_aut" strong_bg_aut :: CInt -> (Ptr CAut) -> IO (Ptr CAut) + +foreign import ccall "aa.h f_aut" f_aut :: (Ptr CAut) -> IO (Ptr CAut) +foreign import ccall "aa.h bf_aut" bf_aut :: CInt -> (Ptr CAut) -> IO (Ptr CAut) +foreign import ccall "aa.h weak_bf_aut" weak_bf_aut :: CInt -> (Ptr CAut) -> IO (Ptr CAut) + +foreign import ccall "aa.h until_aut" until_aut :: (Ptr CAut) -> (Ptr CAut) -> IO (Ptr CAut) +foreign import ccall "aa.h buntil_aut" buntil_aut :: CInt -> (Ptr CAut) -> (Ptr CAut) -> IO (Ptr CAut) +foreign import ccall "aa.h waitfor_aut" waitfor_aut :: (Ptr CAut) -> (Ptr CAut) -> IO (Ptr CAut) +foreign import ccall "aa.h bwaitfor_aut" bwaitfor_aut :: CInt -> (Ptr CAut) -> (Ptr CAut) -> IO (Ptr CAut) + +foreign import ccall "aa.h release_aut" release_aut :: (Ptr CAut) -> (Ptr CAut) -> IO (Ptr CAut) +foreign import ccall "aa.h brelease_aut" brelease_aut :: CInt -> (Ptr CAut) -> (Ptr CAut) -> IO (Ptr CAut) +foreign import ccall "aa.h strong_release_aut" strong_release_aut :: (Ptr CAut) -> (Ptr CAut) -> IO (Ptr CAut) +foreign import ccall "aa.h strong_brelease_aut" strong_brelease_aut :: CInt -> (Ptr CAut) -> (Ptr CAut) -> IO (Ptr CAut) + +foreign import ccall "aa.h automaton2dot" automaton_to_dot :: CString -> (Ptr CAut) -> CString -> IO () +foreign import ccall "aa.h weak_aut" weak_aut :: (Ptr CAut) -> IO (Ptr CAut) +foreign import ccall "aa.h universal_aut" universal_aut :: (Ptr CAut) -> IO (Ptr CAut) +foreign import ccall "aa.h get_aut_context" get_aut_context :: (Ptr CAut) -> IO (Ptr CAutCtx) + +foreign import ccall "aa.h aut_prefix_rollout" aut_prefix_rollout :: (Ptr CAut) -> CInt -> IO (Ptr CExpr) +foreign import ccall "aa.h aut_suffix_rollout" aut_suffix_rollout :: (Ptr CAut) -> CInt -> IO (Ptr (Ptr CExpr)) + +foreign import ccall "vhdl.h vhdl_build_monitor" vhdl_build_monitor :: CString -> CInt -> CInt -> CInt -> (Ptr CExpr) -> (Ptr CAut) -> (Ptr (Ptr (Ptr CExpr))) -> IO () + +type AutPtr = ForeignPtr CAut + +mkAutPtr :: Ptr CAut -> IO AutPtr +mkAutPtr = newForeignPtr free_automaton + +-- precondition: a is nondeterministic +simpliesAut :: AutPtr -> AutPtr -> IO AutPtr +simpliesAut a b = withForeignPtr2 a b simplies_aut >>= mkAutPtr + +abortAut :: AutPtr -> AutPtr -> IO AutPtr +abortAut a b = withForeignPtr2 a b abort_aut >>= mkAutPtr + +-- precondition: a is nondeterministic +kleeneAut :: AutPtr -> IO AutPtr +kleeneAut a = withForeignPtr a kleene_aut >>= mkAutPtr + +unionAut :: AutPtr -> AutPtr -> IO AutPtr +unionAut a b = withForeignPtr2 a b union_aut >>= mkAutPtr + +-- precondition: a is nondeterministic +concAut :: AutPtr -> AutPtr -> IO AutPtr +concAut a b = withForeignPtr2 a b conc_aut >>= mkAutPtr + +-- precondition: a is nondeterministic +oconcAut :: AutPtr -> AutPtr -> IO AutPtr +oconcAut a b = withForeignPtr2 a b oconc_aut >>= mkAutPtr + +emptyAut :: AutCtxPtr -> IO AutPtr +emptyAut ctx = (withForeignPtr ctx $ empty_aut) >>= mkAutPtr + +constAut :: AutCtxPtr -> Bool -> IO AutPtr +constAut ctx b = (withForeignPtr ctx $ (\ctx -> const_aut ctx (fromBool b))) >>= mkAutPtr + +propAut :: AutCtxPtr -> [CLong] -> IO AutPtr +propAut ctx l = do + prop <- newArray l + ret <- (withForeignPtr ctx (\ctx -> prop_aut ctx prop (int2c $ length l))) >>= mkAutPtr + free prop + return ret + +npropAut :: AutCtxPtr -> [CLong] -> IO AutPtr +npropAut ctx l = do + prop <- newArray l + ret <- (withForeignPtr ctx (\ctx -> nprop_aut ctx prop (int2c $ length l))) >>= mkAutPtr + free prop + return ret + +andAut :: AutPtr -> AutPtr -> IO AutPtr +andAut a b = withForeignPtr2 a b and_aut >>= mkAutPtr + +orAut :: AutPtr -> AutPtr -> IO AutPtr +orAut a b = withForeignPtr2 a b or_aut >>= mkAutPtr + +impliesAut :: AutPtr -> AutPtr -> IO AutPtr +impliesAut a b = withForeignPtr2 a b implies_aut >>= mkAutPtr + +dualAut :: AutPtr -> IO AutPtr +dualAut a = withForeignPtr a dual_aut >>= mkAutPtr + +-- +nextAut :: AutPtr -> IO AutPtr +nextAut a = withForeignPtr a next_aut >>= mkAutPtr + +bnextAut :: Int -> AutPtr -> IO AutPtr +bnextAut i a = withForeignPtr a (bnext_aut (int2c i)) >>= mkAutPtr + +-- +wnextAut :: AutPtr -> IO AutPtr +wnextAut a = withForeignPtr a wnext_aut >>= mkAutPtr + +wbnextAut :: Int -> AutPtr -> IO AutPtr +wbnextAut i a = withForeignPtr a (bwnext_aut (int2c i)) >>= mkAutPtr + +-- +gAut :: AutPtr -> IO AutPtr +gAut a = withForeignPtr a g_aut >>= mkAutPtr + +bgAut :: Int -> AutPtr -> IO AutPtr +bgAut i a = withForeignPtr a (bg_aut (int2c i)) >>= mkAutPtr + +sbgAut :: Int -> AutPtr -> IO AutPtr +sbgAut i a = withForeignPtr a (strong_bg_aut (int2c i)) >>= mkAutPtr + +-- +fAut :: AutPtr -> IO AutPtr +fAut a = withForeignPtr a f_aut >>= mkAutPtr + +bfAut :: Int -> AutPtr -> IO AutPtr +bfAut i a = withForeignPtr a (bf_aut (int2c i)) >>= mkAutPtr + +wbfAut :: Int -> AutPtr -> IO AutPtr +wbfAut i a = withForeignPtr a (weak_bf_aut (int2c i)) >>= mkAutPtr + +-- +untilAut :: AutPtr -> AutPtr -> IO AutPtr +untilAut a b = withForeignPtr2 a b until_aut >>= mkAutPtr + +buntilAut :: Int -> AutPtr -> AutPtr -> IO AutPtr +buntilAut i a b = withForeignPtr2 a b (buntil_aut (int2c i)) >>= mkAutPtr + +waitforAut :: AutPtr -> AutPtr -> IO AutPtr +waitforAut a b = withForeignPtr2 a b waitfor_aut >>= mkAutPtr + +bwaitforAut :: Int -> AutPtr -> AutPtr -> IO AutPtr +bwaitforAut i a b = withForeignPtr2 a b (bwaitfor_aut (int2c i)) >>= mkAutPtr + +-- +releaseAut :: AutPtr -> AutPtr -> IO AutPtr +releaseAut a b = withForeignPtr2 a b release_aut >>= mkAutPtr + +breleaseAut :: Int -> AutPtr -> AutPtr -> IO AutPtr +breleaseAut i a b = withForeignPtr2 a b (brelease_aut (int2c i)) >>= mkAutPtr + +sreleaseAut :: AutPtr -> AutPtr -> IO AutPtr +sreleaseAut a b = withForeignPtr2 a b strong_release_aut >>= mkAutPtr + +sbreleaseAut :: Int -> AutPtr -> AutPtr -> IO AutPtr +sbreleaseAut i a b = withForeignPtr2 a b (strong_brelease_aut (int2c i)) >>= mkAutPtr + +-- +weakAut :: AutPtr -> IO AutPtr +weakAut a = withForeignPtr a weak_aut >>= mkAutPtr + +universalAut :: AutPtr -> IO (AutCtxPtr, AutPtr) +universalAut a = do + ua <- withForeignPtr a universal_aut >>= mkAutPtr + ctx <- getAutCtx ua + return (ctx,ua) + +getAutCtx :: AutPtr -> IO AutCtxPtr +getAutCtx a = withForeignPtr a get_aut_context >>= mkAutCtx + +autToDot :: String -> AutPtr -> String -> IO () +autToDot fname a name = do + f <- newCString fname + n <- newCString name + withForeignPtr a $ (\a -> automaton_to_dot f a n) + free f + free n + +autPrefixRollout :: Int -> AutPtr -> IO ExprPtr +autPrefixRollout h a = withForeignPtr a (\x -> aut_prefix_rollout x (int2c h)) >>= mkExprPtr + +autSuffixRollout :: Int -> AutPtr -> IO [ExprPtr] +autSuffixRollout b a = do + arr <- withForeignPtr a (\x -> aut_suffix_rollout x (int2c b)) + ret <- peekArray0 nullPtr arr >>= mapM mkExprPtr + free arr + return ret + +-- monitor +-- file +-- hor +-- prop_count +-- subf_count +-- global_out_expr +-- prefix_state_machine +-- oexpr field +-- TODO c-bindings: all arrays are 0-terminated, gets a c-string as filename + +-- make sure the suffix expressions are ordered corresponding to ptabel +vhdlBuildMonitor :: String -> Int -> Int -> Int -> ExprPtr -> AutPtr -> [[ExprPtr]] -> IO () +vhdlBuildMonitor fname h pc sc po pa so = do + f <- newCString fname + ret <- withForeignPtr2List so (\so -> withForeignPtr2 po pa (\po pa -> vhdl_build_monitor f (int2c h) (int2c pc) (int2c sc) po pa so)) + free f + return ret diff --git a/haskell-bindings/CExpr.hs b/haskell-bindings/CExpr.hs new file mode 100644 index 0000000..e9def13 --- /dev/null +++ b/haskell-bindings/CExpr.hs @@ -0,0 +1,150 @@ +{- *** MOCS-COPYRIGHT-NOTICE-BEGIN *** + - + - This copyright notice is auto-generated by ./add-copyright-notice. + - Additional copyright notices must be added below the last line of this notice. + - + - MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "haskell-bindings/CExpr.hs". + - The content of this file is copyright of Saarland University - + - Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . + - + - This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). + - + - License: three-clause BSD style license. + - The license text can be found in the file LICENSE. + - + - *** MOCS-COPYRIGHT-NOTICE-END *** -} + +{-# LANGUAGE ForeignFunctionInterface #-} +module CExpr where + +import Foreign +import ForeignPtr +import Foreign.C.Types +import Foreign.C.String +import Foreign.Marshal.Array + +-- -------------------------------------------------------------------------- -- +-- Utils +int2c i = fromInteger $ toInteger i + +-- Maybe we shall use the following: +-- nest :: [(r -> a) -> a] -> ([r] -> a) -> a +-- nest xs = runCont (sequence (map Cont xs)) +-- or alternatively: nest = runCont . sequence . map Cont + +withForeignPtr2 :: ForeignPtr a -> ForeignPtr b -> (Ptr a -> Ptr b -> IO c) -> IO c +withForeignPtr2 a b act = do + let aptr = unsafeForeignPtrToPtr a + let bptr = unsafeForeignPtrToPtr b + ret <- act aptr bptr + touchForeignPtr a + touchForeignPtr b + return ret + +withForeignPtrList :: [ForeignPtr a] -> (Ptr (Ptr a) -> IO b) -> IO b +withForeignPtrList l act = do + let x = map unsafeForeignPtrToPtr l + arr <- newArray0 nullPtr x + ret <- act arr + mapM touchForeignPtr l + free arr + return ret + +withForeignPtr2List :: [[ForeignPtr a]] -> (Ptr (Ptr (Ptr a)) -> IO b) -> IO b +withForeignPtr2List l act = do + let x = map (map unsafeForeignPtrToPtr) l + arr <- mapM (newArray0 nullPtr) x + arr2 <- newArray0 nullPtr arr + ret <- act arr2 + mapM (mapM touchForeignPtr) l + mapM free arr + free arr2 + return ret + +-- -------------------------------------------------------------------------- -- +-- Context +data CExprCtx = CExprCtx +foreign import ccall "context.h &free_context" free_context :: FunPtr (Ptr CExprCtx -> IO ()) +foreign import ccall "context.h new_context" new_context :: IO (Ptr CExprCtx) +foreign import ccall "context.h context_size" context_size :: (Ptr CExprCtx) -> IO CInt + +type ExprCtxPtr = ForeignPtr CExprCtx + +mkExprCtx :: Ptr CExprCtx -> IO ExprCtxPtr +mkExprCtx = newForeignPtr free_context + +newExprCtx :: IO ExprCtxPtr +newExprCtx = new_context >>= mkExprCtx + +contextSize :: ExprCtxPtr -> IO Integer +contextSize p = withForeignPtr p context_size >>= return.toInteger + +-- -------------------------------------------------------------------------- -- +-- Expr +data CExpr = CExpr +foreign import ccall "expr.h &expr_free" expr_free :: FunPtr (Ptr CExpr -> IO ()) + +foreign import ccall "expr.h expr_and" expr_and :: (Ptr CExpr) -> (Ptr CExpr) -> IO (Ptr CExpr) +foreign import ccall "expr.h expr_or" expr_or :: (Ptr CExpr) -> (Ptr CExpr) -> IO (Ptr CExpr) +foreign import ccall "expr.h expr_expr2dot" expr_expr2dot :: CString -> (Ptr CExpr) -> CString -> IO () +foreign import ccall "expr.h expr_exprs2dot_" expr_exprs2dot_ :: CString -> Ptr (Ptr CExpr) -> CString -> IO () +foreign import ccall "expr.h expr_to_string" expr_to_string :: (Ptr CExpr) -> IO CString +foreign import ccall "expr.h expr_get_context" expr_get_context :: (Ptr CExpr) -> IO (Ptr CExprCtx) +foreign import ccall "expr.h expr_eq" expr_eq :: (Ptr CExpr) -> (Ptr CExpr) -> IO Bool +foreign import ccall "expr.h expr_is_false" expr_is_false :: (Ptr CExpr) -> IO Bool +foreign import ccall "expr.h expr_is_true" expr_is_true :: (Ptr CExpr) -> IO Bool +foreign import ccall "expr.h expr_size" expr_size :: (Ptr CExpr) -> IO CInt +foreign import ccall "expr.h exprs_size" exprs_size :: Ptr (Ptr CExpr) -> IO CInt + +type ExprPtr = ForeignPtr CExpr + +mkExprPtr :: Ptr CExpr -> IO ExprPtr +mkExprPtr = newForeignPtr expr_free + +andExpr :: ExprPtr -> ExprPtr -> IO ExprPtr +andExpr a b = withForeignPtr2 a b expr_and >>= mkExprPtr + +orExpr :: ExprPtr -> ExprPtr -> IO ExprPtr +orExpr a b = withForeignPtr2 a b expr_or >>= mkExprPtr + +getExprCtx :: ExprPtr -> IO ExprCtxPtr +getExprCtx a = withForeignPtr a expr_get_context >>= mkExprCtx + +exprToDot :: String -> ExprPtr -> String -> IO () +exprToDot fname a name = do + f <- newCString fname + n <- newCString name + withForeignPtr a $ (\a -> expr_expr2dot f a n) + free f + free n + +exprsToDot :: String -> [ExprPtr] -> String -> IO () +exprsToDot fname a name = do + f <- newCString fname + n <- newCString name + withForeignPtrList a $ (\x -> expr_exprs2dot_ f x n) + free f + free n + +exprToString :: ExprPtr -> IO String +exprToString e = do + cstr <- withForeignPtr e expr_to_string + str <- peekCString cstr + free cstr + return str + +exprEq :: ExprPtr -> ExprPtr -> IO Bool +exprEq e0 e1 = withForeignPtr2 e0 e1 expr_eq + +exprIsFalse :: ExprPtr -> IO Bool +exprIsFalse e = withForeignPtr e expr_is_false + +exprIsTrue :: ExprPtr -> IO Bool +exprIsTrue e = withForeignPtr e expr_is_true + +exprSize :: ExprPtr -> IO Integer +exprSize e = withForeignPtr e expr_size >>= return.toInteger + +exprsSize :: [ExprPtr] -> IO Integer +exprsSize e = withForeignPtrList e exprs_size >>= return.toInteger + diff --git a/haskell-bindings/CStateMachine.hs b/haskell-bindings/CStateMachine.hs new file mode 100644 index 0000000..e7492b2 --- /dev/null +++ b/haskell-bindings/CStateMachine.hs @@ -0,0 +1,62 @@ +{- *** MOCS-COPYRIGHT-NOTICE-BEGIN *** + - + - This copyright notice is auto-generated by ./add-copyright-notice. + - Additional copyright notices must be added below the last line of this notice. + - + - MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "haskell-bindings/CStateMachine.hs". + - The content of this file is copyright of Saarland University - + - Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . + - + - This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). + - + - License: three-clause BSD style license. + - The license text can be found in the file LICENSE. + - + - *** MOCS-COPYRIGHT-NOTICE-END *** -} + +{-# LANGUAGE ForeignFunctionInterface #-} +module CStateMachine where + +import Foreign +import ForeignPtr +import Foreign.C.String + +import CExpr +import CAut + +-- -------------------------------------------------------------------------- -- +-- StateMachine Context +type CStateMachineCtx = CExprCtx +type StateMachineCtxPtr = ExprCtxPtr +newStateMachineCtx = newExprCtx +mkStateMachineCtx = mkExprCtx + + +-- -------------------------------------------------------------------------- -- +-- StateMachine +data CStateMachine = CStateMachine +foreign import ccall "sm.h &free_state_machine" free_state_machine :: FunPtr (Ptr CStateMachine -> IO ()) + +foreign import ccall "sm.h mk_state_machine" mk_state_machine :: (Ptr CAut) -> IO (Ptr CStateMachine) +foreign import ccall "sm.h state_machine2dot" state_machine_to_dot :: CString -> (Ptr CStateMachine) -> CString -> IO () +foreign import ccall "sm.h get_sm_context" get_sm_context :: (Ptr CStateMachine) -> IO (Ptr CStateMachineCtx) + +type StateMachinePtr = ForeignPtr CStateMachine + +mkStateMachinePtr :: Ptr CStateMachine -> IO StateMachinePtr +mkStateMachinePtr = newForeignPtr free_state_machine + +mkStateMachine :: AutPtr -> IO StateMachinePtr +mkStateMachine a = withForeignPtr a mk_state_machine >>= mkStateMachinePtr + +getStateMachineCtx :: StateMachinePtr -> IO StateMachineCtxPtr +getStateMachineCtx a = withForeignPtr a get_sm_context >>= mkStateMachineCtx + +smToDot :: String -> StateMachinePtr -> String -> IO () +smToDot fname a name = do + f <- newCString fname + n <- newCString name + withForeignPtr a $ (\a -> state_machine_to_dot f a n) + free f + free n + diff --git a/haskell-bindings/Makefile b/haskell-bindings/Makefile new file mode 100644 index 0000000..79be5b7 --- /dev/null +++ b/haskell-bindings/Makefile @@ -0,0 +1,25 @@ +# *** MOCS-COPYRIGHT-NOTICE-BEGIN *** +# +# This copyright notice is auto-generated by ./add-copyright-notice. +# Additional copyright notices must be added below the last line of this notice. +# +# MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "haskell-bindings/Makefile". +# The content of this file is copyright of Saarland University - +# Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . +# +# This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). +# +# License: three-clause BSD style license. +# The license text can be found in the file LICENSE. +# +# *** MOCS-COPYRIGHT-NOTICE-END *** + +ROOT=.. + +include $(ROOT)/Makefile.pre + +HSMODULETARGETS=CExpr CAut CStateMachine + +MODULEDEPS=libaaut c-bindings + +include $(ROOT)/Makefile.post diff --git a/haskell-frontend/Main.hs b/haskell-frontend/Main.hs new file mode 100644 index 0000000..0d87764 --- /dev/null +++ b/haskell-frontend/Main.hs @@ -0,0 +1,261 @@ +{- *** MOCS-COPYRIGHT-NOTICE-BEGIN *** + - + - This copyright notice is auto-generated by ./add-copyright-notice. + - Additional copyright notices must be added below the last line of this notice. + - + - MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "haskell-frontend/Main.hs". + - The content of this file is copyright of Saarland University - + - Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . + - + - This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). + - + - License: three-clause BSD style license. + - The license text can be found in the file LICENSE. + - + - *** MOCS-COPYRIGHT-NOTICE-END *** -} + +-- | Main MoCS module +module Main where + +import Control.Monad + +import Data.List +import Data.Maybe +import System.Console.GetOpt +import System ( getArgs ) +import System.Exit ( exitSuccess ) +import qualified Data.Map as M +import Foreign.C.Types +import IO + +import PSL +import ToString +import PSLFragment +import T2Automaton +import Ordinal + +import CExpr +import CAut + +-- generated by make +import MoCSVersion + +-- -------------------------------------------------------------------------- -- +-- Program Options +data Options = Options { version :: Bool + , formula :: Maybe PSL -- takes an input method + , help :: Bool + , output :: String + } + +options :: [OptDescr (Options -> Options)] +options = [ Option ['V'] ["version"] (NoArg (\o -> o {version = True})) "show version number" + , Option ['f'] ["formula"] (ReqArg (\s o -> o {formula = getFormula s}) "STRING") "formula string" + , Option ['h'] ["help"] (NoArg (\o -> o {help = True})) "display help text" + , Option ['o'] ["output"] (ReqArg (\s o -> o {output = s}) "STRING") "output file name" + ] + +defaultOpts :: Options +defaultOpts = Options + { version = False + , formula = Nothing + , help = False + , output = "/dev/stdout" + } + +getOptions :: [String] -> IO Options +getOptions args = do + case getOpt RequireOrder options args of + (o,[f],[]) -> x (foldl (flip id) defaultOpts o, Just f) + (o,[],[]) -> x (foldl (flip id) defaultOpts o, Nothing) + (_,(_:t),[]) -> error ("Unexpected parameters: " ++ concat t ++ "\n" ++ commandLineHelp) + (_,_,errs) -> error (concat errs ++ commandLineHelp) + where + x (o@(Options { formula = Just _ }), _ ) = return o + x (o@(Options { formula = Nothing }) , Just f ) = do { x <- parseFormulaFile f; return $ o { formula = x } } + x (o@(Options { formula = Nothing }) , Nothing ) = do { x <- getContents; return $ o { formula = getFormula x } } --error ("Either option '-f' or a parameter with a formula file must be givien\n" ++ commandLineHelp) + parseFormulaFile f = readFile f >>= (return.getFormula) + +getFormula s = either (error . show) Just (parsePSL s) + +usageHeader = "\ +\MoCS [--ouput FILE] FILE\n\ +\MoCS [--output FILE] --formula STRING\n\ +\MoCS [--output FILE]\n\ +\MoCS --help\n\ +\MoCS --version\n\n\ +\The formula is provided either via the -f option or in a file.\n\ +\By default the formula is read from stdin and the result is written to stdout." + +name = "MoCS" +versionInfo = name ++ " (version " ++ mocsVersion ++ " revision " ++ mocsRevision ++ ")\n\n" ++ + "Copyright (C) 2010 Saarland University\n" ++ + "Author: Lars Kuhtz \n\n" ++ + "All rights reserved. Usage exclusively under the terms of the license\n\ + \available from: http://react.cs-uni-sb.de/tools/mocs/LICENSE\n\n" ++ + "There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A\n\ + \PARTICULAR PURPOSE." + + +syntaxHelp = "\ +\Syntax for formulas:\n\ +\\n\ +\Formula ::= '(' Formula ')' | RegEx | '\\strong' Regex\n\ +\ | PrefixOp Formula | BPrefixOp BoundExpr Formula\n\ +\ | Formula BinaryOp Formula | Formula BBinaryOp BoundExpr Formula\n\ +\ | Formula '\\abort' Prop | RegEx '\\simplies' Formula\n\ +\\n\ +\PrefixOp ::= '\\not' | '\\N' | '\\wN' | '\\G' | '\\F'\n\ +\BPreifxOp ::= '\\BN' | '\\wBN' | '\\BG' | '\\BF' | '\\sBG' | '\\wBF' \n\ +\\n\ +\BinaryOp ::= '\\and' | '\\or' | '\\implies' | '\\equiv'\n\ +\ | '\\U' | '\\W' | '\\R' | '\\sR'\n\ +\BBinaryOp ::= '\\BU' | '\\BR' | '\\BW' | '\\SBR'\n\ +\\n\ +\Prop ::= '(' Prop ')' | Var | 'true' | 'false' | '-' Prop\n\ +\ | Prop '+' Prop | Prop '^' Prop\n\ +\\n\ +\RegEx ::= '(' RegEx ')' | Prop | 'epsilon'\n\ +\ | RegEx '&&' RegEx | RegEx '|' RegEx | RegEx ':' RegEx | RegEx ';' RegEx\n\ +\ | RegEx '*' | RegEx '[' Ordinal ']'\n\ +\\n\ +\Var ::= \"[_a-zA-Z][_a-zA-Z0-9]*\"\n\ +\\n\ +\BoundExpr ::= '(' BoundExpr ')' | Ordinal\n\ +\ | BoundExpr '*' BoundExpr | '-' BoundExpr | BoundExpr '++'\n\ +\\n\ +\Ordinal ::= [0-9]+ | 'infty'" + +commandLineHelp = usageInfo usageHeader options ++ "\n\n" ++ syntaxHelp + +-- -------------------------------------------------------------------------- -- +-- main program +{-- + main = do + - x <- newAutCtx + - - a0 <- propAut x [1,2] + - - a1 <- constAut x True + - - a2 <- propAut x [2,3] + - - a3 <- andAut a0 a1 + - - a4 <- orAut a3 a2 + - - a5 <- dualAut a4 + - - a6 <- nextAut =<< gAut =<< (untilAut a4 a3) + - - autToDot "test.dot" a6 "aut" + - - print "done" + - +--} + + +-- enable / disable debugging +d a = a + +main = do + + -- get arguments + args <- getArgs + opts <- getOptions args + + when (version opts) (putStrLn versionInfo >> exitSuccess) + when (help opts) (putStrLn commandLineHelp >> exitSuccess) + + -- Parse Formula + let f = fromJust $ formula opts + --d putStrLn $ toString f + --d putStrLn $ show $ horizon f + + -- Separate + let (prefix,suffix) = separate f + let hor = maximum $ map horizon suffix + --d putSep + --d putStrLn $ "prefix-formula:" + --d putStrLn $ toString prefix + + ------------------------------------------------------------------------------ + -- Prefix Automaton + (_,ptable,a) <- createAut prefix + --d putStrLn $ "prefix-automaton (ptable):" + --d putStrLn $ toString $ ptable + + -- autToDot "pre.dot" a "prefix-automaton" + --sctx <- contextSize ctx + --d putStrLn $ "size of prefix-automaton-context: " ++ (show sctx) + + -- Universal prefix automaton + --d putStrLn $ "universal prefix-automaton:" + (_,b) <- universalAut a + -- autToDot "preu.dot" b "universal prefix-automaton" + --suctx <- contextSize uctx + --d putStrLn $ "size of universal prefix-automaton-context: " ++ (show suctx) + + -- Build state machine + -- sm <- mkStateMachine b + -- smToDot "sm.dot" sm "state machine" + + -- rollout + --d putStrLn $ "rollout " ++ (show hor) ++ " steps:" + e <- autPrefixRollout (fromInteger $ finite $ hor) b + -- putStrLn $ "get size of rollout context" + --se <- getExprCtx e >>= contextSize + --d putStrLn $ "size of rollout-context: " ++ (show $ se) + + ------------------------------------------------------------------------------ + -- Suffix Automata + -- putSep + --d putStrLn $ "number of suffixes: " ++ show (length suffix) + tmpctx <- newAutCtx + (_,stable,as) <- foldM doSuffix (tmpctx,M.empty,[]) (zip [0..] suffix) + oexprs <- mapM (rollmap hor) as + + -- exprsToDot "suffix_exprs.dot" (concatMap snd oexprs) "suffix_expressions" + + -- oexprs is a map from suffix-formulas (toString as used in variables names of prefix) + -- to its oexprs list + + -- print "build vhdl monitor" + + callVhdlBuildMonitor (output opts) (fromInteger $ finite $ hor) b ptable e oexprs stable + + -- print "done" + -- putStrLn $ concat (parMap rnf doSuffix' suffix) + + + where + rollmap h (i,a) = do + exprs <- autSuffixRollout (fromInteger $ finite $ h) a + return (i,exprs) + +doSuffix (ctx,table,as) (_,s) = do + (nctx,ntable,sa) <- createAutWithCtxAndTable ctx table s + -- putStrLn $ toString sa + -- putStrLn $ A.stats sa + -- autToDot ("suf" ++ show i ++ ".dot") sa ("suffix-automaton " ++ toString s) + --bracket (openFile ("suf" ++ show i) WriteMode) hClose (\h -> A.doA2dot h $ mkInt sa) + -- putSep + return (nctx,ntable,as ++ [(toString s,sa)]) -- what does ntable look like? + +putSep = putStrLn $ "--------------------" + +callVhdlBuildMonitor :: String -> Int -> AutPtr -> PropTable -> ExprPtr -> [(String,[ExprPtr])] -> PropTable -> IO () +callVhdlBuildMonitor + fname -- filename + hor -- horizon + prefix_automaton + ptable -- variable index tabel for prefix automaton + pa_expr -- output expression of prefix automaton + suffix_expressions -- map from suffix formulae (variable name) to list of output expressions + stable -- variable index tabel for suffix automata + = do + vhdlBuildMonitor fname hor (M.size stable) (M.size ptable) pa_expr prefix_automaton sexprs + where + sexprs :: [[ExprPtr]] + sexprs = + let + swap (a,b) = (b,a) + swap_sort_ptable :: [(CLong,String)] + swap_sort_ptable = sortBy (comp) (map swap (M.toList ptable)) + comp a b = if a < b then LT else (if b < a then GT else EQ) + in + map (\(_,v) -> maybe (lookuperror v) id (lookup v suffix_expressions)) swap_sort_ptable + + lookuperror v = error $ "variable " ++ v ++ " in ptable but not in suffix expressions" + diff --git a/haskell-frontend/Main2.hs b/haskell-frontend/Main2.hs new file mode 100644 index 0000000..3a7bc9c --- /dev/null +++ b/haskell-frontend/Main2.hs @@ -0,0 +1,162 @@ +{- *** MOCS-COPYRIGHT-NOTICE-BEGIN *** + - + - This copyright notice is auto-generated by ./add-copyright-notice. + - Additional copyright notices must be added below the last line of this notice. + - + - MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "haskell-frontend/Main2.hs". + - The content of this file is copyright of Saarland University - + - Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . + - + - This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). + - + - License: three-clause BSD style license. + - The license text can be found in the file LICENSE. + - + - *** MOCS-COPYRIGHT-NOTICE-END *** -} + +module Main where + +import Control.Monad + +import Data.List +import qualified Data.Map as M +import Foreign.C.Types +import System( getArgs ) +import IO + +import PSL +import ToString +import PSLFragment +import T2Automaton +import Ordinal + +import CExpr +import CAut + +{-- + main = do + - x <- newAutCtx + - - a0 <- propAut x [1,2] + - - a1 <- constAut x True + - - a2 <- propAut x [2,3] + - - a3 <- andAut a0 a1 + - - a4 <- orAut a3 a2 + - - a5 <- dualAut a4 + - - a6 <- nextAut =<< gAut =<< (untilAut a4 a3) + - - autToDot "test.dot" a6 "aut" + - - print "done" + - +--} + +d a = a + +main = do + + -- get arguments + args <- getArgs + let mfile = if args == [] then "monitor.vhdl" else (let (h:_) = args in h) + + -- Parse Formula + s <- getContents + f <- either (error . show) (return) (parsePSL s) + --d putStrLn $ toString f + --d putStrLn $ show $ horizon f + + -- Separate + let (prefix,suffix) = altSeparate f + --putStrLn $ toString prefix + --putStrLn $ concatMap toString suffix + let hor = maximum $ map horizon suffix + --d putSep + --d putStrLn $ "prefix-formula:" + --d putStrLn $ toString prefix + + ------------------------------------------------------------------------------ + -- Prefix Automaton + (_,ptable,a) <- createAut prefix + --d putStrLn $ "prefix-automaton (ptable):" + --d putStrLn $ toString $ ptable + + -- autToDot "pre.dot" a "prefix-automaton" + --sctx <- contextSize ctx + --d putStrLn $ "size of prefix-automaton-context: " ++ (show sctx) + + -- Universal prefix automaton + --d putStrLn $ "universal prefix-automaton:" + (_,b) <- universalAut a + -- autToDot "preu.dot" b "universal prefix-automaton" + --suctx <- contextSize uctx + --d putStrLn $ "size of universal prefix-automaton-context: " ++ (show suctx) + + -- Build state machine + -- sm <- mkStateMachine b + -- smToDot "sm.dot" sm "state machine" + + -- rollout + --d putStrLn $ "rollout " ++ (show hor) ++ " steps:" + e <- autPrefixRollout (fromInteger $ finite $ hor) b + -- putStrLn $ "get size of rollout context" + -- se <- getExprCtx e >>= contextSize + --d putStrLn $ "size of rollout-context: " ++ (show $ se) + + ------------------------------------------------------------------------------ + -- Suffix Automata + -- putSep + --d putStrLn $ "number of suffixes: " ++ show (length suffix) + tmpctx <- newAutCtx + (_,stable,as) <- foldM doSuffix (tmpctx,M.empty,[]) (zip [0..] suffix) + oexprs <- mapM (rollmap hor) as + + -- exprsToDot "suffix_exprs.dot" (concatMap snd oexprs) "suffix_expressions" + + -- oexprs is a map from suffix-formulas (toString as used in variables names of prefix) + -- to its oexprs list + + -- print "build vhdl monitor" + + callVhdlBuildMonitor mfile (fromInteger $ finite $ hor) b ptable e oexprs stable + + -- print "done" + -- putStrLn $ concat (parMap rnf doSuffix' suffix) + + + where + rollmap h (i,a) = do + exprs <- autSuffixRollout (fromInteger $ finite $ h) a + return (i,exprs) + +doSuffix (ctx,table,as) (_,s) = do + (nctx,ntable,sa) <- createAutWithCtxAndTable ctx table s + -- putStrLn $ toString sa + -- putStrLn $ A.stats sa + -- autToDot ("suf" ++ show i ++ ".dot") sa ("suffix-automaton " ++ toString s) + --bracket (openFile ("suf" ++ show i) WriteMode) hClose (\h -> A.doA2dot h $ mkInt sa) + -- putSep + return (nctx,ntable,as ++ [(toString s,sa)]) -- what does ntable look like? + +putSep = putStrLn $ "--------------------" + +callVhdlBuildMonitor :: String -> Int -> AutPtr -> PropTable -> ExprPtr -> [(String,[ExprPtr])] -> PropTable -> IO () +callVhdlBuildMonitor + fname -- filename + hor -- horizon + prefix_automaton + ptable -- variable index tabel for prefix automaton + pa_expr -- output expression of prefix automaton + suffix_expressions -- map from suffix formulae (variable name) to list of output expressions + stable -- variable index tabel for suffix automata + = do + vhdlBuildMonitor fname hor (M.size stable) (M.size ptable) pa_expr prefix_automaton sexprs + where + sexprs :: [[ExprPtr]] + sexprs = + let + swap (a,b) = (b,a) + swap_sort_ptable :: [(CLong,String)] + swap_sort_ptable = sortBy (comp) (map swap (M.toList ptable)) + comp a b = if a < b then LT else (if b < a then GT else EQ) + in + map (\(_,v) -> maybe (lookuperror v) id (lookup v suffix_expressions)) swap_sort_ptable + + lookuperror v = error $ "variable " ++ v ++ " in ptable but not in suffix expressions" + diff --git a/haskell-frontend/Makefile b/haskell-frontend/Makefile new file mode 100644 index 0000000..733b6c6 --- /dev/null +++ b/haskell-frontend/Makefile @@ -0,0 +1,27 @@ +# *** MOCS-COPYRIGHT-NOTICE-BEGIN *** +# +# This copyright notice is auto-generated by ./add-copyright-notice. +# Additional copyright notices must be added below the last line of this notice. +# +# MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "haskell-frontend/Makefile". +# The content of this file is copyright of Saarland University - +# Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . +# +# This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). +# +# License: three-clause BSD style license. +# The license text can be found in the file LICENSE. +# +# *** MOCS-COPYRIGHT-NOTICE-END *** + +ROOT=.. + +include $(ROOT)/Makefile.pre + +MODULEDEPS=libaaut c-bindings haskell-bindings + +HSTARGETS=Main Main2 + +Main: MoCSVersion.hs + +include $(ROOT)/Makefile.post diff --git a/haskell-frontend/Ordinal.hs b/haskell-frontend/Ordinal.hs new file mode 100644 index 0000000..8466366 --- /dev/null +++ b/haskell-frontend/Ordinal.hs @@ -0,0 +1,65 @@ +{- *** MOCS-COPYRIGHT-NOTICE-BEGIN *** + - + - This copyright notice is auto-generated by ./add-copyright-notice. + - Additional copyright notices must be added below the last line of this notice. + - + - MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "haskell-frontend/Ordinal.hs". + - The content of this file is copyright of Saarland University - + - Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . + - + - This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). + - + - License: three-clause BSD style license. + - The license text can be found in the file LICENSE. + - + - *** MOCS-COPYRIGHT-NOTICE-END *** -} + +module Ordinal (Ordinal(Infty,Finite),isFinite,isInfty,parseOrdinal,finite) where + +import qualified Text.ParserCombinators.Parsec as P +import PSLLexer +import ToString + +data Ordinal = Finite Integer + | Infty + deriving (Ord,Eq,Show) + +-- TODO: make sure all finite values are allways positive + +instance Num Ordinal where + (Infty) + _ = Infty + _ + (Infty) = Infty + (Finite a) + (Finite b) = Finite (a+b) + + (Infty) - _ = Infty + _ - (Infty) = Finite 0 + (Finite a) - (Finite b) = Finite (max (a-b) 0) + + negate _ = Finite 0 + + (Infty) * _ = Infty + _ * (Infty) = Infty + (Finite a) * (Finite b) = Finite (a*b) + + abs x = x -- there are no negative values! + signum (Finite 0) = 0 + signum _ = 1 + + fromInteger x | x < 0 = error "Can not build ordinal from negaive Integer" + | otherwise = Finite x + +instance ToString Ordinal where + toString (Finite x) = show x + toString Infty = "infty" + +isInfty (Infty) = True +isInfty _ = False + +isFinite = not . isInfty + +parseOrdinal :: P.Parser Ordinal +parseOrdinal = (natural >>= return . fromInteger) P.<|> (P.string "infty" >> return Infty) + +finite (Finite i) = i +finite _ = error "Can not extract integer from infty value" + diff --git a/haskell-frontend/PSL.hs b/haskell-frontend/PSL.hs new file mode 100644 index 0000000..169fbd0 --- /dev/null +++ b/haskell-frontend/PSL.hs @@ -0,0 +1,138 @@ +{- *** MOCS-COPYRIGHT-NOTICE-BEGIN *** + - + - This copyright notice is auto-generated by ./add-copyright-notice. + - Additional copyright notices must be added below the last line of this notice. + - + - MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "haskell-frontend/PSL.hs". + - The content of this file is copyright of Saarland University - + - Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . + - + - This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). + - + - License: three-clause BSD style license. + - The license text can be found in the file LICENSE. + - + - *** MOCS-COPYRIGHT-NOTICE-END *** -} + +{-# LANGUAGE IncoherentInstances, ExistentialQuantification, TypeSynonymInstances, Rank2Types #-} +module PSL where + +import Text.ParserCombinators.Parsec + +import Data.List + +import qualified Propositional as P +import qualified Regular as R +import qualified Temporal as T +import PSLLexer +import ToString +import Ordinal +import qualified PSLFragment as PSL + +-------------------------------------------------------------------------------- +type PSL = T.Formula R.Expression P.Formula +type RegularExpression = R.Expression P.Formula +type Proposition = P.Formula + +-- data TR = forall a. TempReg a => TR a -- needed for implementation of pslSubf +class PSL.PSLFragment a => TempReg a where + mkProp :: Proposition -> a + mkTemporal :: a -> PSL + isConstant :: a -> Bool + -- formulaFoldCond x :: (a -> [TR a]) -> (a -> [a] -> a) -> a -> x +-- pslSubf :: (a -> [TR]) +instance TempReg PSL where + mkProp = T.mkProp + mkTemporal = id + isConstant (T.Prop (P.Const _)) = True + isConstant _ = False + -- formualFoldCond subfFunc func f = func f (map (formulaFoldCond func) (subfFunc f)) +-- pslSubf (T.WeakReg r) = [TR r] +-- pslSubf (T.StrongReg r) = [TR r] +-- pslSubf (T.SImplies r f) = [TR r,TR f] +-- pslSubf f = map TR (PSL.subf f) +instance TempReg RegularExpression where + mkProp = R.mkProp + mkTemporal = T.mkWeakReg + isConstant (R.Prop (P.Const _)) = True + isConstant _ = False +-- pslSubf f = map TR (PSL.subf f) + -- formualFoldCond subfFunc func f = func f (map (formulaFoldCond func) (subfFunc f)) +-- +-- separate f = formulaFoldCond subfFunc func f +-- where +-- subfFunc f = if (isFinite.PSL.horizon f) then [] else pslSubf f +-- func f [] = sep f +-- func (TR (T.WeakReg f)) l = ((T.mkWeakReg f), l) +-- func (TR (T.StrongReg f)) l = ((T.mkStrongReg f), l) +-- func f l = ((PSL.constr f), (map fst l)), concatMap snd l) +-- sep x = if isConstant x then (x,[]) else ((mkProp.P.mkVar.toString) x,[mkTemporal x]) + +-- grec rf f = let l = map rf (PSL.subf f) in ((PSL.constr f) (map fst l), concatMap snd l) +-- rec (T.Prop f) = error "A proposition must not have infinit horizon." +-- rec (T.WeakReg f) = un rseparate T.mkWeakReg f +-- rec (T.StrongReg f) = un rseparate T.mkStrongReg f +-- rec (T.SImplies r f) = let (a0,b0) = rseparate r; (a1,b1) = separate' crit f in (T.mkSImplies a0 a1, b0 ++ b1) +-- rec f = grec (separate' crit) f +-- un f c s = let (a,b) = f s in (c a, b) + +-------------------------------------------------------------------------------- +-- computes the separation formulas of f +-- returns a list of separation formulas, the formula f where each separation +-- formula is replaced by a fresh variable, and a mapping (or hash table?) between these +-- variable and the separation formulas. +-- TODO: for now the mapping is implicit through the nameing of the fresh variables +-- (these are generated by use of toString) + +separate f = separate' (isFinite.PSL.horizon) f +separate' :: (forall a. PSL.PSLFragment a => a -> Bool) -> PSL -> (PSL,[PSL]) +separate' crit f = if crit f then sep f else rec f + where + -- TODO provide generic PSL recursion scheme/ fold operator instead + grec rf f = let l = map rf (PSL.subf f) in ((PSL.constr f) (map fst l), concatMap snd l) + rec (T.Prop _) = error "A proposition must not have infinit horizon." + rec (T.WeakReg f) = un rseparate T.mkWeakReg f + rec (T.StrongReg f) = un rseparate T.mkStrongReg f + rec (T.SImplies r f) = let (a0,b0) = rseparate r; (a1,b1) = separate' crit f in (T.mkSImplies a0 a1, b0 ++ b1) + rec f = grec (separate' crit) f + un f c s = let (a,b) = f s in (c a, b) + + rseparate r = if crit r then sep r else grec rseparate r + + -- This is safe, since equality propagates to toString (as it produces + -- a term that is equivalent to the parsed expression + -- Constants get propagated + sep x = if isConstant x then (x,[]) else ((mkProp.P.mkVar.toString) x,[mkTemporal x]) + +altSeparate f = separate' (null.PSL.subf) f + +freshProp :: PSL -> PSL +freshProp f = T.mkProp $ P.mkVar $ freshString (map toString $ allVars f) + where + freshString list = head (seps \\ list) + seps = map (((++) "sep") . show) [0..] + +allVars f = tAllVars f + where + tAllVars (T.Prop x) = P.allVars x + tAllVars (T.WeakReg x) = rAllVars x + tAllVars (T.StrongReg x) = rAllVars x + tAllVars f = concatMap tAllVars $ T.allRegProps f + + rAllProps (R.Prop x) = P.allVars x + rAllProps _ = error "rAllProps must be called only on Propositions" + + rAllVars r = concatMap rAllProps $ R.allProps r + + + +-------------------------------------------------------------------------------- +parsePSL s = parse pslParser "" s + +pslParser :: Parser PSL +pslParser = do + whiteSpace + x <- T.parser + eof + return x + diff --git a/haskell-frontend/PSLFragment.hs b/haskell-frontend/PSLFragment.hs new file mode 100644 index 0000000..9b9089d --- /dev/null +++ b/haskell-frontend/PSLFragment.hs @@ -0,0 +1,87 @@ +{- *** MOCS-COPYRIGHT-NOTICE-BEGIN *** + - + - This copyright notice is auto-generated by ./add-copyright-notice. + - Additional copyright notices must be added below the last line of this notice. + - + - MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "haskell-frontend/PSLFragment.hs". + - The content of this file is copyright of Saarland University - + - Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . + - + - This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). + - + - License: three-clause BSD style license. + - The license text can be found in the file LICENSE. + - + - *** MOCS-COPYRIGHT-NOTICE-END *** -} + +module PSLFragment where + +import Data.List +import Data.Either +import qualified Text.ParserCombinators.Parsec as Parsec +import ToString +import Ordinal + +type Bound = Ordinal + +type Horizon = Ordinal + +fixpoint f a = if a == na then a else fixpoint f na + where na = f a + +-- minimal set of methods: +-- dual, horizon, parser, subf, subfmap, constant + +class (Show a, ToString a, Eq a, Ord a) => PSLFragment a where + + dual :: a -> a + isDual :: a -> a -> Bool + isDual x y = (x == dual y) + + horizon :: a -> Horizon + + allSubf :: a -> [a] + allSubf f = fixpoint (\x -> nub $ x ++ (concatMap subf x)) [f] + -- Seems that this is principally not possibly with []-Monad because of order of nub and >>= (concatMap). + -- Probably the nub should go inbetween concat and Map! We would need a list-monad with concatNubMap + -- which would in fact be some kind of Set-Monad + -- allSubf f = mfix (\x -> nub $ [f] ++ subf x) + + + -- All Leaves (including duplicates) + allLeaves :: a -> [a] + allLeaves f = fixpoint (concatMap (\y -> if (subf y) == [] then [y] else subf y)) [f] + + parser :: Parsec.CharParser () a + parse :: [Char] -> Either Parsec.ParseError a + parse s = Parsec.parse parser "" s + + simplify :: a -> a + simplify = id + + constant :: Bool -> a + + atomic :: a -> Bool + atomic = null.subf + + constr :: a -> ([a] -> a) + + ------------------------------------------------------------------------------ + -- rather technical + + -- All (immediate) subformulas + subf :: a -> [a] + + -- Apply first parameter to subformulas of second parameter + -- Usefull for mutual recursive defintions (see e.g. pushNegations) + subfmap :: (a -> a) -> a -> a + + bottomUpRec :: (a -> a) -> a -> a + bottomUpRec o f = o $ subfmap (bottomUpRec o) f + + topDownRec :: (a -> a) -> a -> a + topDownRec o f = subfmap (topDownRec o) (o f) + + topDownRecCond :: (a -> (Bool,a)) -> a -> a + topDownRecCond o f = let (recurse,result) = (o f) in if recurse then subfmap (topDownRecCond o) result else result + diff --git a/haskell-frontend/PSLLexer.hs b/haskell-frontend/PSLLexer.hs new file mode 100644 index 0000000..a4c8875 --- /dev/null +++ b/haskell-frontend/PSLLexer.hs @@ -0,0 +1,100 @@ +{- *** MOCS-COPYRIGHT-NOTICE-BEGIN *** + - + - This copyright notice is auto-generated by ./add-copyright-notice. + - Additional copyright notices must be added below the last line of this notice. + - + - MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "haskell-frontend/PSLLexer.hs". + - The content of this file is copyright of Saarland University - + - Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . + - + - This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). + - + - License: three-clause BSD style license. + - The license text can be found in the file LICENSE. + - + - *** MOCS-COPYRIGHT-NOTICE-END *** -} + +module PSLLexer where + +--import Prelude +import Text.ParserCombinators.Parsec +import qualified Text.ParserCombinators.Parsec.Token as T + +------------------------------------------------------------------------------- +-- Lexer + +lexer = T.makeTokenParser lang + where + lang = T.LanguageDef { + T.commentStart = "{-", + T.commentEnd = "-}", + T.commentLine = "--", + T.nestedComments = True, + T.identStart = (letter <|> char '_'), + T.identLetter = (alphaNum <|> char '_'), +-- T.opStart = oneOf "\\*;:|&", + T.opStart = letter, + T.opLetter = pzero, + T.reservedNames = ["true","false","epsilon"], + T.reservedOpNames = [ + -- PSL + "\\strong" + + , "\\not" + , "\\and" + , "\\or" + + , "\\implies" + , "\\equiv" + + , "\\N" + , "\\BN" + , "\\wN" + , "\\wBN" + + , "\\G" + , "\\BG" + , "\\sBG" + , "\\F" + , "\\BF" + , "\\wBF" + + , "\\U" + , "\\W" + , "\\BU" + , "\\BW" + + , "\\R" + , "\\sR" + , "\\BR" + , "\\sBR" + + , "\\simplies" + , "\\abort" + + -- Expression + , "+" + , "^" + , "-" + + -- SERE + , "|" + , "*" + , "&&" + , ";" + , ":" + + -- bound Expression + , "++" + ], + T.caseSensitive = False + } + +identifier = T.identifier lexer +parens = T.parens lexer +brackets = T.brackets lexer +reserved = T.reserved lexer +reservedOp = T.reservedOp lexer +natural = T.natural lexer +whiteSpace = T.whiteSpace lexer +squares = T.squares lexer diff --git a/haskell-frontend/Propositional.hs b/haskell-frontend/Propositional.hs new file mode 100644 index 0000000..4b74ab9 --- /dev/null +++ b/haskell-frontend/Propositional.hs @@ -0,0 +1,134 @@ +{- *** MOCS-COPYRIGHT-NOTICE-BEGIN *** + - + - This copyright notice is auto-generated by ./add-copyright-notice. + - Additional copyright notices must be added below the last line of this notice. + - + - MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "haskell-frontend/Propositional.hs". + - The content of this file is copyright of Saarland University - + - Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . + - + - This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). + - + - License: three-clause BSD style license. + - The license text can be found in the file LICENSE. + - + - *** MOCS-COPYRIGHT-NOTICE-END *** -} + +module Propositional where + +import qualified Text.ParserCombinators.Parsec as P +import Text.ParserCombinators.Parsec.Expr + +import Data.List + +import ToString +import PSLLexer +import PSLFragment + +data Formula + = Var String + | Const Bool + | Or Formula Formula + | And Formula Formula + | Negate Formula + deriving (Eq,Ord,Show) + + +mkVar s = Var s +mkConst b = Const b +mkAnd x y | x < y = And x y + | otherwise = And y x +mkOr x y | x < y = Or x y + | otherwise = Or y x +mkNegate x = Negate x + +instance ToString Formula where + toString e = case e of + (Var s) -> s + (Const True) -> "true" + (Const False) -> "false" + (And x y) -> bin "^" x y + (Or x y) -> bin "+" x y + (Negate x) -> un "-" x + where + un o f = o ++ toString f + bin o f g = "(" ++ toString f ++ " " ++ o ++ " " ++ toString g ++ ")" + +instance PSLFragment Formula where + horizon _ = 0 + dual = dual' + subf = subf' + subfmap = rec + parser = formula + constant = mkConst + constr = error "not implemented yet" + + +------------------------------------------------------------------------------- +-- usefull for variable substitution + +-- subformulas as list +subf' (Negate f) = [f] +subf' (Or f g) = [f, g] +subf' (And f g) = [f, g] +subf' _ = [] + +allVars :: Formula -> [Formula] +allVars h = case h of + (Const _) -> [] + (Var _) -> return h + _ -> subf h >>= allVars + +-- Usefull for mutual recursive defintions (see e.g. pushNegations) +rec a (Negate f) = mkNegate (a f) +rec a (Or f g) = mkOr (a f) (a g) +rec a (And f g) = mkAnd (a f) (a g) +rec _ f = f + +------------------------------------------------------------------------------- +-- Dualities +dual' (Var s) = mkNegate (mkVar s) +dual' (Const True) = mkConst False +dual' (Const False) = mkConst True + +dual' (Negate f) = f +dual' (Or f g) = mkAnd (dual' f) (dual' g) +dual' (And f g) = mkOr (dual' f) (dual' g) + +------------------------------------------------------------------------------- +-- Push negations to state level + +pushNegations (Negate f) = dual f +pushNegations f = rec pushNegations f + +------------------------------------------------------------------------------- +-- misc +isBinary f = length (subf f) == 2 + +allEq [] = True +allEq [_] = True +allEq (a:b:t) = (a == b) && (allEq (b:t)) + +------------------------------------------------------------------------------- +-- Formula-Parser + +-- formula :: CharParser st Formula +formula = + buildExpressionParser table expr + P. "Formula: formula" + +expr = parens formula + P.<|> (identifier >>= return . mkVar) + P.<|> (reserved "true" >> return (mkConst True)) + P.<|> (reserved "false" >> return (mkConst False)) + P. "Formula: atomic expression" + + +-- table :: OperatorTable Char () Formula +table = [ [prefix "-" mkNegate] + , [binary "^" mkAnd AssocLeft, binary "+" mkOr AssocLeft] + ] + +binary name fun assoc = Infix (reservedOp name >> return fun) assoc +prefix name fun = Prefix (reservedOp name >> return fun) + diff --git a/haskell-frontend/Regular.hs b/haskell-frontend/Regular.hs new file mode 100644 index 0000000..180ca39 --- /dev/null +++ b/haskell-frontend/Regular.hs @@ -0,0 +1,133 @@ +{- *** MOCS-COPYRIGHT-NOTICE-BEGIN *** + - + - This copyright notice is auto-generated by ./add-copyright-notice. + - Additional copyright notices must be added below the last line of this notice. + - + - MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "haskell-frontend/Regular.hs". + - The content of this file is copyright of Saarland University - + - Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . + - + - This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). + - + - License: three-clause BSD style license. + - The license text can be found in the file LICENSE. + - + - *** MOCS-COPYRIGHT-NOTICE-END *** -} + +-- TODO Use submodule for r2aut +module Regular where + +import qualified Text.ParserCombinators.Parsec as P +import Text.ParserCombinators.Parsec.Expr + +import Data.List + +import PSLLexer +import ToString +import PSLFragment +import Ordinal + +data Expression prop + = Prop prop + | Conc (Expression prop) (Expression prop) + | OConc (Expression prop) (Expression prop) + | Union (Expression prop) (Expression prop) + | Intersection (Expression prop) (Expression prop) + | Epsilon + | Kleene Ordinal (Expression prop) + deriving (Eq,Ord,Show) + +mkProp e = Prop e +mkConc x y = Conc x y +mkOConc x y = OConc x y +mkUnion x y | x < y = Union x y + | otherwise = Union y x +mkIntersection x y | x < y = Intersection x y + | otherwise = Intersection y x +mkEpsilon = Epsilon +mkKleene b x = Kleene b x + +instance (ToString prop) => ToString (Expression prop) where + toString r = case r of + (Prop e) -> toString e + (Conc x y) -> bin ";" x y + (OConc x y) -> bin ":" x y + (Union x y) -> bin "|" x y + (Intersection x y) -> bin "&&" x y + (Epsilon) -> "epsilon" + (Kleene Infty x) -> toString x ++ "*" + (Kleene b x) -> toString x ++ "[" ++ toString b ++ "]" + where + bin o f g = "(" ++ toString f ++ " " ++ o ++ " " ++ toString g ++ ")" + +-- TODO: dual, horizon, subf, subfmap +instance (PSLFragment prop) => PSLFragment (Expression prop) where + dual = id + horizon = horizon' + subf x = subf' x + subfmap _ = id + parser = formula + constant = mkProp . constant + constr = constr' + +horizon' (Conc x y) = horizon' x + horizon' y + 1 +horizon' (OConc x y) = horizon' x + horizon' y +horizon' (Prop y) = horizon y +horizon' (Union x y) = max (horizon' x) (horizon' y) +horizon' (Intersection x y) = max (horizon' x) (horizon' y) +horizon' (Epsilon) = 0 +horizon' (Kleene b x) = (((horizon' x)+1) * b) - 1 + +------------------------------------------------------------------------------- + +subf' (Conc x y) = [x,y] +subf' (OConc x y) = [x,y] +subf' (Union x y) = [x,y] +subf' (Intersection x y) = [x,y] +subf' (Kleene _ x) = [x] +subf' _ = [] + +allProps :: (PSLFragment prop) => Expression prop -> [Expression prop] +allProps h = case h of + (Prop _) -> return h + _ -> subf h >>= allProps + +constr' f = case f of + (Prop _) -> const f + (Conc _ _) -> bin mkConc + (OConc _ _) -> bin mkOConc + (Union _ _) -> bin mkUnion + (Intersection _ _) -> bin mkIntersection + (Epsilon) -> const f + (Kleene b _) -> bun mkKleene b + where + bun c b = \(x:_) -> c b x + bin c = \(l:r:_) -> c l r + +------------------------------------------------------------------------------- +-- Expression-Parser + +formula :: (PSLFragment prop) => P.CharParser () (Expression prop) +formula = + buildExpressionParser table aexpr + P. "Expression: formula" + +aexpr :: (PSLFragment prop) => P.CharParser () (Expression prop) +aexpr = P.try (parser >>= return . mkProp) + P.<|> (reserved "epsilon" >> return mkEpsilon) + P.<|> parens formula + P. "Expression: atomic expression" + + +table :: (PSLFragment prop) => [[Operator Char () (Expression prop)]] +table = [ [repetition] + , [kleene] + , [binary "|" mkUnion AssocLeft, binary "&&" mkIntersection AssocLeft] + , [binary ";" mkConc AssocLeft, binary ":" mkOConc AssocLeft] + ] + +binary name fun assoc = Infix (reservedOp name >> return fun) assoc +aBinary name fun assoc = Infix (reservedOp name >> return fun) assoc +repetition = Postfix (squares parseOrdinal >>= return . mkKleene) +kleene = Postfix (reservedOp "*" >> return (mkKleene Infty)) + diff --git a/haskell-frontend/T2Automaton.hs b/haskell-frontend/T2Automaton.hs new file mode 100644 index 0000000..75af241 --- /dev/null +++ b/haskell-frontend/T2Automaton.hs @@ -0,0 +1,224 @@ +{- *** MOCS-COPYRIGHT-NOTICE-BEGIN *** + - + - This copyright notice is auto-generated by ./add-copyright-notice. + - Additional copyright notices must be added below the last line of this notice. + - + - MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "haskell-frontend/T2Automaton.hs". + - The content of this file is copyright of Saarland University - + - Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . + - + - This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). + - + - License: three-clause BSD style license. + - The license text can be found in the file LICENSE. + - + - *** MOCS-COPYRIGHT-NOTICE-END *** -} + +module T2Automaton where + +import Control.Monad.State +import qualified Data.Map as M + +-- import Debug.Trace +import Foreign.C.Types + +import CExpr +import CAut + +import Ordinal +import PSLFragment +import qualified Temporal as T +import qualified Regular as R +import qualified Propositional as P + +xxx a b = do { x <- a; lift $ b x} +yyy a b c = do { x <- a; y <- b; lift $ c x y} + +------------------------------------------------------------------------------- +-- | Maps propositions to the corresponding port-numbers of the automaton +type PropTable = M.Map String CLong + +------------------------------------------------------------------------------- +-- p2aut +p2aut :: P.Formula -> StateT (AutCtxPtr,PropTable) IO AutPtr +p2aut (P.Var s) = do + (ctx,table) <- get + let (ntable,p) = query table s + put (ctx,ntable) + lift $ propAut ctx [p] + +p2aut (P.Const b) = do { ctx <- gets fst; lift $ constAut ctx b} +p2aut (P.Or a b) = yyy (p2aut a) (p2aut b) orAut +p2aut (P.And a b) = yyy (p2aut a) (p2aut b) andAut +p2aut (P.Negate a) = p2aut a `xxx` dualAut + +------------------------------------------------------------------------------- +-- r2aut +query table e = maybe (M.insert e (int2c $ M.size table) table, (int2c $ M.size table)) + (\x -> (table, x)) + (M.lookup e table) + +r2aut :: R.Expression P.Formula -> StateT (AutCtxPtr,PropTable) IO AutPtr +r2aut (R.Prop e) = p2aut e + +-- Conc +r2aut (f `R.Conc` g) = yyy (r2aut f) (r2aut g) concAut +r2aut (f `R.OConc` g) = yyy (r2aut f) (r2aut g) oconcAut + +-- Kleene Closure +r2aut (R.Kleene Infty f) = xxx (r2aut f) kleeneAut + +-- Finite bound: reduce to Conc +r2aut (R.Kleene (Finite 0) _) = r2aut R.mkEpsilon +r2aut (R.Kleene b r) = r2aut (r `R.Conc` (R.mkKleene (b-1) r)) + +-- Union +r2aut (f `R.Union` g) = yyy (r2aut f) (r2aut g) unionAut + +-- Epsilon +r2aut R.Epsilon = do { ctx <- gets fst; lift $ emptyAut ctx} + +{-- +-- Intersection +r2aut (R.Intersection r0 r1) = liftM2 autIntersection (r2aut r0) (r2aut r1) >>= mkUnique +--} + +r2aut x = error $ "not implemented yet: " ++ (show x) + +-- ----------------------------------------------------------------------------- +-- | Build an alternating automaton from 'T.Formula' over 'R.Expression' + +createAut :: T.Formula R.Expression P.Formula -> IO (AutCtxPtr,PropTable,AutPtr) +createAut f = do + ctx <- newAutCtx + (a,(x,t)) <- runStateT (t2aut f) (ctx,M.empty) + return (x,t,a) + +createAutWithTable :: PropTable -> T.Formula R.Expression P.Formula -> IO (AutCtxPtr,PropTable,AutPtr) +createAutWithTable table f = do + ctx <- newAutCtx + (a,(x,t)) <- runStateT (t2aut f) (ctx,table) + return (x,t,a) + +createAutWithCtx :: AutCtxPtr -> T.Formula R.Expression P.Formula -> IO (AutCtxPtr,PropTable,AutPtr) +createAutWithCtx ctx f = do + (a,(x,t)) <- runStateT (t2aut f) (ctx,M.empty) + return (x,t,a) + +createAutWithCtxAndTable :: AutCtxPtr -> PropTable -> T.Formula R.Expression P.Formula -> IO (AutCtxPtr,PropTable,AutPtr) +createAutWithCtxAndTable ctx table f = do + (a,(x,t)) <- runStateT (t2aut f) (ctx,table) + return (x,t,a) + +-- A StateT Monad over IO. Passes around the context and a PropTabel +t2aut :: T.Formula R.Expression P.Formula -> StateT (AutCtxPtr,PropTable) IO AutPtr + +t2aut f = -- trace ("t2aut: " ++ toString f) $ + t2aut' f + +-- Prop (strong by default) -- FIXME does not happen for now, there are SEREs! +t2aut' (T.Prop p) = p2aut p + +-- r2aut implements tight modeling. Hence we need to append (true)* +-- Reg (default semantics as implemented by r2aut is strong!) +--t2aut' (T.StrongReg r) = r2aut (r `R.mkConc` R.mkKleene Infty (R.mkProp (P.mkConst True))) +t2aut' (T.StrongReg r) = r2aut (r `R.mkConc` tail_aut) +--t2aut' (T.StrongReg r) = r2aut r + where + tail_aut = either (error "") (id) (parse "epsilon|true") + +-- WeakReg +--t2aut' (T.WeakReg r) = r2aut (r `R.mkConc` R.mkKleene Infty (R.mkProp (P.mkConst True))) `xxx` weakAut +t2aut' (T.WeakReg r) = r2aut (r `R.mkConc` tail_aut) `xxx` weakAut +--t2aut' (T.WeakReg r) = r2aut r `xxx` weakAut + where + tail_aut = either (error "") (id) (parse "epsilon|true") + +-- Negate +t2aut' (T.Negate f) = t2aut f `xxx` dualAut +-- And +t2aut' (f `T.And` g) = yyy (t2aut f) (t2aut g) andAut +-- Or +t2aut' (f `T.Or` g) = yyy (t2aut f) (t2aut g) orAut + +-- Build alternating automaton for 'T.Next' +t2aut' (T.Next Infty f) = t2aut f `xxx` nextAut +t2aut' (T.Next b f) = t2aut f `xxx` bnextAut (int2c (finite b)) +t2aut' (T.WNext Infty f) = t2aut f `xxx` wnextAut +t2aut' (T.WNext b f) = t2aut f `xxx` wbnextAut (int2c (finite b)) + +-- Globally +t2aut' (T.Globally (Finite 0) f) = t2aut f +t2aut' (T.Globally Infty f) = t2aut f `xxx` gAut +t2aut' (T.Globally b f) = t2aut f `xxx` bgAut (int2c (finite b)) + +-- strong Globally (TODO) +t2aut' (T.SGlobally Infty _) = error "Monitoring strong unbounded globally is meaningless. If you want to replace it by 'false' enable this in PSLFragment.hs." +-- t2aut' (T.SGlobally Infty f) = p2aut (P.mkConst False) +t2aut' (T.SGlobally b f) = t2aut f `xxx` sbgAut (int2c (finite b)) + +-- Eventually +t2aut' (T.Eventually (Finite 0) f) = t2aut f +t2aut' (T.Eventually Infty f) = t2aut f `xxx` fAut +t2aut' (T.Eventually b f) = t2aut f `xxx` bfAut (int2c (finite b)) + +-- weak Eventually (TODO) +t2aut' (T.WEventually Infty _) = error "Monitoring weak unbounded eventually is meaningless. If you want to replace it by 'true' enable this in PSLFragment.hs." +-- t2aut' (T.WEventually Infty f) = p2aut (P.mkConst True) +t2aut' (T.WEventually b f) = t2aut f `xxx` wbfAut (int2c (finite b)) + +-- Until +t2aut' (T.Until (Finite 0) _ g) = t2aut g +t2aut' (T.Until Infty f g) = yyy (t2aut f) (t2aut g) untilAut +t2aut' (T.Until b f g) = yyy (t2aut f) (t2aut g) (buntilAut (int2c (finite b))) + +-- Waitfor (TODO) +t2aut' (T.Waitfor (Finite 0) _ g) = t2aut g +t2aut' (T.Waitfor Infty f g) = yyy (t2aut f) (t2aut g) waitforAut +t2aut' (T.Waitfor b f g) = yyy (t2aut f) (t2aut g) (bwaitforAut (int2c (finite b))) + +-- Release +t2aut' (T.Release (Finite 0) _ g) = t2aut g +t2aut' (T.Release Infty f g) = yyy (t2aut f) (t2aut g) releaseAut +t2aut' (T.Release b f g) = yyy (t2aut f) (t2aut g) (breleaseAut (int2c (finite b))) + +-- strong Release (TODO) +t2aut' (T.SRelease (Finite 0) _ g) = t2aut g +t2aut' (T.SRelease Infty f g) = yyy (t2aut f) (t2aut g) sreleaseAut +t2aut' (T.SRelease b f g) = yyy (t2aut f) (t2aut g) (sbreleaseAut (int2c (finite b))) + +-- Build alternating automaton for 'T.Abort' +t2aut' (T.Abort f b) = yyy (t2aut f) (p2aut b) abortAut +{-- + a <- t2aut f + st <- newUnique + let delta' = M.map (\x -> (x `mkAnd` (NProp b)) `mkOr` ((State st) `mkAnd` (Prop b))) (delta a) + let delta'' = M.insert st (Const False) (delta') + return $ a { states = S.insert st (states a) + , final = S.insert st (final a) + , delta = delta' + } +--} + +-- Build alternating automaton for 'T.SImplies' +-- NOTE: Use strong semantics (and tight?) for r (as implemented by r2aut) +-- Reason: the context can switch to weak either through negation (in this +-- case the dualization does the right thing) or by some weak temporal +-- operator (in this case the acceptance does not to be adjusted recursively). +t2aut' (T.SImplies r f) = yyy (r2aut r) (t2aut f) simpliesAut + +{-- +t2aut' (T.SImplies r f) = do + ar <- r2aut r + dar <- mkUnique $ autDual ar + af <- t2aut f + let delta' = (delta af) `M.union` (delta dar) `M.union` (M.map (mapExprCond (const (initial af)) (isFinal ar)) (delta ar)) + return $ A { props = (props ar) `S.union` (props dar) `S.union` (props af) + , states = (states ar) `S.union` (states dar) `S.union` (states af) + , initial = (initial ar) `mkOr` (initial dar) + , final = (final af) `S.union` (final dar) + , delta = delta' + } +--} + +-- t2aut' x = error $ "not implemented yet: " ++ (show x) diff --git a/haskell-frontend/Temporal.hs b/haskell-frontend/Temporal.hs new file mode 100644 index 0000000..38a6020 --- /dev/null +++ b/haskell-frontend/Temporal.hs @@ -0,0 +1,627 @@ +{- *** MOCS-COPYRIGHT-NOTICE-BEGIN *** + - + - This copyright notice is auto-generated by ./add-copyright-notice. + - Additional copyright notices must be added below the last line of this notice. + - + - MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "haskell-frontend/Temporal.hs". + - The content of this file is copyright of Saarland University - + - Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . + - + - This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). + - + - License: three-clause BSD style license. + - The license text can be found in the file LICENSE. + - + - *** MOCS-COPYRIGHT-NOTICE-END *** -} + +{-# LANGUAGE FlexibleContexts #-} +{- Logic: + - * Prop + - * WeakReg (weak) + - * StrongReg (strong) + - + - * Negate + - * And + - * Or + - + - * Next (weak) + - * BNext (weak) + - * WNext (strong) + - * WBNext (strong) + - + - * Until (strong) (sugar) + - * Waitfor (weak) (sugar) + - * BUntil (strong) + - * BWaitfor (weak) + - + - * Release (weak) (sugar) + - * SRelease (strong) (sugar) + - * BRelease (weak) + - * SBRelease (strong) + - + - * Globally (weak) (sugar) + - * BGlobally (weak) + - * SBGlobally (strong) + - + - * Eventually (strong) (sugar) + - * BEventually (strong) + - * WBEventually (weak) + - + - * Abort + - * Simplies + -} + +module Temporal + ( Formula(..) + , mkProp + , mkWeakReg + , mkStrongReg + + , mkNegate + , mkAnd + , mkOr + + , mkNext + , mkBNext + , mkWNext + , mkWBNext + + , mkUntil + , mkWaitfor + , mkBUntil + , mkBWaitfor + + , mkRelease + , mkSRelease + , mkBRelease + , mkSBRelease + + , mkGlobally + , mkBGlobally + , mkSBGlobally + + , mkEventually + , mkBEventually + , mkWBEventually + + , mkAbort + , mkSImplies + + , mkImplies + , mkEquiv + + , formula + , parser + , pushNegations + , simplify + --, unfoldLevelF + --, unfoldF + --, unfoldAllF + --, unfoldBoundedF + , pushNextRec + , allSubf + , allLeaves + , dual + , rec + , toString + , allRegProps + , allRegs + , allProps + , isBounded + ) + +where + +import qualified Text.ParserCombinators.Parsec as P +import Text.ParserCombinators.Parsec.Expr + +import Data.Typeable +import Data.List + +import PSLLexer +import ToString +import PSLFragment +import Ordinal + +-- usualy reg should be defined upon prop as well. +data Formula reg prop + = Prop prop + | WeakReg (reg prop) + | StrongReg (reg prop) + + | Negate (Formula reg prop) + | And (Formula reg prop) (Formula reg prop) + | Or (Formula reg prop) (Formula reg prop) + + | Next Bound (Formula reg prop) + | WNext Bound (Formula reg prop) + + | Until Bound (Formula reg prop) (Formula reg prop) + | Waitfor Bound (Formula reg prop) (Formula reg prop) + | Release Bound (Formula reg prop) (Formula reg prop) + | SRelease Bound (Formula reg prop) (Formula reg prop) + + | Globally Bound (Formula reg prop) + | SGlobally Bound (Formula reg prop) + | Eventually Bound (Formula reg prop) + | WEventually Bound (Formula reg prop) + + | Abort (Formula reg prop) prop + | SImplies (reg prop) (Formula reg prop) + deriving (Eq, Ord,Show) + +instance (Typeable (reg prop), Typeable prop) => Typeable (Formula reg prop) where + typeOf f = mkTyConApp (mkTyCon "Formula") [typeOf f] + +instance (PSLFragment (reg prop), PSLFragment prop) => PSLFragment (Formula reg prop) where + horizon = horizon' + dual = dual' + subfmap = rec + subf = subf' + parser = formula + constant = mkProp . constant + simplify = simplify' + constr = constr' + +-- horizon +horizon' (Prop p) = horizon p +horizon' (WeakReg r) = horizon r +horizon' (StrongReg r) = horizon r + +horizon' (Negate f) = horizon' f +horizon' (And f g) = max (horizon' f) (horizon' g) +horizon' (Or f g) = max (horizon' f) (horizon' g) + +horizon' (Next b f) = horizon' f + b +horizon' (WNext b f) = horizon' f + b + +horizon' (Until b f g) = max (b + horizon' f) ((b - 1) + horizon' g) +horizon' (Waitfor b f g) = max (b + horizon' f) ((b - 1) + horizon' g) +horizon' (Release b f g) = max (b + horizon' f) (b + horizon' g) +horizon' (SRelease b f g) = max (b + horizon' f) (b + horizon' g) + +horizon' (Globally b f) = horizon' f + b +horizon' (SGlobally b f) = horizon' f + b +horizon' (Eventually b f) = horizon' f + b +horizon' (WEventually b f) = horizon' f + b + +horizon' (Abort f _) = horizon' f +horizon' (SImplies r f) = (horizon r) + (horizon' f) - 1 + +-- generator +mkProp e = Prop e +mkWeakReg s = WeakReg s +mkStrongReg b = StrongReg b + +mkNegate x = Negate x +mkAnd x y | x < y = And x y + | otherwise = And y x +mkOr x y | x < y = Or x y + | otherwise = Or y x + +mkNext x = Next 1 x +mkWNext x = WNext 1 x + +mkBNext b x = Next b x +mkWBNext b x = WNext b x + +mkUntil x y = Until Infty x y +mkWaitfor x y = Waitfor Infty x y +mkBUntil b x y = Until b x y +mkBWaitfor b x y = Waitfor b x y + +mkRelease x y = Release Infty x y +mkSRelease x y = SRelease Infty x y +mkBRelease b x y = Release b x y +mkSBRelease b x y = SRelease b x y + +mkGlobally x = Globally Infty x +mkBGlobally b x = Globally b x +mkSBGlobally b x = SGlobally b x + +mkEventually x = Eventually Infty x +mkBEventually b x = Eventually b x +mkWBEventually b x = WEventually b x + +mkAbort f e = Abort f e +mkSImplies r f = SImplies r f + +-- suguar +mkImplies x y = mkOr (mkNegate x) y +mkEquiv x y = mkAnd (mkImplies x y) (mkImplies y x) + +------------------------------------------------------------------------------- +-- Note: we maintain arguments of associative operators (and, or) ordered. +-- Alternatively we could have coded this into the instanciation of EQ. +-- The ordered approach is probably more efficient. It Requires, however, that +-- The mk-Constructors are always used to create new Formulas. + + +------------------------------------------------------------------------------- +-- constr +constr' f = case f of + (Prop _) -> const f + (StrongReg _) -> const f + (WeakReg _) -> const f + (Negate _) -> un mkNegate + (And _ _) -> bin mkAnd + (Or _ _) -> bin mkOr + (Next b _) -> bun mkBNext b + (WNext b _) -> bun mkWBNext b + (Until b _ _) -> bbin mkBUntil b + (Waitfor b _ _) -> bbin mkBWaitfor b + (Release b _ _) -> bbin mkBRelease b + (SRelease b _ _) -> bbin mkSBRelease b + (Globally b _) -> bun mkBGlobally b + (SGlobally b _) -> bun mkSBGlobally b + (Eventually b _) -> bun mkBEventually b + (WEventually b _) -> bun mkWBEventually b + (Abort _ e) -> (\(x:_) -> mkAbort x e) + (SImplies r _) -> (\(x:_) -> mkSImplies r x) + where + un c = \(x:_) -> c x + bun c b = \(x:_) -> c b x + bin c = \(l:r:_) -> c l r + bbin c b = \(l:r:_) -> c b l r + +------------------------------------------------------------------------------- +-- show +-- Currently prints out format used by parser +-- TODO set parenthesis only where needed +instance (Show prop, Show (reg prop), ToString (reg prop), ToString prop) => ToString (Formula reg prop) where + toString f = case f of + (Prop e) -> toString e + (StrongReg r) -> un "\\strong" r + (WeakReg r) -> toString r + + (Negate f) -> un "\\not" f + (And f g) -> bin "\\and" f g + (Or f g) -> bin "\\or" f g + + (Next Infty f) -> un "\\N" f + (WNext Infty f) -> un "\\wN" f + (Next b f) -> bbin "\\BN" b f + (WNext b f) -> bbin "\\wBN" b f + + (Until Infty f g) -> bin "\\U" f g + (Waitfor Infty f g) -> bin "\\W" f g + (Until b f g) -> tri "\\BU" b f g + (Waitfor b f g) -> tri "\\BW" b f g + + (Release Infty f g) -> bin "\\R" f g + (SRelease Infty f g) -> bin "\\sR" f g + (Release b f g) -> tri "\\BR" b f g + (SRelease b f g) -> tri "\\sBR" b f g + + (Globally Infty f) -> un "\\G" f + (Globally b f) -> bbin "\\BG" b f + (SGlobally b f) -> bbin "\\sBG" b f + + (Eventually Infty f) -> un "\\F" f + (Eventually b f) -> bbin "\\BF" b f + (WEventually b f) -> bbin "\\wBF" b f + + (Abort f e) -> bin "\\abort" f e + (SImplies r f) -> bin "\\simplies" r f + + where + un o f = o ++ " " ++ toString f + bin o f g = "(" ++ toString f ++ " " ++ o ++ " " ++ toString g ++ ")" + bbin o b f = o ++ " " ++ p b ++ " " ++ toString f + tri o b f g = "(" ++ toString f ++ " " ++ o ++ " " ++ p b ++ " " ++ toString g ++ ")" + p b = toString b + +------------------------------------------------------------------------------- +-- usefull for variable substitution + +-- subformulas as list +subf' (Negate f) = [f] +subf' (Or f g) = [f, g] +subf' (And f g) = [f, g] + +subf' (Next _ f) = [f] +subf' (WNext _ f) = [f] + +subf' (Globally _ f) = [f] +subf' (SGlobally _ f) = [f] +subf' (Eventually _ f) = [f] +subf' (WEventually _ f) = [f] + +subf' (Until _ f g) = [f, g] +subf' (Waitfor _ f g) = [f, g] +subf' (Release _ f g) = [f, g] +subf' (SRelease _ f g) = [f, g] + +subf' (Abort f _) = [f] +subf' (SImplies _ f) = [f] + +subf' _ = [] + +allRegs :: Formula reg prop -> [Formula reg prop] +allRegs h = case h of + (WeakReg _) -> return h + (StrongReg _) -> return h + _ -> subf' h >>= allRegs + +allProps :: Formula reg prop -> [Formula reg prop] +allProps h = case h of + (Prop _) -> return h + _ -> subf' h >>= allProps + +allRegProps :: Formula reg prop -> [Formula reg prop] +allRegProps h = case h of + (WeakReg _) -> return h + (StrongReg _) -> return h + (Prop _) -> return h + _ -> subf' h >>= allRegProps + + +-- Usefull for mutual recursive defintions (see e.g. pushNegations) +rec :: (Ord (reg prop), Ord prop, PSLFragment (Formula reg prop)) => + (Formula reg prop -> Formula reg prop) -> Formula reg prop -> Formula reg prop +rec a f = if atomic f then f else (constr f) (map a (subf f)) + +------------------------------------------------------------------------------- +-- Dualities +dual' (Prop f) = mkNegate (mkProp f) +dual' (WeakReg f) = mkNegate (mkWeakReg f) +dual' (StrongReg f) = mkNegate (mkStrongReg f) + +dual' (Negate f) = f +dual' (Or f g) = mkAnd (dual f) (dual g) +dual' (And f g) = mkOr (dual f) (dual g) + +dual' (Next b f) = mkWBNext b (dual f) +dual' (WNext b f) = mkBNext b (dual f) + +dual' (Globally b f) = mkBEventually b (dual f) +dual' (SGlobally b f) = mkWBEventually b (dual f) +dual' (Eventually b f) = mkBGlobally b (dual f) +dual' (WEventually b f) = mkSBGlobally b (dual f) + +dual' (Until b f g) = mkBRelease b (dual f) (dual g) +dual' (Waitfor b f g) = mkSBRelease b (dual f) (dual g) +dual' (Release b f g) = mkBUntil b (dual f) (dual g) +dual' (SRelease b f g) = mkBWaitfor b (dual f) (dual g) + +dual' (Abort f e) = mkNegate (mkAbort f e) +dual' (SImplies r f) = (mkNegate (StrongReg r)) `mkOr` (r `mkSImplies` (dual f)) + +------------------------------------------------------------------------------- +-- Push negations to state level + +pushNegations (Negate f) = dual f +pushNegations f = rec pushNegations f + +------------------------------------------------------------------------------- +-- Push Next-Operators +pushNext h = case h of + (Next b (Negate f)) -> mkNegate $ mkWBNext b f + (WNext b (Negate f)) -> mkNegate $ mkBNext b f + (Next b f) -> rec (mkBNext b) f + (WNext b f) -> rec (mkWBNext b) f + _ -> h + +pushNextRec h = bottomUpRec p' h + where + p' h = case h of { (Next b f) -> topDownRec pushNext (mkBNext b f); _ -> h} + +------------------------------------------------------------------------------- +-- misc +isBinary f = length (subf f) == 2 + +isBounded (Next u _) = isFinite u +isBounded (WNext u _) = isFinite u +isBounded (Globally u _) = isFinite u +isBounded (SGlobally u _) = isFinite u +isBounded (Eventually u _) = isFinite u +isBounded (WEventually u _) = isFinite u +isBounded (Until u _ _) = isFinite u +isBounded (Waitfor u _ _) = isFinite u +isBounded (Release u _ _) = isFinite u +isBounded (SRelease u _ _) = isFinite u +isBounded _ = True + +allEq [] = True +allEq [_] = True +allEq (a:b:t) = (a == b) && (allEq (b:t)) + +------------------------------------------------------------------------------- +-- Simplification rules + +simplify' f = bottomUpRec (simple5 . simple4 . simple3 . simple2 . simple1) f + +simple1 (Abort f e) = mkAbort f e +simple1 (SImplies r f) = mkSImplies r f +simple1 h = if isBinary h && allEq (subf h) then head (subf h) else h + +-- (Constants are not part of PSL any more) +simple2 = id + +{- +-- Dualities for binary operators +simple3 (Or f g) | isDual f g = mkConst True + | otherwise = mkOr f g +simple3 (And f g) | isDual f g = mkConst False + | otherwise = mkAnd f g +simple3 (BUntil b f g) | isDual f g = mkBUntil b (Const True) g + | otherwise = mkBUntil b f g +simple3 (BRelease b f g) | isDual f g = mkConst True + | otherwise = mkBRelease b f g +simple3 (WBUntil b f g) | isDual f g = mkWBUntil b (Const True) g + | otherwise = mkWBUntil b f g +simple3 (WBRelease b f g) | isDual f g = mkConst True + | otherwise = mkWBRelease b f g +simple3 f = f +-} +simple3 = id + +-- Negation +simple4 (Negate f) = dual f +simple4 f = f + +-- temporal nesting with equal subformulas +{- +simple5 x = case x of + (f `Until` (g `Until` h)) -> if f == h || f == g then (g `mkUntil` h) else x + ((f `Until` g) `Until` h) -> if f == h then (g `mkUntil` f) else + if g == h then (f `mkUntil` g) else x + (BUntil b0 f (BUntil b1 g h)) -> if f == h || f == g then (BUntil (b0+b1) g h) else x + (BUntil b0 (BUntil b1 f g) h) -> if f == h then (BUntil b0 g f) else + if g == h then (BUntil b1 f g) else x + -- TODO weak version + (f `Release` (g `Release` h)) -> if f == h then (h `mkRelease` g) else + if f == g then (g `mkRelease` h) else x + ((f `Release` g) `Release` h) -> if f == h || g == h then (f `mkRelease` g) else x + -- TODO bounded version + -- TODO weak version + _ -> x +-} +simple5 = id +--balance (And (And f g) h) = +-- TODO: flatten it into a list (use list-monad), elimiate duplicate subformulas, +-- check for contradictions and rebuild a balanced tree. + +-- TODO: add more simplification rules in a more systematic way. + +------------------------------------------------------------------------------- +-- Unfold temporal operators + +{- +-- unfold top level operator +unfoldF f = unfoldF' unfoldF f + +-- unfold f i steps +unfoldLevelF 0 f = f +unfoldLevelF i f = unfoldF' (unfoldLevelF (i-1)) f + +-- recursively unfold all operators +unfoldAllF f = bottomUpRec unfoldF f + +-- recursively unfold all bounded operators +unfoldBoundedF f = bottomUpRec (\x -> if isBounded x then unfoldF x else x) f + +-- Fixpoint characterization +unfoldF' r (BUntil (0,0) f g) = g +unfoldF' r (BUntil (_,0) f g) = error "lower bound must not be greater than upper bound" +unfoldF' r (BUntil (0,u) f g) = g `mkOr` (f `mkAnd` (mkNext (r (mkBUntil (0,u-1) f g)))) +unfoldF' r (BUntil (l,u) f g) = mkNext (mkBUntil (l-1,u-1) f g) + +unfoldF' r (WBUntil (0,0) f g) = g +unfoldF' r (WBUntil (_,0) f g) = error "lower bound must not be greater than upper bound" +unfoldF' r (WBUntil (0,u) f g) = g `mkOr` (f `mkAnd` (mkWNext (r (mkBUntil (0,u-1) f g)))) +unfoldF' r (WBUntil (l,u) f g) = mkWNext (mkWBUntil (l-1,u-1) f g) + +unfoldF' r (BRelease (0,0) f g) = g +unfoldF' r (BRelease (_,0) f g) = error "lower bound must not be greater than upper bound" +unfoldF' r (BRelease (0,u) f g) = g `mkAnd` (f `mkOr` (mkNext (r (mkBRelease (0,u-1) f g)))) +unfoldF' r (BRelease (l,u) f g) = mkNext (mkBRelease (l-1,u-1) f g) + +unfoldF' r (WBRelease (0,0) f g) = g +unfoldF' r (WBRelease (_,0) f g) = error "lower bound must not be greater than upper bound" +unfoldF' r (WBRelease (0,u) f g) = g `mkAnd` (f `mkOr` (mkWNext (r (mkWBRelease (0,u-1) f g)))) +unfoldF' r (WBRelease (l,u) f g) = mkWNext (mkWBRelease (l-1,u-1) f g) + +-- Causes a blowup in the formula (not in the ciruit!) +unfoldF' r (Abort (BUntil (0,0) f g) e) = ((mkProp e) `mkOr` (g `mkAbort`e)) +unfoldF' r (Abort (BUntil (_,0) f g) e) = error "lower bound must not be greater than upper bound" +unfoldF' r (Abort (BUntil (0,u) f g) e) = ((mkProp e) `mkOr` ((g `mkAbort`e) `mkOr` ((f `mkAbort`e) `mkAnd` (mkNext (r ((mkBUntil (0,u-1) f g) `mkAbort` e)))))) +unfoldF' r (Abort (BUntil (l,u) f g) e) = ((mkProp e) `mkOr` mkNext (mkAbort (mkBUntil (l-1,u-1) f g) e)) + +unfoldF' r (Abort (WBUntil (0,0) f g) e) = ((mkProp e) `mkOr` (g `mkAbort`e)) +unfoldF' r (Abort (WBUntil (_,0) f g) e) = error "lower bound must not be greater than upper bound" +unfoldF' r (Abort (WBUntil (0,u) f g) e) = ((mkProp e) `mkOr` ((g `mkAbort`e) `mkOr` ((f `mkAbort`e) `mkAnd` (mkWNext (r ((mkBUntil (0,u-1) f g) `mkAbort` e)))))) +unfoldF' r (Abort (WBUntil (l,u) f g) e) = ((mkProp e) `mkOr` mkWNext (mkAbort (mkWBUntil (l-1,u-1) f g) e)) + +unfoldF' r (Abort (BRelease (0,0) f g) e) = ((mkProp e) `mkOr` (g `mkAbort`e)) +unfoldF' r (Abort (BRelease (_,0) f g) e) = error "lower bound must not be greater than upper bound" +unfoldF' r (Abort (BRelease (0,u) f g) e) = ((mkProp e) `mkOr` ((g `mkAbort`e) `mkAnd` ((f `mkAbort`e) `mkOr` (mkNext (r ((mkBRelease (0,u-1) f g) `mkAbort` e)))))) +unfoldF' r (Abort (BRelease (l,u) f g) e) = ((mkProp e) `mkOr` mkNext (mkAbort (mkBRelease (l-1,u-1) f g) e)) + +unfoldF' r (Abort (WBRelease (0,0) f g) e) = ((mkProp e) `mkOr` (g `mkAbort`e)) +unfoldF' r (Abort (WBRelease (_,0) f g) e) = error "lower bound must not be greater than upper bound" +unfoldF' r (Abort (WBRelease (0,u) f g) e) = ((mkProp e) `mkOr` ((g `mkAbort`e) `mkAnd` ((f `mkAbort`e) `mkOr` (mkWNext (r ((mkWBRelease (0,u-1) f g) `mkAbort` e)))))) +unfoldF' r (Abort (WBRelease (l,u) f g) e) = ((mkProp e) `mkOr` mkWNext (mkAbort (mkWBRelease (l-1,u-1) f g) e)) + +-- There is no unfolding for SImplies :-( +unfoldF' r f = f +-} +------------------------------------------------------------------------------- +-- PSL-Parser + +formula :: (PSLFragment (reg prop), PSLFragment prop) => P.Parser (Formula reg prop) +formula = buildExpressionParser table prefixExpr + P. "PSL: formula" + +atomicP :: (PSLFragment (reg prop), PSLFragment prop) => P.Parser (Formula reg prop) +atomicP = P.try (parser >>= return . mkWeakReg) + P.<|> (reservedOp "\\strong" >> parser >>= return . mkStrongReg) + P.<|> parens formula + P. "PSL: atomic expression" + +-- Note: all prefix operator have highest precedence +-- buildExpressionParser does not allow for nesting of prefixes of same precedence. +-- Moreover it seems that nesting of lower precedence prefix operators in higher precedence +-- prefix operators does not work as well. Seems that I do not understand something there ... +prefixExpr :: (PSLFragment (reg prop), PSLFragment prop) => P.Parser (Formula reg prop) +prefixExpr = P.try atomicP + P.<|> prefix "\\not" mkNegate + P.<|> pPrefix "\\BN" mkBNext + P.<|> pPrefix "\\wBN" mkWBNext + P.<|> prefix "\\N" mkNext + P.<|> prefix "\\wN" mkWNext + P.<|> pPrefix "\\BG" mkBGlobally + P.<|> pPrefix "\\BF" mkBEventually + P.<|> pPrefix "\\sBG" mkSBGlobally + P.<|> pPrefix "\\wBF" mkWBEventually + P.<|> prefix "\\G" mkGlobally + P.<|> prefix "\\F" mkEventually + P. "PSL: prefix expression" + where + prefix name fun = (reservedOp name >> prefixExpr >>= return . fun) + pPrefix name fun = (reservedOp name >> do { b <- bound ; f <- prefixExpr ; return (fun b f) }) + +table :: (PSLFragment (reg prop), PSLFragment prop) => [[Operator Char () (Formula reg prop)]] +table = [ [binary "\\and" mkAnd AssocLeft] + , [binary "\\or" mkOr AssocLeft] + , [binary "\\implies" mkImplies AssocRight] + , [binary "\\equiv" mkEquiv AssocLeft] + + , [pBinary "\\BU" mkBUntil AssocRight, pBinary "\\BR" mkBRelease AssocLeft] + , [pBinary "\\BW" mkBWaitfor AssocRight, pBinary "\\sBR" mkSBRelease AssocLeft] + , [binary "\\U" mkUntil AssocRight, binary "\\R" mkRelease AssocLeft] + , [binary "\\W" mkWaitfor AssocRight, binary "\\sR" mkSRelease AssocLeft] + + , [abort] + , [simplies] + ] + +-- TODO: better move simplies to pslexpr +binary name fun assoc = Infix (reservedOp name >> return fun) assoc +pBinary name fun assoc = Infix (reservedOp name >> bound >>= return . fun) assoc +prefix name fun = Prefix (reservedOp name >> return fun) +-- pPrefix name fun = Prefix (reservedOp name >> bound >>= return . fun) +postfix name fun = Postfix (reservedOp name >> return fun) + +abort :: (PSLFragment (reg prop), PSLFragment prop) => Operator Char () (Formula reg prop) +abort = Postfix (reservedOp "\\abort" >> parser >>= return . (flip mkAbort)) + +simplies :: (PSLFragment (reg prop), PSLFragment prop) => Operator Char () (Formula reg prop) +simplies = Prefix ( P.try $ do { x <- parser; reservedOp "\\simplies"; return (mkSImplies x)} ) + +-- bounds +-- bound :: P.GenParser Char st a +bound = boundExpr + +boundExpr = buildExpressionParser boundTable boundTerm + +boundTerm = (parens boundExpr) P.<|> (parseOrdinal) + +boundTable :: OperatorTable Char () Ordinal +boundTable = [ [prefix "-" negate, prefix "+" id] + , [postfix "++" (+1)] + , [binary "*" (*) AssocLeft {-, binary "/" (div) AssocLeft-} ] + , [binary "+" (+) AssocLeft, binary "-" (-) AssocLeft] + ] + + diff --git a/haskell-frontend/ToString.hs b/haskell-frontend/ToString.hs new file mode 100644 index 0000000..8669264 --- /dev/null +++ b/haskell-frontend/ToString.hs @@ -0,0 +1,58 @@ +{- *** MOCS-COPYRIGHT-NOTICE-BEGIN *** + - + - This copyright notice is auto-generated by ./add-copyright-notice. + - Additional copyright notices must be added below the last line of this notice. + - + - MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "haskell-frontend/ToString.hs". + - The content of this file is copyright of Saarland University - + - Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . + - + - This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). + - + - License: three-clause BSD style license. + - The license text can be found in the file LICENSE. + - + - *** MOCS-COPYRIGHT-NOTICE-END *** -} + +{-# LANGUAGE TypeSynonymInstances, OverlappingInstances, UndecidableInstances, IncoherentInstances #-} +module ToString where + +import Data.List as List +import Data.Set as Set +import Data.Map as Map + +import Foreign.C.Types + +class ToString a where + toString :: a -> String + +instance ToString Int where + toString i = show i + +instance ToString Integer where + toString i = show i + +instance ToString Char where + toString c = [c] + +instance ToString String where + toString s = s + +instance ToString a => ToString (Set a) where + toString s = "{" ++ concat (intersperse "," (List.map toString $ Set.toList s)) ++ "}" + +instance (ToString a, ToString b) => ToString (Map a b) where + toString m = "{" ++ concat (intersperse "," (List.map toString $ Map.toList m)) ++ "}" + +instance (ToString a, ToString b) => ToString (a,b) where + toString p = "(" ++ toString (fst p) ++ "," ++ toString (snd p) ++ ")" + +instance (ToString a) => ToString [a] where + toString l = "[" ++ concat (intersperse "," (List.map toString l)) ++ "]" + +instance ToString CLong where + toString i = show i + +--instance (Show a) => ToString a where +-- toString a = show a + diff --git a/libaaut/Makefile b/libaaut/Makefile new file mode 100644 index 0000000..ec1cfc5 --- /dev/null +++ b/libaaut/Makefile @@ -0,0 +1,27 @@ +# *** MOCS-COPYRIGHT-NOTICE-BEGIN *** +# +# This copyright notice is auto-generated by ./add-copyright-notice. +# Additional copyright notices must be added below the last line of this notice. +# +# MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "libaaut/Makefile". +# The content of this file is copyright of Saarland University - +# Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . +# +# This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). +# +# License: three-clause BSD style license. +# The license text can be found in the file LICENSE. +# +# *** MOCS-COPYRIGHT-NOTICE-END *** + +ROOT=.. + +include $(ROOT)/Makefile.pre + +LIBTARGETS=libaaut.a + +expr.o: expr.cc expr.hh util.hh expr.tcc expr_util.hh config.h +state-machine.o: state-machine.cc state-machine.hh expr.hh aa.hh aa.tcc expr.tcc expr_util.hh util.hh config.h +vhdl.o: vhdl.cc vhdl.hh expr.hh aa.hh aa.tcc expr.tcc expr_util.hh util.hh config.h + +include $(ROOT)/Makefile.post diff --git a/libaaut/aa.hh b/libaaut/aa.hh new file mode 100644 index 0000000..b6203de --- /dev/null +++ b/libaaut/aa.hh @@ -0,0 +1,167 @@ +/* *** MOCS-COPYRIGHT-NOTICE-BEGIN *** + * + * This copyright notice is auto-generated by ./add-copyright-notice. + * Additional copyright notices must be added below the last line of this notice. + * + * MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "libaaut/aa.hh". + * The content of this file is copyright of Saarland University - + * Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . + * + * This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). + * + * License: three-clause BSD style license. + * The license text can be found in the file LICENSE. + * + * *** MOCS-COPYRIGHT-NOTICE-END *** */ + +#ifndef _AA_HH_ +#define _AA_HH_ + +#include "config.h" + +#include +#include + +#include "util.hh" +#include "expr.hh" + +struct automaton_t { + automaton_t(const efac_ptr& c) : init(new_state(c->mkConst(false))) {} + automaton_t(const state_t& s) : init(s) {} + state_t init; +}; + +typedef unsigned int bound_t; + +/* ************************************************************************** */ +/* SEREs */ + +// TODO implement test if an automaton is nondeterministic + +// precondition: a is a nondeterministic automaton!!! +automaton_t conc_aut(const automaton_t& a, const automaton_t& b); +automaton_t oconc_aut(const automaton_t& a, const automaton_t& b); + +// same as or_aut +automaton_t union_aut(const automaton_t& a, const automaton_t& b); + +// requires synchronization of accepting states +// Hardware/ statemachine: aditionally to input-or use input-and-gate, but +// only for acceptance. Requires duplication of accepting states - for +// "normal/ transitional/ non-accepting" use and acceptance. Synchronization +// propagates through existential branches. Within SEREs all universal branches +// synchronize. +// How do we extend the automaton model for this purpose. Can we do it +// only by local annotations on the states? May be introducing "collecting" states +// that are interpreted "backward", i.e. having a pre-relation that incodes the +// synchronization condition. This collecting state is then used as the accepting +// state of the intersection-automaton. The pre-transition is an epsilon transition! +// +// Implementation: we need determinization anyway. Hence, better don't use it! +//precondition: a and b are nondeterministic ??? do we need this ?? +automaton_t intersection_aut(const automaton_t& a, const automaton_t& b); + +automaton_t empty_aut(efac_ptr c); + +//precondition: a is nondeterministic!!! +automaton_t kleene_aut(const automaton_t& a); + + +/* ************************************************************************** */ + +// SImplies +// precondition: a is nondeterministic! +automaton_t simplies_aut(const automaton_t& a, const automaton_t& b); + +// Abort +automaton_t abort_aut(const automaton_t& a, const automaton_t& b); + +// Proposition +automaton_t prop_aut(efac_ptr c, const prop_t& p); + +// Negated Proposition +automaton_t nprop_aut(efac_ptr c, const prop_t& p); + +// Constant +automaton_t const_aut(efac_ptr c, bool p); + +// Conjunction +automaton_t operator&&(const automaton_t& a, const automaton_t& b); +automaton_t and_aut(const automaton_t& a, const automaton_t& b); + +// Disjunction +automaton_t operator||(const automaton_t& a, const automaton_t& b); +automaton_t or_aut(const automaton_t& a, const automaton_t& b); + +// Negation (dualization) +automaton_t operator~(const automaton_t& a); +automaton_t dual_aut(const automaton_t& a); + +// Implication +automaton_t operator>>(const automaton_t& a, const automaton_t& b); + +// Next +automaton_t operator++(const automaton_t& a); +automaton_t next_aut(const automaton_t& a); +automaton_t next_aut(bound_t i, const automaton_t& a); +automaton_t wnext_aut(const automaton_t& a); +automaton_t wnext_aut(bound_t i, const automaton_t& a); + +// Globally +automaton_t operator*(const automaton_t& a); +automaton_t operator*(bound_t i, const automaton_t& a); +automaton_t g_aut(const automaton_t& a); +automaton_t g_aut(bound_t i, const automaton_t& a); +automaton_t strong_g_aut(bound_t i, const automaton_t& a); + +// Eventually +automaton_t operator+(const automaton_t& a); +automaton_t operator+(bound_t j, const automaton_t& a); +automaton_t f_aut(const automaton_t& a); +automaton_t f_aut(bound_t i, const automaton_t& a); +automaton_t weak_f_aut(bound_t i, const automaton_t& a); + +// Until +automaton_t until_aut(const automaton_t& a,const automaton_t& b); +automaton_t until_aut(bound_t i, const automaton_t& a,const automaton_t& b); + +// waitfor +automaton_t waitfor_aut(const automaton_t& a,const automaton_t& b); +automaton_t waitfor_aut(bound_t i, const automaton_t& a,const automaton_t& b); + +// Release +automaton_t release_aut(const automaton_t& a,const automaton_t& b); +automaton_t release_aut(bound_t i, const automaton_t& a,const automaton_t& b); + +// strong release +automaton_t strong_release_aut(const automaton_t& a,const automaton_t& b); +automaton_t strong_release_aut(bound_t i, const automaton_t& a,const automaton_t& b); + +// abort +// a abort b: +// foreach state of a: suc' = suc || b + +// simplies: +// similar to concatenation of SEREs + +// makeWeak +automaton_t weak_aut(const automaton_t& a); + +// Universalization +automaton_t universal_aut(const automaton_t& a); + +// Nondeterminization +automaton_t nondeterministic_aut(const automaton_t& a); + +// Rollout +template +efac_ptr suffix_rollout(const automaton_t&, bound_t, std::back_insert_iterator); +std::pair prefix_rollout(const automaton_t& a, bound_t b); + +// pretty-printing +std::ostream& automaton2dot(std::ostream& o, const automaton_t& a, const std::string& name = "automaton"); + +#include "aa.tcc" + +#endif // _AA_HH_ + diff --git a/libaaut/aa.tcc b/libaaut/aa.tcc new file mode 100644 index 0000000..e60d3c8 --- /dev/null +++ b/libaaut/aa.tcc @@ -0,0 +1,837 @@ +/* *** MOCS-COPYRIGHT-NOTICE-BEGIN *** + * + * This copyright notice is auto-generated by ./add-copyright-notice. + * Additional copyright notices must be added below the last line of this notice. + * + * MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "libaaut/aa.tcc". + * The content of this file is copyright of Saarland University - + * Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . + * + * This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). + * + * License: three-clause BSD style license. + * The license text can be found in the file LICENSE. + * + * *** MOCS-COPYRIGHT-NOTICE-END *** */ + +#include +#include +#include + +#include "expr_util.hh" + +namespace +{ + struct aborter : expr::util::expr_rewriter + { + aborter(const automaton_t& b) : b(b), expr_rewriter() {} + + expr_t state_rec(const expr_t& x, state_t& new_state) + { + *new_state = rec(*x.state()) || *b.init; + new_state.set_final(x.state().final()); + return c->mkState(new_state); + } + + automaton_t b; + }; + + struct concer : expr::util::expr_rewriter + { + concer(const automaton_t& b) : b(b), lock(false), expr_rewriter() {} + + // precondition: argument is nondeterministic automaton! + // but no restriction on b! + + // if a state is reached: + // if final : suc' = suc || suc(b.init) + // for each state-less accepting disjunctiv branch b in suc: + // b' = b && state(b.init) + // + // When we travers suc of state s we do set a lock if we enter a + // subbranch for which we already added state(b.init). I.e. if a + // the algorithm is in locked state it only does recursive copy until + // it enters a new state. + + expr_t state_rec(const expr_t& x, state_t& new_state) + { + bool uplock=lock; + lock=false; + + if ( ! lock && expr::util::successor_states_count(x.state()) == 0) { + lock=true; + *new_state = rec(*x.state()) && c->mkState(b.init); + lock=false; + } else { + *new_state = rec(*x.state()); + } + + if (x.state().final()) { + *new_state = *new_state || *b.init; + new_state.set_final(b.init.final()); + } + + lock=uplock; + + return c->mkState(new_state); + } + + expr_t or_rec(const expr_t& e) + { + expr_t left, right; + + if (! lock && e.left().op() != Or && expr::util::successor_states_count(e.left()) == 0) { + lock=true; + left = rec(e.left()) && c->mkState(b.init); + lock=false; + } else { + left = rec(e.left()); + } + + if (! lock && e.right().op() != Or && expr::util::successor_states_count(e.right()) == 0) { + lock=true; + right = rec(e.right()) && c->mkState(b.init); + lock=false; + } else { + right = rec(e.right()); + } + + return left || right; + } + + // if we find conjunction we know that either we are locked or exactly one side is state-less. + // We lock that stateless side, and Handle only the state-carrying side. + expr_t and_rec(const expr_t& e) + { + expr_t left, right; + + if (! lock && e.left().op() != And && expr::util::successor_states_count(e.left()) == 0) { + lock=true; + left = rec(e.left()); // && c->mkState(b.init); + lock=false; + } else { + left = rec(e.left()); + } + + if (! lock && e.right().op() != And && expr::util::successor_states_count(e.right()) == 0) { + lock=true; + right = rec(e.right()); // && c->mkState(b.init); + lock=false; + } else { + right = rec(e.right()); + } + + return left && right; + } + + automaton_t b; + bool lock; + }; + + struct oconcer : expr::util::expr_rewriter + { + oconcer(const automaton_t& b) : b(b), lock(false), expr_rewriter() {} + + virtual expr_t operator()(const expr_t& e) + { + expr_t r = expr_rewriter::operator()(e); + if (r.op() != State) { + state_t s = state_map[e.state()]; + return c->mkState(s); + } else { + return r; + } + } + + virtual expr_t state_rec(const expr_t& x, state_t& new_state) + { + bool uplock=lock; + lock=false; + + if ( ! lock && expr::util::successor_states_count(x.state()) == 0) { + lock=true; + *new_state = rec(*x.state()) && *b.init; + lock=false; + } else { + *new_state = rec(*x.state()); + } + + lock=uplock; + + return cache_conv(x,new_state); + } + + virtual expr_t cache_conv(const expr_t& x, const state_t& new_state) + { + if (x.state().final()) { + (const_cast(&new_state))->set_final(b.init.final()); + return c->mkState(new_state) || *b.init; + } else { + return c->mkState(new_state); + } + } + + virtual expr_t or_rec(const expr_t& e) + { + expr_t left, right; + + if (! lock && e.left().op() != Or && expr::util::successor_states_count(e.left()) == 0) { + lock=true; + left = rec(e.left()) && *b.init; + lock=false; + } else { + left = rec(e.left()); + } + + if (! lock && e.right().op() != Or && expr::util::successor_states_count(e.right()) == 0) { + lock=true; + right = rec(e.right()) && *b.init; + lock=false; + } else { + right = rec(e.right()); + } + + return left || right; + } + + // if we find conjunction we know that either we are locked or exactly one side is state-less. + // We lock that stateless side, and Handle only the state-carrying side. + expr_t and_rec(const expr_t& e) + { + expr_t left, right; + + if (! lock && e.left().op() != And && expr::util::successor_states_count(e.left()) == 0) { + lock=true; + left = rec(e.left()); // && c->mkState(b.init); + lock=false; + } else { + left = rec(e.left()); + } + + if (! lock && e.right().op() != And && expr::util::successor_states_count(e.right()) == 0) { + lock=true; + right = rec(e.right()); // && c->mkState(b.init); + lock=false; + } else { + right = rec(e.right()); + } + + return left && right; + } + + automaton_t b; + bool lock; + }; + + struct simplier : oconcer + { + simplier(const automaton_t& b) : oconcer(b) {} + virtual expr_t cache_conv(const expr_t& x, const state_t& new_state) + { + if (x.state().final()) { + return c->mkState(new_state) && *b.init; + } else { + return c->mkState(new_state); + } + } + }; + + struct kleener : expr::util::expr_rewriter + { + kleener(const automaton_t& a) : a(a), lock(false), expr_rewriter() {} + + expr_t state_rec(const expr_t& x, state_t& new_state) + { + state_map_t::const_iterator r = state_map.find(a.init); + state_t init = r->second; + + bool uplock=lock; + lock=false; + + if ( ! lock && expr::util::successor_states_count(x.state()) == 0) { + lock=true; + *new_state = rec(*x.state()) && c->mkState(init); + lock=false; + } else { + *new_state = rec(*x.state()); + } + + if (x.state().final()) { + *new_state = *new_state || rec(*a.init); + new_state.set_final(a.init.final()); + } + + lock=uplock; + return c->mkState(new_state); + } + + expr_t or_rec(const expr_t& e) + { + state_map_t::const_iterator r = state_map.find(a.init); + state_t init = r->second; + + expr_t left, right; + + if (! lock && e.left().op() != Or && expr::util::successor_states_count(e.left()) == 0) { + lock=true; + left = rec(e.left()) && c->mkState(init); + lock=false; + } else { + left = rec(e.left()); + } + + if (! lock && e.right().op() != Or && expr::util::successor_states_count(e.right()) == 0) { + lock=true; + right = rec(e.right()) && c->mkState(init); + lock=false; + } else { + right = rec(e.right()); + } + + return left || right; + } + + // if we find conjunction we know that either we are locked or exactly one side is state-less. + // We lock that stateless side, and Handle only the state-carrying side. + expr_t and_rec(const expr_t& e) + { + expr_t left, right; + + if (! lock && e.left().op() != And && expr::util::successor_states_count(e.left()) == 0) { + lock=true; + left = rec(e.left()); // && c->mkState(b.init); + lock=false; + } else { + left = rec(e.left()); + } + + if (! lock && e.right().op() != And && expr::util::successor_states_count(e.right()) == 0) { + lock=true; + right = rec(e.right()); // && c->mkState(b.init); + lock=false; + } else { + right = rec(e.right()); + } + + return left && right; + } + + automaton_t a; + bool lock; + }; +} + +inline automaton_t simplies_aut(const automaton_t& a, const automaton_t& b) +{ + expr_t tmp = a.init->efac()->mkState(a.init); + expr_t n = simplier(b)(tmp); + return oconc_aut(a,kleene_aut(const_aut(a.init->efac(),true))) >> automaton_t(n.state()); +} + +inline automaton_t abort_aut(const automaton_t& a, const automaton_t& b) +{ + expr_t tmp = a.init->efac()->mkState(a.init); + expr_t n = aborter(b)(tmp); + return automaton_t(n.state()); +} + +// concatenation a;b +// * for accepting states of a: suc' = suc || suc(b.init) +// remove acceptance from a +// * dead-end states of a: suc' = suc && suc(b.init) +// NOTE: a is copied within the same context. b is used unchanged. +inline automaton_t conc_aut(const automaton_t& a, const automaton_t& b) +{ + expr_t tmp = a.init->efac()->mkState(a.init); + expr_t n = concer(b)(tmp); + return automaton_t(n.state()); +} + +inline automaton_t oconc_aut(const automaton_t& a, const automaton_t& b) +{ + expr_t tmp = a.init->efac()->mkState(a.init); + expr_t n = oconcer(b)(tmp); + return automaton_t(n.state()); +} + +// like concatenation but use suc(a.init) instead of suc(b.init). All accepting states +// of a remain accepting. +inline automaton_t kleene_aut(const automaton_t& a) +{ + automaton_t b = a; + if (! a.init.final()) { + b = automaton_t(new_state(*a.init,true)); + } + expr_t tmp = b.init->efac()->mkState(b.init); + expr_t n = kleener(b)(tmp); + return automaton_t(n.state()); +} + +inline automaton_t union_aut(const automaton_t& a, const automaton_t& b) +{ + return or_aut(a,b); +} + +inline automaton_t empty_aut(efac_ptr c) +{ + return automaton_t(new_state(c->mkConst(false),true)); +} + +inline automaton_t prop_aut(efac_ptr c, const prop_t& p) +{ + return automaton_t(new_state(c->mkProp(p))); +} + +inline automaton_t nprop_aut(efac_ptr c, const prop_t& p) +{ + return automaton_t(new_state(c->mkNProp(p),true)); +} + +inline automaton_t const_aut(efac_ptr c, bool p) +{ + return automaton_t(new_state(c->mkConst(p))); +} + +inline automaton_t and_aut(const automaton_t& a, const automaton_t& b) +{ + if (a.init.final() && a.init->is_true()) { return b; } + if (b.init.final() && b.init->is_true()) { return a; } + return automaton_t(new_state(*a.init && *b.init,a.init.final() && b.init.final())); +} + +inline automaton_t or_aut(const automaton_t& a, const automaton_t& b) +{ + return automaton_t(new_state(*a.init || *b.init,a.init.final() || b.init.final())); +} + +// g +inline automaton_t g_aut(const automaton_t& a) +{ + state_t s = new_state(true); + s.set_suc(*a.init && a.init->efac()->mkState(s)); + return automaton_t(s); +} + +inline automaton_t g_aut(bound_t i, const automaton_t& a) +{ + if (i == 0) { + return a; + } else { + return and_aut(a,wnext_aut(g_aut(i-1,a))); + } +} + +// strong g +inline automaton_t strong_g_aut(bound_t i, const automaton_t& a) +{ + if (i == 0) { + return a; + } else { + return and_aut(a,next_aut(strong_g_aut(i-1,a))); + } +} + +// f +inline automaton_t f_aut(const automaton_t& a) +{ + state_t s = new_state(); + s.set_suc(*a.init || a.init->efac()->mkState(s)); + return automaton_t(s); +} + +inline automaton_t f_aut(bound_t i, const automaton_t& a) +{ + if (i == 0) { + return a; + } else { + return or_aut(a,next_aut(f_aut(i-1,a))); + } +} + +// weak f +inline automaton_t weak_f_aut(bound_t i, const automaton_t& a) +{ + if (i == 0) { + return a; + } else { + return or_aut(a,wnext_aut(weak_f_aut(i-1,a))); + } +} + +// next +inline automaton_t next_aut(const automaton_t& a) +{ + state_t n = new_state(*a.init); + return automaton_t(new_state(n->efac()->mkState(n))); +} + +inline automaton_t next_aut(bound_t i, const automaton_t& a) +{ + if (i == 0) { + return a; + } else { + return next_aut(next_aut(i-1,a)); + } +} + +inline automaton_t wnext_aut(const automaton_t& a) +{ + state_t n = new_state(*a.init,true); + return automaton_t(new_state(n->efac()->mkState(n),true)); +} + +inline automaton_t wnext_aut(bound_t i, const automaton_t& a) +{ + if (i == 0) { + return a; + } else { + return wnext_aut(wnext_aut(i-1,a)); + } +} + +// until +inline automaton_t until_aut(const automaton_t& a,const automaton_t& b) +{ + state_t s = new_state(); + s.set_suc(*b.init || (*a.init && a.init->efac()->mkState(s))); + return automaton_t(s); +} + +inline automaton_t until_aut(bound_t i, const automaton_t& a,const automaton_t& b) +{ + if (i == 0) { + return b; + } else { + return or_aut(b,and_aut(a,next_aut(until_aut(i-1,a,b)))); + } +} + +// waitfor +inline automaton_t waitfor_aut(const automaton_t& a,const automaton_t& b) +{ + state_t s = new_state(true); + s.set_suc(*b.init || (*a.init && a.init->efac()->mkState(s))); + return automaton_t(s); +} + +inline automaton_t waitfor_aut(bound_t i, const automaton_t& a,const automaton_t& b) +{ + if (i == 0) { + return b; + } else { + return or_aut(b,and_aut(a,wnext_aut(waitfor_aut(i-1,a,b)))); + } +} + +// release +inline automaton_t release_aut(const automaton_t& a,const automaton_t& b) +{ + state_t s = new_state(true); + s.set_suc(*b.init && (*a.init || a.init->efac()->mkState(s))); + return automaton_t(s); +} + +inline automaton_t release_aut(bound_t i, const automaton_t& a,const automaton_t& b) +{ + if (i == 0) { + return b; + } else { + return and_aut(b,or_aut(a,wnext_aut(release_aut(i-1,a,b)))); + } +} + +// strong release +inline automaton_t strong_release_aut(const automaton_t& a,const automaton_t& b) +{ + state_t s = new_state(); + s.set_suc(*b.init && (*a.init || a.init->efac()->mkState(s))); + return automaton_t(s); +} + +inline automaton_t strong_release_aut(bound_t i, const automaton_t& a,const automaton_t& b) +{ + if (i == 0) { + return b; + } else { + return and_aut(b,or_aut(a,next_aut(strong_release_aut(i-1,a,b)))); + } +} + +inline automaton_t dual_aut(const automaton_t& a) +{ + return automaton_t(new_state(expr::util::dual(*a.init), ! a.init.final())); +} + +inline automaton_t weak_aut(const automaton_t& a) +{ + return automaton_t(expr::util::weak(a.init->efac()->mkState(a.init)).state()); +} + +namespace +{ + + typedef std::pair lambda_cache_key_t; + typedef std::pair lambda_cache_value_t; + + std::size_t hash_value(const lambda_cache_key_t& k) + { + std::size_t s = 0; + boost::hash_combine(s,k.first.uid()); + boost::hash_combine(s,k.second); + return s; + } + + struct lambda_cache_hasher + { + std::size_t operator()(const lambda_cache_key_t& k) const { return hash_value(k); } + }; + + typedef multi_index_container< + lambda_cache_value_t, + indexed_by,lambda_cache_hasher > > + > lambda_cache_t; + + /* specialized rollauts + * - uses new efac for all roll outs over the pipline --> becomes the resulting circuit + * - uses new efac for all roll outs over (subf,pos) + state of prefix trans state machine + */ + struct rollaut + { + RUNTIME_ERROR(expr_type_error); + + expr_t state_rollout(const state_t& state) + { + return c->mkNProp(prop_t(1, (long) state.uid())) || lambda(*state,0); + } + + struct state_rollout_dfs : public dfs + { + state_rollout_dfs(rollaut* context, expr_t& result) : context(context), result(result) {} + void state_hook(const expr_t& e) + { + result = result && context->state_rollout(e.state()); + } + rollaut* context; + expr_t& result; + }; + + rollaut(const automaton_t& a, bound_t b) : + c(efac::newEfac()), + a(a), + b(b) + {} + + // returns the list of all output gates of the circuit + template + efac_ptr operator()(std::back_insert_iterator out) + { + for(bound_t i = 0; i <= b; ++i) { + // std::cerr << "rollout: " << i; + out = lambda(*a.init,i); + // std::cerr << ", size: " << c->size() << std::endl; + } + return c; + } + + // returns the (only) output gate of the circuit + // inputs of the circuit are the propositions and + // all states! + // + // During search of init put each encountered that into the list! + // + // NOTE: after rollout each input-prop is index by a vector of length two + // (namely (subf,h)). The special state input (from the ptsm) is + // indexed by the vector of length 1 namely (mem-addr-of-state). + std::pair operator()() + { + // rollout for each state. Result (NProp state_signal || rollout_for state) + // Build conjunction over all rollouts + expr_t result = state_rollout(a.init); + state_rollout_dfs(this,result).run(a.init.suc()); + return std::make_pair(result,c); + } + + lambda_cache_t cache; + expr_t lambda(const expr_t& x, bound_t i) + { +#define LAMBDA_CACHE +#ifdef LAMBDA_CACHE + lambda_cache_t::const_iterator it = cache.find(std::make_pair(x,i)); + if ( it != cache.end() ) { + return it->second; + } +#endif + expr_t ret; + if (i == b) { + switch (x.op()) { + case And: ret = lambda(x.left(),i) && lambda(x.right(),i); break; + case Or: ret = lambda(x.left(),i) || lambda(x.right(),i); break; + case Const: ret = c->copy(x); break; + case Prop: ret = c->mkProp(new_prop(x.prop(),i)); break; + case NProp: ret = c->mkNProp(new_prop(x.nprop(),i)); break; + case State: ret = x.state().final() ? c->mkTrue() : c->mkFalse(); break; + } + } else { + switch (x.op()) { + case And: ret = lambda(x.left(),i) && lambda(x.right(),i); break; + case Or: ret = lambda(x.left(),i) || lambda(x.right(),i); break; + case Const: ret = c->copy(x); break; + case Prop: ret = c->mkProp(new_prop(x.prop(),i)); break; + case NProp: ret = c->mkNProp(new_prop(x.nprop(),i)); break; + case State: ret = lambda(*x.state(),i+1); break; + } + } +#ifdef LAMBDA_CACHE + cache.insert(std::make_pair(std::make_pair(x,i),ret)); +#endif + return ret; + } + + prop_t new_prop(const prop_t& p, bound_t i) const + { + // derive canonic and unique prop name from p an i + prop_t n = p; + n.push_back(i); + return n; + } + + efac_ptr c; + automaton_t a; + bound_t b; + }; +}; // anonymous + + +template +efac_ptr suffix_rollout(const automaton_t& a, + bound_t b, + std::back_insert_iterator i) +{ + return rollaut(a,b)(i); +} + +inline std::pair prefix_rollout(const automaton_t& a, bound_t b) +{ + return rollaut(a,b)(); +} + +/* ************************************************************************** */ +/* Universalization */ + +// cnf: +namespace { +#define main univ +#define neutral_accept false +#define DOP || +#define OP && +#define get_op expr::util::get_conj +#define get_dualop_states expr::util::get_disj_states +#define is_final has_final +#define split expr::util::split_disj +#define mkNF expr::util::mkCNF +#ifdef DEBUG_UNIV +#define DEBUG_SUBSET +#endif +#include "subsetconstruction.tcc" +#undef main +#undef neutral_accept +#undef DOP +#undef OP +#undef get_op +#undef get_dualop_states +#undef is_final +#undef split +#undef mkNF +}; + +inline automaton_t universal_aut(const automaton_t& a) +{ + return ns_univ::univ(a); +} + +/* ************************************************************************** */ +/* Nondeterminization */ + +// dnf: +namespace { +#define main nondet +#define neutral_accept true +#define DOP && +#define OP || +#define get_op expr::util::get_disj +#define get_dualop_states expr::util::get_conj_states +#define is_final all_final +#define split expr::util::split_conj +#define mkNF expr::util::mkDNF +#ifdef DEBUG_NONDET +#define DEBUG_SUBSET +#endif +#include "subsetconstruction.tcc" +#undef main +#undef neutral_accept +#undef DOP +#undef OP +#undef get_op +#undef get_dualop_states +#undef is_final +#undef split +#undef mkNF +}; + +inline automaton_t nondeterministic_aut(const automaton_t& a) +{ + return ns_nondet::nondet(a); +} + + +inline automaton_t operator&&(const automaton_t& a, const automaton_t& b) +{ + return and_aut(a,b); +} + +inline automaton_t operator||(const automaton_t& a, const automaton_t& b) +{ + return or_aut(a,b); +} + +inline automaton_t operator~(const automaton_t& a) +{ + return dual_aut(a); +} + +inline automaton_t operator>>(const automaton_t& a, const automaton_t& b) +{ + return or_aut(~a,b); +} + +inline automaton_t operator++(const automaton_t& a) +{ + return next_aut(a); +} + +inline automaton_t operator*(bound_t i, const automaton_t& a) +{ + return g_aut(i,a); +} + +inline automaton_t operator*(const automaton_t& a) +{ + return g_aut(a); +} + +inline automaton_t operator+(bound_t i, const automaton_t& a) +{ + return f_aut(i,a); +} + +inline automaton_t operator+(const automaton_t& a) +{ + return f_aut(a); +} + +inline std::ostream& automaton2dot(std::ostream& o, const automaton_t& a, const std::string& name) +{ + expr_t tmp = a.init->efac()->mkState(a.init); + return expr2dot(o,tmp,name); +} + diff --git a/libaaut/config.h b/libaaut/config.h new file mode 100644 index 0000000..66b0a93 --- /dev/null +++ b/libaaut/config.h @@ -0,0 +1,44 @@ +/* *** MOCS-COPYRIGHT-NOTICE-BEGIN *** + * + * This copyright notice is auto-generated by ./add-copyright-notice. + * Additional copyright notices must be added below the last line of this notice. + * + * MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "libaaut/config.h". + * The content of this file is copyright of Saarland University - + * Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . + * + * This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). + * + * License: three-clause BSD style license. + * The license text can be found in the file LICENSE. + * + * *** MOCS-COPYRIGHT-NOTICE-END *** */ + +// do not deallocate expressions (within efac). (Does not not seem to have much effect) +//#define NO_EXPR_DEALLOC + +// Use iterative implementation of get_ops (enableing make things worth) +//#define NOREC_GET_OPS + +// User iterative implementation of distr (enableing make things worth) +//#define NOREC_DISTR + +// use dynamic programming to cache calls to lambda +#define LAMBDA_CACHE + +// does help somewhat cnf(a \or b \or c) is computed as cnf ((cnf (cnf(a) \or b)) \or c) +// each call to cnf is cached +#define CNF_WRAPPER_CACHE +#define SPLIT_WRAPPER_CACHE +#define UNIV_GET_NEXT_STATE_EXPR_CACHE +#define SUC_EXPR_CACHE +#define SUBSET_OP_CACHE + +/* ************************************************************************** */ +/* Debugging */ + +#define NDEBUG +//#define DEBUG +//#define DEBUG_UNIV +//#define EFAC_HASH_INTERFACE +//#define CHECK_ASSERTIONS diff --git a/libaaut/expr.cc b/libaaut/expr.cc new file mode 100644 index 0000000..b699f65 --- /dev/null +++ b/libaaut/expr.cc @@ -0,0 +1,239 @@ +/* *** MOCS-COPYRIGHT-NOTICE-BEGIN *** + * + * This copyright notice is auto-generated by ./add-copyright-notice. + * Additional copyright notices must be added below the last line of this notice. + * + * MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "libaaut/expr.cc". + * The content of this file is copyright of Saarland University - + * Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . + * + * This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). + * + * License: three-clause BSD style license. + * The license text can be found in the file LICENSE. + * + * *** MOCS-COPYRIGHT-NOTICE-END *** */ + +#include + +#include "expr.hh" + +std::ostream& operator<<(std::ostream& o, const expr_impl_t& e) +{ + switch (e.op) { + case Const: return o << std::boolalpha << e.con; + case Prop: return o << "p" << e.prop; + case NProp: return o << "~" << "p" << e.prop; + case State: return o << (long) e.state.uid(); + case And: return o << "(" << *e.left << " && " << *e.right << ")"; + case Or: return o << "(" << *e.left << " || " << *e.right << ")"; + default: return o << "error"; + } +} + +std::ostream& operator<<(std::ostream& o, const expr_t& e) +{ + if (e == expr_t()) return o << "[??]"; + return o << *e.e; +} + +template +expr_t expr_t::merge(const expr_t& r) const +{ + const expr_t& l = *this; + // get set of conj/ disj for both sides + std::set s; + get_ops(l,std::inserter(s,s.begin())); + get_ops(r,std::inserter(s,s.begin())); + // rebuild tree + expr_impl_ptr tree = *s.begin(); + s.erase(s.begin()); + foreach(const expr_impl_ptr& e, s) { + tree = ptr->check_hash(expr_impl_t(o,0,state_t(),prop_t(),ptr,tree,e)); + } + return expr_t(tree,ptr); +} + +expr_t expr_t::operator&& (expr_t r) const +{ + if (ptr != r.ptr) { + std::runtime_error("context error"); + } + if (*this == expr_t()) { + return r; + } + if (r == expr_t()) { + return *this; + } + if (is_true() || r.is_false() ) { + return r; + } + if (is_false() || r.is_true()) { + return *this; + } + if (r.e == e) { + return *this; + } +#if 0 + if (e < r.e) { + return expr_t(ptr->check_hash(expr_impl_t(And,0,state_t(),prop_t(),ptr,e,r.e)),ptr); + } else { + return expr_t(ptr->check_hash(expr_impl_t(And,0,state_t(),prop_t(),ptr,r.e,e)),ptr); + } +#endif + return merge(r); +} + +expr_t expr_t::operator|| (expr_t r) const +{ + if (ptr != r.ptr) { + std::runtime_error("context error"); + } + if (*this == expr_t()) { + return r; + } + if (r == expr_t()) { + return *this; + } + if (is_true() || r.is_false() ) { + return *this; + } + if (is_false() || r.is_true()) { + return r; + } + if (r.e == e) { + return *this; + } +#if 0 + if (e < r.e) { + return expr_t(ptr->check_hash(expr_impl_t(Or,0,state_t(),prop_t(),ptr,e,r.e)),ptr); + } else { + return expr_t(ptr->check_hash(expr_impl_t(Or,0,state_t(),prop_t(),ptr,r.e,e)),ptr); + } +#endif + return merge(r); +} + +namespace +{ + + struct expr2dot_dfs : public dfs + { + struct expr_less + { + bool operator()(const expr_t& a, const expr_t& b) { return a.uid() < b.uid(); } + }; + + typedef std::set out_ports_t; + + std::ostream& o; + out_ports_t out_ports; + + expr2dot_dfs(std::ostream& o) : o(o), out_ports(), dfs() {} + + template + expr2dot_dfs(std::ostream& o, const T& p) : o(o), out_ports(p.begin(),p.end()), dfs() {} + + void init_hook(const expr_t& e) { out_ports.insert(e); } + + void node_hook(const expr_t& e) { + std::string color = (out_ports.find(e) != out_ports.end()) ? "red" : "black"; + int peripheries = 2; + switch (e.op()) { + case And: o << quote(e.uid()) << " " << branch_attr("*",color) << ";\n"; break; + case Or: o << quote(e.uid()) << " " << branch_attr("+",color) << ";\n"; break; + case State: peripheries = e.state().final() ? 2 : 1; + case Const: + case NProp: + case Prop: o << quote(e.uid()) << " [label=" << quote(e) + << ", fontcolor=" << quote(color) + << ", peripheries=" << peripheries + << "];\n"; break; + default: o << "error\n"; + } + } + + void edge_hook(const expr_t& s, const expr_t& t) + { + o << quote(s.uid()) << " -> " << quote(t.uid()) << ";\n"; + } + + std::string branch_attr(const std::string& l, const std::string& color) const + { + return "[label=" + quote(l) + ", shape=plaintext, peripheries=0, height=0.2, width=0.2, fixedsize=true, fontcolor=" + quote(color) + "]"; + } + }; +}; + +std::ostream& expr2dot(std::ostream& o, const expr_t& e, const std::string& name) +{ + const char* q = "\""; + o << "digraph " << quote(name) << " {\n"; + o << "node [peripheries=1];\n"; + expr2dot_dfs(o).run(e); + o << "}" << std::endl; +} + +std::ostream& exprs2dot(std::ostream& o, const std::list& l, const std::string& name) +{ + const char* q = "\""; + o << "digraph " << quote(name) << " {\n"; + o << "node [peripheries=1];\n"; + expr2dot_dfs(o,l).run(l.begin(),l.end()); + int i = 0; + foreach(const expr_t& x, l) { + std::string n = "port_" + STRCAST(i); + o << quote(n) << "[color=\"red\"];\n"; + o << quote(n) << " -> " << quote(x.uid()) << ";\n"; + ++i; + } + o << "}" << std::endl; +} + +namespace +{ + + std::string branch_attr(const std::string& l) + { + return "[label=" + quote(l) + ", shape=plaintext, peripheries=0, height=0.2, width=0.2, fixedsize=true]"; + } + + std::ostream& edge2dot(std::ostream& o, const expr_t& s, const expr_t& t) + { + return o << quote(s.uid()) << " -> " << quote(t.uid()) << ";\n"; + } + + std::ostream& gate2dot(std::ostream& o, const expr_t& e) + { + std::string color; + int peripheries = 2; + switch (e.op()) { + case And: o << quote(e.uid()) << " " << branch_attr("*") << ";\n"; + edge2dot(o,e,e.left()); + edge2dot(o,e,e.right()); break; + case Or: o << quote(e.uid()) << " " << branch_attr("+") << ";\n"; + edge2dot(o,e,e.right()); + edge2dot(o,e,e.left()); break; + case State: peripheries = e.state().final() ? 2 : 1; + o << quote(e.uid()) << " [label=" << quote(e.state().uid()) << ", peripheries=" << peripheries << "];\n"; + edge2dot(o,e,*e.state()); break; + case Const: + case NProp: + case Prop: o << quote(e.uid()) << " [label=" << quote(e) << ", peripheries=" << peripheries << "];\n"; break; + default: o << "error\n"; + } + } + +}; + +std::ostream& efac2dot(std::ostream& o, const efac_ptr& c, const std::string& name) +{ + o << "digraph " << quote(name) << " {\n"; + o << "node [peripheries=1];\n"; + foreach(expr_impl_ptr x, c->cache) + { + gate2dot(o,expr_t(x,c)); + } + o << "}" << std::endl; +} + diff --git a/libaaut/expr.hh b/libaaut/expr.hh new file mode 100644 index 0000000..f37042b --- /dev/null +++ b/libaaut/expr.hh @@ -0,0 +1,263 @@ +/* *** MOCS-COPYRIGHT-NOTICE-BEGIN *** + * + * This copyright notice is auto-generated by ./add-copyright-notice. + * Additional copyright notices must be added below the last line of this notice. + * + * MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "libaaut/expr.hh". + * The content of this file is copyright of Saarland University - + * Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . + * + * This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). + * + * License: three-clause BSD style license. + * The license text can be found in the file LICENSE. + * + * *** MOCS-COPYRIGHT-NOTICE-END *** */ + +#ifndef _EXPR_HH_ +#define _EXPR_HH_ + +#include "config.h" +#include "util.hh" + +#include +#include +#include +#include + +using boost::multi_index_container; +using namespace boost::multi_index; + +/* ************************************************************************** */ +/* state_t */ + +class expr_t; + +// Note: the identity of state must not depend on the semantics of +// the label! Otherwise it would not be possibly to construct +// cyclic automata with expr caching because the hash of the state +// appears in the hash of an expr. +class state_impl_t; + +class state_t +{ +public: + + RUNTIME_ERROR(illegal_constructor_error); + + typedef boost::shared_ptr impl_ptr_t; + + state_t(); + state_t(const state_t& s); + + static state_t new_state(bool final = false); + static state_t new_state(const expr_t& e, bool final = false); + + state_t& operator=(const state_t& s); + + const void* uid() const; + const expr_t& suc() const; + bool final() const; + + // syntactic sugar + expr_t& operator*(); + const expr_t& operator*() const; + expr_t* operator->(); + const expr_t* operator->() const; + + void set_suc(const expr_t& e); + void set_final(bool f = true); + + bool operator==(const state_t& r) const; + bool operator!=(const state_t& r) const; + bool operator<(const state_t& r) const; + +private: + state_t(bool final); + state_t(const expr_t& e, bool final); + impl_ptr_t impl_ptr; +}; + +state_t new_state(bool final = false); +state_t new_state(const expr_t& e, bool final = false); + + +/* ************************************************************************** */ +/* expr_t */ + +typedef std::vector prop_t; + +enum op_t { And, Or, Prop, NProp, State, Const }; + +std::size_t hash_value(const state_t& state); + +class expr_impl_t; +typedef boost::intrusive_ptr expr_impl_ptr; +void intrusive_ptr_add_ref(const expr_impl_t* e); +void intrusive_ptr_release(const expr_impl_t* e); + +class efac; +typedef boost::shared_ptr efac_ptr; +typedef boost::weak_ptr weak_efac_ptr; +typedef efac* raw_efac_ptr; + +class expr_t +{ + friend class dfs; + friend class efac; + friend std::ostream& operator<<(std::ostream& o, const expr_t& e); + friend std::ostream& rec_expr2dot(std::ostream& o, const expr_t& e); + friend std::ostream& efac2dot(std::ostream& o, const efac_ptr& c, const std::string& name); + +public: + + expr_t operator&& (expr_t r) const; + expr_t operator|| (expr_t r) const; + bool is_false() const; + bool is_true() const; + + expr_t& operator=(const expr_t& r); + bool operator==(const expr_t& r) const; + + expr_t(); + efac_ptr efac() const; + std::list childs() const; + + // a unique identifier for the underlying expr, s.t. + // expr == expr -> expr.uid == expr.uid + // (e.g. usefull for output) + const void* uid() const; + + op_t op() const; + expr_t left() const; + expr_t right() const; + prop_t prop() const; + prop_t nprop() const; + state_t state() const; + bool con() const; + + std::size_t size() const; + +#ifdef DEBUG + expr_impl_ptr impl() const; +#endif + +protected: + + template static void get_ops(const expr_t& e, std::insert_iterator out); + template expr_t merge(const expr_t& r) const; + + expr_t(const expr_impl_ptr e, const efac_ptr&); + expr_t(const expr_impl_ptr e, const weak_efac_ptr&); + expr_impl_ptr e; + efac_ptr ptr; +}; // expr_t + +template +std::size_t size(const T& exprs); + +/* ************************************************************************** */ +/* efac */ + +class efac +{ + typedef const expr_impl_t* expr_impl_wptr; + typedef multi_index_container< + expr_impl_wptr, + indexed_by > > + > expr_impl_hash_t; + + friend std::ostream& efac2dot(std::ostream& o, const efac_ptr& c, const std::string& name); + friend class expr_t; + friend void intrusive_ptr_release(const expr_impl_t* e); + +public: + + static boost::shared_ptr newEfac(); + static boost::shared_ptr newEfac(unsigned int n); + + // copy expr from a different efac + expr_t copy(const expr_t& e); + + expr_t mkProp(prop_t p); + expr_t mkNProp(prop_t p); + expr_t mkState(const state_t& state); + expr_t mkConst(bool b); + expr_t mkTrue(); + expr_t mkFalse(); + + std::size_t size() const; + +#ifdef EFAC_HASH_INTERFACE + std::size_t bucket_count() const; + float load_factor() const; + float max_load_factor() const; + void max_load_factor(float z); + void rehash(unsigned int n); + std::size_t max_buck() const; +#endif + +private: + + efac(); + efac(unsigned int n); + + expr_impl_hash_t cache; + boost::weak_ptr ptr; + const expr_impl_ptr check_hash(const expr_impl_t& expr); +}; // efac + + +/* ************************************************************************** */ +/* dfs */ + +class dfs +{ +public: + dfs() : hash() {} + void run(const expr_t& x); + template void run(I a, I e); + +protected: + virtual ~dfs() {} + + virtual void pre_hook() {} + virtual void post_hook() {} + virtual void init_hook(const expr_t& x) {} + virtual void node_hook(const expr_t& x) {} + virtual void and_hook(const expr_t& x) {} + virtual void or_hook(const expr_t& x) {} + virtual void state_hook(const expr_t& x) {} + virtual void const_hook(const expr_t& x) {} + virtual void prop_hook(const expr_t& x) {} + virtual void nprop_hook(const expr_t& x) {} + virtual void edge_hook(const expr_t& s, const expr_t& t) {} + +private: + struct expr_uid_hasher + { + boost::hash hasher; + std::size_t operator()(const expr_t& e) const { return hasher(e.uid()); } + }; + + typedef multi_index_container< + expr_t, + indexed_by,expr_uid_hasher > > + > expr_hash_t; + + void rec(const expr_t& x); + + expr_hash_t hash; +}; + +/* ************************************************************************** */ +/* printing */ + +std::ostream& operator<<(std::ostream& o, const expr_t& e); +std::ostream& expr2dot(std::ostream& o, const expr_t& e, const std::string& name = "expr"); +std::ostream& exprs2dot(std::ostream& o, const std::list& l, const std::string& name = "exprs"); +std::ostream& efac2dot(std::ostream& o, const efac_ptr& c, const std::string& name = "efac"); + +#include "expr.tcc" + +#endif // _EXPR_HH_ diff --git a/libaaut/expr.tcc b/libaaut/expr.tcc new file mode 100644 index 0000000..22cb9e4 --- /dev/null +++ b/libaaut/expr.tcc @@ -0,0 +1,515 @@ +/* *** MOCS-COPYRIGHT-NOTICE-BEGIN *** + * + * This copyright notice is auto-generated by ./add-copyright-notice. + * Additional copyright notices must be added below the last line of this notice. + * + * MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "libaaut/expr.tcc". + * The content of this file is copyright of Saarland University - + * Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . + * + * This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). + * + * License: three-clause BSD style license. + * The license text can be found in the file LICENSE. + * + * *** MOCS-COPYRIGHT-NOTICE-END *** */ + +/* ************************************************************************** */ +/* expr_impl_t */ + +class expr_impl_t { + + friend const expr_impl_ptr check_hash(const expr_impl_t& expr); + friend std::size_t hash_value(const expr_impl_t& e); + friend std::ostream& operator<<(std::ostream& o, const expr_impl_t& e); + friend expr_t mkProp(prop_t p); + friend expr_t mkNProp(prop_t p); + friend expr_t mkState(state_t state); + friend class expr_t; + friend std::ostream& rec_expr2dot(std::ostream& o, const expr_t& e); + friend class dfs; + +public: + bool operator==(const expr_impl_t& r) const + { + /* + debug(); + r.debug(); + std::cerr << "\n"; + */ + return + hash == r.hash && + op == r.op && + con == r.con && + state == r.state && + prop == r.prop && + left == r.left && + right == r.right; + } + + void debug() const + { + std::cerr << "===============\n"; + std::cerr << "op: " << op << "\n"; + std::cerr << "con: " << con << "\n"; + std::cerr << "state: " << state.uid() << "\n"; + std::cerr << "prop: " << prop << "\n"; + std::cerr << "left: " << left << "\n"; + std::cerr << "right: " << right << "\n"; + std::cerr << "hash: " << hash << "\n"; + } + + +//protected: + + const op_t op; + const bool con; + const state_t state; + const prop_t prop; + const expr_impl_ptr left; + const expr_impl_ptr right; + const std::size_t hash; + + mutable int ref_c; + weak_efac_ptr eptr; + + ~expr_impl_t() {} + + expr_impl_t(const expr_impl_t& e) : + op(e.op), + con(e.con), + state(e.state), + prop(e.prop), + left(e.left), + right(e.right), + hash(e.hash), + ref_c(0), + eptr(e.eptr) + {} + + expr_impl_t(op_t op, + bool con, + state_t state, + prop_t prop, + weak_efac_ptr eptr, + const expr_impl_ptr left = expr_impl_ptr(), + const expr_impl_ptr right = expr_impl_ptr()) : + op(op), + con(con), + state(state), + prop(prop), + left(left), + right(right), + hash(make_hash(op,con,state,prop,left,right)), + ref_c(0), + eptr(eptr) + { +#if 0 + using namespace std::rel_ops; + assert((left == expr_impl_ptr() && right == expr_impl_ptr()) || + (left != expr_impl_ptr() && right != expr_impl_ptr())); + assert(left != expr_impl_ptr() || (eptr == left->eptr && eptr == right->eptr)); +#endif + } + + std::size_t make_hash(op_t op, + bool con, + state_t state, + prop_t prop, + const expr_impl_ptr left, + const expr_impl_ptr right) + { + std::size_t s = 0; + boost::hash_combine(s, op); + boost::hash_combine(s, con); + boost::hash_combine(s, state); + boost::hash_combine(s, prop); + if (left) boost::hash_combine(s, *left); + if (right) boost::hash_combine(s, *right); + return s; + } +}; + +inline std::size_t hash_value(const expr_impl_t& e) +{ + return e.hash; +} + + +/* ************************************************************************** */ +/* state_t */ + +struct state_impl_t +{ + state_impl_t(bool final) : suc(), final(final) {} + state_impl_t(const expr_t& e, bool final = false) : suc(e), final(final) {} + expr_t suc; + bool final; +}; + +inline state_t::state_t() : impl_ptr() { /* throw illegal_constructor_error(""); */ } +inline state_t::state_t(const state_t& s) : impl_ptr(s.impl_ptr) {} + +inline state_t::state_t(bool final) : impl_ptr(new state_impl_t(final)) {} +inline state_t::state_t(const expr_t& e, bool final) : impl_ptr(new state_impl_t(e,final)) {} + +inline state_t state_t::new_state(bool final) { return state_t(final); } +inline state_t state_t::new_state(const expr_t& e, bool final) { return state_t(e,final); } + +inline state_t& state_t::operator=(const state_t& s) +{ + impl_ptr = s.impl_ptr; + return *this; +} + +inline const void* state_t::uid() const { return impl_ptr.get(); } +inline const expr_t& state_t::suc() const { return impl_ptr->suc; } +inline bool state_t::final() const { return impl_ptr->final; } + +// syntactic sugar +inline expr_t& state_t::operator*() { return impl_ptr->suc; } +inline const expr_t& state_t::operator*() const { return impl_ptr->suc; } +inline expr_t* state_t::operator->() { return &impl_ptr->suc;} +inline const expr_t* state_t::operator->() const { return &impl_ptr->suc;} + +inline void state_t::set_suc(const expr_t& e) { impl_ptr->suc = e; } +inline void state_t::set_final(bool f) { impl_ptr->final = f; } + +// FIXME make a difference between semantic and syntactic equality +inline bool state_t::operator==(const state_t& r) const +{ + return uid() == r.uid(); + //return suc_ == r.suc_ && final_ == r.final_; +} + +inline bool state_t::operator!=(const state_t& r) const +{ + return uid() != r.uid(); + //return suc_ != r.suc_ || final_ != r.final_; +} + +inline bool state_t::operator<(const state_t& r) const +{ + return uid() < r.uid(); + //return suc_ < r.suc_ || (suc_ == r.suc_ && final_ < r.final_); +} + +inline state_t new_state(bool final) { return state_t::new_state(final); } +inline state_t new_state(const expr_t& e, bool final) { return state_t::new_state(e,final); } + +inline std::size_t hash_value(const state_t& state) +{ + return boost::hash()(state.uid()); +} + +/* ************************************************************************** */ +/* expr_t */ + +inline const void* expr_t::uid() const +{ + return (void*) e.get(); +} + +inline efac_ptr expr_t::efac() const { return ptr; } + +#ifdef DEBUG +inline expr_impl_ptr expr_t::impl() const { return e; } +#endif + +#ifdef NOREC_GET_OPS +// non-recursive version +#include +template +void expr_t::get_ops(const expr_t& e, std::insert_iterator out) +{ + std::queue q; + q.push(e); + while (! q.empty()) { + expr_t cur = q.front(); + q.pop(); + if (cur.op() == o) { + q.push(cur.left()); + q.push(cur.right()); + } else { + out = cur.e; + } + } +} +#else +template +void expr_t::get_ops(const expr_t& e, std::insert_iterator out) +{ + switch(e.op()) { + case o: get_ops(e.left(),out); get_ops(e.right(),out); break; + default: out = e.e; + } +} +#endif + +inline expr_t::expr_t() : e(), ptr() {} +inline expr_t::expr_t(const expr_impl_ptr e, const efac_ptr& ptr) : e(e), ptr(ptr) {} +inline expr_t::expr_t(const expr_impl_ptr e, const weak_efac_ptr& ptr) : e(e), ptr(ptr.lock()) {} + +inline bool expr_t::is_false() const +{ + return e->op == Const && ! e->con; +} + +inline bool expr_t::is_true() const +{ + return e->op == Const && e->con; +} + +inline expr_t& expr_t::operator=(const expr_t& r) +{ + e = r.e; + ptr = r.ptr; + return *this; +} + +inline bool expr_t::operator==(const expr_t& r) const +{ + // TODO check ptr == r.ptr + return (e == 0 && r.e == 0) || (e != 0 && r.e != 0 && *e == *r.e); +} + +inline std::list expr_t::childs() const +{ + std::list l; + if (e->op == And || e->op == Or) { + l.push_back(expr_t(e->left,ptr)); + l.push_back(expr_t(e->right,ptr)); + } + return l; +} + +inline op_t expr_t::op() const { return e->op; } + +inline expr_t expr_t::left() const +{ + // TODO check! + return expr_t(e->left,ptr); +} + +inline expr_t expr_t::right() const +{ + // TODO check! + return expr_t(e->right,ptr); +} + +inline prop_t expr_t::prop() const +{ + // TODO check! + return e->prop; +} + +inline prop_t expr_t::nprop() const +{ + // TODO check! + return e->prop; +} + +inline state_t expr_t::state() const +{ + // TODO check! + return e->state; +} + +inline bool expr_t::con() const +{ + // TODO check! + return e->con; +} + +inline std::size_t expr_t::size() const +{ + struct counter : dfs { + counter() : c(0) {} + void node_hook(const expr_t& e) { c++; } + void edge_hook(const expr_t& e1, const expr_t& e2) { c++; } + std::size_t c; + }; + + counter c; + c.run(*this); + return c.c; +} + +template +std::size_t size(const T& exprs) +{ + struct counter : dfs { + counter() : c(0) {} + void node_hook(const expr_t& e) { c++; } + void edge_hook(const expr_t& e1, const expr_t& e2) { c++; } + std::size_t c; + }; + + counter c; + c.run(exprs.begin(),exprs.end()); + return c.c; +} + + + +/* ************************************************************************** */ +/* efac */ + +inline boost::shared_ptr efac::newEfac() +{ + boost::shared_ptr e(new efac()); + e->ptr = boost::weak_ptr(e); + return e; +} + +inline boost::shared_ptr efac::newEfac(unsigned int n) +{ + boost::shared_ptr e(new efac(n)); + e->ptr = boost::weak_ptr(e); + return e; +} + +// copy expr from a different efac +inline expr_t efac::copy(const expr_t& e) +{ + switch (e.op()) { + case And: return copy(e.left()) && copy(e.right()); + case Or: return copy(e.left()) || copy(e.right()); + case Const: return mkConst(e.con()); + case Prop: return mkProp(e.prop()); + case NProp: return mkNProp(e.nprop()); + case State: return mkState(e.state()); + } +} + +inline expr_t efac::mkProp(prop_t p) +{ + return expr_t(check_hash(expr_impl_t(Prop,0,state_t(),p,ptr)),ptr); +} + +inline expr_t efac::mkNProp(prop_t p) +{ + return expr_t(check_hash(expr_impl_t(NProp,0,state_t(),p,ptr)),ptr); +} + +inline expr_t efac::mkState(const state_t& state) +{ + return expr_t(check_hash(expr_impl_t(State,0,state,prop_t(),ptr)),ptr); +} + +inline expr_t efac::mkConst(bool b) +{ + return expr_t(check_hash(expr_impl_t(Const,b,state_t(),prop_t(),ptr)),ptr); +} + +inline expr_t efac::mkTrue() +{ + return expr_t(check_hash(expr_impl_t(Const,true,state_t(),prop_t(),ptr)),ptr); +} + +inline expr_t efac::mkFalse() +{ + return expr_t(check_hash(expr_impl_t(Const,false,state_t(),prop_t(),ptr)),ptr); +} + +inline std::size_t efac::size() const { return cache.size(); } + +#ifdef EFAC_HASH_INTERFACE +inline std::size_t efac::bucket_count() const { return cache.bucket_count(); } +inline float efac::load_factor() const { return cache.load_factor(); } +inline float efac::max_load_factor() const { return cache.max_load_factor(); } +inline void efac::max_load_factor(float z) { cache.max_load_factor(z); } +inline void efac::rehash(unsigned int n) { cache.rehash(n); } + +inline std::size_t efac::max_buck() const +{ + std::size_t m = 0; + for (int i = 0; i < cache.bucket_count(); ++i) { + m = std::max(m,cache.bucket_size(i)); + } + return m; +} +#endif + +inline efac::efac() : cache(), ptr() {} +inline efac::efac(unsigned int n) : cache(), ptr() { cache.rehash(n); } + +inline const expr_impl_ptr efac::check_hash(const expr_impl_t& expr) +{ + expr_impl_hash_t::const_iterator r = cache.find(expr); + if (r != cache.end()) { + return expr_impl_ptr(*r); + } else { + const expr_impl_ptr n = expr_impl_ptr(new expr_impl_t(expr)); + cache.insert(n.get()); + return n; + } +} + + +/* ************************************************************************** */ +/* dfs */ +inline void dfs::run(const expr_t& x) +{ + pre_hook(); + init_hook(x); + rec(x); + post_hook(); +} + +inline void dfs::rec(const expr_t& x) +{ + if (hash.find(x) != hash.end()) return; + hash.insert(x); + node_hook(x); + switch (x.e->op) { + case And: and_hook(x); break; + case Or: or_hook(x); break; + case State: state_hook(x); break; + case Prop: prop_hook(x); break; + case NProp: nprop_hook(x); break; + case Const: const_hook(x); break; + } + if (x.op() == State) { + edge_hook(x,*x.e->state); + rec(*(x.e->state)); + } else { + foreach(const expr_t& y, x.childs()) { + edge_hook(x,y); + rec(y); + } + } +} + +template +void dfs::run(I a, I e) +{ + pre_hook(); + foreach(typename I::value_type const& x, std::make_pair(a,e)) + { + init_hook(x); + rec(x); + } + post_hook(); +} + +/* ************************************************************************** */ +/* expr_impl_t */ + +inline void intrusive_ptr_add_ref(const expr_impl_t* e) +{ + ++(e->ref_c); +} + +inline void intrusive_ptr_release(const expr_impl_t* e) +{ +#ifndef NO_EXPR_DEALLOC + if ( --(e->ref_c) == 0) { + if (efac_ptr tmp = e->eptr.lock()) { + tmp ->cache.erase(*e); + } + delete e; + } +#endif +} + diff --git a/libaaut/expr_util.hh b/libaaut/expr_util.hh new file mode 100644 index 0000000..5dde279 --- /dev/null +++ b/libaaut/expr_util.hh @@ -0,0 +1,437 @@ +/* *** MOCS-COPYRIGHT-NOTICE-BEGIN *** + * + * This copyright notice is auto-generated by ./add-copyright-notice. + * Additional copyright notices must be added below the last line of this notice. + * + * MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "libaaut/expr_util.hh". + * The content of this file is copyright of Saarland University - + * Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . + * + * This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). + * + * License: three-clause BSD style license. + * The license text can be found in the file LICENSE. + * + * *** MOCS-COPYRIGHT-NOTICE-END *** */ + +#ifndef _EXPR_UTIL_HH +#define _EXPR_UTIL_HH + +#include "config.h" + +#ifdef NOREC_DISTR +#include +#endif + +#include "expr.hh" + + +namespace expr { namespace util +{ + RUNTIME_ERROR(expr_type_error); + + /* Makes an expression weak. recurses on states, detects cycles. */ + inline expr_t weak(const expr_t& e); + + /* Dualizes an expression. recurses on states, detects cycles.*/ + expr_t dual(const expr_t& e); + + + /* Collects all conjuncts of a conjunction */ + template void get_conj(const expr_t& e, std::back_insert_iterator i); + + /* Collects all states from a disjunction over states */ + template void get_disj_states(const expr_t& e, std::insert_iterator i); + + /* splits a Disjunction into a disjunction of states and the rest */ + std::pair split_disj(const expr_t& e, const efac_ptr& state_efac, const efac_ptr& rest_efac); + + /* Recursively distributes disjuncts over a conjunction (used by mkCNF) */ + expr_t distr_disj(const expr_t& a, const expr_t& b); + + /* Transforms an expr into CNF */ + expr_t mkCNF(const expr_t& e, const efac_ptr& out_efac); + + + /* Collects all disjuncts of a conjunction */ + template void get_disj(const expr_t& e, std::back_insert_iterator i); + + /* Collects all states from a conjunction over states */ + template void get_disj_states(const expr_t& e, std::insert_iterator i); + + /* splits a Conjunction into a conjcution of states and the rest */ + std::pair split_disj(const expr_t& e, const efac_ptr& state_efac, const efac_ptr& rest_efac); + + /* Recursively distributes conjuncts over a disjunction (used by mkCNF) */ + expr_t distr_disj(const expr_t& a, const expr_t& b); + + /* Transforms an expr into DNF */ + expr_t mkDNF(const expr_t& e, const efac_ptr& out_efac); + + + /* Collects all successor states */ + template + void successor_states(const state_t& s, std::back_insert_iterator&); + + std::size_t successor_states_count(const state_t& s); + std::size_t successor_states_count(const expr_t& e); + + /* ************************************************************************** */ + /* expr hash map */ + + // from http://www.boost.org/doc/libs/1_38_0/libs/multi_index/doc/tutorial/techniques.html#emulate_assoc_containers + template + struct mutable_pair + { + typedef T1 first_type; + typedef T2 second_type; + + mutable_pair():first(T1()),second(T2()){} + mutable_pair(const T1& f,const T2& s):first(f),second(s){} + mutable_pair(const std::pair& p):first(p.first),second(p.second){} + + T1 first; + mutable T2 second; + }; + + struct expr_hasher { + std::size_t operator() (const expr_t& e) const + { + boost::hash()(e.uid()); + } + }; + +#define EXPR_HASH_MAP(Value) multi_index_container< mutable_pair, indexed_by,expr_t,&mutable_pair::first>,expr_hasher > > > + + + /* ********************************************************************** */ + /* Implementation */ + + namespace + { + struct expr_dualizer + { + typedef std::map state_map_t; + expr_dualizer() : state_map() {} + + expr_t operator()(const expr_t& e) { return rec(e); } + + expr_t rec(const expr_t& x) + { + efac_ptr c = x.efac(); + switch (x.op()) { + case And: return rec(x.left()) || rec(x.right()); + case Or: return rec(x.left()) && rec(x.right()); + case Prop: return c->mkNProp(x.prop()); + case NProp: return c->mkProp(x.prop()); + case Const: return c->mkConst(! x.con()); + case State: state_map_t::const_iterator r = state_map.find(x.state()); + if (r != state_map.end()) return c->mkState(r->second); + state_t s = new_state(); + state_map.insert(std::make_pair(x.state(),s)); + *s = rec(*x.state()); + s.set_final(! x.state().final()); + return c->mkState(s); + } + } + state_map_t state_map; + }; + + struct expr_rewriter + { + typedef std::map state_map_t; + expr_rewriter(efac_ptr ctx = efac_ptr()) : state_map(), c(ctx) {} + + virtual ~expr_rewriter() { } + + virtual expr_t operator()(const expr_t& e) { + if (! c ) { + c = e.efac(); + return rec(e); + c = efac_ptr(); + } else { + return rec(e); + } + } + + virtual expr_t and_rec(const expr_t& x) { return rec(x.left()) && rec(x.right()); } + virtual expr_t or_rec(const expr_t& x) { return rec(x.left()) || rec(x.right()); } + virtual expr_t prop_rec(const expr_t& x) { return c->mkProp(x.prop()); } + virtual expr_t nprop_rec(const expr_t& x) { return c->mkNProp(x.prop()); } + virtual expr_t const_rec(const expr_t& x) { return c->mkConst(x.con()); } + virtual expr_t state_rec(const expr_t& x, state_t& new_state) + { + *new_state = rec(*x.state()); + new_state.set_final(x.state().final()); + return c->mkState(new_state); + } + virtual expr_t cache_conv(const expr_t& x, const state_t& new_state) + { + return c->mkState(new_state); + } + + expr_t rec(const expr_t& x) + { + switch (x.op()) { + case And: return and_rec(x); + case Or: return or_rec(x); + case Prop: return prop_rec(x); + case NProp: return nprop_rec(x); + case Const: return const_rec(x); + case State: state_map_t::const_iterator r = state_map.find(x.state()); + if (r != state_map.end()) return cache_conv(x,r->second); + state_t s = new_state(); + state_map.insert(std::make_pair(x.state(),s)); + return state_rec(x,s); + } + } + state_map_t state_map; + efac_ptr c; + }; + }; + + inline expr_t dual(const expr_t& e) + { + return expr_dualizer()(e); + } + + // make expr (automaton) weak + namespace + { + struct expr_weaker : expr_rewriter + { + expr_t state_rec(const expr_t& x, state_t& ns) + { + *ns = rec(*x.state()); + ns.set_final(); + return c->mkState(ns); + } + }; + }; + + inline expr_t weak(const expr_t& e) + { + return expr_weaker()(e); + } + +/* ************************************************************************** */ + + // CNF + // TODO do we need to distribut state-less expressions? + // would be more efficient to not touch them at all??? + // TODO check naming of subroutines (e.g. split_disj is missleading or at least ambigious) + + template + void get_conj(const expr_t& e, std::back_insert_iterator i) + { + switch (e.op()) { + case And: get_conj(e.left(),i); get_conj(e.right(),i); break; + default: i = e; break; + } + } + + template + void get_disj_states(const expr_t& e, std::insert_iterator i) + { + switch (e.op()) { + case Or: get_disj_states(e.left(),i); get_disj_states(e.right(),i); break; + case State: i = e.state(); break; + default: throw expr_type_error("Expr should be a disjunction of states."); + } + } + + // first: states, second: rest + inline std::pair split_disj(const expr_t& e, + const efac_ptr& state_efac, + const efac_ptr& rest_efac) + { + std::pair r,l; + switch (e.op()) { + case And: throw expr_type_error("In a CNF a conjunct must not contain conjunctions"); + case Or: l = split_disj(e.left(),state_efac,rest_efac); + r = split_disj(e.right(),state_efac,rest_efac); + return std::make_pair(l.first || r.first, l.second || r.second); + case Prop: return std::make_pair(expr_t(),rest_efac->mkProp(e.prop())); + case NProp: return std::make_pair(expr_t(),rest_efac->mkNProp(e.nprop())); + case Const: return std::make_pair(expr_t(),rest_efac->mkConst(e.con())); + case State: return std::make_pair(state_efac->mkState(e.state()),expr_t()); + } + } + +#ifdef NOREC_DISTR + inline expr_t distr_disj(const expr_t& a, const expr_t& b) + { + std::queue > q; + q.push(std::make_pair(a,b)); + expr_t result; + while (! q.empty()) { + expr_t a = q.front().first; + expr_t b = q.front().second; + q.pop(); + if (a.op() == And) { + q.push(std::make_pair(a.left(),b)); + q.push(std::make_pair(a.right(),b)); + } else if (b.op() == And) { + q.push(std::make_pair(a,b.left())); + q.push(std::make_pair(a,b.right())); + } else { + result = result && (a || b); + } + } + return result; + } +#else + inline expr_t distr_disj(const expr_t& a, const expr_t& b) + { + if (a.op() == And) { + return distr_disj(a.left(),b) && distr_disj(a.right(),b); + } else if (b.op() == And) { + return distr_disj(a,b.left()) && distr_disj(a,b.right()); + } else { + return a || b; + } + } +#endif + + + inline expr_t mkCNF(const expr_t& e, const efac_ptr& out_efac) + { + switch (e.op()) { + case And: return mkCNF(e.left(),out_efac) && mkCNF(e.right(),out_efac); + case Or: return distr_disj (mkCNF(e.left(),out_efac), mkCNF(e.right(),out_efac)); + case Prop: return out_efac->mkProp(e.prop()); + case NProp: return out_efac->mkNProp(e.nprop()); + case Const: return out_efac->mkConst(e.con()); + case State: return out_efac->mkState(e.state()); + } + } + +/* ************************************************************************** */ + + template + void get_disj(const expr_t& e, std::back_insert_iterator i) + { + switch (e.op()) { + case Or: get_disj(e.left(),i); get_disj(e.right(),i); break; + default: i = e; break; + } + } + + template + void get_conj_states(const expr_t& e, std::insert_iterator i) + { + switch (e.op()) { + case And: get_conj_states(e.left(),i); get_conj_states(e.right(),i); break; + case State: i = e.state(); break; + default: throw expr_type_error("Expr should be a conjunction of states."); + } + } + + // first: states, second: rest + inline std::pair split_conj(const expr_t& e, + const efac_ptr& state_efac, + const efac_ptr& rest_efac) + { + std::pair r,l; + switch (e.op()) { + case Or: throw expr_type_error("in a DNF a disjunct must not contain disunctions"); + case And: l = split_conj(e.left(),state_efac,rest_efac); + r = split_conj(e.right(),state_efac,rest_efac); + return std::make_pair(l.first && r.first, l.second && r.second); + case Prop: return std::make_pair(expr_t(),rest_efac->mkProp(e.prop())); + case NProp: return std::make_pair(expr_t(),rest_efac->mkNProp(e.nprop())); + case Const: return std::make_pair(expr_t(),rest_efac->mkConst(e.con())); + case State: return std::make_pair(state_efac->mkState(e.state()),expr_t()); + } + } + +#ifdef NOREC_DISTR + inline expr_t distr_conj(const expr_t& a, const expr_t& b) + { + std::queue > q; + q.push(std::make_pair(a,b)); + expr_t result; + while (! q.empty()) { + expr_t a = q.front().first; + expr_t b = q.front().second; + q.pop(); + if (a.op() == Or) { + q.push(std::make_pair(a.left(),b)); + q.push(std::make_pair(a.right(),b)); + } else if (b.op() == Or) { + q.push(std::make_pair(a,b.left())); + q.push(std::make_pair(a,b.right())); + } else { + result = result || (a && b); + } + } + return result; + } +#else + inline expr_t distr_conj(const expr_t& a, const expr_t& b) + { + if (a.op() == Or) { + return distr_conj(a.left(),b) || distr_conj(a.right(),b); + } else if (b.op() == Or) { + return distr_conj(a,b.left()) || distr_conj(a,b.right()); + } else { + return a && b; + } + } +#endif + + inline expr_t mkDNF(const expr_t& e, const efac_ptr& out_efac) + { + switch (e.op()) { + case Or: return mkDNF(e.left(),out_efac) || mkDNF(e.right(),out_efac); + case And: return distr_conj (mkDNF(e.left(),out_efac), mkDNF(e.right(),out_efac)); + case Prop: return out_efac->mkProp(e.prop()); + case NProp: return out_efac->mkNProp(e.nprop()); + case Const: return out_efac->mkConst(e.con()); + case State: return out_efac->mkState(e.state()); + } + } + +/* ************************************************************************** */ + + namespace { + template + void suc_state_rec(const expr_t& e, std::back_insert_iterator& i) + { + switch (e.op()) { + case And: + case Or: suc_state_rec(e.left(),i); suc_state_rec(e.right(),i); break; + case State: i = e.state(); break; + } + } + + std::size_t suc_state_count_rec(const expr_t& e) + { + switch (e.op()) { + case And: + case Or: return suc_state_count_rec(e.left()) + suc_state_count_rec(e.right()); + case State: return 1; + default: return 0; + } + } + }; + + template + inline void successor_states(const state_t& s, std::back_insert_iterator& i) + { + suc_state_rec(*s, i); + } + + inline std::size_t successor_states_count(const state_t& s) + { + return suc_state_count_rec(*s); + } + + inline std::size_t successor_states_count(const expr_t& e) + { + return suc_state_count_rec(e); + } + +};}; // namespace expr::util + +#endif // _EXPR_UTIL_HH diff --git a/libaaut/state-machine.cc b/libaaut/state-machine.cc new file mode 100644 index 0000000..7596dad --- /dev/null +++ b/libaaut/state-machine.cc @@ -0,0 +1,141 @@ +/* *** MOCS-COPYRIGHT-NOTICE-BEGIN *** + * + * This copyright notice is auto-generated by ./add-copyright-notice. + * Additional copyright notices must be added below the last line of this notice. + * + * MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "libaaut/state-machine.cc". + * The content of this file is copyright of Saarland University - + * Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . + * + * This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). + * + * License: three-clause BSD style license. + * The license text can be found in the file LICENSE. + * + * *** MOCS-COPYRIGHT-NOTICE-END *** */ + +#include "state-machine.hh" + +/* Precondition: The input automaton is universal + * + * FIXME: documentation is outdated! + * + * We need to "invert" suc-expressions: + * Do a dfs where at + * -> state: + * * get all conj (a "maximal/ first" non-and-node) + * * register at each conj + * -> conj (register carrying node) + * * split into (se,re) ( (state-expression, rest), disjunction) + * * if se is empty (se == expr_t()) then FIXME + * * build (not re) and register at conj + * * register conj at se-input-or + * * insert (not re) into input-logic-list + * + * state machine generation: + * state: + * -> input: state-input-or + * + * state-input-or: + * -> or-expr: + * input: all registered exprs + * + * conj (register carrying node): + * -> and-expr: + * input: registered exprs + * + * each expr in input-logic-list: + * -> copy + * + */ + +namespace +{ + typedef const void* reg_key_t; + typedef std::map state_map_t; + typedef std::set visited_t; + + state_t new_state(const state_t& old, state_map_t& state_map, const efac_ptr& new_efac) + { + // new state + state_map_t::const_iterator it = state_map.find(old.uid()); + if (it != state_map.end()) { + return it->second; + } else { + state_t nstate = new_state(new_efac->mkFalse(),old.final()); + state_map[old.uid()] = nstate; + return nstate; + } + } + + void invert_dfs1(const expr_t& cur, const expr_t& state_expr, visited_t& visited, state_map_t& state_map, const efac_ptr& new_efac); + + void invert_dfs0(const state_t& cur, visited_t& visited, state_map_t& state_map, const efac_ptr& new_efac) + { + // check for recursion end + if (visited.find(cur.uid()) != visited.end()) { + return; + } else { + visited.insert(cur.uid()); + } + + state_t nstate = new_state(cur,state_map,new_efac); + + // get conjuncts + std::list l; + expr::util::get_conj(*cur,std::back_inserter(l)); + + // recurse on conjuncts + foreach(expr_t& c, l) { + invert_dfs1(c,new_efac->mkState(nstate),visited,state_map,new_efac); + } + } + + void invert_dfs1(const expr_t& cur, const expr_t& state_expr, visited_t& visited, state_map_t& state_map, const efac_ptr& new_efac) + { + // split conjunct into state and rest + expr_t se, re; + boost::tie(se,re) = expr::util::split_disj(cur,cur.efac(),new_efac); + if (se == expr_t()) { + std::cerr << "FIXME, conjunct without state ..." << std::endl; + } else { + ASSERT(se.op() == State); // is se a singelton ? + expr_t tmp = expr::util::dual(new_efac->mkFalse() || re); // why the disjunction? + + state_t nse = new_state(se.state(),state_map,new_efac); + nse.set_suc(*nse || (state_expr && tmp)); + + // recurse on se + invert_dfs0(se.state(), visited, state_map, new_efac); + } + } +}; // annonymous + + +void state_machine_t::init_state_machine(const automaton_t& a) +{ + // new_efac + efac_ptr new_efac = efac::newEfac(); + + // run dfs + state_map_t state_map; + visited_t visited; + invert_dfs0(a.init,visited,state_map,new_efac); + + foreach (const state_map_t::value_type& v, state_map) { + // std::cerr << (long) v.second.uid() << ": " << *v.second << std::endl; + states.push_back(v.second); + smap[v.second.uid()] = v.first; + } + init = state_map[a.init.uid()]; +} + +std::ostream& state_machine2dot(std::ostream& o, const state_machine_t& a, const std::string& name) +{ + std::list l; + l.push_back(a.init->efac()->mkState(a.init)); + foreach(const std::list::value_type& s, a.states) { + if (s != a.init) l.push_back(a.init->efac()->mkState(s)); + } + return exprs2dot(o,l,name); +} diff --git a/libaaut/state-machine.hh b/libaaut/state-machine.hh new file mode 100644 index 0000000..3b5cde0 --- /dev/null +++ b/libaaut/state-machine.hh @@ -0,0 +1,50 @@ +/* *** MOCS-COPYRIGHT-NOTICE-BEGIN *** + * + * This copyright notice is auto-generated by ./add-copyright-notice. + * Additional copyright notices must be added below the last line of this notice. + * + * MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "libaaut/state-machine.hh". + * The content of this file is copyright of Saarland University - + * Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . + * + * This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). + * + * License: three-clause BSD style license. + * The license text can be found in the file LICENSE. + * + * *** MOCS-COPYRIGHT-NOTICE-END *** */ + +#ifndef _STATE_MACHINE_HH_ +#define _STATE_MACHINE_HH_ + +#include "config.h" + +#include "expr.hh" +#include "aa.hh" + +/* A state machine + * + * Essentially the same data-structure as an (universal) automaton. + * However, the suc (successors/ postcondition) member of states is interpreted as + * pre (predecessor-relation/ precondition). + * + * This allows for a straight forward implementation into circuits. + * + */ + +struct state_machine_t +{ + state_machine_t(const automaton_t& a) : init(), states() {init_state_machine(a);} + state_t init; + std::list states; + std::map smap; + + void init_state_machine(const automaton_t& a); +}; + +// pretty-printing +std::ostream& state_machine2dot(std::ostream& o, const state_machine_t& a, const std::string& name = "state machine"); + + +#endif // _STATE_MACHINE_HH_ + diff --git a/libaaut/subsetconstruction.tcc b/libaaut/subsetconstruction.tcc new file mode 100644 index 0000000..0b123a9 --- /dev/null +++ b/libaaut/subsetconstruction.tcc @@ -0,0 +1,278 @@ +/* *** MOCS-COPYRIGHT-NOTICE-BEGIN *** + * + * This copyright notice is auto-generated by ./add-copyright-notice. + * Additional copyright notices must be added below the last line of this notice. + * + * MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "libaaut/subsetconstruction.tcc". + * The content of this file is copyright of Saarland University - + * Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . + * + * This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). + * + * License: three-clause BSD style license. + * The license text can be found in the file LICENSE. + * + * *** MOCS-COPYRIGHT-NOTICE-END *** */ + +/* ************************************************************************** */ +/* Subset construction */ + +/* ************************************************************************** */ +#if 0 + +// cnf: +#define main univ +#define neutral_accept false +#define DOP || +#define OP && +#define get_op expr::util::get_conj +#define get_dualop_states expr::util::get_disj_states +#define is_final has_final +#define mkNF expr::util::mkCNF +#difine split expr::util::split_disj +#ifdef DEBUG_UNIV +#define DEBUG_SUBSET +#endif + +#endif + +#define _NNAME(x) ns##_##x +#define NNAME(x) _NNAME(x) + +namespace NNAME(main) +{ + RUNTIME_ERROR(expr_type_error); + + typedef std::set state_set_t; + typedef std::map< state_set_t, const state_t > map_t; + + state_t rec(const state_set_t& states, const efac_ptr& new_efac, map_t& map, const expr_t&, const efac_ptr& tmp_efac); + expr_t mk_nf(const state_set_t& states, const efac_ptr& new_efac, map_t& map, const expr_t&, const efac_ptr& tmp_efac); + bool has_final(const state_set_t& states); + bool all_final(const state_set_t& states); + + using namespace expr::util; + + template + struct static_cache + { + typedef T value_t; + typedef expr_t key_t; + typedef EXPR_HASH_MAP(value_t) cache_t; + cache_t cache; + std::string name; + + static_cache(const std::string& name) : name(name) {} + + bool check(const key_t& k, value_t& result) const + { + typename cache_t::const_iterator it = cache.find(k); + if (it != cache.end()) { +#ifdef DEBUG_SUBSET + std::cerr << name << ": hit" << std::endl; +#endif + result = it->second; + return true; + + } else { +#ifdef DEBUG_SUBSET + std::cerr << name << ": miss" << std::endl; +#endif + return false; + } + } + + void update(const key_t& k, const value_t& v) { cache.insert(std::make_pair(k,v)); } + }; + + inline expr_t mkNF_wrapper(const expr_t& e, const efac_ptr& target_efac) + { +#ifdef NF_WRAPPER_CACHE + static static_cache cache("mkNF_wrapper_cache"); + { expr_t tmp; if (cache.check(e,tmp)) { return tmp; }} +#endif + expr_t x = mkNF(e,target_efac); + +#ifdef NF_WRAPPER_CACHE + cache.update(e,x); +#endif + return x; + } + + std::pair split_wrapper(const expr_t& d, const efac_ptr& tmp_efac, const efac_ptr& new_efac) + { +#ifdef SPLIT_WRAPPER_CACHE + static static_cache< std::pair > cache("split_wrapper_cache"); + { std::pair tmp; if (cache.check(d,tmp)) { return tmp; }} +#endif + + std::pair x = split(d,tmp_efac,new_efac); +#ifdef SPLIT_WRAPPER_CACHE + cache.update(d,x); +#endif + return x; + } + +#ifdef SUBSET_GET_NEXT_STATE_EXPR_CACHE + expr_t get_next_state_expr_wrapper(const expr_t& se, const efac_ptr& new_efac, map_t& map, const expr_t& efs, const efac_ptr& tmp_efac) + { + static static_cache cache("get_next_state_expr_wrapper_cache"); + { expr_t tmp; if (cache.check(se,tmp)) { return tmp; }} + + expr_t tmp; + using namespace std::rel_ops; + if (se != expr_t()) { + state_set_t states; + expr::util::get_disj_states(se,std::inserter(states,states.begin())); + state_t state = rec(states,new_efac,map,efs,tmp_efac); + tmp = tmp || new_efac->mkState(state); + } + cache.update(se,tmp); + return tmp; + } +#endif + + automaton_t main(const automaton_t& a) + { + // 1. map.insert ({init},ninit) + // 2. cur = {init} + // 3. build cnf from suc of cur + // 4. for each conj create new state (if any) + // create conj in new efac + // if (nstate not in map) { + // map.insert ({old-states},nstate) + // recurse on new state (or add it to queue) + // 5. create suc of cur + // + + // Experiment: + // add disjunctive false state to each suc + state_t fs = new_state(neutral_accept); + fs.set_suc(a.init->efac()->mkState(fs)); + expr_t false_state_expr = a.init->efac()->mkState(fs); + + efac_ptr new_efac = efac::newEfac(); + efac_ptr tmp_efac = efac::newEfac(); + map_t map; + state_set_t init_set; + init_set.insert(a.init); +#ifndef DEBUG_SUBSET + return automaton_t(rec(init_set,new_efac,map,false_state_expr,tmp_efac)); +#else + automaton_t ret(rec(init_set,new_efac,map,false_state_expr,tmp_efac)); + std::cerr << "exit univ" << std::endl; + return ret; +#endif + } + + inline bool has_final(const state_set_t& states) + { + foreach(const state_t& s, states) { + if (s.final()) return true; + } + return false; + } + + inline bool all_final(const state_set_t& states) + { + foreach(const state_t& s, states) { + if (! s.final()) return false; + } + return true; + } + + + // Gets a set of states from old-efac and returns a state in new-efac + // updates map with (states,new-state). + state_t rec(const state_set_t& states, const efac_ptr& new_efac, map_t& map, const expr_t& efs, const efac_ptr& tmp_efac) + { + map_t::const_iterator it = map.find(states); + if (it != map.end()) return it->second; +#ifdef DEBUG_SUBSET + static long count; + count++; + std::cerr << "count: " << count << ", states: " << states.size() << std::endl; +#endif + + // We insert the new state before computing its + // suc, because during that computation we do the recursion. + state_t state = new_state(is_final(states)); + map.insert(std::make_pair(states,state)); + + // mk_cnf recurses (calls back into rec) + state.set_suc(mk_nf(states,new_efac,map,efs,tmp_efac)); + + return state; + } + + // takes an expr within old-efac. Returns an cnf-expr within new-efac. + // recurses on successor states + expr_t mk_nf(const state_set_t& states, const efac_ptr& new_efac, map_t& map, const expr_t& efs, const efac_ptr& tmp_efac) + { + // build cnf + expr_t common_suc = efs; + foreach(const state_t& st, states) { + common_suc = common_suc DOP mkNF_wrapper(*st,tmp_efac); + } + common_suc = mkNF_wrapper(common_suc,tmp_efac); + +#ifdef SUC_EXPR_CACHE + static static_cache suc_expr_cache("suc_expr_cache"); + { expr_t tmp; if (suc_expr_cache.check(common_suc,tmp)) { return tmp; }} +#endif + + // get conjuncts + std::list l; + get_op(common_suc, std::back_inserter(l)); + + // merge states in each conjunct + // i.e. split each conjunct into states and rest. + // states remain into tmp_efac rest goes into new_efac + expr_t root; + foreach(const expr_t& d, l) { + +#ifdef SUBSET_OP_CACHE + static static_cache op_cache("conj_cache"); + {expr_t tmp; if (op_cache.check(d,tmp)) { root = root && tmp; continue; }} +#endif + + // split conjunct into state-disjunct and rest + // rest is copied into new-efac on the fly + // se remains in tmp-efac + expr_t se, re; + boost::tie(se,re) = split_wrapper(d,tmp_efac,new_efac); + + // se is a disjunction of states: get state_set from se + // create new state in new-efac from it + using namespace std::rel_ops; +#ifdef SUBSET_GET_NEXT_STATE_EXPR_CACHE + expr_t tmp = get_next_state_expr_wrapper(se,new_efac,map,efs,tmp_efac); +#else + expr_t tmp; + if (se != expr_t()) { + state_set_t states; + get_dualop_states(se,std::inserter(states,states.begin())); + state_t state = rec(states,new_efac,map,efs,tmp_efac); + tmp = tmp DOP new_efac->mkState(state); + } +#endif + if (re != expr_t()) { + tmp = tmp DOP re; + } + assert( tmp != expr_t()); + +#ifdef CONJ_CACHE + conj_cache.update(d,tmp); +#endif + + // join new state with rest and add it the root + root = root OP tmp; + } + +#ifdef SUC_EXPR_CACHE + suc_expr_cache.update(common_suc,root); +#endif + return root; + } +}; + diff --git a/libaaut/util.hh b/libaaut/util.hh new file mode 100644 index 0000000..b69837a --- /dev/null +++ b/libaaut/util.hh @@ -0,0 +1,157 @@ +/* *** MOCS-COPYRIGHT-NOTICE-BEGIN *** + * + * This copyright notice is auto-generated by ./add-copyright-notice. + * Additional copyright notices must be added below the last line of this notice. + * + * MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "libaaut/util.hh". + * The content of this file is copyright of Saarland University - + * Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . + * + * This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). + * + * License: three-clause BSD style license. + * The license text can be found in the file LICENSE. + * + * *** MOCS-COPYRIGHT-NOTICE-END *** */ + +#ifndef _UTIL_HXX_ +#define _UTIL_HXX_ + +#include "config.h" + +#ifdef CHECK_ASSERTIONS +// define NDEBUG before including assert.h in order to disable asseration checking +#include +#include +//#else +//#define NDEBUG +//#include +#endif + +#include +#include +#include +#include + +#include +#include + +#include +#define foreach BOOST_FOREACH + +#define STRCAST(x) boost::lexical_cast(x) + +/** \name Macro to simplify definition of standard runtime errors + */ +#define RUNTIME_ERROR(x) struct x : public std::runtime_error { explicit x (const std::string& what = "") : std::runtime_error(what) {}; }; + +#define RUNTIME_ERROR2(x,y) struct x : public y { explicit x (const std::string& what = "") : y(what) {}; }; + +// Make sure to set NDEBUG as long as performance does not matter! +#if !defined(NDEBUG) +#define BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING +#define BOOST_MULTI_INDEX_ENABLE_SAFE_MODE +#endif + +#include +#include +#include +#include +#include + +#ifdef CHECK_ASSERTIONS +#define ASSERT(x) assert(x) +#else +#define ASSERT(x) "" +#endif + +/* ************************************************************************** */ +/* quoting */ +namespace +{ + template + struct quote_t + { + const T& x; + quote_t(const T& x) : x(x) {} + }; +}; + +template +inline quote_t quote(const T& x) +{ + return quote_t(x); +} + +template +std::ostream& operator<<(std::ostream& o, const quote_t& q) +{ + return o << "\"" << q.x << "\""; +} + +inline std::string quote(const std::string& s) +{ + return "\"" + s + "\""; +} +/* ************************************************************************** */ +/* listing */ + +#include + +namespace +{ + template + struct list_format_t + { + typedef boost::function formator_t; + const T& x; + const std::string& s; + formator_t f; + list_format_t(const std::string& s, const T& x, formator_t f) : x(x),s(s),f(f) {} + list_format_t(const std::string& s, const T& x) : x(x),s(s),f() {} + }; +} + +template +inline list_format_t list_format(const std::string& s, const T& x, + const typename list_format_t::formator_t& f) +{ + return list_format_t(s,x,f); +} + +template +inline list_format_t list_format(const std::string& s, const T& x) +{ + return list_format_t(s,x); +} + +template +std::ostream& operator<<(std::ostream& o, const list_format_t& l) +{ + typename T::const_iterator it = l.x.begin(); + if (it == l.x.end()) return o; + if ( ! l.f ) { + o << *it; + for (++it; it != l.x.end(); ++it) + { + o << l.s << *it; + } + } else { + o << l.f(*it); + for (++it; it != l.x.end(); ++it) + { + o << l.s << l.f(*it); + } + } + return o; +} + +/* ************************************************************************** */ + +inline std::ostream& operator<<(std::ostream& o, const std::vector& p) +{ + return o << "<" << list_format(",",p) << ">"; +} + +#endif + diff --git a/libaaut/vhdl.cc b/libaaut/vhdl.cc new file mode 100644 index 0000000..bab7eba --- /dev/null +++ b/libaaut/vhdl.cc @@ -0,0 +1,799 @@ +/* *** MOCS-COPYRIGHT-NOTICE-BEGIN *** + * + * This copyright notice is auto-generated by ./add-copyright-notice. + * Additional copyright notices must be added below the last line of this notice. + * + * MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "libaaut/vhdl.cc". + * The content of this file is copyright of Saarland University - + * Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . + * + * This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). + * + * License: three-clause BSD style license. + * The license text can be found in the file LICENSE. + * + * *** MOCS-COPYRIGHT-NOTICE-END *** */ + +#include "vhdl.hh" +#include "state-machine.hh" + +namespace +{ + using namespace vhdl; + + /* ********************************************************************** */ + /* utilities */ + + typedef long sig_t; + typedef std::set sig_set_t; + typedef std::map reg_t; + typedef std::list logic_list_t; + + std::string output_port_name(int formula_idx, int pos_idx) + { + return "output" + STRCAST(formula_idx) + "(" + STRCAST(pos_idx) + ")"; + } + + std::string input_port_name(int prop, int pos_idx) + { + return "input" + STRCAST(prop) + "(" + STRCAST(pos_idx) + ")"; + } + + std::string input_port_name(const prop_t& p, bool array = false) + { + if (p.size() == 1 && ! array) { + return "input" + STRCAST(p[0]); + } else if (p.size() == 1 && array) { + return "input(" + STRCAST(p[0]) + ")"; + } else if (p.size() == 2) { + return input_port_name(p[0],p[1]); + } + } + + sig_t signal(const expr_t& s) + { + return (long) s.uid(); + } + + sig_t signal(const state_t& s) + { + return (long) s.uid(); + } + + std::string signal_name(const void* s) + { + return "s" + STRCAST((long)s); + } + + std::string signal_name(const state_t& s) + { + return "s" + STRCAST(signal(s)); + } + + std::string signal_name(const expr_t& s) + { + if (s.op() != State) { + return "s" + STRCAST(signal(s)); + } else { + return signal_name(s.state()); + } + } + + std::string signal_name(const sig_t& s) + { + return "s" + STRCAST(s); + } + + // out-port-field iterator: iterators over (2 dimensional) out_ports_field_t + struct opf_it : + public std::iterator + { + typedef out_ports_field_t f_t; + typedef opf_it self_t; + typedef f_t::const_iterator o_it; + typedef o_it::value_type i_it; + + opf_it(const f_t& f) : + f(f), + o(f.begin()), + i(f.begin()->begin()) + {} + + static self_t begin(const f_t& f) + { + return self_t(f); + } + + static self_t end(const f_t& f) + { + self_t it = self_t(f); + it.o = f.end(); + it.i = f.back().end(); // FIXME + return it; + } + + self_t& operator++() + { + ++i; + if (i == o->end()) { + ++o; + if (o != f.end()) i = o->begin(); + } + return *this; + } + + reference operator*() const + { + return *i; + } + + pointer operator->() const + { + return i.operator->(); + } + + bool operator==(const self_t& r) const + { + return f == r.f && o == r.o && i == r.i; + } + + const f_t& f; + f_t::const_iterator o; + f_t::const_iterator::value_type::const_iterator i; + }; + + /* generate function for a signal (except state) + */ + std::ostream& signal_func(std::ostream& o, const expr_t& s, bool array = false) + { + o << " " << signal_name(s) << " <= "; + switch (s.op()) { + case Prop: o << input_port_name(s.prop(),array); break; + case NProp: o << " not " << input_port_name(s.nprop(),array); break; + case And: o << signal_name(s.left()) << " and " << signal_name(s.right()); break; + case Or: o << signal_name(s.left()) << " or " << signal_name(s.right()); break; + case Const: if (s.con() ) o << "'1'"; else o << "'0'"; break; + default: expr_type_error("a boolean circuit must not contain States."); // FIXME + } + return o << ";\n"; + } + + std::ostream& sensitives(std::ostream& o, const expr_t& s, bool array = false) + { + if (s.op() != Const) { + o << "("; + switch (s.op()) { + case Prop: o << input_port_name(s.prop(),array); break; + case NProp: o << input_port_name(s.nprop(),array); break; + case And: o << signal_name(s.left()) << "," << signal_name(s.right()); break; + case Or: o << signal_name(s.left()) << "," << signal_name(s.right()); break; + case Const: o << ""; break; + case State: o << signal_name(*s.state()); break; + } + return o << ")"; + } else { + return o; + } + } + + struct signal_decl_dfs : public dfs + { + signal_decl_dfs(std::ostream& o) : o(o) {} + void node_hook(const expr_t& s) + { + o << " signal " << signal_name(s) << " : STD_LOGIC;\n"; + } + std::ostream& o; + }; + + template + std::ostream& signal_decl(std::ostream& o, const T& l) + { + foreach(const typename T::value_type& s, l) { + o << " signal " << signal_name(s) << " : STD_LOGIC;\n"; + } + return o; + } + + std::ostream& signal_decl(std::ostream& o, const sig_t& s) + { + o << " signal " << signal_name(s) << " : STD_LOGIC;\n"; + return o; + } + + std::ostream& signal_decl(std::ostream& o, const std::string& s) + { + o << " signal " << s << " : STD_LOGIC;\n"; + return o; + } + + // build process + struct build_logic_dfs : public dfs + { + build_logic_dfs(std::ostream& o, bool array = false) : o(o), array(array) {} + void node_hook(const expr_t& s) + { + if (s.op() == Const) { + signal_func(o,s,array); + o << "\n\n"; + + } else if (s.op() == State) { + o << " state" << signal_name(s) << " : entity work.dff\n"; + o << " port map(CLOCK => CLOCK,\n"; + o << " input => " << signal_name(*s.state()) << ",\n"; + o << " output => " << signal_name(s) << ");\n\n"; + + } else if (s.op() == Or || s.op() == And || s.op() == Prop || s.op() == NProp){ + o << " process"; + sensitives(o,s,array); + o << "\n"; + o << " begin\n"; + signal_func(o,s,array); + o << " end process;\n\n"; + + } else { + /* ERROR */ + ASSERT(false); + } + } + + std::ostream& o; + bool array; + }; + + std::ostream& create_header(std::ostream& o) + { + o << "use work.general.all;\n"; + o << "library IEEE;\n"; + o << "use IEEE.STD_LOGIC_1164.ALL;\n"; + o << "use IEEE.numeric_std.all;\n"; + return o; + } + + std::string in_port_decl(const prop_t& p) + { + return " " + input_port_name(p) + " : in STD_LOGIC"; + } + + /* ********************************************************************** */ + /* st - suffic transducer */ + + std::ostream& create_stoc_entity(std::ostream& o, + std::size_t prop_count, + const out_ports_field_t& out_ports, + const std::string& name) + { + o << "entity " << name << " is\n"; + o << " Port (\n"; + + // input ports + for (std::size_t i = 0; i < prop_count; ++i) { + o << "input" << i << " : in unsigned(hor_range);\n"; + } + + // output ports + std::size_t subf_count = out_ports.size(); + for(std::size_t i = 0; i < subf_count; ++i) + { + o << "output" << i << " : out unsigned(hor_range)"; + if (i < subf_count - 1) o << ";\n"; + } + + o << "\n );\n"; + o << "end " << name << ";\n\n"; + return o; + } + + std::ostream& create_stoc_architecture(std::ostream& o, + const out_ports_field_t& out_ports, + const std::string& name) + { + o << "architecture Behavioral of " << name << " is\n"; + + signal_decl_dfs(o).run(opf_it::begin(out_ports),opf_it::end(out_ports)); + + o << "\nbegin\n\n"; + + build_logic_dfs(o).run(opf_it::begin(out_ports),opf_it::end(out_ports)); + + o << "\n"; + + // FIXME to complicated: it suffices to know the sizes! + std::size_t i = 0; + foreach(const out_ports_t& l, out_ports) { + std::size_t j = 0; + foreach(const expr_t& x, l) { + o << " " << output_port_name(i,j) << " <= " << signal_name(x) << ";\n"; + ++j; + } + ++i; + } + + o << "\nend Behavioral;\n"; + return o; + } + + /* Suffix Transducer: + * + * use work.general.all; + * library IEEE; + * use IEEE.STD_LOGIC_1164.ALL; + * use IEEE.numeric_std.all; + * + * entity suffix_transducer is + * Port( CLOCK : in STD_LOGIC; + * input : in unsigned(prop_range); -- props from 0 to prop_count-1 + * output0: out unsigned(hor_range); -- for subf 0 and each pos + * output1: out unsigned(hor_range) + * ...); + * end suffix_transducer; + * + * architecture Behavioral of suffix_transducer is + * signal s0 : unsigned(hor_range); -- connects prop0 pipline with trans + * ... + * + * begin + * pipe0 : entity work.pipeline + * portmap(CLOCK => CLOCK; + * input => input(0), + * output => s0); + * ... + * + * trans : stoc + * portmap(input0 => s0, + * input1 => s1, + * ... + * output0 => output0 + * output1 => output1 + * ...); + * end Behavioral; + * + */ + std::ostream& st(std::ostream& o, std::size_t prop_count, std::size_t subf_count) + { + o << "use work.general.all;\n"; + o << "library IEEE;\n"; + o << "use IEEE.STD_LOGIC_1164.ALL;\n"; + o << "use IEEE.numeric_std.all;\n"; + + o << "\n"; + + o << "entity suffix_transducer is\n"; + o << " Port( CLOCK : in STD_LOGIC;\n"; + o << " input : in unsigned(prop_range);\n"; + + for (std::size_t i = 0; i < subf_count; ++i) { + o << " output" << i << " : out unsigned(hor_range)"; + if (i < subf_count -1) o << ";\n"; + else o << ");\n"; + } + + o << "end suffix_transducer;\n"; + + o << "\n"; + + o << "architecture Behavioral of suffix_transducer is\n"; + + for (std::size_t i = 0; i < prop_count; ++i) { + o << " signal s" << i << " : unsigned(hor_range); -- connects prop0 pipline with trans\n"; + } + + o << "\n"; + + o << "begin\n"; + + + for (std::size_t i = 0; i < prop_count; ++i) { + o << " pipe" << i << " : entity work.pipeline\n"; + o << " generic map(LENGTH => hor)\n"; + o << " port map(CLOCK => CLOCK,\n"; + o << " input => input(" << i << "),\n"; + o << " output => s" << i << ");\n"; + } + + o << "\n"; + + o << " trans : entity work.stoc \n"; + o << " port map(\n"; + + for (std::size_t i = 0; i < prop_count; ++i) { + o << " input" << i << " => s" << i <<",\n"; + } + + for (std::size_t i = 0; i < subf_count; ++i) { + o << " output" << i << " => output" << i; + if (i < subf_count -1) o << ",\n"; + else o << ");\n"; + } + + o << " end Behavioral;\n"; + + o << "\n"; + + return o; + + } + + /* ********************************************************************** */ + /* general declarations */ + + /* library IEEE; + * use IEEE.STD_LOGIC_1164.ALL; + * use IEEE.numeric_std.all; + * + * package general is + * + * constant prop_count : natural := XXX; + * constant hor : natural := XXX; + * constant subf_count : natural := XXX; + * + * subtype prop_range is natural range 0 to prop_count - 1; + * subtype subf_range is natural range 0 to subf_count - 1; + * subtype ptsm_range is natural range 0 to subf_count; + * subtype hor_range is natural range 0 to hor; + * + * subtype prop_array is unsigned(0 to (prop_count - 1)); + * + * end package general; + */ + + std::ostream& general(std::ostream& o, + std::size_t prop_count, + std::size_t horizon, + std::size_t subf_count) + { + o << "library IEEE;\n"; + o << "use IEEE.STD_LOGIC_1164.ALL;\n"; + o << "use IEEE.numeric_std.all;\n"; + + o << "package general is\n\n"; + + o << " constant prop_count : natural := " << prop_count << ";\n"; + o << " constant hor : natural := " << horizon << ";\n"; + o << " constant subf_count : natural := " << subf_count << ";\n\n"; + + o << " subtype prop_range is natural range 0 to prop_count - 1;\n"; + o << " subtype subf_range is natural range 0 to subf_count - 1;\n"; + o << " subtype ptsm_range is natural range 0 to subf_count;\n"; + o << " subtype hor_range is natural range 0 to hor;\n\n"; + + o << " subtype prop_array is unsigned(0 to (prop_count - 1));\n\n"; + + o << "end package general;\n\n"; + return o; + } + + /* ********************************************************************** */ + /* ptoc */ + + template + std::ostream& ptoc_entity(std::ostream& o, + std::size_t horizon, + std::size_t subf_count, + const T& ptsm_states) + { + const std::string name = "ptoc"; + o << "entity " << name << " is\n"; + o << " Port (\n"; + + foreach (long state_id, ptsm_states) { + o << " input" << state_id << " : in STD_LOGIC;\n"; + } + + for (std::size_t i = 0; i < subf_count; ++i) { + o << " input" << i << " : in unsigned(hor_range);\n"; + } + + o << " output : out STD_LOGIC"; + o << "\n );\n"; + o << "end " << name << ";\n\n"; + return o; + } + + std::ostream& ptoc_architecture(std::ostream& o, + const expr_t& out_expr) + { + // TODO connection between ptsm-state and ptoc + // How to connect state to circuit + const std::string name = "ptoc"; + o << "architecture Behavioral of " << name << " is\n"; + signal_decl_dfs(o).run(out_expr); + o << "\nbegin\n\n"; + build_logic_dfs(o).run(out_expr); + o << "\n"; + o << " " << "output" << " <= " << signal_name(out_expr) << ";\n"; + o << "\nend Behavioral;\n"; + return o; + } + + // create prefix transducer output circuit + template + std::ostream& ptoc(std::ostream& o, + std::size_t& horizon, + std::size_t& subf_count, + const T& ptsm_states, + const expr_t& out_expr) + { + create_header(o); + ptoc_entity(o,horizon,subf_count,ptsm_states); + ptoc_architecture(o,out_expr); + } + + /* ********************************************************************** */ + /* ptsm */ + + std::ostream& ptsm_entity(std::ostream& o, const size_t max_state) + { + using namespace boost::lambda; + + const std::string name = "ptsm"; + o << "entity " << name << " is\n"; + o << " Port (CLOCK : in STD_LOGIC;\n"; + o << " input : in unsigned(ptsm_range);\n"; + o << " output: out unsigned(0 to " << max_state << "));\n"; + o << "end " << name << ";\n\n"; + return o; + } + + /* Precondition: psm is universal + */ + std::ostream& ptsm_architecture(std::ostream& o, const state_machine_t& sm) + { + const std::string name = "ptsm"; + + o << "architecture Behavioral of " << name << " is\n"; + + // signal declarations + std::list sexprs; + foreach(const state_t& s, sm.states) { + sexprs.push_back(s->efac()->mkState(s)); + } + signal_decl_dfs(o).run(sexprs.begin(),sexprs.end()); + + o << "\nbegin\n\n"; + + // generate input logic + build_logic_dfs(o,true).run(sexprs.begin(),sexprs.end()); + + // output + size_t i = 0; + foreach(const state_t s, sm.states) { + o << " output(" << i++ << ") <= " << signal_name(s) << ";\n"; + } + + o << "\nend Behavioral;\n"; + return o; + } + + // state machine of prefix transducer + std::ostream& ptsm(std::ostream& o,const state_machine_t& sm, std::size_t horizon) + { + // TODO build counter of bit-width + // long max_bit = long(ceil(log2(h))); + + create_header(o); + ptsm_entity(o,sm.states.size()-1); + ptsm_architecture(o,sm); + return o; + } + + std::ostream& build_counter(std::ostream& o, const std::string& out_sig) + { + o << " countdown : entity work.countdown\n"; + o << " generic map(max => hor)\n"; + o << " port map(CLOCK => CLOCK,\n"; + o << " output => " << out_sig << ");\n\n"; + return o; + } + + // prefix transducer + std::ostream& pt(std::ostream& o, const state_machine_t& sm, std::size_t subf_count) + { + create_header(o); + + o << "\n"; + + o << "entity prefix_transducer is\n"; + o << " Port( CLOCK : in STD_LOGIC;\n"; + + for (std::size_t i = 0; i < subf_count; ++i) { + o << " input" << i << " : in unsigned (hor_range);\n"; + } + + o << " output : out STD_LOGIC"; + + o << "\n );\n"; + o << "end prefix_transducer;\n"; + + o << "\n"; + + o << "architecture Behavioral of prefix_transducer is\n"; + + o << " signal states : unsigned(0 to " << sm.states.size()-1 << ");\n"; + o << " signal counter_out : STD_LOGIC;\n"; + o << " signal ptsm_in : unsigned(ptsm_range);\n"; + + o << "\n"; + + o << "begin\n"; + + // add an instance of counter that triggers the init signal + build_counter(o,"counter_out"); + + // build input for ptsm + std::string x; + for(std::size_t i = 0; i < subf_count; ++i) { + x += "input" + STRCAST(i) + "(0) & "; + } + x += " counter_out"; + o << "ptsm_in <= " << x << ";\n\n"; + + // ptsm + o << "ptsm : entity work.ptsm\n"; + o << " port map(CLOCK => CLOCK,\n"; + o << " input => ptsm_in,\n"; + o << " output => states);\n"; + + o << "\n"; + + // ptoc + o << " ptoc : entity work.ptoc \n"; + o << " port map(\n"; + + std::size_t i = 0; + foreach (const state_t& s, sm.states) { + o << " input" << (long) sm.smap.find(s.uid())->second << " => states(" << i++ << "),\n"; + } + + i = 0; + for (;i < subf_count-1; ++i) { + o << " input" << i << " => input" << i << ",\n"; } + o << " input" << i << " => input" << subf_count-1 << ",\n"; + o << " output => output);\n"; + + o << " end Behavioral;\n"; + + o << "\n"; + + return o; + } + + template + struct ptsm_states_dfs : public dfs + { + ptsm_states_dfs(std::back_insert_iterator out) : out(out) {} + std::back_insert_iterator out; + + void state_hook(const expr_t& e) + { + out = signal(e.state()); + } + }; + + template + ptsm_states_dfs mk_ptsm_states_dfs(std::back_insert_iterator x) { return ptsm_states_dfs(x); } + + // monitor + std::ostream& m(std::ostream& o, std::size_t subf_count) + { + create_header(o); + + o << "\n"; + + // entity + o << "entity monitor is\n"; + o << " Port(CLOCK : in STD_LOGIC;\n"; + o << " input : in unsigned(prop_range);\n"; + o << " output : out STD_LOGIC);\n"; + o << "end monitor;\n"; + + o << "\n"; + + // architecture + o << "architecture Behavioral of monitor is\n"; + + // signals + for(std::size_t i = 0; i < subf_count; ++i) { + o << " signal signal" << i << " : unsigned(hor_range);\n"; + } + o << " signal o : STD_LOGIC;\n"; + + o << "\n"; + + o << "begin\n"; + + // suffix_transducer + o << "suffix_transducer : entity work.suffix_transducer\n"; + o << " port map(CLOCK => CLOCK,\n"; + for(std::size_t i = 0; i < subf_count; ++i) { + o << " output" << i << " => signal" << i << ",\n"; + } + o << " input => input);\n"; + + o << "\n"; + + // prefix_transducer + o << " prefix_transducer: entity work.prefix_transducer \n"; + o << " port map(CLOCK => CLOCK,\n"; + for(std::size_t i = 0; i < subf_count; ++i) { + o << " input" << i << " => signal" << i << ",\n"; + } + o << " output => o);\n"; + + // throw output through a d-fip-flop + o << " outdff: entity work.dff \n"; + o << " port map(CLOCK => CLOCK,\n"; + o << " input => o,\n"; + o << " output => output);\n"; + + o << " end Behavioral;\n"; + + o << "\n"; + + return o; + } +}; + +namespace vhdl { + std::ostream& monitor(std::ostream& o, + std::size_t horizon, + std::size_t prop_count, + std::size_t subf_count, + const expr_t& global_out_expr, + const automaton_t& prefix_automaton, + const out_ports_field_t& out_ports) +{ + std::string stoc_name = "stoc"; + + // general header + general(o,prop_count,horizon,subf_count); + + o << "-- ----------------------------------------------------------------- --\n"; + + // output circuit of suffix_transducer + create_header(o); + create_stoc_entity(o,prop_count,out_ports,stoc_name); + create_stoc_architecture(o,out_ports,stoc_name); + + o << "-- ----------------------------------------------------------------- --\n"; + + // suffix transducer + st(o,prop_count,subf_count); + + o << "-- ----------------------------------------------------------------- --\n"; + + // get states of universal prefix automaton + std::list ptsm_states; + mk_ptsm_states_dfs(std::back_inserter(ptsm_states)).run(prefix_automaton.init->efac()->mkState(prefix_automaton.init)); + + // output circuit of prefix transducer + ptoc(o,horizon,subf_count,ptsm_states,global_out_expr); + + o << "-- ----------------------------------------------------------------- --\n"; + + // get state machine + state_machine_t sm(prefix_automaton); + // add init_signal ?? + prop_t p; + p.push_back(subf_count); + expr_t init_signal = sm.init->efac()->mkProp(p); + sm.init.set_suc(* sm.init || init_signal); + + // state machine of prefix transducer + ptsm(o,sm,horizon); + + o << "-- ----------------------------------------------------------------- --\n"; + + // prefix transducer + pt(o,sm,subf_count); + + o << "-- ----------------------------------------------------------------- --\n"; + + // monitor + m(o,subf_count); + + return o; +} +}; + diff --git a/libaaut/vhdl.hh b/libaaut/vhdl.hh new file mode 100644 index 0000000..0e20ba3 --- /dev/null +++ b/libaaut/vhdl.hh @@ -0,0 +1,138 @@ +/* *** MOCS-COPYRIGHT-NOTICE-BEGIN *** + * + * This copyright notice is auto-generated by ./add-copyright-notice. + * Additional copyright notices must be added below the last line of this notice. + * + * MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "libaaut/vhdl.hh". + * The content of this file is copyright of Saarland University - + * Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . + * + * This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). + * + * License: three-clause BSD style license. + * The license text can be found in the file LICENSE. + * + * *** MOCS-COPYRIGHT-NOTICE-END *** */ + +#ifndef _VHDL_HH_ +#define _VHDL_HH_ + +#include "config.h" + +#include +#include +#include + +#include "util.hh" +#include "expr.hh" +#include "aa.hh" + +// make string concatenation work in boost::lambda +namespace boost { + namespace lambda { + + template<> + struct plain_return_type_2, std::string, std::string> { + typedef std::string type; + }; + } +} +#define LSTR(x) bind(constructor(),x) +#define LSTRCAST(x,y) bind(&boost::lexical_cast,_1) + + +/* +-- Description: Output-Circuit for the suffix transducer (over the input pipline) +-- The pipline positions are variables of the form p_at_

, where +-- is the variable number and

the position in the pipline. +-- Position 0 in the pipeline is the current input. Positions 1 .. h +-- are the inputs from 1 .. h steps ago. +-- s0 to s are the bounded formulas. s0_at_

is the corresponding +-- output of the suffix circuit. +-- +-- Dependencies: +-- +-- Revision: +-- Revision 0.01 - File Created +-- Additional Comments: +-- +---------------------------------------------------------------------------------- +library IEEE; +use IEEE.STD_LOGIC_1164.ALL; +use IEEE.STD_LOGIC_ARITH.ALL; +use IEEE.STD_LOGIC_UNSIGNED.ALL; + +---- Uncomment the following library declaration if instantiating +---- any Xilinx primitives in this code. +--library UNISIM; +--use UNISIM.VComponents.all; + +entity suffix_out is + Port ( p0_at_0 : in STD_LOGIC; + p1_at_0 : in STD_LOGIC; + ... + pn_at_h : in STD_LOGIC; + + s0_at_0 : out STD_LOGIC; + s1_at_0 : out STD_LOGIC; + ... + sm_at_h : out STD_LOGIC; + ); +end suffix_out; + +architecture Behavioral of suffix_out is + {for each link (s.id,tid):} + signal _TO_ : STD_LOGIC; + +begin + + process(CLOCK) + begin + {for each prop node (v,i):} + <= pv_at_i; + + {for each nprop node (v,i):} + <= not pv_at_i; + + {for each and/or node:} + <= and/or ; + end process; + {for each out_port of formula j at i:} + sj_at_i <= ; + +end Behavioral; +*/ + +RUNTIME_ERROR(expr_type_error); + +namespace vhdl +{ + typedef std::list out_ports_t; + typedef std::list out_ports_field_t; + + /* - std::ostream o + * - std::string name + * - std::list > out_ports -> for each formula a list of expr for position + */ +}; + +#if 0 +std::ostream& suffix_transducer(std::ostream& o, + std::size_t horizon, + std::size_t prop_count, + std::size_t subf_count, + const vhdl::out_ports_field_t& out_ports); + +#endif + +namespace vhdl { + std::ostream& monitor(std::ostream& o, + std::size_t horizon, // the horizon + std::size_t prop_count, // number of propositions + std::size_t subf_count, // number suffix-subformulas + const expr_t& global_out_expr, // output expr of the prefix state machine + const automaton_t& prefix_state_machine, // prefix state machine + const out_ports_field_t& out_ports); // field of output expressions from the suffix expr +}; + +#endif // _VHDL_HH_ diff --git a/test/Makefile b/test/Makefile new file mode 100644 index 0000000..eb50b69 --- /dev/null +++ b/test/Makefile @@ -0,0 +1,27 @@ +# *** MOCS-COPYRIGHT-NOTICE-BEGIN *** +# +# This copyright notice is auto-generated by ./add-copyright-notice. +# Additional copyright notices must be added below the last line of this notice. +# +# MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "test/Makefile". +# The content of this file is copyright of Saarland University - +# Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . +# +# This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). +# +# License: three-clause BSD style license. +# The license text can be found in the file LICENSE. +# +# *** MOCS-COPYRIGHT-NOTICE-END *** + +ROOT=.. + +include $(ROOT)/Makefile.pre + +CBINTARGETS=ctest +CCBINTARGETS=auttest exprtest +HSTARGETS=Rollout RolloutStat SuffixRolloutStat + +MODULEDEPS=libaaut c-bindings haskell-bindings + +include $(ROOT)/Makefile.post diff --git a/test/Rollout.hs b/test/Rollout.hs new file mode 100644 index 0000000..e1e50ad --- /dev/null +++ b/test/Rollout.hs @@ -0,0 +1,59 @@ +{- *** MOCS-COPYRIGHT-NOTICE-BEGIN *** + - + - This copyright notice is auto-generated by ./add-copyright-notice. + - Additional copyright notices must be added below the last line of this notice. + - + - MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "test/Rollout.hs". + - The content of this file is copyright of Saarland University - + - Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . + - + - This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). + - + - License: three-clause BSD style license. + - The license text can be found in the file LICENSE. + - + - *** MOCS-COPYRIGHT-NOTICE-END *** -} + +-- plot: echo "plot 'data.gplot'" | gnuplot -persist +module Main where + +import Control.Monad + +import Data.List +-- import qualified Data.Map as M + +import IO + +import PSL +import ToString +import T2Automaton + +import CExpr +import CAut + +main = do + + -- Parse Formula + s <- getLine + f <- either (error . show) (return) (parsePSL s) + -- putStrLn $ toString f + + -- Get steps + i <- read `liftM` getLine + + -- Automaton + (ctx,_,a) <- createAut f + -- putStrLn $ "automaton:" + -- putStrLn $ toString $ ptable + + autToDot "aut" a "automaton" + sctx <- contextSize ctx + putStrLn $ "size of context: " ++ (show sctx) + + e <- autPrefixRollout (fromInteger i) a + exprToDot "rollout" e ("rollout of " ++ toString f) + se <- getExprCtx e >>= contextSize + putStrLn $ "size of rollout context: " ++ (show se) + es <- exprSize e + putStrLn $ "size of expr: " ++ (show es) + diff --git a/test/RolloutStat.hs b/test/RolloutStat.hs new file mode 100644 index 0000000..da50e1c --- /dev/null +++ b/test/RolloutStat.hs @@ -0,0 +1,60 @@ +{- *** MOCS-COPYRIGHT-NOTICE-BEGIN *** + - + - This copyright notice is auto-generated by ./add-copyright-notice. + - Additional copyright notices must be added below the last line of this notice. + - + - MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "test/RolloutStat.hs". + - The content of this file is copyright of Saarland University - + - Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . + - + - This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). + - + - License: three-clause BSD style license. + - The license text can be found in the file LICENSE. + - + - *** MOCS-COPYRIGHT-NOTICE-END *** -} + +-- plot: echo "plot 'data.gplot'" | gnuplot -persist +module Main where + +import Debug.Trace + +import Control.Monad + +import Data.List +-- import qualified Data.Map as M + +import IO + +import PSL +import T2Automaton + +import CExpr +import CAut + +main = do + + -- Parse Formula + s <- getLine + f <- either (error . show) (return) (parsePSL s) + + -- Get steps + i <- read `liftM` getLine + + -- Automaton + (_,_,a) <- createAut f + -- putStrLn $ "automaton:" + -- putStrLn $ toString $ ptable + + autToDot "aut" a "automaton" + -- sctx <- contextSize ctx + -- putStrLn $ "size of context: " ++ (show sctx) + + mapM (rsize a) [0..i] + + where + rsize a x = trace (show x) $ do + e <- autPrefixRollout (fromInteger x) a + se <- exprSize e + putStrLn $ show x ++ " " ++ show se + diff --git a/test/SuffixRolloutStat.hs b/test/SuffixRolloutStat.hs new file mode 100644 index 0000000..8bb1963 --- /dev/null +++ b/test/SuffixRolloutStat.hs @@ -0,0 +1,65 @@ +{- *** MOCS-COPYRIGHT-NOTICE-BEGIN *** + - + - This copyright notice is auto-generated by ./add-copyright-notice. + - Additional copyright notices must be added below the last line of this notice. + - + - MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "test/SuffixRolloutStat.hs". + - The content of this file is copyright of Saarland University - + - Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . + - + - This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). + - + - License: three-clause BSD style license. + - The license text can be found in the file LICENSE. + - + - *** MOCS-COPYRIGHT-NOTICE-END *** -} + +-- plot: echo "plot 'data.gplot'" | gnuplot -persist +module Main where + +import Control.Monad +import Data.List +import IO + +import PSL +import T2Automaton + +import CExpr +import CAut + +main = do + + -- Parse Formula + -- s <- getLine + let i = 150 + -- putStrLn $ toString f + + -- Automaton + -- (ctx,ptable,a) <- createAut f + -- putStrLn $ "automaton:" + -- putStrLn $ toString $ ptable + + --autToDot "aut" a "automaton" + -- sctx <- contextSize ctx + -- putStrLn $ "size of context: " ++ (show sctx) + + l <- mapM rsize [1..i] + mapM (\(x,y) -> putStrLn ((show x) ++ " " ++ (show y))) l + + where + rsize i = do + a <- aut i + el <- autSuffixRollout (fromInteger i) a + se <- getExprCtx (head el) >>= contextSize + --mapM (\x -> getExprCtx x >>= contextSize >>= (putStrLn.show)) el + return (i,se) + + --s i = "(a \\BU " ++ show i ++ " b) \\U (c \\BR " ++ show i ++ " d)" + s i = let j = i `div` 2 in + "(a \\BU " ++ show j ++ " b) \\BU " ++ show j ++ " (((b*);(a[" ++ show j ++ "]);(true*)) \\BR " ++ show j ++ " d)" + + aut i = do + formula <- either (error . show) (return) (parsePSL (s i)) + (_,_,a) <- createAut formula + return a + diff --git a/test/auttest.cc b/test/auttest.cc new file mode 100644 index 0000000..c0281ea --- /dev/null +++ b/test/auttest.cc @@ -0,0 +1,84 @@ +/* *** MOCS-COPYRIGHT-NOTICE-BEGIN *** + * + * This copyright notice is auto-generated by ./add-copyright-notice. + * Additional copyright notices must be added below the last line of this notice. + * + * MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "test/auttest.cc". + * The content of this file is copyright of Saarland University - + * Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . + * + * This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). + * + * License: three-clause BSD style license. + * The license text can be found in the file LICENSE. + * + * *** MOCS-COPYRIGHT-NOTICE-END *** */ + +#include +#include "aa.hh" + +prop_t prop(int i) +{ + return prop_t(1,i); +} + +int main(int argsc, char ** args) +{ + typedef automaton_t A; + efac_ptr c = efac::newEfac(); + + A b0 = prop_aut(c,prop(0)); + A b1 = prop_aut(c,prop(1)); + A b2 = prop_aut(c,prop(2)); + A b3 = prop_aut(c,prop(3)); + A b4 = prop_aut(c,prop(4)); + + std::ofstream f0("x.dot"); + std::ofstream f1("ux.dot"); + + A a5 = ( + * b0); + std::string n = "(F G b0)"; + if (argsc > 1) { + std::string arg(args[1]); + if (arg == "G") { + a5 = *b0; + n = "G(0)"; + } else if ( arg == "F") { + a5 = +b0; + n = "F(0)"; + } else if ( arg == "GF") { + a5 = *+b0; + n = "GF(0)"; + } else if ( arg == "FG") { + a5 = +*b0; + n = "FG(0)"; + } else if ( arg == "p") { + a5 = b0; + n = "0"; + } else if ( arg == "or") { + a5 = b0 || b1; + n = "0 or 1"; + } else if ( arg == "andor") { + a5 = b0 && (b1 || b2); + n = "0 and (1 or 2)"; + } else if ( arg == "orand") { + a5 = b0 || (b1 && b2); + n = "0 or (1 and 2)"; + } else if ( arg == "until") { + a5 = until_aut(b0,b1); + n = "0 until 1"; + } else if ( arg == "untilGF") { + a5 = until_aut( *b0, +b1); + n = "(G 0) until (F 1)"; + } + } + + automaton2dot(f0,a5, n); + + A a6 = universal_aut( a5 ); + automaton2dot(f1,a6, "universal " + n); + + f0.close(); + f1.close(); + return 0; +} diff --git a/test/ctest.c b/test/ctest.c new file mode 100644 index 0000000..60f5fc0 --- /dev/null +++ b/test/ctest.c @@ -0,0 +1,27 @@ +/* *** MOCS-COPYRIGHT-NOTICE-BEGIN *** + * + * This copyright notice is auto-generated by ./add-copyright-notice. + * Additional copyright notices must be added below the last line of this notice. + * + * MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "test/ctest.c". + * The content of this file is copyright of Saarland University - + * Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . + * + * This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). + * + * License: three-clause BSD style license. + * The license text can be found in the file LICENSE. + * + * *** MOCS-COPYRIGHT-NOTICE-END *** */ + +#include "aa.h" + +int main(int argsc, char ** args) +{ + context_ptr c = new_context(); + automaton_ptr a0 = const_aut(c,1); + free_automaton(a0); + free_context(c); + return 0; +} + diff --git a/test/exprtest.cc b/test/exprtest.cc new file mode 100644 index 0000000..3579cff --- /dev/null +++ b/test/exprtest.cc @@ -0,0 +1,79 @@ +/* *** MOCS-COPYRIGHT-NOTICE-BEGIN *** + * + * This copyright notice is auto-generated by ./add-copyright-notice. + * Additional copyright notices must be added below the last line of this notice. + * + * MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "test/exprtest.cc". + * The content of this file is copyright of Saarland University - + * Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . + * + * This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). + * + * License: three-clause BSD style license. + * The license text can be found in the file LICENSE. + * + * *** MOCS-COPYRIGHT-NOTICE-END *** */ + +#include +#include "expr.hh" + +prop_t prop(int i) +{ + return prop_t(1,i); +} + +int main(int argsc, char ** args) +{ + efac_ptr c = efac::newEfac(); + + expr_t p0 = c->mkProp(prop(0)); + expr_t p1 = c->mkProp(prop(1)); + expr_t p2 = c->mkProp(prop(2)); + + std::cerr << "check: " << "3 == " << c->size() << std::endl; + + expr_t p0_ = c->mkProp(prop(0)); + expr_t p1_ = c->mkProp(prop(1)); + expr_t p2_ = c->mkProp(prop(2)); + + //p0.impl()->debug(); + //p0_.impl()->debug(); + + std::cerr << "check: " << "3 == " << c->size() << std::endl; + + expr_t ct = c->mkConst(true); + expr_t cf = c->mkConst(false); + + std::cerr << "check: " << "5 == " << c->size() << std::endl; + + expr_t ct_ = c->mkConst(true); + expr_t cf_ = c->mkConst(false); + + std::cerr << "check: " << "5 == " << c->size() << std::endl; + + expr_t np0 = c->mkNProp(prop(0)); + expr_t np1 = c->mkNProp(prop(1)); + expr_t np2 = c->mkNProp(prop(2)); + + std::cerr << "check: " << "8 == " << c->size() << std::endl; + + expr_t np0_ = c->mkNProp(prop(0)); + expr_t np1_ = c->mkNProp(prop(1)); + expr_t np2_ = c->mkNProp(prop(2)); + + std::cerr << "check: " << "8 == " << c->size() << std::endl; + + expr_t p0_and_p0 = p0 && p0; + + std::cerr << "check: " << "8 == " << c->size() << std::endl; + + expr_t a0 = p0 && p1; + + std::cerr << "check: " << "9 == " << c->size() << std::endl; + + expr_t a1 = p0 && p1 && p2; + + std::cerr << "check: " << "10 == " << c->size() << std::endl; + + return 0; +} diff --git a/test/formulas/f0.psl b/test/formulas/f0.psl new file mode 100644 index 0000000..b4e6800 --- /dev/null +++ b/test/formulas/f0.psl @@ -0,0 +1 @@ +((c*);d)*\BU 20 ((((a*);((b*);c);(((d*);e | (b*);c)*);f)*) | (e*);a)* diff --git a/test/funcs.sh b/test/funcs.sh new file mode 100644 index 0000000..c4f3f35 --- /dev/null +++ b/test/funcs.sh @@ -0,0 +1,18 @@ +# *** MOCS-COPYRIGHT-NOTICE-BEGIN *** +# +# This copyright notice is auto-generated by ./add-copyright-notice. +# Additional copyright notices must be added below the last line of this notice. +# +# MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "test/funcs.sh". +# The content of this file is copyright of Saarland University - +# Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . +# +# This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). +# +# License: three-clause BSD style license. +# The license text can be found in the file LICENSE. +# +# *** MOCS-COPYRIGHT-NOTICE-END *** + +function show { (echo "$@"; echo "2") | ./Rollout && dot -T ps -o aut.ps aut && gv aut.ps; } + diff --git a/vhdl/countdown.vhdl b/vhdl/countdown.vhdl new file mode 100644 index 0000000..7313931 --- /dev/null +++ b/vhdl/countdown.vhdl @@ -0,0 +1,50 @@ +-- *** MOCS-COPYRIGHT-NOTICE-BEGIN *** +-- +-- This copyright notice is auto-generated by ./add-copyright-notice. +-- Additional copyright notices must be added below the last line of this notice. +-- +-- MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "vhdl/countdown.vhdl". +-- The content of this file is copyright of Saarland University - +-- Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . +-- +-- This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). +-- +-- License: three-clause BSD style license. +-- The license text can be found in the file LICENSE. +-- +-- *** MOCS-COPYRIGHT-NOTICE-END *** + +-- Static down-counter based on integer decrement +-- Counts clock ticks +library IEEE; +use IEEE.STD_LOGIC_1164.ALL; + +entity countdown is + generic(max : Integer := 0); + port(CLOCK : in STD_LOGIC; + output : out STD_LOGIC := '1'); +end countdown; + +-- Better provide a structural architecture +architecture Behavioral of countdown is +begin + process(CLOCK) + variable cnt: Integer := max-1; + begin + + if (max > 0) then + if (cnt > -1 and CLOCK'event and CLOCK='1') then + cnt := cnt - 1; + end if; + if (cnt = 0) then output <= '1'; end if; + if (cnt = -1) then output <= '0'; end if; + else + if (CLOCK'event and CLOCK='1') then + cnt := cnt - 1; + end if; + if (cnt = -2) then output <= '1'; end if; + if (cnt < -2) then output <= '0'; end if; + end if; + end process; +end Behavioral; + diff --git a/vhdl/countdown_tb.vhdl b/vhdl/countdown_tb.vhdl new file mode 100644 index 0000000..bc95326 --- /dev/null +++ b/vhdl/countdown_tb.vhdl @@ -0,0 +1,55 @@ +-- *** MOCS-COPYRIGHT-NOTICE-BEGIN *** +-- +-- This copyright notice is auto-generated by ./add-copyright-notice. +-- Additional copyright notices must be added below the last line of this notice. +-- +-- MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "vhdl/countdown_tb.vhdl". +-- The content of this file is copyright of Saarland University - +-- Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . +-- +-- This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). +-- +-- License: three-clause BSD style license. +-- The license text can be found in the file LICENSE. +-- +-- *** MOCS-COPYRIGHT-NOTICE-END *** + +-- ----------------------------------------------------------------------------- +library IEEE; +use IEEE.STD_LOGIC_1164.ALL; +use work.countdown; + +entity countdown_tb is +end countdown_tb; + +architecture Behavioral of countdown_tb is + + constant max : Integer := 5; + signal CLOCK, o : STD_LOGIC; + signal ticks : Integer := 0; -- interal + +begin + process + begin + CLOCK <= '1'; wait for 5 ns; + CLOCK <= '0'; wait for 5 ns; + end process; + + countdown0 : entity work.countdown(Behavioral) + generic map(max => max) + port map(CLOCK,o); + + check0 : process(CLOCK) + begin + if (CLOCK'event and CLOCK='1') then + ticks <= ticks + 1; + end if; + end process; + + check1 : process(CLOCK) + begin + assert (ticks < max-1) xor (o = '1') report "counter failed"; + assert (0 = 1) report "ticks = " & integer'image(ticks) & ", o = " & std_logic'image(o); + end process; +end Behavioral; + diff --git a/vhdl/d.vhdl b/vhdl/d.vhdl new file mode 100644 index 0000000..5912ba2 --- /dev/null +++ b/vhdl/d.vhdl @@ -0,0 +1,39 @@ +-- *** MOCS-COPYRIGHT-NOTICE-BEGIN *** +-- +-- This copyright notice is auto-generated by ./add-copyright-notice. +-- Additional copyright notices must be added below the last line of this notice. +-- +-- MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "vhdl/d.vhdl". +-- The content of this file is copyright of Saarland University - +-- Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . +-- +-- This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). +-- +-- License: three-clause BSD style license. +-- The license text can be found in the file LICENSE. +-- +-- *** MOCS-COPYRIGHT-NOTICE-END *** + +library IEEE; +use IEEE.STD_LOGIC_1164.ALL; + +-- A very simple D-flip-flop (I hope) + +entity dff is + Port (CLOCK : in STD_LOGIC; + input : in STD_LOGIC; + output: out STD_LOGIC := '0'); +end dff; + +architecture Behavioral of dff is + +begin + process (CLOCK) + begin + if (CLOCK'event and CLOCK='1') then + output <= input; + end if; + end process; + +end Behavioral; + diff --git a/vhdl/d_tb.vhdl b/vhdl/d_tb.vhdl new file mode 100644 index 0000000..7ddf0bc --- /dev/null +++ b/vhdl/d_tb.vhdl @@ -0,0 +1,56 @@ +-- *** MOCS-COPYRIGHT-NOTICE-BEGIN *** +-- +-- This copyright notice is auto-generated by ./add-copyright-notice. +-- Additional copyright notices must be added below the last line of this notice. +-- +-- MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "vhdl/d_tb.vhdl". +-- The content of this file is copyright of Saarland University - +-- Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . +-- +-- This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). +-- +-- License: three-clause BSD style license. +-- The license text can be found in the file LICENSE. +-- +-- *** MOCS-COPYRIGHT-NOTICE-END *** + +-- ----------------------------------------------------------------------------- +library IEEE; +use IEEE.STD_LOGIC_1164.ALL; +use work.dff; + +entity dff_tb is +end dff_tb; + +architecture Behavioral of dff_tb is + + signal CLOCK, i, o : STD_LOGIC; + signal t0, t1 : STD_LOGIC; + +begin + + dff0 : entity work.dff(Behavioral) + port map (CLOCK, i, t0); + + dff1 : entity work.dff(Behavioral) + port map (CLOCK, t0, t1); + + dff2 : entity work.dff(Behavioral) + port map (CLOCK, t1, o); + + process + begin + CLOCK <= '1'; wait for 5 ns; + CLOCK <= '0'; wait for 5 ns; + end process; + + process + begin + i <= '0'; wait for 8 ns; + i <= '1'; wait for 11 ns; + i <= '0'; wait for 13 ns; + i <= '1'; wait for 3 ns; + wait; + end process; +end Behavioral; + diff --git a/vhdl/monitor_tb.vhdl b/vhdl/monitor_tb.vhdl new file mode 100644 index 0000000..abee36f --- /dev/null +++ b/vhdl/monitor_tb.vhdl @@ -0,0 +1,70 @@ +-- *** MOCS-COPYRIGHT-NOTICE-BEGIN *** +-- +-- This copyright notice is auto-generated by ./add-copyright-notice. +-- Additional copyright notices must be added below the last line of this notice. +-- +-- MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "vhdl/monitor_tb.vhdl". +-- The content of this file is copyright of Saarland University - +-- Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . +-- +-- This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). +-- +-- License: three-clause BSD style license. +-- The license text can be found in the file LICENSE. +-- +-- *** MOCS-COPYRIGHT-NOTICE-END *** + +-- ----------------------------------------------------------------- -- +use work.general.all; +use work.monitor; +library IEEE; +use IEEE.STD_LOGIC_1164.ALL; +use IEEE.numeric_std.all; + + -- A testbench has no ports. +entity monitor_tb is +end entity monitor_tb; + + architecture behav of monitor_tb is + signal CLOCK, output : STD_LOGIC; + signal p : unsigned(prop_range); + begin + -- Component instantiation. + monitor_0: entity work.monitor(Behavioral) + port map (CLOCK, p, output); + + clk : process + begin + CLOCK <= '0'; wait for 5 ns; + CLOCK <= '1'; wait for 5 ns; + end process; + + stimulus0 : process is + begin + p(0) <= '0'; + wait for 11 ns; p(0) <= '1'; + wait for 9 ns; p(0) <= '0'; + + wait for 33 ns; p(0) <= '1'; + wait for 9 ns; p(0) <= '0'; + + wait for 35 ns; p(0) <= '1'; + wait for 20 ns; p(0) <= '0'; + wait; + end process stimulus0; + + stimulus1 : process is + begin + p(1) <= '0'; + wait for 27 ns; p(1) <= '1'; + wait for 7 ns; p(1) <= '0'; + + --wait for 8 ns; p(1) <= '1'; + --wait for 7 ns; p(1) <= '0'; + + wait for 93 ns; p(1) <= '1'; + wait for 20 ns; p(1) <= '0'; + wait; + end process stimulus1; + end behav; + diff --git a/vhdl/pipeline.vhdl b/vhdl/pipeline.vhdl new file mode 100644 index 0000000..2b6a07c --- /dev/null +++ b/vhdl/pipeline.vhdl @@ -0,0 +1,52 @@ +-- *** MOCS-COPYRIGHT-NOTICE-BEGIN *** +-- +-- This copyright notice is auto-generated by ./add-copyright-notice. +-- Additional copyright notices must be added below the last line of this notice. +-- +-- MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "vhdl/pipeline.vhdl". +-- The content of this file is copyright of Saarland University - +-- Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . +-- +-- This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). +-- +-- License: three-clause BSD style license. +-- The license text can be found in the file LICENSE. +-- +-- *** MOCS-COPYRIGHT-NOTICE-END *** + +-- ----------------------------------------------------------------- -- +-- use work.general.all; +library IEEE; +use IEEE.STD_LOGIC_1164.all; +use IEEE.numeric_std.all; + +-- the pipeline for a single prop +entity pipeline is + generic (LENGTH : integer := 32); + Port (CLOCK : in STD_LOGIC; + input : in STD_LOGIC; + output : out unsigned(LENGTH downto 0)); +end pipeline; + + +architecture Behavioral of pipeline is + + signal tmp : unsigned(LENGTH - 1 downto 0); + +begin + + process (CLOCK) + begin + if (CLOCK'event and CLOCK='1') then + if (LENGTH > 1) then + tmp <= tmp(LENGTH - 2 downto 0) & input; + elsif (LENGTH = 1) then + tmp <= "" & input; + end if; + end if; + end process; + + output <= tmp & input; + +end Behavioral; + diff --git a/vhdl/pipeline_tb.vhdl b/vhdl/pipeline_tb.vhdl new file mode 100644 index 0000000..223a0a3 --- /dev/null +++ b/vhdl/pipeline_tb.vhdl @@ -0,0 +1,53 @@ +-- *** MOCS-COPYRIGHT-NOTICE-BEGIN *** +-- +-- This copyright notice is auto-generated by ./add-copyright-notice. +-- Additional copyright notices must be added below the last line of this notice. +-- +-- MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "vhdl/pipeline_tb.vhdl". +-- The content of this file is copyright of Saarland University - +-- Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . +-- +-- This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). +-- +-- License: three-clause BSD style license. +-- The license text can be found in the file LICENSE. +-- +-- *** MOCS-COPYRIGHT-NOTICE-END *** + +-- ----------------------------------------------------------------- -- +-- use work.general.all; +library IEEE; +use IEEE.STD_LOGIC_1164.all; +use IEEE.numeric_std.all; +use work.pipeline; + +-- the pipeline for a single prop +entity pipeline_tb is +end pipeline_tb; + +architecture Behavioral of pipeline_tb is + signal CLOCK : STD_LOGIC; + signal i : STD_LOGIC; + signal o : unsigned(5 downto 0); + +begin + + pipeline0: entity work.pipeline(Behavioral) + generic map (LENGTH => 5) + port map (CLOCK,i,o); + + clk: process + begin + CLOCK <= '1'; wait for 5 ns; + CLOCK <= '0'; wait for 5 ns; + end process; + + stimulus: process + begin + i <= '0'; wait for 8 ns; + i <= '1'; wait for 11 ns; + i <= '0'; wait for 13 ns; + i <= '1'; wait for 3 ns; + wait; + end process; +end Behavioral; diff --git a/vhdl/ptsm_tb.vhdl b/vhdl/ptsm_tb.vhdl new file mode 100644 index 0000000..9475e5c --- /dev/null +++ b/vhdl/ptsm_tb.vhdl @@ -0,0 +1,60 @@ +-- *** MOCS-COPYRIGHT-NOTICE-BEGIN *** +-- +-- This copyright notice is auto-generated by ./add-copyright-notice. +-- Additional copyright notices must be added below the last line of this notice. +-- +-- MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/): "vhdl/ptsm_tb.vhdl". +-- The content of this file is copyright of Saarland University - +-- Copyright (C) 2009 Saarland University, Reactive Systems Group, Lars Kuhtz . +-- +-- This file is part of MoCS (https://lewis.cs.uni-saarland.de/tools/mocs/). +-- +-- License: three-clause BSD style license. +-- The license text can be found in the file LICENSE. +-- +-- *** MOCS-COPYRIGHT-NOTICE-END *** + +-- ----------------------------------------------------------------- -- +use work.general.all; +use work.ptsm; +library IEEE; +use IEEE.STD_LOGIC_1164.ALL; +use IEEE.numeric_std.all; + + -- A testbench has no ports. +entity ptsm_tb is +end entity ptsm_tb; + + architecture Behavioral of ptsm_tb is + + signal CLOCK, output : STD_LOGIC; + signal i : unsigned(subf_range); + signal f : STD_LOGIC; -- false_state + signal o : STD_LOGIC; -- output (current state) + + begin + + ptsm0: entity work.ptsm(Behavioral) + port map(Clock, i, f, o); + + clk : process + begin + CLOCK <= '0'; wait for 5 ns; + CLOCK <= '1'; wait for 5 ns; + end process; + + -- This process does the real job. + stimulus : process is + begin + -- TODO Loop over subf_range with random values as generic behavior + i(0) <= '0'; wait for 1 ns; + i(0) <= '1'; wait for 23 ns; + i(0) <= '1'; wait for 4 ns; + i(0) <= '0'; wait for 20 ns; + i(0) <= '1'; wait for 10 ns; + i(0) <= '0'; wait for 23 ns; + i(0) <= '1'; wait for 20 ns; + wait; + end process stimulus; + end Behavioral; +