├── .gitignore ├── .lsp └── config.edn ├── README.md ├── project.clj └── src ├── main ├── clojure │ └── discourje │ │ ├── core │ │ ├── async.clj │ │ ├── async │ │ │ ├── buffers.clj │ │ │ ├── channels.clj │ │ │ ├── deadlocks.clj │ │ │ └── monitors.clj │ │ ├── lint.clj │ │ ├── lint │ │ │ ├── benchmarks.clj │ │ │ ├── demonstration.clj │ │ │ ├── job.sh │ │ │ └── jobs.sh │ │ ├── spec.clj │ │ ├── spec │ │ │ ├── ast.clj │ │ │ ├── interp.clj │ │ │ ├── lts.clj │ │ │ └── mcrl2.clj │ │ └── util.clj │ │ └── examples │ │ ├── clojured22 │ │ ├── rps.clj │ │ ├── rps_checked.clj │ │ └── rps_unchecked.clj │ │ ├── config.clj │ │ ├── da │ │ ├── awerbuch.clj │ │ ├── cheung.clj │ │ └── topologies.clj │ │ ├── fm24 │ │ ├── example1_dead.clj │ │ ├── example1_live.clj │ │ ├── example2_dead1.clj │ │ ├── example2_dead2.clj │ │ └── example2_live.clj │ │ ├── games │ │ ├── chess.clj │ │ ├── go_fish.clj │ │ ├── go_fish_types.clj │ │ ├── rock_paper_scissors.clj │ │ └── tic_tac_toe.clj │ │ ├── main.clj │ │ ├── micro │ │ ├── mesh.clj │ │ ├── ring.clj │ │ └── star.clj │ │ ├── npb3 │ │ ├── cg.clj │ │ ├── ft.clj │ │ ├── is.clj │ │ └── mg.clj │ │ └── timer.clj ├── java │ └── discourje │ │ ├── core │ │ ├── AsyncJ.java │ │ ├── SpecJ.java │ │ ├── ctl │ │ │ ├── Channel.java │ │ │ ├── Formula.java │ │ │ ├── Formulas.java │ │ │ ├── Labels.java │ │ │ ├── Model.java │ │ │ ├── ModelChecker.java │ │ │ ├── Rule.java │ │ │ ├── State.java │ │ │ ├── formulas │ │ │ │ ├── And.java │ │ │ │ ├── Atomic.java │ │ │ │ ├── Implies.java │ │ │ │ ├── Not.java │ │ │ │ ├── Or.java │ │ │ │ ├── Temporal.java │ │ │ │ ├── atomic │ │ │ │ │ ├── Act.java │ │ │ │ │ ├── Close.java │ │ │ │ │ ├── Fin.java │ │ │ │ │ ├── Handshake.java │ │ │ │ │ ├── Init.java │ │ │ │ │ ├── Receive.java │ │ │ │ │ ├── Send.java │ │ │ │ │ └── True.java │ │ │ │ └── temporal │ │ │ │ │ ├── AF.java │ │ │ │ │ ├── AG.java │ │ │ │ │ ├── AH.java │ │ │ │ │ ├── AP.java │ │ │ │ │ ├── AS.java │ │ │ │ │ ├── AU.java │ │ │ │ │ ├── AX.java │ │ │ │ │ ├── AY.java │ │ │ │ │ ├── EF.java │ │ │ │ │ ├── EG.java │ │ │ │ │ ├── EH.java │ │ │ │ │ ├── EP.java │ │ │ │ │ ├── ES.java │ │ │ │ │ ├── EU.java │ │ │ │ │ ├── EX.java │ │ │ │ │ └── EY.java │ │ │ ├── package-info.java │ │ │ └── rules │ │ │ │ ├── Causality.java │ │ │ │ ├── CloseChannelsOnlyOnce.java │ │ │ │ ├── ClosedChannelMustBeUsedInPath.java │ │ │ │ ├── ClosedChannelMustBeUsedInProtocol.java │ │ │ │ ├── DoNotSendAfterClose.java │ │ │ │ ├── DoNotSendToSelf.java │ │ │ │ └── UsedChannelsMustBeClosed.java │ │ └── lts │ │ │ ├── Action.java │ │ │ ├── LTS.java │ │ │ ├── LTSs.java │ │ │ ├── State.java │ │ │ ├── States.java │ │ │ └── Transitions.java │ │ └── examples │ │ ├── HelloWorld.java │ │ ├── clbg │ │ ├── Config.java │ │ └── impl │ │ │ ├── mandelbrot.java │ │ │ └── spectralnorm.java │ │ ├── games │ │ └── impl │ │ │ └── chess │ │ │ ├── Engine.java │ │ │ ├── stockfish-linux │ │ │ ├── stockfish-mac │ │ │ ├── stockfish-win32.exe │ │ │ └── stockfish-win64.exe │ │ └── npb3 │ │ ├── Config.java │ │ └── impl │ │ ├── BMInOut │ │ ├── BMArgs.java │ │ └── BMResults.java │ │ ├── BT.java │ │ ├── BTThreads │ │ ├── BTBase.java │ │ ├── RHSAdder.java │ │ ├── RHSCompute.java │ │ ├── XSolver.java │ │ ├── YSolver.java │ │ └── ZSolver.java │ │ ├── CG.java │ │ ├── CGThreads │ │ ├── CGBase.java │ │ ├── CGMessage.java │ │ └── CGWorker.java │ │ ├── DoneMessage.java │ │ ├── ExitMessage.java │ │ ├── FT.java │ │ ├── FTThreads │ │ ├── EvolveMessage.java │ │ ├── EvolveThread.java │ │ ├── FFTMessage.java │ │ ├── FFTSetVariablesMessage.java │ │ ├── FFTThread.java │ │ └── FTBase.java │ │ ├── IS.java │ │ ├── ISThreads │ │ ├── ISBase.java │ │ ├── RankMessage.java │ │ └── RankThread.java │ │ ├── LU.java │ │ ├── LUThreads │ │ ├── Adder.java │ │ ├── LUBase.java │ │ ├── LowerJac.java │ │ ├── RHSCompute.java │ │ ├── Scale.java │ │ └── UpperJac.java │ │ ├── MG.java │ │ ├── MGThreads │ │ ├── Interp.java │ │ ├── InterpMessage.java │ │ ├── MGBase.java │ │ ├── Psinv.java │ │ ├── PsinvMessage.java │ │ ├── Resid.java │ │ ├── ResidMessage.java │ │ ├── Rprj.java │ │ └── RprjMessage.java │ │ ├── Random.java │ │ ├── SP.java │ │ ├── SPThreads │ │ ├── RHSAdder.java │ │ ├── RHSCompute.java │ │ ├── SPBase.java │ │ ├── TXInverse.java │ │ ├── XSolver.java │ │ ├── YSolver.java │ │ └── ZSolver.java │ │ └── Timer.java └── sh │ ├── games-chess.sh │ ├── micro.sh │ └── npb3.sh └── test ├── clojure └── discourje │ ├── core │ ├── async_tests.clj │ ├── ctl │ │ ├── causality.clj │ │ ├── causality_async.clj │ │ ├── close_channels_only_once.clj │ │ ├── close_channels_only_once_async.clj │ │ ├── closed_channel_must_be_used_in_path.clj │ │ ├── closed_channel_must_be_used_in_path_async.clj │ │ ├── closed_channel_must_be_used_in_protocol.clj │ │ ├── closed_channel_must_be_used_in_protocol_async.clj │ │ ├── do_not_send_after_close.clj │ │ ├── do_not_send_after_close_async.clj │ │ ├── do_not_send_to_self.clj │ │ ├── do_not_send_to_self_async.clj │ │ ├── example_applications.clj │ │ ├── performance.clj │ │ ├── used_channels_must_be_closed.clj │ │ ├── used_channels_must_be_closed_async.clj │ │ └── validation_tests.clj │ └── spec_tests.clj │ └── examples │ ├── lint_tests.clj │ └── run_tests.clj └── java └── discourje └── core └── ctl ├── AbstractModelCheckerTest.java ├── ExampleApplicationsTest.java ├── ModelCheckerAsyncTest.java ├── ModelCheckerPerformanceTest.java ├── ModelCheckerTest.java ├── ModelTest.java └── formulas ├── AFTest.java ├── AGTest.java ├── AHTest.java ├── APTest.java ├── ASTest.java ├── AUTest.java ├── AXTest.java ├── AYTest.java ├── AbstractCtlFormulaTest.java ├── AndTest.java ├── CloseTest.java ├── EFTest.java ├── EGTest.java ├── EHTest.java ├── EPTest.java ├── ESTest.java ├── EUTest.java ├── EXTest.java ├── EYTest.java ├── ImpliesTest.java ├── InitTest.java ├── NotTest.java ├── OrTest.java ├── ReceiveTest.java ├── SendTest.java └── TrueTest.java /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | .nrepl-port 3 | **/.DS_Store 4 | .clj-kondo/.cache 5 | .lsp/.cache 6 | .lock 7 | .calva 8 | .lein-failures 9 | .lein-repl-history 10 | -------------------------------------------------------------------------------- /.lsp/config.edn: -------------------------------------------------------------------------------- 1 | {:linters {:clj-kondo {:level :off} 2 | :clj-depend {:level :off}}} -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Discourje 2 | 3 | The Discourje project aims to help programmers cope with channels and concurrency bugs in Clojure programs (that use `core.async`), based on dynamic analysis. The idea is that programmers write not only implementations of communication protocols in their Clojure programs, but also specifications. Discourje then offers a run-time verification library to ensure that channel actions in implementations are safe relative to specifications. 4 | 5 | ## Resources 6 | 7 | Suggested resources to get an overview of Discourje: talk 2 and/or paper 2. 8 | 9 | ### Talks 10 | 11 | 1. Sung-Shik Jongmans. **Automated Correctness Analysis for core.async.** Dutch Clojure Days (DCD), 2022. [[link](https://www.youtube.com/watch?v=AB0rLLVej6U)] 12 | 13 | 2. Sung-Shik Jongmans. **Automated Correctness Analysis for core.async.** Clojure conference in Germany (:clojureD), 2022. [[link](https://www.youtube.com/watch?v=uIcf0rAu5QQ)] 14 | 15 | 3. Sung-Shik Jongmans. **dcj-lint: Analysis of Specifications of Multiparty Sessions.** ACM Joint European Software Engineering Conference and Symposium on the Foundations of Software Engineering (ESEC/FSE), 2021. [[link](https://www.youtube.com/watch?v=f1MgTrxLKeI)] 16 | 17 | 4. Sung-Shik Jongmans. **Discourje: Runtime Verification of Communication Protocols in Clojure.** International Conference on Tools and Algorithms for the Construction and Analysis of Systems (TACAS), 2020. [[link](https://www.morressier.com/o/event/6048becc82fa0a0019cb3048/article/604907f51a80aac83ca25d9e)] 18 | 19 | 5. Ruben Hamers. **Discourje: Automatically validated message exchange patterns in Clojure.** Dutch Clojure Day (DCD), 2019. [[link](https://www.youtube.com/watch?v=Vf6lfrX5caw)] 20 | 21 | ### Papers 22 | 23 | 1. Sung-Shik Jongmans. **Discourje: Run-Time Verification of Communication Protocols in Clojure - Live at Last**. Proceedings of FM'24. [[link](https://doi.org/10.1007/978-3-031-71177-0_11), [pdf](https://sungshik.github.io/papers/fm2024.pdf)] 24 | 25 | 2. Ruben Hamers, Erik Horlings, and Sung-Shik Jongmans. **The Discourje Project: Run-Time Verification of Communication Protocols in Clojure**. International Journal on Software Tools for Technology Transfer, 2022. [[link](https://doi.org/10.1007/s10009-022-00674-y), [pdf](https://sungshik.github.io/papers/sttt24.pdf)] 26 | 27 | 3. Erik Horlings and Sung-Shik Jongmans. **dcj-lint: Analysis of Specifications of Multiparty Sessions.** Proceedings of ESEC/FSE'21. [[link](https://doi.org/10.1145/3468264.3473127), [pdf](https://sungshik.github.io/papers/esecfse2021.pdf)] 28 | 29 | 4. Ruben Hamers and Sung-Shik Jongmans. **Discourje: Runtime Verification of Communication Protocols in Clojure.** Proceedings of TACAS'20. [[link](https://doi.org/10.1007/978-3-030-45190-5_15), [pdf](https://sungshik.github.io/papers/tacas2020.pdf)] 30 | 31 | ## Contributors 32 | 33 | - Ruben Hamers 34 | - Erik Horlings 35 | - Sung-Shik Jongmans 36 | -------------------------------------------------------------------------------- /project.clj: -------------------------------------------------------------------------------- 1 | (defproject discourje "2.0.0" 2 | :description "The Discourje project aims to help programmers cope with channels and 3 | concurrency bugs in Clojure programs, based on dynamic analysis. The idea is 4 | that programmers write not only implementations of communication protocols in 5 | their Clojure programs, but also specifications. Discourje then offers a 6 | run-time verification library to ensure that channel actions in implementations 7 | are safe relative to specifications." 8 | 9 | :url "https://github.com/discourje" 10 | :dependencies [[org.clojure/clojure "1.11.0"] 11 | [org.clojure/core.async "0.4.500"] 12 | [org.clojure/tools.nrepl "0.2.13"]] 13 | :source-paths ["src/main/clojure"] 14 | :test-paths ["src/test/clojure" "src/test/java"] 15 | :java-source-paths ["src/main/java"] 16 | :main discourje.examples.main 17 | :profiles {:examples {:main discourje.examples.main 18 | :aot [discourje.core.async 19 | discourje.core.spec 20 | discourje.examples.main] 21 | :uberjar-name "discourje-examples.jar"} 22 | :dev {:dependencies [[org.junit.jupiter/junit-jupiter "5.7.0"] 23 | [org.mockito/mockito-all "1.10.19"]]}}) 24 | 25 | ;; $ lein with-profile examples uberjar 26 | -------------------------------------------------------------------------------- /src/main/clojure/discourje/core/async/buffers.clj: -------------------------------------------------------------------------------- 1 | (ns discourje.core.async.buffers 2 | (:refer-clojure :exclude [type])) 3 | 4 | (deftype Buffer [type n]) 5 | 6 | (defn buffer? [x] 7 | (= (clojure.core/type x) Buffer)) 8 | 9 | (defn fixed-buffer [n] 10 | {:pre [(> n 0)]} 11 | (->Buffer :fixed-buffer n)) 12 | 13 | (defn dropping-buffer [n] 14 | {:pre [(> n 0)]} 15 | (->Buffer :dropping-buffer n)) 16 | 17 | (defn sliding-buffer [n] 18 | {:pre [(> n 0)]} 19 | (->Buffer :sliding-buffer n)) 20 | 21 | ;(defn promise-buffer [] 22 | ; {:pre [true]} 23 | ; (->Buffer :promise-buffer 0)) 24 | 25 | (defn n [buffer] 26 | {:pre [(buffer? buffer)]} 27 | (.-n buffer)) 28 | 29 | (defn type [buffer] 30 | {:pre [(buffer? buffer)]} 31 | (.-type buffer)) 32 | 33 | ;(defn unblocking-buffer? [buffer] 34 | ; {:pre [(buffer? buffer)]} 35 | ; (contains? #{:dropping-buffer :sliding-buffer :promise-buffer} (.-type buffer))) -------------------------------------------------------------------------------- /src/main/clojure/discourje/core/async/monitors.clj: -------------------------------------------------------------------------------- 1 | (ns discourje.core.async.monitors 2 | (:require [discourje.core.spec.lts :as lts])) 3 | 4 | (deftype Monitor [lts current-states flag]) 5 | 6 | (defn monitor 7 | [lts] 8 | {:pre [(lts/lts? lts)]} 9 | (->Monitor lts 10 | (atom (lts/initial-states lts)) 11 | (atom false))) 12 | 13 | (defn monitor? 14 | [x] 15 | (= (type x) Monitor)) 16 | 17 | (defn str-lts 18 | [monitor] 19 | {:pre [(monitor? monitor)]} 20 | (str (.-lts monitor))) 21 | 22 | (defn str-current-states 23 | [monitor] 24 | {:pre [(monitor? monitor)]} 25 | (let [s (str @(.-current_states monitor))] 26 | (subs s 1 (dec (count s))))) 27 | 28 | (defn- runtime-exception [lts current-states type message sender receiver] 29 | (ex-info (str "[SESSION FAILURE] Action " 30 | (case type :sync "‽" :send "!" :receive "?" :close "C" (throw (Exception.))) 31 | "(" 32 | (if (nil? message) "" (str message ",")) 33 | sender 34 | "," 35 | receiver 36 | ") is not enabled in current state(s): " 37 | current-states 38 | ". LTS in Aldebaran format:\n\n" 39 | lts 40 | "\n\n") 41 | {;:lts lts 42 | ;:current-states current-states 43 | :type type 44 | :message message 45 | :sender sender 46 | :receiver receiver})) 47 | 48 | (defn verify! 49 | [monitor type message sender receiver] 50 | {:pre [(or (monitor? monitor) (nil? monitor))]} 51 | (if (nil? monitor) 52 | true 53 | (loop [] 54 | (let [source-states @(.-current_states monitor) 55 | target-states (lts/expand-then-perform! source-states 56 | type 57 | message 58 | sender 59 | receiver)] 60 | 61 | (if (compare-and-set! (.-flag monitor) false true) 62 | (if (compare-and-set! (.-current_states monitor) source-states target-states) 63 | (if (empty? target-states) 64 | (runtime-exception (.-lts monitor) source-states type message sender receiver) 65 | true) 66 | (do 67 | (reset! (.-flag monitor) false) 68 | (recur))) 69 | (recur)))))) 70 | 71 | (defn lower-flag! 72 | [monitor] 73 | {:pre [(or (monitor? monitor) (nil? monitor))]} 74 | (if (nil? monitor) 75 | nil 76 | (do (reset! (.-flag monitor) false) 77 | nil))) -------------------------------------------------------------------------------- /src/main/clojure/discourje/core/lint/benchmarks.clj: -------------------------------------------------------------------------------- 1 | (ns discourje.core.lint.benchmarks 2 | (:gen-class) 3 | (:require [clojure.test :refer :all] 4 | [clojure.pprint :refer :all] 5 | [discourje.core.spec :as s] 6 | [discourje.core.lint :as c] 7 | [discourje.core.spec.lts :as lts] 8 | [discourje.core.spec.mcrl2 :as mcrl2])) 9 | 10 | (defn -main [& args] 11 | (let [input (read-string (clojure.string/join " " args)) 12 | algorithm (:algorithm input) 13 | initiator (:initiator input) 14 | network ((eval (read-string (str "discourje.core.lint.benchmarks/" (name (:network input))))) (:n input)) 15 | spec (s/session algorithm [initiator network]) 16 | 17 | begin-lts (System/nanoTime) 18 | lts (lts/lts spec) 19 | end-lts (System/nanoTime) 20 | time-lts (long (/ (- end-lts begin-lts) 1000000)) 21 | 22 | begin-lint (System/nanoTime) 23 | results (binding [mcrl2/*mcrl2-bin* (str (:mcrl2-bin input)) 24 | mcrl2/*mcrl2-tmp* (str (:mcrl2-tmp input))] 25 | (c/lint lts 26 | :engine (:engine input) 27 | :witness false 28 | :exclude #{:send-before-close :causality})) 29 | end-lint (System/nanoTime) 30 | time-lint (long (/ (- end-lint begin-lint) 1000000)) 31 | 32 | output (clojure.string/join " " [(:engine input) 33 | (:algorithm input) 34 | (:initiator input) 35 | (:network input) 36 | (:n input) 37 | (let [s (str lts) 38 | [_ transitions states] (.split (.substring 39 | s 40 | (inc (.indexOf s "(")) 41 | (.indexOf s ")")) ",")] 42 | (str "(" states "," transitions ")")) 43 | time-lts 44 | time-lint])] 45 | (.println System/out results) 46 | (.println System/err output) 47 | (if (nil? (:no-exit input)) 48 | (System/exit 0)))) 49 | 50 | (deftest -main-test 51 | (let [input {:engine :dcj, 52 | :mcrl2-bin "/Applications/mCRL2.app/Contents/bin", 53 | :mcrl2-tmp "/Users/sungshik/Desktop/tmp", 54 | :algorithm :awerbuch, 55 | :initiator 0, 56 | :network :ring, 57 | :n 4 58 | :no-exit true} 59 | args (clojure.string/split (str input) #" ")] 60 | (apply -main args))) -------------------------------------------------------------------------------- /src/main/clojure/discourje/core/lint/job.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | #SBATCH -N 1 3 | #SBATCH -p normal 4 | #SBATCH -o results/out.%A 5 | #SBATCH -e results/err.%A 6 | #SBATCH -t 12:00:00 7 | 8 | JAVA=/home/ssj/jdk-16.0.1/bin/java 9 | JAR=/home/ssj/fse2021.jar 10 | 11 | MCRL2_BIN=/home/ssj/mcrl2/build/stage/bin 12 | MCRL2_TMP=/home/ssj/tmp 13 | MCRL2_TMP=$(mktemp -d) 14 | 15 | ENGINE=$1 # :dcj, :mcrl2, or :mcrl2-split 16 | ALGORITHM=$2 # :cheung or :awerbuch 17 | NETWORK=$3 # :ring 18 | 19 | PROCS=$4 20 | ITERS=$5 21 | 22 | module load 2020 23 | module load GCC/9.3.0 24 | 25 | echo "ENGINE=$1, ALGORITHM=$2, NETWORK=$3, ITERS=$4" 26 | echo 27 | hostname 28 | echo 29 | cat /proc/cpuinfo 30 | echo 31 | 32 | for N in $(seq 2 1 $PROCS); do 33 | for I in $(seq 1 $ITERS); do 34 | $JAVA -jar $JAR {:mcrl2-bin \"$MCRL2_BIN\", :mcrl2-tmp \"$MCRL2_TMP\", :engine $ENGINE, :algorithm $ALGORITHM, :initiator 0, :network $NETWORK, :n $N} 35 | done 36 | done 37 | -------------------------------------------------------------------------------- /src/main/clojure/discourje/core/lint/jobs.sh: -------------------------------------------------------------------------------- 1 | COMMAND=$1 2 | PROCS=$2 3 | ITERS=$3 4 | 5 | $COMMAND job.sh :dcj :cheung :ring $PROCS $ITERS 6 | $COMMAND job.sh :dcj :cheung :star $PROCS $ITERS 7 | $COMMAND job.sh :dcj :cheung :tree $PROCS $ITERS 8 | $COMMAND job.sh :dcj :cheung :mesh-2d $PROCS $ITERS 9 | $COMMAND job.sh :dcj :cheung :mesh-full $PROCS $ITERS 10 | 11 | $COMMAND job.sh :mcrl2 :cheung :ring $PROCS $ITERS 12 | $COMMAND job.sh :mcrl2 :cheung :star $PROCS $ITERS 13 | $COMMAND job.sh :mcrl2 :cheung :tree $PROCS $ITERS 14 | $COMMAND job.sh :mcrl2 :cheung :mesh-2d $PROCS $ITERS 15 | $COMMAND job.sh :mcrl2 :cheung :mesh-full $PROCS $ITERS 16 | 17 | $COMMAND job.sh :mcrl2-split :cheung :ring $PROCS $ITERS 18 | $COMMAND job.sh :mcrl2-split :cheung :star $PROCS $ITERS 19 | $COMMAND job.sh :mcrl2-split :cheung :tree $PROCS $ITERS 20 | $COMMAND job.sh :mcrl2-split :cheung :mesh-2d $PROCS $ITERS 21 | $COMMAND job.sh :mcrl2-split :cheung :mesh-full $PROCS $ITERS 22 | 23 | $COMMAND job.sh :dcj :awerbuch :ring $PROCS $ITERS 24 | $COMMAND job.sh :dcj :awerbuch :star $PROCS $ITERS 25 | $COMMAND job.sh :dcj :awerbuch :tree $PROCS $ITERS 26 | $COMMAND job.sh :dcj :awerbuch :mesh-2d $PROCS $ITERS 27 | $COMMAND job.sh :dcj :awerbuch :mesh-full $PROCS $ITERS 28 | 29 | $COMMAND job.sh :mcrl2 :awerbuch :ring $PROCS $ITERS 30 | $COMMAND job.sh :mcrl2 :awerbuch :star $PROCS $ITERS 31 | $COMMAND job.sh :mcrl2 :awerbuch :tree $PROCS $ITERS 32 | $COMMAND job.sh :mcrl2 :awerbuch :mesh-2d $PROCS $ITERS 33 | $COMMAND job.sh :mcrl2 :awerbuch :mesh-full $PROCS $ITERS 34 | 35 | $COMMAND job.sh :mcrl2-split :awerbuch :ring $PROCS $ITERS 36 | $COMMAND job.sh :mcrl2-split :awerbuch :star $PROCS $ITERS 37 | $COMMAND job.sh :mcrl2-split :awerbuch :tree $PROCS $ITERS 38 | $COMMAND job.sh :mcrl2-split :awerbuch :mesh-2d $PROCS $ITERS 39 | $COMMAND job.sh :mcrl2-split :awerbuch :mesh-full $PROCS $ITERS 40 | -------------------------------------------------------------------------------- /src/main/clojure/discourje/core/spec/lts.clj: -------------------------------------------------------------------------------- 1 | (ns discourje.core.spec.lts 2 | (:require [clojure.set :refer [union]] 3 | [clojure.java.shell :refer [sh]] 4 | [discourje.core.spec.interp :as interp]) 5 | (:import (java.util.function Function Predicate) 6 | (discourje.core.lts Action Action$Type State States LTS LTSs))) 7 | 8 | ;;;; 9 | ;;;; Actions 10 | ;;;; 11 | 12 | (defn- action-type-keyword-to-enum [keyword] 13 | {:pre [(keyword? keyword)]} 14 | (case keyword 15 | :sync Action$Type/SYNC 16 | :send Action$Type/SEND 17 | :receive Action$Type/RECEIVE 18 | :close Action$Type/CLOSE 19 | (throw (Exception.)))) 20 | 21 | (defn action [interp-action] 22 | {:pre [(interp/action? interp-action)]} 23 | (Action. (:name interp-action) 24 | (action-type-keyword-to-enum (:type interp-action)) 25 | (reify Predicate (test [_ message] ((:predicate interp-action) message))) 26 | (:sender interp-action) 27 | (:receiver interp-action))) 28 | 29 | ;;;; 30 | ;;;; States 31 | ;;;; 32 | 33 | (defn expand-then-perform! [source-states type message sender receiver] 34 | (States/expandThenPerform source-states 35 | (action-type-keyword-to-enum type) 36 | message 37 | sender 38 | receiver)) 39 | 40 | ;;;; 41 | ;;;; LTSs 42 | ;;;; 43 | 44 | (defn lts? [x] 45 | (= (type x) LTS)) 46 | 47 | (defn lts [ast & {:keys [on-the-fly history] 48 | :or {on-the-fly false, history false}}] 49 | (let [initial (if history [ast []] ast) 50 | expander (if history 51 | (reify 52 | Function 53 | (apply [_ [ast hist]] 54 | (let [successors (interp/successors-with-hist ast hist)] 55 | (zipmap (map #(action (interp/action %)) (keys successors)) 56 | (vals successors))))) 57 | (reify 58 | Function 59 | (apply [_ ast] 60 | (let [successors (interp/successors ast)] 61 | (zipmap (map #(action (interp/action %)) (keys successors)) 62 | (map #(mapv (fn [ast] (interp/simplify ast)) %) (vals successors))))))) 63 | lts (LTS. #{initial} expander)] 64 | (if (not on-the-fly) 65 | (.expandRecursively lts)) 66 | lts)) 67 | 68 | (defn initial-states [lts] 69 | (.getInitialStates lts)) 70 | 71 | (defn channels [lts] 72 | (into (sorted-set) 73 | (reduce clojure.set/union 74 | (map (fn [^State s] 75 | (reduce clojure.set/union 76 | (map (fn [a] #{[(.getSender a) (.getReceiver a)]}) 77 | (.getActions (.getTransitionsOrNull s))))) 78 | (.getStates lts))))) 79 | 80 | (defn roles [lts] 81 | (into (sorted-set) 82 | (reduce clojure.set/union 83 | (map (fn [^State s] 84 | (reduce clojure.set/union 85 | (map (fn [a] #{(.getSender a) (.getReceiver a)}) 86 | (.getActions (.getTransitionsOrNull s))))) 87 | (.getStates lts))))) 88 | 89 | (defn bisimilar? [lts1 lts2] 90 | (LTSs/bisimilar lts1 lts2)) 91 | 92 | (defn not-bisimilar? [lts1 lts2] 93 | (not (bisimilar? lts1 lts2))) -------------------------------------------------------------------------------- /src/main/clojure/discourje/core/spec/mcrl2.clj: -------------------------------------------------------------------------------- 1 | (ns discourje.core.spec.mcrl2 2 | (:require [clojure.string :refer [join]] 3 | [clojure.java.shell :refer [sh]] 4 | [clojure.pprint :refer [pprint]] 5 | [discourje.core.spec.lts :as lts]) 6 | (:import (java.io File))) 7 | 8 | (def ^:dynamic *mcrl2-bin* nil) 9 | (def ^:dynamic *mcrl2-tmp* nil) 10 | 11 | (defn mcrl2 [tool] 12 | (if *mcrl2-bin* 13 | (str *mcrl2-bin* File/separator (name tool)) 14 | (throw (Exception.)))) 15 | 16 | (defn ltsgraph [lts] 17 | (future 18 | (let [aut-file (str *mcrl2-tmp* File/separator "ltsgraph-" (System/currentTimeMillis) ".aut")] 19 | (spit aut-file (str lts)) 20 | (sh (mcrl2 :ltsgraph) aut-file)))) 21 | 22 | (defn lts2pbes-pbes2bool [lts formulas] 23 | (future 24 | (let [timestamp (System/currentTimeMillis) 25 | aut-file (str *mcrl2-tmp* File/separator "lts2pbes-pbes2bool-" timestamp ".aut") 26 | mcrl2-file (str *mcrl2-tmp* File/separator "lts2pbes-pbes2bool-" timestamp ".mcrl2") 27 | mcf-file (str *mcrl2-tmp* File/separator "lts2pbes-pbes2bool-" timestamp ".mcf") 28 | pbes-file (str *mcrl2-tmp* File/separator "lts2pbes-pbes2bool-" timestamp ".pbes")] 29 | 30 | (let [lts-string (str lts) 31 | lts-string (clojure.string/replace lts-string #"(‽|!)\([a-zA-Z]*," "$1(") 32 | lts-string (clojure.string/replace lts-string "[" "(") 33 | lts-string (clojure.string/replace lts-string "]" ")") 34 | lts-string (clojure.string/replace lts-string "‽" "handshake") 35 | lts-string (clojure.string/replace lts-string "!" "send") 36 | lts-string (clojure.string/replace lts-string "?" "receive") 37 | lts-string (clojure.string/replace lts-string "C" "close")] 38 | (spit aut-file lts-string)) 39 | 40 | (let [mcrl2-string (join "\n" [(str "sort Role = struct " 41 | (join " | " (distinct (map #(if-let [[_ name _] (re-matches #"(.+)\[([0-9]+)\]" %)] 42 | (str name "(Nat)") 43 | %) 44 | (sort (lts/roles lts))))) 45 | ";") 46 | "act" 47 | " handshake, send, receive: Role # Role;" 48 | " close: Role # Role;"])] 49 | (spit mcrl2-file mcrl2-string)) 50 | 51 | (loop [formulas formulas 52 | bools (sorted-map)] 53 | (if (empty? formulas) 54 | bools 55 | (let [begin (System/nanoTime) 56 | [name formula] (first formulas) 57 | _ (spit mcf-file formula) 58 | lts2pbes (sh (mcrl2 :lts2pbes) "-D" mcrl2-file "-f" mcf-file aut-file pbes-file) 59 | ;_ (println (:err lts2pbes)) 60 | pbes2bool (sh (mcrl2 :pbes2bool) pbes-file) 61 | ;_ (println (:err pbes2bool)) 62 | bool (read-string (:out pbes2bool)) 63 | end (System/nanoTime) 64 | time (long (/ (- end begin) 1000000))] 65 | (recur (rest formulas) 66 | (assoc bools name {:verdict bool 67 | :time time}))))) 68 | 69 | ;(clojure.java.io/delete-file mcf-file) 70 | ;(clojure.java.io/delete-file mcrl2-file) 71 | ;(clojure.java.io/delete-file pbes-file) 72 | ))) -------------------------------------------------------------------------------- /src/main/clojure/discourje/core/util.clj: -------------------------------------------------------------------------------- 1 | (ns discourje.core.util 2 | (:require [discourje.core.async :as a])) 3 | 4 | ;;;; 5 | ;;;; Networks 6 | ;;;; 7 | 8 | (defn- network 9 | [chs meta] 10 | (with-meta (fn 11 | ([] chs) 12 | ([i j] (get chs [i j]))) 13 | (merge {:network true} meta))) 14 | 15 | (defn ring [fn-chan ids] 16 | {:pre [(>= (count ids) 2)]} 17 | (network (loop [ids ids 18 | m {[(last ids) (first ids)] (fn-chan) 19 | [(first ids) (last ids)] (fn-chan)}] 20 | (if (or (empty? ids) (empty? (rest ids))) 21 | m 22 | (recur (rest ids) (merge m {[(first ids) (first (rest ids))] (fn-chan) 23 | [(first (rest ids)) (first ids)] (fn-chan)})))) 24 | {:network-type :ring})) 25 | 26 | (defn star [fn-chan root-id leaf-ids] 27 | {:pre [(>= (count leaf-ids) 2)]} 28 | (network (reduce merge (for [i leaf-ids] 29 | {[root-id i] (fn-chan) 30 | [i root-id] (fn-chan)})) 31 | {:network-type :star 32 | :root-id root-id})) 33 | 34 | (defn mesh [fn-chan ids] 35 | {:pre [(>= (count ids) 2)]} 36 | (network (reduce merge (for [i ids 37 | j (remove #{i} ids)] 38 | {[i j] (fn-chan)})) 39 | {:network-type :mesh})) 40 | 41 | ;;;; 42 | ;;;; Operations on networks 43 | ;;;; 44 | 45 | (defn putter-id [network c] 46 | {:pre [(contains? (meta network) :network)]} 47 | (first (first (first (filter #(= (second %) c) (network)))))) 48 | 49 | (defn taker-id [network c] 50 | {:pre [(contains? (meta network) :network)]} 51 | (second (first (first (filter #(= (second %) c) (network)))))) 52 | 53 | (defn puts [network [putter-id v] taker-ids] 54 | {:pre [(contains? (meta network) :network)]} 55 | (map (fn [taker-id] [(network putter-id taker-id) v]) taker-ids)) 56 | 57 | (defn takes [network putter-ids taker-id] 58 | {:pre [(contains? (meta network) :network)]} 59 | (map (fn [putter-id] (network putter-id taker-id)) putter-ids)) 60 | 61 | ;;;; 62 | ;;;; Monitors 63 | ;;;; 64 | 65 | (defn link-ring [network fn-role monitor] 66 | {:pre [(contains? #{:ring :mesh} (:network-type (meta network)))]} 67 | (doseq [[[i j] c] (network)] 68 | (a/link c (fn-role i) (fn-role j) monitor))) 69 | 70 | (defn link-star [network fn-role-root fn-role-leaf monitor] 71 | {:pre [(contains? #{:star} (:network-type (meta network)))]} 72 | (let [root-id (:root-id (meta network)) 73 | fn-role-root (if (= root-id nil) 74 | (fn [_] (fn-role-root)) 75 | fn-role-root)] 76 | (doseq [[[i j] c] (network)] 77 | (if (= i root-id) 78 | (a/link c (fn-role-root i) (fn-role-leaf j) monitor)) 79 | (if (= j root-id) 80 | (a/link c (fn-role-leaf i) (fn-role-root j) monitor))))) 81 | 82 | (defn link-mesh [network fn-role monitor] 83 | {:pre [(contains? #{:ring :mesh} (:network-type (meta network)))]} 84 | (doseq [[[i j] c] (network)] 85 | (a/link c (fn-role i) (fn-role j) monitor))) 86 | -------------------------------------------------------------------------------- /src/main/clojure/discourje/examples/clojured22/rps.clj: -------------------------------------------------------------------------------- 1 | (ns discourje.examples.clojured22.rps) 2 | 3 | (def MOVES [:rock :paper :scissors]) 4 | (def BEATS {:rock :scissors, :paper :rock, :scissors :paper}) 5 | 6 | (defn winner [[name1 move1] [name2 move2]] 7 | (cond 8 | (= move1 move2) "no one" 9 | (= move2 (BEATS move1)) name1 10 | :else name2)) 11 | 12 | (defn report [winner] 13 | (println) 14 | (println winner "wins!")) -------------------------------------------------------------------------------- /src/main/clojure/discourje/examples/clojured22/rps_checked.clj: -------------------------------------------------------------------------------- 1 | (ns discourje.examples.clojured22.rps-checked 2 | (:require [clojure.test :refer [deftest]] 3 | [discourje.core.async :refer [thread chan >!! "alice" "judge") 10 | (s/--> "bob" "judge") 11 | (s/--> "judge" "main"))) 12 | 13 | (def m (monitor :rps :n 4)) 14 | 15 | (defn rand-player [name] 16 | (let [out (chan name "judge" m {})] 17 | (thread 18 | (>!! out [name (rand-nth MOVES)])) 19 | out)) 20 | 21 | (defn judge [p1 p2] 22 | (let [out (chan "judge" "main" m {})] 23 | (thread 24 | (let [m1 (!! out (winner m1 m2)))) 27 | out)) 28 | 29 | (deftest rps-checked-good 30 | (let [x (rand-player "alice") 31 | y (rand-player "bob") 32 | z (judge x y)] 33 | (report (!! out name))) 56 | out)) 57 | 58 | (let [x (rand-player "alice") 59 | y (rand-player "bob") 60 | z (judge x y)] 61 | (report (!! !! out [name (rand-nth MOVES)])) 10 | out)) 11 | 12 | (defn judge [p1 p2] 13 | (let [out (chan)] 14 | (thread 15 | (let [m1 (!! out (winner m1 m2)))) 18 | out)) 19 | 20 | (deftest rps-unchecked-good 21 | (let [x (rand-player "alice") 22 | y (rand-player "bob") 23 | z (judge x y)] 24 | (report (!! out name))) 47 | out)) 48 | 49 | (let [x (rand-player "alice") 50 | y (rand-player "bob") 51 | z (judge x y)] 52 | (report ( (::process j) (::process k)) 24 | (s/--> (::process k) (::process j)))) 25 | (::awerbuch i j (assoc parents j i) topology)) 26 | 27 | (s/if (not (empty? todo)) 28 | (s/alt-every [k todo] 29 | (s/cat (s/--> (::process j) (::process k)) 30 | (::awerbuch j k parents topology))) 31 | 32 | (s/let [k (get parents j)] 33 | (s/if (some? k) 34 | (s/cat (s/--> (::process j) (::process k)) 35 | (::awerbuch j k parents topology)))))))) 36 | 37 | (defn spec [] 38 | (awerbuch (:initiator config/*input*) 39 | (condp = (:topology config/*input*) 40 | :ring (topologies/ring (:k config/*input*)) 41 | :tree (topologies/tree (:k config/*input*)) 42 | :mesh-2d (topologies/mesh-2d (:k config/*input*)) 43 | :star (topologies/star (:k config/*input*)) 44 | :mesh-full (topologies/mesh-full (:k config/*input*))))) 45 | 46 | (when (some? config/*lint*) 47 | (set! config/*output* (l/lint (spec)))) -------------------------------------------------------------------------------- /src/main/clojure/discourje/examples/da/cheung.clj: -------------------------------------------------------------------------------- 1 | (ns discourje.examples.da.cheung 2 | (:require [discourje.core.spec :as s] 3 | [discourje.core.lint :as l] 4 | [discourje.examples.config :as config] 5 | [discourje.examples.da.topologies :as topologies])) 6 | 7 | ;;;;; 8 | ;;;;; Specification 9 | ;;;;; 10 | 11 | (s/defrole ::process) 12 | 13 | (s/defsession ::cheung [initiator topology] 14 | (::cheung nil initiator {} topology)) 15 | 16 | (s/defsession ::cheung [i j parents topology] 17 | (s/let [neighbours (get topology j) 18 | todo (s/difference neighbours (set (keys parents)))] 19 | 20 | (s/if (not (contains? parents j)) 21 | (::cheung i j (assoc parents j i) topology) 22 | 23 | (s/if (not (empty? todo)) 24 | (s/alt-every [k todo] 25 | (s/cat (s/--> (::process j) (::process k)) 26 | (::cheung j k parents topology))) 27 | 28 | (s/let [k (get parents j)] 29 | (s/if (some? k) 30 | (s/cat (s/--> (::process j) (::process k)) 31 | (::cheung j k parents topology)))))))) 32 | 33 | (defn spec [] 34 | (cheung (:initiator config/*input*) 35 | (condp = (:topology config/*input*) 36 | :ring (topologies/ring (:k config/*input*)) 37 | :tree (topologies/tree (:k config/*input*)) 38 | :mesh-2d (topologies/mesh-2d (:k config/*input*)) 39 | :star (topologies/star (:k config/*input*)) 40 | :mesh-full (topologies/mesh-full (:k config/*input*))))) 41 | 42 | (when (some? config/*lint*) 43 | (set! config/*output* (l/lint (spec)))) -------------------------------------------------------------------------------- /src/main/clojure/discourje/examples/da/topologies.clj: -------------------------------------------------------------------------------- 1 | (ns discourje.examples.da.topologies) 2 | 3 | (defn ring [n] 4 | (into (sorted-map) 5 | (map (fn [i] 6 | [i (sorted-set (mod (inc i) n) 7 | (mod (dec i) n))]) 8 | (range n)))) 9 | 10 | (defn star [n] 11 | (into (sorted-map) 12 | (map (fn [i] 13 | (if (= i 0) 14 | [i (apply sorted-set (range 1 n))] 15 | [i #{0}])) 16 | (range n)))) 17 | 18 | (defn tree [n] 19 | (into (sorted-map) 20 | (map (fn [i] 21 | (let [j1 (try (dec (Long/parseLong (.replaceFirst (Long/toBinaryString (inc i)) ".$" "") 2)) 22 | (catch Exception e -1)) 23 | j2 (dec (Long/parseLong (str (Long/toBinaryString (inc i)) "0") 2)) 24 | j3 (dec (Long/parseLong (str (Long/toBinaryString (inc i)) "1") 2))] 25 | [i (apply sorted-set (filter #{j1 j2 j3} (range n)))])) 26 | (range n)))) 27 | 28 | (defn mesh-2d [n] 29 | (into (sorted-map) 30 | (map (fn [i] 31 | (let [len (long (Math/ceil (Math/sqrt n))) 32 | row (long (/ i len)) 33 | col (mod i len) 34 | j1 (if (> row 0) (clojure.core/+ (clojure.core/* (dec row) len) col) -1) 35 | j2 (if (< row (dec len)) (clojure.core/+ (clojure.core/* (inc row) len) col) -1) 36 | j3 (if (> col 0) (clojure.core/+ (clojure.core/* row len) (dec col)) -1) 37 | j4 (if (< col (dec len)) (clojure.core/+ (clojure.core/* row len) (inc col)) -1)] 38 | [i (apply sorted-set (filter (set (list j1 j2 j3 j4)) (range n)))])) 39 | (range n)))) 40 | 41 | (defn mesh-full [n] 42 | (into (sorted-map) 43 | (map (fn [i] 44 | [i (apply sorted-set (remove #{i} (range n)))]) 45 | (range n)))) -------------------------------------------------------------------------------- /src/main/clojure/discourje/examples/fm24/example1_dead.clj: -------------------------------------------------------------------------------- 1 | (ns discourje.examples.fm24.example1-dead 2 | (:require [discourje.core.async :refer :all] 3 | [discourje.core.spec :refer [defthread defsession -->> --> close alt cat par role]])) 4 | 5 | (defthread :buyer1) 6 | (defthread :buyer2) 7 | (defthread :seller) 8 | 9 | (defsession :two-buyer [] 10 | (cat 11 | (-->> String :buyer1 :seller) 12 | (par 13 | (cat 14 | (-->> Double :seller :buyer1) 15 | (-->> Double :buyer1 :buyer2)) 16 | (-->> Double :seller :buyer2)) 17 | (-->> Boolean :buyer2 :seller))) 18 | 19 | (def c1 (chan 1)) 20 | (def c2 (chan 1)) 21 | (def c3 (chan 1)) 22 | (def c4 (chan 1)) 23 | (def c5 (chan 1)) 24 | (def c6 (chan 1)) 25 | 26 | (def m (monitor :two-buyer :n 3)) 27 | (link c1 :buyer1 :buyer2 m) 28 | (link c2 :buyer1 :seller m) 29 | (link c3 :buyer2 :buyer1 m) 30 | (link c4 :buyer2 :seller m) 31 | (link c5 :seller :buyer1 m) 32 | (link c6 :seller :buyer2 m) 33 | 34 | (thread ;; Buyer1 35 | (>!! c2 "book") 36 | (let [x (!! c1 y))) 39 | 40 | (thread ;; Buyer2 41 | (let [x (!! c4 z))) 45 | 46 | (thread ;; Seller 47 | (!! c5 20.00) 49 | (>!! c6 20.00) 50 | (println (> --> close alt cat par role]])) 4 | 5 | (defthread :buyer1) 6 | (defthread :buyer2) 7 | (defthread :seller) 8 | 9 | (defsession :two-buyer [] 10 | (cat 11 | (-->> String :buyer1 :seller) 12 | (par 13 | (cat 14 | (-->> Double :seller :buyer1) 15 | (-->> Double :buyer1 :buyer2)) 16 | (-->> Double :seller :buyer2)) 17 | (-->> Boolean :buyer2 :seller))) 18 | 19 | (def c1 (chan 1)) 20 | (def c2 (chan 1)) 21 | (def c3 (chan 1)) 22 | (def c4 (chan 1)) 23 | (def c5 (chan 1)) 24 | (def c6 (chan 1)) 25 | 26 | (def m (monitor :two-buyer :n 3)) 27 | (link c1 :buyer1 :buyer2 m) 28 | (link c2 :buyer1 :seller m) 29 | (link c3 :buyer2 :buyer1 m) 30 | (link c4 :buyer2 :seller m) 31 | (link c5 :seller :buyer1 m) 32 | (link c6 :seller :buyer2 m) 33 | 34 | (thread ;; Buyer1 35 | (>!! c2 "book") 36 | (let [x (!! c1 y))) 39 | 40 | (thread ;; Buyer2 41 | (let [x (!! c4 z))) 45 | 46 | (thread ;; Seller 47 | (!! c5 20.00) 49 | (>!! c6 20.00) 50 | (println (> --> close alt cat par role]])) 4 | 5 | (defthread :c) 6 | (defthread :b) 7 | (defthread :s1) 8 | (defthread :s2) 9 | 10 | (defsession :load-balancer [] 11 | (cat 12 | (--> Long :c :b) 13 | (alt 14 | (cat 15 | (-->> Long :b :s1) 16 | (--> Long :s1 :c)) 17 | (cat 18 | (-->> Long :b :s2) 19 | (--> Long :s2 :c))))) 20 | 21 | (def c1 (chan)) 22 | (def c2 (chan)) 23 | (def c3 (chan)) 24 | (def c4 (chan 512)) 25 | (def c5 (chan 1024)) 26 | 27 | (def m (monitor :load-balancer :n 4)) 28 | (link c1 :c :b m) 29 | (link c2 :s1 :c m) 30 | (link c3 :s2 :c m) 31 | (link c4 :b :s1 m) 32 | (link c5 :b :s2 m) 33 | 34 | (thread ;; Load Balancer 35 | (let [x (!! c1 5) 41 | (alts!! [c2 c3])) 42 | 43 | (thread ;; Server1 44 | (let [x (!! c2 y))) 47 | 48 | (thread ;; Server2 49 | (let [x (!! c3 y))) -------------------------------------------------------------------------------- /src/main/clojure/discourje/examples/fm24/example2_dead2.clj: -------------------------------------------------------------------------------- 1 | (ns discourje.examples.fm24.example2-dead2 2 | (:require [discourje.core.async :refer :all] 3 | [discourje.core.spec :refer [defthread defsession -->> --> close alt cat par role]])) 4 | 5 | (defthread :c) 6 | (defthread :b) 7 | (defthread :s1) 8 | (defthread :s2) 9 | 10 | (defsession :load-balancer [] 11 | (cat 12 | (--> Long :c :b) 13 | (alt 14 | (cat 15 | (-->> Long :b :s1) 16 | (--> Long :s1 :c)) 17 | (cat 18 | (-->> Long :b :s2) 19 | (--> Long :s2 :c))))) 20 | 21 | (def c1 (chan)) 22 | (def c2 (chan)) 23 | (def c3 (chan)) 24 | (def c4 (chan 512)) 25 | (def c5 (chan 1024)) 26 | 27 | (def m (monitor :load-balancer :n 4)) 28 | (link c1 :c :b m) 29 | (link c2 :s1 :c m) 30 | (link c3 :s2 :c m) 31 | (link c4 :b :s1 m) 32 | (link c5 :b :s2 m) 33 | 34 | (thread ;; Load Balancer 35 | (let [x (!! c1 5) 41 | (alts!! [c2 c3])) 42 | 43 | (thread ;; Server1 44 | (let [x (!! c2 y))) 47 | 48 | (thread ;; Server2 49 | (let [x (!! c3 y))) -------------------------------------------------------------------------------- /src/main/clojure/discourje/examples/fm24/example2_live.clj: -------------------------------------------------------------------------------- 1 | (ns discourje.examples.fm24.example2-live 2 | (:require [discourje.core.async :refer :all] 3 | [discourje.core.spec :refer [defthread defsession -->> --> close alt cat par role]])) 4 | 5 | (defthread :c) 6 | (defthread :b) 7 | (defthread :s1) 8 | (defthread :s2) 9 | 10 | (defsession :load-balancer [] 11 | (cat 12 | (--> Long :c :b) 13 | (alt 14 | (par 15 | (cat 16 | (-->> Long :b :s1) 17 | (--> Long :s1 :c)) 18 | (close :b :s2)) 19 | (par 20 | (cat 21 | (-->> Long :b :s2) 22 | (--> Long :s2 :c)) 23 | (close :b :s1))))) 24 | 25 | (def c1 (chan)) 26 | (def c2 (chan)) 27 | (def c3 (chan)) 28 | (def c4 (chan 512)) 29 | (def c5 (chan 1024)) 30 | 31 | (def m (monitor :load-balancer :n 4)) 32 | (link c1 :c :b m) 33 | (link c2 :s1 :c m) 34 | (link c3 :s2 :c m) 35 | (link c4 :b :s1 m) 36 | (link c5 :b :s2 m) 37 | 38 | (thread ;; Load Balancer 39 | (let [x (!! c1 5) 47 | (alts!! [c2 c3])) 48 | 49 | (thread ;; Server1 50 | (let [x (!! c2 y)))) 53 | 54 | (thread ;; Server2 55 | (let [x (!! c3 y)))) -------------------------------------------------------------------------------- /src/main/clojure/discourje/examples/games/chess.clj: -------------------------------------------------------------------------------- 1 | (ns discourje.examples.games.chess 2 | (:require [clojure.core.async] 3 | [discourje.core.async] 4 | [discourje.core.spec :as s] 5 | [discourje.core.lint :as l] 6 | [discourje.examples.config :as config]) 7 | (:import (discourje.examples.games.impl.chess Engine))) 8 | 9 | ;;;;; 10 | ;;;;; Specification 11 | ;;;;; 12 | 13 | (s/defrole ::white) 14 | (s/defrole ::black) 15 | 16 | (s/defsession ::chess [] 17 | (::chess-turn ::white ::black)) 18 | 19 | (s/defsession ::chess-turn [r1 r2] 20 | (s/--> String r1 r2) 21 | (s/alt (::chess-turn r2 r1) 22 | (s/par (s/close r1 r2) 23 | (s/close r2 r1)))) 24 | 25 | (defn spec [] (chess)) 26 | 27 | (when (some? config/*lint*) 28 | (set! config/*output* (l/lint (spec)))) 29 | 30 | ;;;;; 31 | ;;;;; Implementation 32 | ;;;;; 33 | 34 | (config/clj-or-dcj) 35 | 36 | (when (some? config/*run*) 37 | (let [input config/*input* 38 | stockfish (:stockfish input) 39 | turns-per-player (:turns-per-player input) 40 | time-per-player (:time-per-player input)] 41 | 42 | ;; Configure Engine 43 | (if stockfish (set! Engine/STOCKFISH stockfish)) 44 | (if turns-per-player (set! Engine/TURNS_PER_PLAYER turns-per-player)) 45 | (if time-per-player (set! Engine/TIME_PER_PLAYER time-per-player)) 46 | 47 | (let [;; Create channels 48 | w->b (a/chan) 49 | b->w (a/chan) 50 | 51 | ;; Link monitor [optional] 52 | _ 53 | (if (= config/*run* :dcj) 54 | (let [m (a/monitor (spec) :n 2)] 55 | (a/link w->b white black m) 56 | (a/link b->w black white m))) 57 | 58 | ;; Spawn threads 59 | white 60 | (a/thread (let [e (Engine. false)] 61 | (a/>!! w->b (.turn e nil)) 62 | (loop [] 63 | (let [m (a/w)] 64 | (if (not= m "(none)") 65 | (let [m (.turn e m)] 66 | (a/>!! w->b m) 67 | (if (not= m "(none)") 68 | (recur)))))) 69 | (a/close! w->b) 70 | (.kill e))) 71 | 72 | black 73 | (a/thread (let [e (Engine. false)] 74 | (loop [] 75 | (let [m (a/b)] 76 | (if (not= m "(none)") 77 | (let [m (.turn e m)] 78 | (a/>!! b->w m) 79 | (if (not= m "(none)") 80 | (recur)))))) 81 | (a/close! b->w) 82 | (.kill e))) 83 | 84 | ;; Await termination 85 | output 86 | (do (a/Card suit rank))) 23 | 24 | (defn shuffled-deck [] 25 | (shuffle deck)) 26 | 27 | (defrecord Turn []) 28 | (defn turn [] (->Turn)) 29 | 30 | (defrecord Ask [suit rank]) 31 | (defn ask [suit rank] (->Ask suit rank)) 32 | 33 | (defrecord Go []) 34 | (defn go [] (->Go)) 35 | 36 | (defrecord Fish []) 37 | (defn fish [] (->Fish)) 38 | 39 | (defrecord OutOfCards []) 40 | (defn out-of-cards [] (->OutOfCards)) -------------------------------------------------------------------------------- /src/main/clojure/discourje/examples/main.clj: -------------------------------------------------------------------------------- 1 | (ns discourje.examples.main 2 | (:gen-class) 3 | (:require [discourje.core.lint :as l] 4 | [discourje.core.spec.mcrl2 :as mcrl2] 5 | [discourje.core.spec.ast :as ast] 6 | [discourje.examples.config :as config])) 7 | 8 | (defn main [settings program input] 9 | (binding [config/*lint* (:lint settings) 10 | config/*run* (:run settings) 11 | config/*input* input 12 | config/*output* nil 13 | l/*engine* (:lint settings) 14 | l/*witness* (if (some? (:witness settings)) (:witness settings) l/*witness*) 15 | l/*exclude* (if (some? (:exclude settings)) (:exclude settings) l/*exclude*) 16 | mcrl2/*mcrl2-bin* (:mcrl2-bin settings) 17 | mcrl2/*mcrl2-tmp* (:mcrl2-tmp settings)] 18 | 19 | (when (some? (:timeout settings)) 20 | (.start (Thread. ^Runnable (fn [] 21 | (Thread/sleep (* 1000 (:timeout settings))) 22 | (prn "timeout") 23 | (System/exit 0))))) 24 | (let [begin (System/nanoTime) 25 | _ (require program :reload) 26 | end (System/nanoTime)] 27 | {:settings settings 28 | :program program 29 | :input config/*input* 30 | :output config/*output* 31 | :time (int (/ (- end begin) (* 1000 1000)))}))) 32 | 33 | (defmacro commit [] 34 | (clojure.string/trim-newline (:out (clojure.java.shell/sh "git" "rev-parse" "--short" "HEAD")))) 35 | 36 | (defn -main [& args] 37 | (try 38 | (let [[settings program-short input] (read-string (str "[" (clojure.string/join " " args) "]")) 39 | program (symbol (str "discourje.examples" "." program-short)) 40 | output (main settings program input)] 41 | (prn output) 42 | (System/exit 0)) 43 | 44 | (catch Throwable t 45 | (println) 46 | (println (str "Discourje Examples (" (commit) ")")) 47 | (println (str "Usage: java -jar discourje-examples.jar ")) 48 | (println (str " \u2208 {" 49 | (clojure.string/join ", " ["micro.mesh" "micro.ring" "micro.star" 50 | "games.chess" "games.go-fish" "games.rock-paper-scissors" "games.tic-tac-toe" 51 | "npb3.cg" "npb3.ft" "npb3.is" "npb3.mg"]) 52 | "}")) 53 | (println) 54 | (.printStackTrace t) 55 | (println)))) 56 | 57 | (comment 58 | (.start 59 | (Thread. 60 | #(do 61 | (println "begin") 62 | (main {:run :dcj} 63 | 'discourje.examples.games.go-fish 64 | {:k 3}) 65 | (println "end"))))) 66 | -------------------------------------------------------------------------------- /src/main/clojure/discourje/examples/micro/mesh.clj: -------------------------------------------------------------------------------- 1 | (ns discourje.examples.micro.mesh 2 | (:require [clojure.core.async] 3 | [discourje.core.async] 4 | [discourje.core.util :as u] 5 | [discourje.core.spec :as s] 6 | [discourje.core.lint :as l] 7 | [discourje.examples.config :as config])) 8 | 9 | ;;;;; 10 | ;;;;; Specification 11 | ;;;;; 12 | 13 | (s/defrole ::worker) 14 | 15 | (s/defsession ::mesh-unbuffered [k] 16 | (s/* (s/alt-every [i (range k) 17 | j (remove #{i} (range k))] 18 | (s/--> Boolean (::worker i) (::worker j))))) 19 | 20 | (s/defsession ::mesh-buffered [k] 21 | (s/par-every [i (range k) 22 | j (remove #{i} (range k))] 23 | (s/* (s/-->> Boolean (::worker i) (::worker j))))) 24 | 25 | (defn spec [] 26 | (condp = (:flags config/*input*) 27 | #{:unbuffered} 28 | (mesh-unbuffered (:k config/*input*)) 29 | #{:buffered} 30 | (mesh-buffered (:k config/*input*)))) 31 | 32 | (when (some? config/*lint*) 33 | (set! config/*output* (l/lint (spec)))) 34 | 35 | ;;;;; 36 | ;;;;; Implementation 37 | ;;;;; 38 | 39 | (config/clj-or-dcj) 40 | 41 | (when (some? config/*run*) 42 | (let [input config/*input* 43 | flags (:flags input) 44 | k (:k input) 45 | n (:n input)] 46 | 47 | (let [;; Create channels 48 | mesh 49 | (cond (contains? flags :unbuffered) 50 | (u/mesh a/chan (range k)) 51 | (contains? flags :buffered) 52 | (u/mesh (partial a/chan 1) (range k))) 53 | 54 | ;; Link monitor [optional] 55 | _ 56 | (if (= config/*run* :dcj) 57 | (let [m (a/monitor (spec) :n k)] 58 | (u/link-mesh mesh worker m))) 59 | 60 | ;; Spawn threads 61 | workers 62 | (mapv (fn [i] (a/thread (loop [to-put (zipmap (remove #{i} (range k)) (repeat n)) 63 | to-take (zipmap (remove #{i} (range k)) (repeat n))] 64 | (let [keep-fn (fn [[j count]] (if (> count 0) j)) 65 | puts (u/puts mesh [i true] (keep keep-fn to-put)) 66 | takes (u/takes mesh (keep keep-fn to-take) i) 67 | puts-and-takes (into puts takes)] 68 | (if (not-empty puts-and-takes) 69 | (let [[_ c] (a/alts!! puts-and-takes)] 70 | (if (= (u/putter-id mesh c) i) 71 | (recur (update to-put (u/taker-id mesh c) dec) to-take) 72 | (recur to-put (update to-take (u/putter-id mesh c) dec))))))))) 73 | (range k)) 74 | 75 | ;; Await termination 76 | output 77 | (doseq [worker workers] 78 | (a/ Boolean (::worker i) (::worker (mod (inc i) k)))))) 18 | 19 | (s/defsession ::ring-buffered [k] 20 | (s/* (s/cat-every [i (range k)] 21 | (s/-->> Boolean (::worker i) (::worker (mod (inc i) k)))))) 22 | 23 | (defn spec [] 24 | (condp = (:flags config/*input*) 25 | #{:unbuffered} 26 | (ring-unbuffered (:k config/*input*)) 27 | #{:buffered} 28 | (ring-buffered (:k config/*input*)))) 29 | 30 | (when (some? config/*lint*) 31 | (set! config/*output* (l/lint (spec)))) 32 | 33 | ;;;;; 34 | ;;;;; Implementation 35 | ;;;;; 36 | 37 | (config/clj-or-dcj) 38 | 39 | (when (some? config/*run*) 40 | (let [input config/*input* 41 | flags (:flags input) 42 | k (:k input) 43 | n (:n input)] 44 | 45 | (let [;; Create channels 46 | ring 47 | (cond (contains? flags :unbuffered) 48 | (u/ring a/chan (range k)) 49 | (contains? flags :buffered) 50 | (u/ring (partial a/chan 1) (range k))) 51 | 52 | ;; Link monitor [optional] 53 | _ 54 | (if (= config/*run* :dcj) 55 | (let [m (a/monitor (spec) :n k)] 56 | (u/link-ring ring worker m))) 57 | 58 | ;; Spawn threads 59 | worker0 60 | (a/thread (doseq [_ (range n)] 61 | (a/>!! (ring 0 1) true) 62 | (a/!! (ring i (mod (inc i) k)) true)))) 68 | (range 1 k)) 69 | 70 | ;; Await termination 71 | output 72 | (do (a/> discourje.examples.npb3.impl.CGThreads.CGMessage ::master (::worker i)) 20 | (s/-->> discourje.examples.npb3.impl.DoneMessage (::worker i) ::master)))) 21 | (s/par-every [i (range k)] 22 | (s/cat (s/-->> discourje.examples.npb3.impl.ExitMessage ::master (::worker i)) 23 | (s/-->> discourje.examples.npb3.impl.DoneMessage (::worker i) ::master))) 24 | (s/par (s/par-every [i (range k)] 25 | (s/close ::master (::worker i))) 26 | (s/par-every [i (range k)] 27 | (s/close (::worker i) ::master))))) 28 | 29 | ;(s/defsession ::cg [k] 30 | ; (s/cat (s/* (s/cat (s/cat-every [i (range k)] 31 | ; (s/-->> discourje.examples.npb3.impl.CGThreads.CGMessage ::master (::worker i))) 32 | ; (s/cat-every [i (range k)] 33 | ; (s/-->> discourje.examples.npb3.impl.DoneMessage (::worker i) ::master)))) 34 | ; (s/cat-every [i (range k)] 35 | ; (s/cat (s/-->> discourje.examples.npb3.impl.ExitMessage ::master (::worker i)) 36 | ; (s/-->> discourje.examples.npb3.impl.DoneMessage (::worker i) ::master))) 37 | ; (s/cat-every [i (range k)] 38 | ; (s/close ::master (::worker i))) 39 | ; (s/cat-every [i (range k)] 40 | ; (s/close (::worker i) ::master)))) 41 | 42 | (defn spec [] 43 | (cg (:k config/*input*))) 44 | 45 | (when (some? config/*lint*) 46 | (set! config/*output* (l/lint (spec)))) 47 | 48 | ;;;;; 49 | ;;;;; Implementation 50 | ;;;;; 51 | 52 | (config/clj-or-dcj) 53 | 54 | (when (some? config/*run*) 55 | (let [input config/*input* 56 | k (:k input) 57 | class (:class input) 58 | verbose (:verbose input)] 59 | 60 | (let [;; Configure 61 | _ (do (Config/verbose verbose) 62 | (case config/*run* 63 | :clj (Config/clj) 64 | :dcj (Config/dcj) 65 | :dcj-nil (Config/dcjNil))) 66 | 67 | ;; Run 68 | output (CG/main (into-array String [(str "np=" k) (str "CLASS=" class)]))] 69 | 70 | (Config/verbose true) 71 | (set! config/*output* output)))) -------------------------------------------------------------------------------- /src/main/clojure/discourje/examples/npb3/is.clj: -------------------------------------------------------------------------------- 1 | (ns discourje.examples.npb3.is 2 | (:require [clojure.core.async] 3 | [discourje.core.async] 4 | [discourje.core.spec :as s] 5 | [discourje.core.lint :as l] 6 | [discourje.examples.config :as config]) 7 | (:import (discourje.examples.npb3 Config) 8 | (discourje.examples.npb3.impl IS))) 9 | 10 | ;;;;; 11 | ;;;;; Specification 12 | ;;;;; 13 | 14 | (s/defrole ::master) 15 | (s/defrole ::worker) 16 | 17 | (s/defsession ::is [k] 18 | (s/cat (s/* (s/par-every [i (range k)] 19 | (s/cat (s/-->> discourje.examples.npb3.impl.ISThreads.RankMessage ::master (::worker i)) 20 | (s/-->> discourje.examples.npb3.impl.DoneMessage (::worker i) ::master)))) 21 | (s/par-every [i (range k)] 22 | (s/cat (s/-->> discourje.examples.npb3.impl.ExitMessage ::master (::worker i)) 23 | (s/-->> discourje.examples.npb3.impl.DoneMessage (::worker i) ::master))) 24 | (s/par (s/par-every [i (range k)] 25 | (s/close ::master (::worker i))) 26 | (s/par-every [i (range k)] 27 | (s/close (::worker i) ::master))))) 28 | 29 | ;(s/defsession ::is [k] 30 | ; (s/cat (s/* (s/cat (s/cat-every [i (range k)] 31 | ; (s/-->> discourje.examples.npb3.impl.ISThreads.RankMessage ::master (::worker i))) 32 | ; (s/cat-every [i (range k)] 33 | ; (s/-->> discourje.examples.npb3.impl.DoneMessage (::worker i) ::master)))) 34 | ; (s/cat-every [i (range k)] 35 | ; (s/cat (s/-->> discourje.examples.npb3.impl.ExitMessage ::master (::worker i)) 36 | ; (s/-->> discourje.examples.npb3.impl.DoneMessage (::worker i) ::master))) 37 | ; (s/cat (s/cat-every [i (range k)] 38 | ; (s/close ::master (::worker i))) 39 | ; (s/cat-every [i (range k)] 40 | ; (s/close (::worker i) ::master))))) 41 | 42 | (defn spec [] 43 | (is (:k config/*input*))) 44 | 45 | (when (some? config/*lint*) 46 | (set! config/*output* (l/lint (spec)))) 47 | 48 | ;;;;; 49 | ;;;;; Implementation 50 | ;;;;; 51 | 52 | (config/clj-or-dcj) 53 | 54 | (when (some? config/*run*) 55 | (let [input config/*input* 56 | k (:k input) 57 | class (:class input) 58 | verbose (:verbose input)] 59 | 60 | (let [;; Configure 61 | _ (do (Config/verbose verbose) 62 | (case config/*run* 63 | :clj (Config/clj) 64 | :dcj (Config/dcj) 65 | :dcj-nil (Config/dcjNil))) 66 | 67 | ;; Run 68 | output (IS/main (into-array String [(str "np=" k) (str "CLASS=" class)]))] 69 | 70 | (Config/verbose true) 71 | (set! config/*output* output)))) -------------------------------------------------------------------------------- /src/main/clojure/discourje/examples/timer.clj: -------------------------------------------------------------------------------- 1 | (ns discourje.examples.timer 2 | (:refer-clojure :exclude [update longs quot])) 3 | 4 | ;;;; 5 | ;;;; Stats 6 | ;;;; 7 | 8 | (defrecord Stats [n big-m big-s x-min x-max]) 9 | 10 | (defn stats [] 11 | (->Stats 0 nil nil nil nil)) 12 | 13 | ;; References: 14 | ;; * Knuth: The art of computer programming, Volume II: Seminumerical Algorithms, 3rd Edition. Addison-Wesley 1998. (§4.2.2) 15 | ;; * Hoefler, Belli: Scientific benchmarking of parallel computing systems: twelve ways to tell the masses when reporting 16 | ;; performance results. SC 2015. 17 | 18 | (defn update [stats x'] 19 | (let [n (:n stats) 20 | big-m (:big-m stats)] 21 | (if (= n 0) 22 | (assoc stats :n 1 :big-m x' :big-s 0 :x-min x' :x-max x') 23 | (let [n' (inc n) 24 | big-m' (+ big-m (/ (- x' big-m) n')) 25 | big-s' (+ (:big-s stats) (* (- x' big-m) (- x' big-m'))) 26 | x-min' (min (:x-min stats) x') 27 | x-max' (max (:x-max stats) x')] 28 | (assoc stats :n n' :big-m big-m' :big-s big-s' :x-min x-min' :x-max x-max'))))) 29 | 30 | ;; References: 31 | ;; * Salkind: Encyclopedia of Research Design, Volume I. SAGE Publications 2010. (Central Tendency, Measures of) 32 | ;; * Salkind: Encyclopedia of Research Design, Volume II. SAGE Publications 2010. (Pooled Variance) 33 | 34 | (defn pool [& statss] 35 | (if (empty? statss) 36 | nil 37 | (let [n (reduce + (map #(:n %) statss))] 38 | (assoc (stats) :n n 39 | :big-m (if (> n 0) (reduce + (map #(* (/ (:n %) n) (:big-m %)) statss))) 40 | :big-s (if (> n (count statss)) 41 | (/ (reduce + (map #(* (dec (:n %)) (:big-s %)) statss)) (- n (count statss)))) 42 | :x-min (apply min (map #(:x-min %) statss)) 43 | :x-max (apply max (map #(:x-max %) statss)))))) 44 | 45 | ;;;; 46 | ;;;; Timer 47 | ;;;; 48 | 49 | (defrecord Timer [resolution ticks stats nanos aggregate]) 50 | 51 | (defn timer [resolution] 52 | (->Timer resolution 0 (stats) (System/nanoTime) false)) 53 | 54 | (defn tick [t] 55 | {:pre [(not (:aggregate t))]} 56 | (let [ticks' (inc (:ticks t))] 57 | (if (= 0 (mod ticks' (:resolution t))) 58 | (assoc t :ticks ticks' 59 | :stats (update (:stats t) (- (System/nanoTime) (:nanos t))) 60 | :nanos (System/nanoTime)) 61 | (assoc t :ticks ticks')))) 62 | 63 | (defn aggregate [& timers] 64 | {:pre [(not (empty? timers)) (every? #(= (:resolution %) (:resolution (first timers))) (rest timers))]} 65 | (assoc (timer (:resolution (first timers))) :ticks (reduce + (map #(:ticks %) timers)) 66 | :stats (apply pool (mapv #(:stats %) timers)) 67 | :nanos nil 68 | :aggregate true)) 69 | 70 | (defn report [t] 71 | (let [stats (:stats t)] 72 | {:ticks (:ticks t) 73 | :stats {:n (:n stats) 74 | :μ-hat (long (:big-m stats)) 75 | :σ-hat (if (and (:bis-s stats) (> (:n stats) 1)) 76 | (long (Math/sqrt (/ (:big-s stats) (dec (:n stats)))))) 77 | :x-min (:x-min stats) 78 | :x-max (:x-max stats)} 79 | :aggregate (:aggregate t)})) 80 | -------------------------------------------------------------------------------- /src/main/java/discourje/core/SpecJ.java: -------------------------------------------------------------------------------- 1 | package discourje.core; 2 | 3 | import clojure.java.api.Clojure; 4 | import clojure.lang.IFn; 5 | 6 | import java.util.Arrays; 7 | import java.util.function.Supplier; 8 | 9 | public class SpecJ { 10 | 11 | public interface Role extends Supplier { 12 | } 13 | 14 | public interface Session extends Supplier { 15 | } 16 | 17 | private static IFn fnRequire; 18 | private static IFn fnEval; 19 | private static IFn fnVec; 20 | private static IFn fnRead; 21 | 22 | private static IFn fnRole; 23 | private static IFn fnSession; 24 | 25 | static { 26 | System.out.print("Loading SpecJ... "); 27 | var begin = System.currentTimeMillis(); 28 | var ns = ""; 29 | 30 | ns = "clojure.core"; 31 | fnRequire = Clojure.var(ns, "require"); 32 | fnEval = Clojure.var(ns, "eval"); 33 | fnVec = Clojure.var(ns, "vec"); 34 | fnRead = Clojure.var(ns, "read-string"); 35 | 36 | ns = "discourje.core.spec.ast"; 37 | fnRole = Clojure.var(ns, "role"); 38 | fnSession = Clojure.var(ns, "session"); 39 | 40 | var end = System.currentTimeMillis(); 41 | System.out.println("Done (" + (end - begin) + " ms)."); 42 | } 43 | 44 | public static void defRole(String nameKey) { 45 | fnRequire.invoke(fnRead.invoke("[discourje.core.spec :refer :all]")); 46 | var s = "(defrole " + nameKey + ")"; 47 | fnEval.invoke(fnRead.invoke(s)); 48 | } 49 | 50 | public static void defSession(String nameKey, String[] vars, String body) { 51 | fnRequire.invoke(fnRead.invoke("[discourje.core.spec :refer :all]")); 52 | var s = "(defsession " + nameKey + " " + Arrays.toString(vars) + " " + body + ")"; 53 | fnEval.invoke(fnRead.invoke(s)); 54 | } 55 | 56 | public static Role role(String nameExpr, Object... indexVals) { 57 | var o = fnRole.invoke(fnRead.invoke(nameExpr), fnVec.invoke(indexVals)); 58 | return () -> o; 59 | } 60 | 61 | public static Session session(String nameKey, Object[] vals) { 62 | var o = fnSession.invoke(fnRead.invoke(nameKey), fnVec.invoke(vals)); 63 | return () -> o; 64 | } 65 | 66 | public static Session parse(String s) { 67 | fnRequire.invoke(fnRead.invoke("[discourje.core.spec :refer :all]")); 68 | var o = fnEval.invoke(Clojure.read(s)); 69 | return () -> o; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/discourje/core/ctl/Channel.java: -------------------------------------------------------------------------------- 1 | package discourje.core.ctl; 2 | 3 | import java.util.Objects; 4 | 5 | public class Channel { 6 | private final String sender; 7 | private final String receiver; 8 | 9 | public Channel(String sender, String receiver) { 10 | this.sender = sender; 11 | this.receiver = receiver; 12 | } 13 | 14 | public String getSender() { 15 | return sender; 16 | } 17 | 18 | public String getReceiver() { 19 | return receiver; 20 | } 21 | 22 | @Override 23 | public boolean equals(Object o) { 24 | if (this == o) return true; 25 | if (o == null || getClass() != o.getClass()) return false; 26 | Channel channel = (Channel) o; 27 | return sender.equals(channel.sender) && 28 | receiver.equals(channel.receiver); 29 | } 30 | 31 | @Override 32 | public int hashCode() { 33 | return Objects.hash(sender, receiver); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/discourje/core/ctl/Formula.java: -------------------------------------------------------------------------------- 1 | package discourje.core.ctl; 2 | 3 | import discourje.core.lts.Action; 4 | import java.util.Collections; 5 | import java.util.List; 6 | 7 | public interface Formula { 8 | 9 | default boolean isAction() { 10 | return false; 11 | } 12 | 13 | boolean isTemporal(); 14 | 15 | Labels label(Model model); 16 | 17 | default List> extractWitness(Model model) { 18 | for (var s : model.getInitialStates()) { 19 | if (!model.hasLabel(s, this)) { 20 | return extractWitness(model, s); 21 | } 22 | } 23 | throw new IllegalArgumentException(); 24 | } 25 | 26 | List> extractWitness(Model model, State source); 27 | 28 | default List split() { 29 | return Collections.singletonList(this); 30 | } 31 | 32 | default String toMCRL2() { 33 | throw new UnsupportedOperationException(getClass().getSimpleName()); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/discourje/core/ctl/Labels.java: -------------------------------------------------------------------------------- 1 | package discourje.core.ctl; 2 | 3 | import java.util.BitSet; 4 | import java.util.Collection; 5 | 6 | public class Labels { 7 | private final BitSet labels; 8 | 9 | public Labels() { 10 | this.labels = new BitSet(); 11 | } 12 | 13 | public boolean hasLabel(State state) { 14 | return labels.get(state.getIndex()); 15 | } 16 | 17 | public boolean setLabel(State state) { 18 | boolean alreadySet = labels.get(state.getIndex()); 19 | labels.set(state.getIndex()); 20 | return !alreadySet; 21 | } 22 | 23 | public boolean allHaveLabel(Collection> states) { 24 | return states.stream().allMatch(this::hasLabel); 25 | } 26 | 27 | public boolean anyHaveLabel(Collection> states) { 28 | return states.stream().anyMatch(this::hasLabel); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/discourje/core/ctl/ModelChecker.java: -------------------------------------------------------------------------------- 1 | package discourje.core.ctl; 2 | 3 | import discourje.core.lts.LTS; 4 | import discourje.core.ctl.rules.Causality; 5 | import discourje.core.ctl.rules.CloseChannelsOnlyOnce; 6 | import discourje.core.ctl.rules.ClosedChannelMustBeUsedInPath; 7 | import discourje.core.ctl.rules.ClosedChannelMustBeUsedInProtocol; 8 | import discourje.core.ctl.rules.DoNotSendAfterClose; 9 | import discourje.core.ctl.rules.DoNotSendToSelf; 10 | import discourje.core.ctl.rules.UsedChannelsMustBeClosed; 11 | import java.util.Arrays; 12 | import java.util.Collection; 13 | import java.util.List; 14 | import java.util.stream.Collectors; 15 | 16 | public class ModelChecker { 17 | public static final List DEFAULT_RULES = Arrays.asList(new Causality(), 18 | new UsedChannelsMustBeClosed(), 19 | new ClosedChannelMustBeUsedInPath(), 20 | new ClosedChannelMustBeUsedInProtocol(), 21 | new CloseChannelsOnlyOnce(), 22 | new DoNotSendAfterClose(), 23 | new DoNotSendToSelf()); 24 | 25 | private final Model dmModel; 26 | private final Collection rules; 27 | 28 | public ModelChecker(LTS lts) { 29 | this.dmModel = new Model<>(lts); 30 | rules = DEFAULT_RULES; 31 | } 32 | 33 | public ModelChecker(LTS lts, Collection rules) { 34 | this.dmModel = new Model<>(lts); 35 | this.rules = rules; 36 | } 37 | 38 | public List checkModel() { 39 | return rules.stream() 40 | .flatMap(r -> r.getValidationErrors(dmModel).stream()) 41 | .collect(Collectors.toList()); 42 | } 43 | 44 | public static boolean check(LTS lts, Formula f) { 45 | var model = new Model<>(lts); 46 | model.calculateLabels(f); 47 | return model.getInitialStates().stream().allMatch(s -> model.hasLabel(s, f)); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/discourje/core/ctl/Rule.java: -------------------------------------------------------------------------------- 1 | package discourje.core.ctl; 2 | 3 | import java.util.Collection; 4 | import java.util.HashSet; 5 | import java.util.Set; 6 | 7 | public abstract class Rule { 8 | 9 | public Collection getValidationErrors(Model model) { 10 | Set result = new HashSet<>(0); 11 | for (Channel channel : model.getChannels()) { 12 | Formula formula = createCtlFormula(channel.getSender(), channel.getReceiver()); 13 | model.calculateLabels(formula); 14 | 15 | if (model.getInitialStates().stream().anyMatch(s -> !model.hasLabel(s, formula))) { 16 | result.add(createErrorDescription(channel.getSender(), channel.getReceiver())); 17 | } 18 | } 19 | return result; 20 | } 21 | 22 | public abstract String createErrorDescription(String r1, String r2); 23 | 24 | public abstract Formula createCtlFormula(String r1, String r2); 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/discourje/core/ctl/State.java: -------------------------------------------------------------------------------- 1 | package discourje.core.ctl; 2 | 3 | import discourje.core.lts.Action; 4 | 5 | import java.util.*; 6 | import java.util.stream.Collectors; 7 | 8 | public class State { 9 | private final discourje.core.lts.State state; 10 | private final Action action; 11 | private final Collection> nextStates = new LinkedHashSet<>(); 12 | private final Collection> previousStates = new LinkedHashSet<>(); 13 | private final int index; 14 | 15 | public State(discourje.core.lts.State state, Action action, int index) { 16 | this.state = state; 17 | this.action = action; 18 | this.index = index; 19 | } 20 | 21 | public discourje.core.lts.State getState() { 22 | return state; 23 | } 24 | 25 | public Action getAction() { 26 | return action; 27 | } 28 | 29 | public Collection> getNextStates() { 30 | return Collections.unmodifiableCollection(nextStates); 31 | } 32 | 33 | public void addNextState(State state) { 34 | nextStates.add(state); 35 | state.previousStates.add(this); 36 | } 37 | 38 | public Collection> getPreviousStates() { 39 | return Collections.unmodifiableCollection(previousStates); 40 | } 41 | 42 | @Override 43 | public boolean equals(Object o) { 44 | if (this == o) return true; 45 | if (o == null || getClass() != o.getClass()) return false; 46 | State state = (State) o; 47 | return this.state.equals(state.state) && 48 | Objects.equals(action, state.action); 49 | } 50 | 51 | @Override 52 | public int hashCode() { 53 | return Objects.hash(state, action); 54 | } 55 | 56 | @Override 57 | public String toString() { 58 | return previousStates.stream().map(State::getState).collect(Collectors.toList()) + "(" + previousStates.size() + ")" + 59 | " -> " + action + "," + state + " -> " + 60 | nextStates.stream().map(State::getState).collect(Collectors.toList()); 61 | } 62 | 63 | public int getIndex() { 64 | return index; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/discourje/core/ctl/formulas/And.java: -------------------------------------------------------------------------------- 1 | package discourje.core.ctl.formulas; 2 | 3 | import discourje.core.ctl.Formula; 4 | import discourje.core.ctl.Labels; 5 | import discourje.core.ctl.Model; 6 | import discourje.core.ctl.State; 7 | import discourje.core.lts.Action; 8 | import java.util.Arrays; 9 | import java.util.Collection; 10 | import java.util.List; 11 | import java.util.stream.Collectors; 12 | 13 | public class And implements Formula { 14 | private final Formula[] args; 15 | private final int hash; 16 | 17 | public And(Formula... args) { 18 | this.args = args; 19 | hash = Arrays.hashCode(args); 20 | } 21 | 22 | @Override 23 | public boolean isTemporal() { 24 | return Arrays.stream(args).anyMatch(Formula::isTemporal); 25 | } 26 | 27 | @Override 28 | public List> extractWitness(Model model, State source) { 29 | for (Formula arg : args) { 30 | if (!model.hasLabel(source, arg)) { 31 | return arg.extractWitness(model, source); 32 | } 33 | } 34 | 35 | throw new IllegalArgumentException(); 36 | } 37 | 38 | @Override 39 | public Labels label(Model model) { 40 | Labels labels = new Labels(); 41 | Collection argLabels = Arrays.stream(args) 42 | .map(model::calculateLabels) 43 | .collect(Collectors.toList()); 44 | 45 | model.getStates().stream() 46 | .filter(s -> argLabels.stream().allMatch(arg -> arg.hasLabel(s))) 47 | .forEach(labels::setLabel); 48 | return labels; 49 | } 50 | 51 | @Override 52 | public List split() { 53 | return Arrays.asList(args); 54 | } 55 | 56 | @Override 57 | public String toMCRL2() { 58 | String s = "true"; 59 | for (var arg : args) { 60 | if (arg.isAction()) { 61 | s += " && <" + arg.toMCRL2() + ">true"; 62 | } else { 63 | s += " && (" + arg.toMCRL2() + ")"; 64 | } 65 | } 66 | return s; 67 | } 68 | 69 | public String toString() { 70 | return String.format("(%s)", 71 | Arrays.stream(args).map(Object::toString).collect(Collectors.joining(" && ")) 72 | ); 73 | } 74 | 75 | @Override 76 | public boolean equals(Object o) { 77 | if (this == o) return true; 78 | if (o == null || getClass() != o.getClass()) return false; 79 | And that = (And) o; 80 | return Arrays.equals(args, that.args); 81 | } 82 | 83 | @Override 84 | public int hashCode() { 85 | return hash; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/main/java/discourje/core/ctl/formulas/Atomic.java: -------------------------------------------------------------------------------- 1 | package discourje.core.ctl.formulas; 2 | 3 | import discourje.core.lts.Action; 4 | import discourje.core.ctl.Formula; 5 | import discourje.core.ctl.Model; 6 | import discourje.core.ctl.State; 7 | 8 | import java.util.Collections; 9 | import java.util.List; 10 | 11 | public abstract class Atomic implements Formula { 12 | 13 | @Override 14 | public List> extractWitness(Model model, State source) { 15 | if (model.hasLabel(source, this)) { 16 | throw new IllegalArgumentException(); 17 | } 18 | 19 | return Collections.singletonList(Collections.emptyList()); 20 | } 21 | 22 | @Override 23 | public final boolean isTemporal() { 24 | return false; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/discourje/core/ctl/formulas/Implies.java: -------------------------------------------------------------------------------- 1 | package discourje.core.ctl.formulas; 2 | 3 | import discourje.core.ctl.Formula; 4 | import discourje.core.ctl.Labels; 5 | import discourje.core.ctl.Model; 6 | import discourje.core.ctl.State; 7 | import discourje.core.lts.Action; 8 | import java.util.List; 9 | import java.util.Objects; 10 | 11 | public class Implies implements Formula { 12 | private final Formula lhs; 13 | private final Formula rhs; 14 | private final int hash; 15 | 16 | public Implies(Formula lhs, Formula rhs) { 17 | this.lhs = lhs; 18 | this.rhs = rhs; 19 | hash = Objects.hash(this.lhs, this.rhs); 20 | } 21 | 22 | @Override 23 | public boolean isTemporal() { 24 | return lhs.isTemporal() || rhs.isTemporal(); 25 | } 26 | 27 | @Override 28 | public List> extractWitness(Model model, State source) { 29 | if (model.hasLabel(source, this)) { 30 | throw new IllegalArgumentException(); 31 | } 32 | 33 | return rhs.extractWitness(model, source); 34 | } 35 | 36 | @Override 37 | public Labels label(Model model) { 38 | Labels labels = new Labels(); 39 | Labels lhsLabels = model.calculateLabels(lhs); 40 | Labels rhsLabels = model.calculateLabels(rhs); 41 | 42 | for (State state : model.getStates()) { 43 | if (!lhsLabels.hasLabel(state) || rhsLabels.hasLabel(state)) { 44 | labels.setLabel(state); 45 | } 46 | } 47 | return labels; 48 | } 49 | 50 | @Override 51 | public String toMCRL2() { 52 | if (lhs.isAction() && rhs.isAction()) { 53 | throw new UnsupportedOperationException(); 54 | } else if (lhs.isAction() && !rhs.isAction()) { 55 | return "[" + lhs.toMCRL2() + "](" + rhs.toMCRL2() + ")"; 56 | } else if (!lhs.isAction() && rhs.isAction()) { 57 | return "(" + lhs.toMCRL2() + ") => <" + rhs.toMCRL2() + ">true"; 58 | } else if (!lhs.isAction() && !rhs.isAction()) { 59 | return "(" + lhs.toMCRL2() + ") => (" + rhs.toMCRL2() + ")"; 60 | } else { 61 | throw new UnsupportedOperationException(); 62 | } 63 | } 64 | 65 | @Override 66 | public String toString() { 67 | return lhs + " => " + rhs; 68 | } 69 | 70 | @Override 71 | public boolean equals(Object o) { 72 | if (this == o) return true; 73 | if (o == null || getClass() != o.getClass()) return false; 74 | Implies as = (Implies) o; 75 | return lhs.equals(as.lhs) && 76 | rhs.equals(as.rhs); 77 | } 78 | 79 | @Override 80 | public int hashCode() { 81 | return hash; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/main/java/discourje/core/ctl/formulas/Not.java: -------------------------------------------------------------------------------- 1 | package discourje.core.ctl.formulas; 2 | 3 | import discourje.core.ctl.Labels; 4 | import discourje.core.lts.Action; 5 | import discourje.core.ctl.Formula; 6 | import discourje.core.ctl.State; 7 | import discourje.core.ctl.Model; 8 | 9 | import java.util.Collections; 10 | import java.util.List; 11 | import java.util.Objects; 12 | 13 | public class Not implements Formula { 14 | private final Formula arg; 15 | private final int hash; 16 | 17 | public Not(Formula args) { 18 | this.arg = args; 19 | hash = Objects.hash(this.arg); 20 | } 21 | 22 | @Override 23 | public boolean isTemporal() { 24 | return arg.isTemporal(); 25 | } 26 | 27 | @Override 28 | public List> extractWitness(Model model, State source) { 29 | if (isTemporal()) { 30 | throw new IllegalStateException(); 31 | } 32 | 33 | if (model.hasLabel(source, this)) { 34 | throw new IllegalArgumentException(); 35 | } 36 | 37 | return Collections.singletonList(Collections.emptyList()); 38 | } 39 | 40 | @Override 41 | public Labels label(Model model) { 42 | Labels labels = new Labels(); 43 | Labels argLabels = model.calculateLabels(arg); 44 | for (State state : model.getStates()) { 45 | if (!argLabels.hasLabel(state)) { 46 | labels.setLabel(state); 47 | } 48 | } 49 | return labels; 50 | } 51 | 52 | @Override 53 | public String toMCRL2() { 54 | if (arg.isAction()) { 55 | return "[" + arg.toMCRL2() + "]false"; 56 | } else { 57 | return "!(" + arg.toMCRL2() + ")"; 58 | } 59 | } 60 | 61 | public String toString() { 62 | return "!(" + arg + ")"; 63 | } 64 | 65 | @Override 66 | public boolean equals(Object o) { 67 | if (this == o) return true; 68 | if (o == null || getClass() != o.getClass()) return false; 69 | Not that = (Not) o; 70 | return arg.equals(that.arg); 71 | } 72 | 73 | @Override 74 | public int hashCode() { 75 | return hash; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/main/java/discourje/core/ctl/formulas/Or.java: -------------------------------------------------------------------------------- 1 | package discourje.core.ctl.formulas; 2 | 3 | import discourje.core.ctl.Formula; 4 | import discourje.core.ctl.Labels; 5 | import discourje.core.ctl.Model; 6 | import discourje.core.ctl.State; 7 | import discourje.core.lts.Action; 8 | import java.util.Arrays; 9 | import java.util.Collection; 10 | import java.util.Collections; 11 | import java.util.List; 12 | import java.util.stream.Collectors; 13 | 14 | public class Or implements Formula { 15 | private final Formula[] args; 16 | private final int hash; 17 | 18 | public Or(Formula... args) { 19 | this.args = args; 20 | hash = Arrays.hashCode(args); 21 | } 22 | 23 | @Override 24 | public boolean isTemporal() { 25 | return Arrays.stream(args).anyMatch(Formula::isTemporal); 26 | } 27 | 28 | @Override 29 | public List> extractWitness(Model model, State source) { 30 | 31 | if (Arrays.stream(args).filter(Formula::isTemporal).count() > 1) { 32 | throw new IllegalStateException(); 33 | } 34 | 35 | if (model.hasLabel(source, this)) { 36 | throw new IllegalArgumentException(); 37 | } 38 | 39 | for (var arg : args) { 40 | if (arg.isTemporal()) { 41 | return arg.extractWitness(model, source); 42 | } 43 | } 44 | 45 | return Collections.singletonList(Collections.emptyList()); 46 | } 47 | 48 | @Override 49 | public Labels label(Model model) { 50 | Labels labels = new Labels(); 51 | Collection argLabels = Arrays.stream(args) 52 | .map(model::calculateLabels) 53 | .collect(Collectors.toList()); 54 | 55 | model.getStates().stream() 56 | .filter(s -> argLabels.stream().anyMatch(arg -> arg.hasLabel(s))) 57 | .forEach(labels::setLabel); 58 | return labels; 59 | } 60 | 61 | @Override 62 | public String toMCRL2() { 63 | String s = "false"; 64 | for (var arg : args) { 65 | if (arg.isAction()) { 66 | s += " || <" + arg.toMCRL2() + ">true"; 67 | } else { 68 | s += " || (" + arg.toMCRL2() + ")"; 69 | } 70 | } 71 | return s; 72 | } 73 | 74 | public String toString() { 75 | return String.format("(%s)", 76 | Arrays.stream(args).map(Object::toString).collect(Collectors.joining(" || ")) 77 | ); 78 | } 79 | 80 | @Override 81 | public boolean equals(Object o) { 82 | if (this == o) return true; 83 | if (o == null || getClass() != o.getClass()) return false; 84 | Or that = (Or) o; 85 | return Arrays.equals(args, that.args); 86 | } 87 | 88 | @Override 89 | public int hashCode() { 90 | return hash; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/main/java/discourje/core/ctl/formulas/Temporal.java: -------------------------------------------------------------------------------- 1 | package discourje.core.ctl.formulas; 2 | 3 | import discourje.core.ctl.Formula; 4 | 5 | public abstract class Temporal implements Formula { 6 | 7 | @Override 8 | public final boolean isTemporal() { 9 | return true; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/discourje/core/ctl/formulas/atomic/Act.java: -------------------------------------------------------------------------------- 1 | package discourje.core.ctl.formulas.atomic; 2 | 3 | import discourje.core.ctl.Labels; 4 | import discourje.core.ctl.Model; 5 | import discourje.core.ctl.State; 6 | import discourje.core.ctl.formulas.Atomic; 7 | import discourje.core.lts.Action; 8 | import java.util.Objects; 9 | 10 | public class Act extends Atomic { 11 | private final String role; 12 | private final int hash; 13 | 14 | public Act(String role) { 15 | this.role = role; 16 | hash = Objects.hash(this.role); 17 | } 18 | 19 | @Override 20 | public Labels label(Model model) { 21 | Labels labels = new Labels(); 22 | for (State state : model.getStates()) { 23 | Action action = state.getAction(); 24 | if (action != null) { 25 | switch (action.getType()) { 26 | case SYNC: 27 | if (role.equals((action.getSender())) || role.equals(action.getReceiver())) { 28 | labels.setLabel(state); 29 | } 30 | break; 31 | case CLOSE: 32 | case SEND: 33 | if (role.equals((action.getSender()))) { 34 | labels.setLabel(state); 35 | } 36 | break; 37 | case RECEIVE: 38 | if (role.equals(action.getReceiver())) { 39 | labels.setLabel(state); 40 | } 41 | break; 42 | } 43 | } 44 | } 45 | return labels; 46 | } 47 | 48 | @Override 49 | public String toString() { 50 | return String.format("act(%s)", role); 51 | } 52 | 53 | @Override 54 | public boolean equals(Object o) { 55 | if (this == o) return true; 56 | if (o == null || getClass() != o.getClass()) return false; 57 | Act that = (Act) o; 58 | return Objects.equals(role, that.role); 59 | } 60 | 61 | @Override 62 | public int hashCode() { 63 | return hash; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/discourje/core/ctl/formulas/atomic/Close.java: -------------------------------------------------------------------------------- 1 | package discourje.core.ctl.formulas.atomic; 2 | 3 | import discourje.core.ctl.Labels; 4 | import discourje.core.lts.Action; 5 | import discourje.core.ctl.State; 6 | import discourje.core.ctl.Model; 7 | import discourje.core.ctl.formulas.Atomic; 8 | 9 | import java.util.Objects; 10 | 11 | public class Close extends Atomic { 12 | private final String sender; 13 | private final String receiver; 14 | private final int hash; 15 | 16 | public Close(String sender, String receiver) { 17 | this.sender = sender; 18 | this.receiver = receiver; 19 | hash = Objects.hash(this.sender, this.receiver); 20 | } 21 | 22 | @Override 23 | public boolean isAction() { 24 | return true; 25 | } 26 | 27 | @Override 28 | public Labels label(Model model) { 29 | Labels labels = new Labels(); 30 | for (State state : model.getStates()) { 31 | Action action = state.getAction(); 32 | if (action != null && 33 | action.getType() == Action.Type.CLOSE && 34 | (sender == null || sender.equals(action.getSender())) && 35 | (receiver == null || receiver.equals(action.getReceiver()))) { 36 | labels.setLabel(state); 37 | } 38 | } 39 | return labels; 40 | } 41 | 42 | @Override 43 | public String toMCRL2() { 44 | return "close(" + 45 | sender.replace('[', '(').replace(']', ')') + 46 | "," + 47 | receiver.replace('[', '(').replace(']', ')') + 48 | ")"; 49 | } 50 | 51 | public String toString() { 52 | return String.format("close(%s,%s)", sender, receiver); 53 | } 54 | 55 | @Override 56 | public boolean equals(Object o) { 57 | if (this == o) return true; 58 | if (o == null || getClass() != o.getClass()) return false; 59 | Close that = (Close) o; 60 | return sender.equals(that.sender) && 61 | receiver.equals(that.receiver); 62 | } 63 | 64 | @Override 65 | public int hashCode() { 66 | return hash; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/discourje/core/ctl/formulas/atomic/Fin.java: -------------------------------------------------------------------------------- 1 | package discourje.core.ctl.formulas.atomic; 2 | 3 | import discourje.core.ctl.Labels; 4 | import discourje.core.ctl.Model; 5 | import discourje.core.ctl.State; 6 | import discourje.core.ctl.formulas.Atomic; 7 | 8 | public class Fin extends Atomic { 9 | public static final Fin INSTANCE = new Fin(); 10 | public static final int hash = Fin.class.hashCode(); 11 | 12 | private Fin() { 13 | } 14 | 15 | @Override 16 | public Labels label(Model model) { 17 | Labels labels = new Labels(); 18 | for (State state : model.getStates()) { 19 | if (state.getNextStates().isEmpty()) { 20 | labels.setLabel(state); 21 | } 22 | } 23 | return labels; 24 | } 25 | 26 | @Override 27 | public String toMCRL2() { 28 | return "[true]false"; 29 | } 30 | 31 | @Override 32 | public String toString() { 33 | return "fin"; 34 | } 35 | 36 | @Override 37 | public boolean equals(Object o) { 38 | if (this == o) return true; 39 | return o != null && getClass() == o.getClass(); 40 | } 41 | 42 | @Override 43 | public int hashCode() { 44 | return hash; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/discourje/core/ctl/formulas/atomic/Handshake.java: -------------------------------------------------------------------------------- 1 | package discourje.core.ctl.formulas.atomic; 2 | 3 | import discourje.core.ctl.Labels; 4 | import discourje.core.ctl.Model; 5 | import discourje.core.ctl.State; 6 | import discourje.core.ctl.formulas.Atomic; 7 | import discourje.core.lts.Action; 8 | import java.util.Objects; 9 | 10 | public class Handshake extends Atomic { 11 | private final String sender; 12 | private final String receiver; 13 | private final int hash; 14 | 15 | public Handshake(String sender, String receiver) { 16 | this.sender = sender; 17 | this.receiver = receiver; 18 | hash = Objects.hash(this.sender, this.receiver); 19 | } 20 | 21 | @Override 22 | public boolean isAction() { 23 | return true; 24 | } 25 | 26 | @Override 27 | public Labels label(Model model) { 28 | Labels labels = new Labels(); 29 | for (State state : model.getStates()) { 30 | Action action = state.getAction(); 31 | if (action != null && action.getType() == Action.Type.SYNC && 32 | (sender == null || sender.equals(action.getSender())) && 33 | (receiver == null || receiver.equals(action.getReceiver()))) { 34 | labels.setLabel(state); 35 | } 36 | } 37 | return labels; 38 | } 39 | 40 | @Override 41 | public String toMCRL2() { 42 | return "handshake(" + 43 | sender.replace('[', '(').replace(']', ')') + 44 | "," + 45 | receiver.replace('[', '(').replace(']', ')') + 46 | ")"; 47 | } 48 | 49 | @Override 50 | public String toString() { 51 | return String.format("handshake(%s,%s)", sender, receiver); 52 | } 53 | 54 | @Override 55 | public boolean equals(Object o) { 56 | if (this == o) return true; 57 | if (o == null || getClass() != o.getClass()) return false; 58 | Handshake that = (Handshake) o; 59 | return Objects.equals(sender, that.sender) && 60 | Objects.equals(receiver, that.receiver); 61 | } 62 | 63 | @Override 64 | public int hashCode() { 65 | return hash; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/discourje/core/ctl/formulas/atomic/Init.java: -------------------------------------------------------------------------------- 1 | package discourje.core.ctl.formulas.atomic; 2 | 3 | import discourje.core.ctl.Labels; 4 | import discourje.core.lts.Action; 5 | import discourje.core.ctl.State; 6 | import discourje.core.ctl.Model; 7 | import discourje.core.ctl.formulas.Atomic; 8 | 9 | public class Init extends Atomic { 10 | public static final Init INSTANCE = new Init(); 11 | public static final int hash = Init.class.hashCode(); 12 | 13 | private Init() { 14 | } 15 | 16 | @Override 17 | public Labels label(Model model) { 18 | Labels labels = new Labels(); 19 | for (State state : model.getStates()) { 20 | Action action = state.getAction(); 21 | if (action == null) { 22 | labels.setLabel(state); 23 | } 24 | } 25 | return labels; 26 | } 27 | 28 | @Override 29 | public String toString() { 30 | return "init"; 31 | } 32 | 33 | @Override 34 | public boolean equals(Object o) { 35 | if (this == o) return true; 36 | return o != null && getClass() == o.getClass(); 37 | } 38 | 39 | @Override 40 | public int hashCode() { 41 | return hash; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/discourje/core/ctl/formulas/atomic/Receive.java: -------------------------------------------------------------------------------- 1 | package discourje.core.ctl.formulas.atomic; 2 | 3 | import discourje.core.ctl.Labels; 4 | import discourje.core.lts.Action; 5 | import discourje.core.ctl.State; 6 | import discourje.core.ctl.Model; 7 | import discourje.core.ctl.formulas.Atomic; 8 | 9 | import java.util.Objects; 10 | 11 | public class Receive extends Atomic { 12 | private final String sender; 13 | private final String receiver; 14 | private final int hash; 15 | 16 | public Receive(String sender, String receiver) { 17 | this.sender = sender; 18 | this.receiver = receiver; 19 | hash = Objects.hash(this.sender, this.receiver); 20 | } 21 | 22 | @Override 23 | public boolean isAction() { 24 | return true; 25 | } 26 | 27 | @Override 28 | public Labels label(Model model) { 29 | Labels labels = new Labels(); 30 | for (State state : model.getStates()) { 31 | Action action = state.getAction(); 32 | if (action != null && action.getType() == Action.Type.RECEIVE && 33 | (sender == null || sender.equals(action.getSender())) && 34 | (receiver == null || receiver.equals(action.getReceiver()))) { 35 | labels.setLabel(state); 36 | } 37 | } 38 | return labels; 39 | } 40 | 41 | @Override 42 | public String toMCRL2() { 43 | return "receive(" + 44 | sender.replace('[', '(').replace(']', ')') + 45 | "," + 46 | receiver.replace('[', '(').replace(']', ')') + 47 | ")"; 48 | } 49 | 50 | @Override 51 | public String toString() { 52 | return String.format("recv(%s,%s)", sender, receiver); 53 | } 54 | 55 | @Override 56 | public boolean equals(Object o) { 57 | if (this == o) return true; 58 | if (o == null || getClass() != o.getClass()) return false; 59 | Receive that = (Receive) o; 60 | return Objects.equals(sender, that.sender) && 61 | Objects.equals(receiver, that.receiver); 62 | } 63 | 64 | @Override 65 | public int hashCode() { 66 | return hash; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/discourje/core/ctl/formulas/atomic/Send.java: -------------------------------------------------------------------------------- 1 | package discourje.core.ctl.formulas.atomic; 2 | 3 | import discourje.core.ctl.Labels; 4 | import discourje.core.lts.Action; 5 | import discourje.core.ctl.State; 6 | import discourje.core.ctl.Model; 7 | import discourje.core.ctl.formulas.Atomic; 8 | 9 | import java.util.Objects; 10 | 11 | public class Send extends Atomic { 12 | private final String sender; 13 | private final String receiver; 14 | private final int hash; 15 | 16 | public Send(String sender, String receiver) { 17 | this.sender = sender; 18 | this.receiver = receiver; 19 | hash = Objects.hash(this.sender, this.receiver); 20 | } 21 | 22 | @Override 23 | public boolean isAction() { 24 | return true; 25 | } 26 | 27 | @Override 28 | public Labels label(Model model) { 29 | Labels labels = new Labels(); 30 | for (State state : model.getStates()) { 31 | Action action = state.getAction(); 32 | if (action != null && action.getType() == Action.Type.SEND && 33 | (sender == null || sender.equals(action.getSender())) && 34 | (receiver == null || receiver.equals(action.getReceiver()))) { 35 | labels.setLabel(state); 36 | } 37 | } 38 | return labels; 39 | } 40 | 41 | @Override 42 | public String toMCRL2() { 43 | return "send(" + 44 | sender.replace('[', '(').replace(']', ')') + 45 | "," + 46 | receiver.replace('[', '(').replace(']', ')') + 47 | ") || handshake(" + 48 | sender.replace('[', '(').replace(']', ')') + 49 | "," + 50 | receiver.replace('[', '(').replace(']', ')') + 51 | ")"; 52 | } 53 | 54 | @Override 55 | public String toString() { 56 | return String.format("send(%s,%s)", sender, receiver); 57 | } 58 | 59 | @Override 60 | public boolean equals(Object o) { 61 | if (this == o) return true; 62 | if (o == null || getClass() != o.getClass()) return false; 63 | Send that = (Send) o; 64 | return Objects.equals(sender, that.sender) && 65 | Objects.equals(receiver, that.receiver); 66 | } 67 | 68 | @Override 69 | public int hashCode() { 70 | return hash; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/discourje/core/ctl/formulas/atomic/True.java: -------------------------------------------------------------------------------- 1 | package discourje.core.ctl.formulas.atomic; 2 | 3 | import discourje.core.ctl.Labels; 4 | import discourje.core.ctl.State; 5 | import discourje.core.ctl.Model; 6 | import discourje.core.ctl.formulas.Atomic; 7 | 8 | public class True extends Atomic { 9 | public static final True INSTANCE = new True(); 10 | public static final int hash = True.class.hashCode(); 11 | 12 | private True() { 13 | } 14 | 15 | @Override 16 | public Labels label(Model model) { 17 | Labels labels = new Labels(); 18 | for (State state : model.getStates()) { 19 | labels.setLabel(state); 20 | } 21 | return labels; 22 | } 23 | 24 | public String toString() { 25 | return "true"; 26 | } 27 | 28 | @Override 29 | public boolean equals(Object o) { 30 | if (this == o) return true; 31 | return o != null && getClass() == o.getClass(); 32 | } 33 | 34 | @Override 35 | public int hashCode() { 36 | return hash; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/discourje/core/ctl/formulas/temporal/AG.java: -------------------------------------------------------------------------------- 1 | package discourje.core.ctl.formulas.temporal; 2 | 3 | import discourje.core.ctl.Labels; 4 | import discourje.core.lts.Action; 5 | import discourje.core.ctl.State; 6 | import discourje.core.ctl.Model; 7 | import discourje.core.ctl.Formula; 8 | import discourje.core.ctl.formulas.Temporal; 9 | 10 | import java.util.*; 11 | import java.util.function.BiFunction; 12 | 13 | import static discourje.core.ctl.Formulas.EF; 14 | import static discourje.core.ctl.Formulas.not; 15 | 16 | public class AG extends Temporal { 17 | private final Formula arg; 18 | private final int hash; 19 | 20 | public AG(Formula arg) { 21 | this.arg = arg; 22 | hash = Objects.hash(this.arg); 23 | } 24 | 25 | @Override 26 | public List> extractWitness(Model model, State source) { 27 | State target = null; 28 | var parents = new HashMap, State>(); 29 | 30 | /* 31 | * Search for a shortest path from source to target, such that: (a) every state on the path, *except* target, 32 | * satisfies arg; (b) target violates arg. 33 | */ 34 | 35 | var done = new HashSet>(); 36 | var todo = new LinkedList>(); 37 | 38 | done.add(source); 39 | todo.offer(source); 40 | 41 | while (!todo.isEmpty()) { 42 | var s = todo.poll(); 43 | if (!model.hasLabel(s, arg)) { 44 | target = s; 45 | break; 46 | } else { 47 | for (State next : s.getNextStates()) { 48 | if (!done.contains(next)) { 49 | parents.put(next, s); 50 | done.add(next); 51 | todo.offer(next); 52 | } 53 | } 54 | } 55 | } 56 | 57 | /* 58 | * Construct segments 59 | */ 60 | 61 | BiFunction, State, List> f = (s, t) -> { 62 | var segment = new ArrayList(); 63 | while (!s.equals(t)) { 64 | segment.add(t.getAction()); 65 | t = parents.get(t); 66 | } 67 | Collections.reverse(segment); 68 | return segment; 69 | }; 70 | 71 | var segment = f.apply(source, target); 72 | var segments = new ArrayList>(); 73 | segments.add(segment); 74 | segments.addAll(arg.extractWitness(model, target)); 75 | return segments; 76 | } 77 | 78 | @Override 79 | public Labels label(Model model) { 80 | Formula ag = not(EF(not(arg))); 81 | return model.calculateLabels(ag); 82 | } 83 | 84 | @Override 85 | public String toMCRL2() { 86 | if (arg.isAction()) { 87 | return "[true*]<" + arg.toMCRL2() + ">true"; 88 | } else { 89 | return "[true*](" + arg.toMCRL2() + ")"; 90 | } 91 | } 92 | 93 | @Override 94 | public String toString() { 95 | return "AG(" + arg + ")"; 96 | } 97 | 98 | @Override 99 | public boolean equals(Object o) { 100 | if (this == o) return true; 101 | if (o == null || getClass() != o.getClass()) return false; 102 | AG that = (AG) o; 103 | return arg.equals(that.arg); 104 | } 105 | 106 | @Override 107 | public int hashCode() { 108 | return hash; 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /src/main/java/discourje/core/ctl/formulas/temporal/AH.java: -------------------------------------------------------------------------------- 1 | package discourje.core.ctl.formulas.temporal; 2 | 3 | import discourje.core.ctl.Labels; 4 | import discourje.core.lts.Action; 5 | import discourje.core.ctl.State; 6 | import discourje.core.ctl.Model; 7 | import discourje.core.ctl.Formula; 8 | import discourje.core.ctl.formulas.Temporal; 9 | 10 | import java.util.Collections; 11 | import java.util.List; 12 | import java.util.Objects; 13 | 14 | import static discourje.core.ctl.Formulas.EP; 15 | import static discourje.core.ctl.Formulas.and; 16 | import static discourje.core.ctl.Formulas.init; 17 | import static discourje.core.ctl.Formulas.not; 18 | 19 | public class AH extends Temporal { 20 | private final Formula arg; 21 | private final int hash; 22 | 23 | public AH(Formula arg) { 24 | this.arg = arg; 25 | hash = Objects.hash(this.arg); 26 | } 27 | 28 | @Override 29 | public List> extractWitness(Model model, State source) { 30 | if (model.hasLabel(source, this)) { 31 | throw new IllegalArgumentException(); 32 | } 33 | 34 | return Collections.emptyList(); 35 | } 36 | 37 | @Override 38 | public Labels label(Model model) { 39 | Formula ah = not(EP(and(not(arg), not(init())))); 40 | return model.calculateLabels(ah); 41 | } 42 | 43 | @Override 44 | public String toString() { 45 | return "AH(" + arg + ")"; 46 | } 47 | 48 | @Override 49 | public boolean equals(Object o) { 50 | if (this == o) return true; 51 | if (o == null || getClass() != o.getClass()) return false; 52 | AH that = (AH) o; 53 | return arg.equals(that.arg); 54 | } 55 | 56 | @Override 57 | public int hashCode() { 58 | return hash; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/discourje/core/ctl/formulas/temporal/AP.java: -------------------------------------------------------------------------------- 1 | package discourje.core.ctl.formulas.temporal; 2 | 3 | import discourje.core.ctl.Formula; 4 | import discourje.core.ctl.Labels; 5 | import discourje.core.ctl.Model; 6 | import discourje.core.ctl.State; 7 | import discourje.core.ctl.formulas.Temporal; 8 | import discourje.core.ctl.formulas.atomic.True; 9 | import discourje.core.lts.Action; 10 | import java.util.Collections; 11 | import java.util.List; 12 | import java.util.Objects; 13 | 14 | public class AP extends Temporal { 15 | private final Formula arg; 16 | private final int hash; 17 | 18 | public AP(Formula arg) { 19 | this.arg = arg; 20 | hash = Objects.hash(this.arg); 21 | } 22 | 23 | @Override 24 | public List> extractWitness(Model model, State source) { 25 | if (model.hasLabel(source, this)) { 26 | throw new IllegalArgumentException(); 27 | } 28 | 29 | return Collections.emptyList(); 30 | } 31 | 32 | @Override 33 | public Labels label(Model model) { 34 | Formula ap = new AS(True.INSTANCE, arg); 35 | return model.calculateLabels(ap); 36 | } 37 | 38 | @Override 39 | public String toString() { 40 | return "AP(" + arg + ")"; 41 | } 42 | 43 | @Override 44 | public boolean equals(Object o) { 45 | if (this == o) return true; 46 | if (o == null || getClass() != o.getClass()) return false; 47 | AP that = (AP) o; 48 | return arg.equals(that.arg); 49 | } 50 | 51 | @Override 52 | public int hashCode() { 53 | return hash; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/discourje/core/ctl/formulas/temporal/AS.java: -------------------------------------------------------------------------------- 1 | package discourje.core.ctl.formulas.temporal; 2 | 3 | import discourje.core.ctl.Labels; 4 | import discourje.core.lts.Action; 5 | import discourje.core.ctl.State; 6 | import discourje.core.ctl.Model; 7 | import discourje.core.ctl.Formula; 8 | import discourje.core.ctl.formulas.Temporal; 9 | 10 | import java.util.*; 11 | 12 | public class AS extends Temporal { 13 | private final Formula lhs; 14 | private final Formula rhs; 15 | private final int hash; 16 | 17 | public AS(Formula lhs, Formula rhs) { 18 | this.lhs = lhs; 19 | this.rhs = rhs; 20 | hash = Objects.hash(this.lhs, this.rhs); 21 | } 22 | 23 | @Override 24 | public List> extractWitness(Model model, State source) { 25 | if (model.hasLabel(source, this)) { 26 | throw new IllegalArgumentException(); 27 | } 28 | 29 | return Collections.emptyList(); 30 | } 31 | 32 | @Override 33 | public Labels label(Model model) { 34 | Labels labels = new Labels(); 35 | Labels lhsLabels = model.calculateLabels(lhs); 36 | Labels rhsLabels = model.calculateLabels(rhs); 37 | 38 | Queue> states = new LinkedList<>(model.getStates()); 39 | while (!states.isEmpty()) { 40 | State state = states.remove(); 41 | if (rhsLabels.hasLabel(state) || 42 | (lhsLabels.hasLabel(state) && !state.getPreviousStates().isEmpty() && labels.allHaveLabel(state.getPreviousStates()))) { 43 | if (labels.setLabel(state)) { 44 | states.addAll(state.getNextStates()); 45 | } 46 | } 47 | } 48 | return labels; 49 | } 50 | 51 | public String toString() { 52 | return "AS(" + lhs + "," + rhs + ")"; 53 | } 54 | 55 | @Override 56 | public boolean equals(Object o) { 57 | if (this == o) return true; 58 | if (o == null || getClass() != o.getClass()) return false; 59 | AS as = (AS) o; 60 | return lhs.equals(as.lhs) && 61 | rhs.equals(as.rhs); 62 | } 63 | 64 | @Override 65 | public int hashCode() { 66 | return hash; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/discourje/core/ctl/formulas/temporal/AU.java: -------------------------------------------------------------------------------- 1 | package discourje.core.ctl.formulas.temporal; 2 | 3 | import discourje.core.ctl.Formula; 4 | import discourje.core.ctl.Labels; 5 | import discourje.core.ctl.Model; 6 | import discourje.core.ctl.State; 7 | import discourje.core.ctl.formulas.Temporal; 8 | import discourje.core.lts.Action; 9 | import java.util.LinkedList; 10 | import java.util.List; 11 | import java.util.Objects; 12 | import java.util.Queue; 13 | 14 | public class AU extends Temporal { 15 | private final Formula lhs; 16 | private final Formula rhs; 17 | private final int hash; 18 | 19 | public AU(Formula lhs, Formula rhs) { 20 | this.lhs = lhs; 21 | this.rhs = rhs; 22 | hash = Objects.hash(this.lhs, this.rhs); 23 | } 24 | 25 | @Override 26 | public List> extractWitness(Model model, State source) { 27 | throw new UnsupportedOperationException(); 28 | } 29 | 30 | @Override 31 | public Labels label(Model model) { 32 | Labels labels = new Labels(); 33 | Labels lhsLabels = model.calculateLabels(lhs); 34 | Labels rhsLabels = model.calculateLabels(rhs); 35 | Queue> states = new LinkedList<>(model.getStates()); 36 | while (!states.isEmpty()) { 37 | State state = states.remove(); 38 | if (rhsLabels.hasLabel(state) || 39 | (lhsLabels.hasLabel(state) && !state.getNextStates().isEmpty() && labels.allHaveLabel(state.getNextStates()))) { 40 | if (labels.setLabel(state)) { 41 | states.addAll(state.getPreviousStates()); 42 | } 43 | } 44 | } 45 | return labels; 46 | } 47 | 48 | public String toString() { 49 | return "AU(" + lhs + "," + rhs + ")"; 50 | } 51 | 52 | @Override 53 | public boolean equals(Object o) { 54 | if (this == o) return true; 55 | if (o == null || getClass() != o.getClass()) return false; 56 | AU as = (AU) o; 57 | return lhs.equals(as.lhs) && 58 | rhs.equals(as.rhs); 59 | } 60 | 61 | @Override 62 | public int hashCode() { 63 | return hash; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/discourje/core/ctl/formulas/temporal/AX.java: -------------------------------------------------------------------------------- 1 | package discourje.core.ctl.formulas.temporal; 2 | 3 | import discourje.core.ctl.Labels; 4 | import discourje.core.lts.Action; 5 | import discourje.core.ctl.State; 6 | import discourje.core.ctl.Model; 7 | import discourje.core.ctl.Formula; 8 | import discourje.core.ctl.formulas.Temporal; 9 | 10 | import java.util.*; 11 | 12 | public class AX extends Temporal { 13 | private final Formula arg; 14 | private final int hash; 15 | 16 | public AX(Formula arg) { 17 | this.arg = arg; 18 | hash = Objects.hash(this.arg); 19 | } 20 | 21 | @Override 22 | public List> extractWitness(Model model, State source) { 23 | if (!model.hasLabel(source, this)) { 24 | var argLabels = model.getLabels(arg); 25 | for (var next : source.getNextStates()) { 26 | if (!argLabels.hasLabel(next)) { 27 | var segments = new ArrayList>(); 28 | segments.add(Collections.singletonList(next.getAction())); 29 | segments.addAll(arg.extractWitness(model, next)); 30 | return segments; 31 | } 32 | } 33 | } 34 | throw new IllegalArgumentException(); 35 | } 36 | 37 | @Override 38 | public Labels label(Model model) { 39 | Labels labels = new Labels(); 40 | Labels argLabels = model.calculateLabels(arg); 41 | for (State state : model.getStates()) { 42 | if (!state.getNextStates().isEmpty() && argLabels.allHaveLabel(state.getNextStates())) { 43 | labels.setLabel(state); 44 | } 45 | } 46 | return labels; 47 | } 48 | 49 | @Override 50 | public String toMCRL2() { 51 | if (arg.isAction()) { 52 | return "true && [true]<" + arg.toMCRL2() + ">true"; 53 | } else { 54 | return "true && [true](" + arg.toMCRL2() + ")"; 55 | } 56 | } 57 | 58 | @Override 59 | public String toString() { 60 | return "AX(" + arg + ")"; 61 | } 62 | 63 | @Override 64 | public boolean equals(Object o) { 65 | if (this == o) return true; 66 | if (o == null || getClass() != o.getClass()) return false; 67 | AX that = (AX) o; 68 | return arg.equals(that.arg); 69 | } 70 | 71 | @Override 72 | public int hashCode() { 73 | return hash; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/discourje/core/ctl/formulas/temporal/AY.java: -------------------------------------------------------------------------------- 1 | package discourje.core.ctl.formulas.temporal; 2 | 3 | import discourje.core.ctl.Labels; 4 | import discourje.core.lts.Action; 5 | import discourje.core.ctl.State; 6 | import discourje.core.ctl.Model; 7 | import discourje.core.ctl.Formula; 8 | import discourje.core.ctl.formulas.Temporal; 9 | 10 | import java.util.Collections; 11 | import java.util.List; 12 | import java.util.Objects; 13 | 14 | public class AY extends Temporal { 15 | private final Formula arg; 16 | private final int hash; 17 | 18 | public AY(Formula arg) { 19 | this.arg = arg; 20 | hash = Objects.hash(this.arg); 21 | } 22 | 23 | @Override 24 | public List> extractWitness(Model model, State source) { 25 | if (model.hasLabel(source, this)) { 26 | throw new IllegalArgumentException(); 27 | } 28 | 29 | return Collections.emptyList(); 30 | } 31 | 32 | @Override 33 | public Labels label(Model model) { 34 | Labels labels = new Labels(); 35 | Labels argLabels = model.calculateLabels(arg); 36 | for (State state : model.getStates()) { 37 | if (!state.getPreviousStates().isEmpty() && argLabels.allHaveLabel(state.getPreviousStates())) { 38 | labels.setLabel(state); 39 | } 40 | } 41 | return labels; 42 | } 43 | 44 | @Override 45 | public String toString() { 46 | return "AY(" + arg + ")"; 47 | } 48 | 49 | @Override 50 | public boolean equals(Object o) { 51 | if (this == o) return true; 52 | if (o == null || getClass() != o.getClass()) return false; 53 | AY that = (AY) o; 54 | return arg.equals(that.arg); 55 | } 56 | 57 | @Override 58 | public int hashCode() { 59 | return hash; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/discourje/core/ctl/formulas/temporal/EF.java: -------------------------------------------------------------------------------- 1 | package discourje.core.ctl.formulas.temporal; 2 | 3 | import discourje.core.ctl.Labels; 4 | import discourje.core.lts.Action; 5 | import discourje.core.ctl.State; 6 | import discourje.core.ctl.Model; 7 | import discourje.core.ctl.Formula; 8 | import discourje.core.ctl.formulas.Temporal; 9 | import discourje.core.ctl.formulas.atomic.True; 10 | 11 | import java.util.Collections; 12 | import java.util.List; 13 | import java.util.Objects; 14 | 15 | public class EF extends Temporal { 16 | private final Formula arg; 17 | private final int hash; 18 | 19 | public EF(Formula arg) { 20 | this.arg = arg; 21 | hash = Objects.hash(this.arg); 22 | } 23 | 24 | @Override 25 | public List> extractWitness(Model model, State source) { 26 | if (!model.hasLabel(source, this)) { 27 | return Collections.singletonList(Collections.emptyList()); 28 | } else { 29 | throw new IllegalArgumentException(); 30 | } 31 | } 32 | 33 | @Override 34 | public Labels label(Model model) { 35 | Formula ef = new EU(True.INSTANCE, arg); 36 | return model.calculateLabels(ef); 37 | } 38 | 39 | @Override 40 | public String toMCRL2() { 41 | if (arg.isAction()) { 42 | return "<" + arg.toMCRL2() + ">true"; 43 | } else { 44 | return "(" + arg.toMCRL2() + ")"; 45 | } 46 | } 47 | 48 | @Override 49 | public String toString() { 50 | return "EF(" + arg + ")"; 51 | } 52 | 53 | @Override 54 | public boolean equals(Object o) { 55 | if (this == o) return true; 56 | if (o == null || getClass() != o.getClass()) return false; 57 | EF that = (EF) o; 58 | return arg.equals(that.arg); 59 | } 60 | 61 | @Override 62 | public int hashCode() { 63 | return hash; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/discourje/core/ctl/formulas/temporal/EG.java: -------------------------------------------------------------------------------- 1 | package discourje.core.ctl.formulas.temporal; 2 | 3 | import discourje.core.ctl.Labels; 4 | import discourje.core.lts.Action; 5 | import discourje.core.ctl.State; 6 | import discourje.core.ctl.Model; 7 | import discourje.core.ctl.Formula; 8 | import discourje.core.ctl.formulas.Temporal; 9 | 10 | import java.util.Collections; 11 | import java.util.List; 12 | import java.util.Objects; 13 | import static discourje.core.ctl.Formulas.not; 14 | import static discourje.core.ctl.Formulas.AF; 15 | 16 | public class EG extends Temporal { 17 | private final Formula arg; 18 | private final int hash; 19 | 20 | public EG(Formula arg) { 21 | this.arg = arg; 22 | hash = Objects.hash(this.arg); 23 | } 24 | 25 | @Override 26 | public List> extractWitness(Model model, State source) { 27 | if (!model.hasLabel(source, this)) { 28 | return Collections.singletonList(Collections.emptyList()); 29 | } else { 30 | throw new IllegalArgumentException(); 31 | } 32 | } 33 | 34 | @Override 35 | public Labels label(Model model) { 36 | Formula eg = not(AF(not(arg))); 37 | return model.calculateLabels(eg); 38 | } 39 | 40 | @Override 41 | public String toString() { 42 | return "EG(" + arg + ")"; 43 | } 44 | 45 | @Override 46 | public boolean equals(Object o) { 47 | if (this == o) return true; 48 | if (o == null || getClass() != o.getClass()) return false; 49 | EG that = (EG) o; 50 | return arg.equals(that.arg); 51 | } 52 | 53 | @Override 54 | public int hashCode() { 55 | return hash; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/discourje/core/ctl/formulas/temporal/EH.java: -------------------------------------------------------------------------------- 1 | package discourje.core.ctl.formulas.temporal; 2 | 3 | import discourje.core.ctl.Labels; 4 | import discourje.core.lts.Action; 5 | import discourje.core.ctl.State; 6 | import discourje.core.ctl.Model; 7 | import discourje.core.ctl.Formula; 8 | import discourje.core.ctl.formulas.Temporal; 9 | 10 | import java.util.Collections; 11 | import java.util.List; 12 | import java.util.Objects; 13 | 14 | import static discourje.core.ctl.Formulas.AP; 15 | import static discourje.core.ctl.Formulas.and; 16 | import static discourje.core.ctl.Formulas.init; 17 | import static discourje.core.ctl.Formulas.not; 18 | 19 | public class EH extends Temporal { 20 | private final Formula arg; 21 | private final int hash; 22 | 23 | public EH(Formula arg) { 24 | this.arg = arg; 25 | hash = Objects.hash(this.arg); 26 | } 27 | 28 | @Override 29 | public List> extractWitness(Model model, State source) { 30 | if (model.hasLabel(source, this)) { 31 | throw new IllegalArgumentException(); 32 | } 33 | 34 | return Collections.emptyList(); 35 | } 36 | 37 | @Override 38 | public Labels label(Model model) { 39 | Formula eh = not(AP(and(not(arg), not(init())))); 40 | return model.calculateLabels(eh); 41 | } 42 | 43 | @Override 44 | public String toString() { 45 | return "EH(" + arg + ")"; 46 | } 47 | 48 | @Override 49 | public boolean equals(Object o) { 50 | if (this == o) return true; 51 | if (o == null || getClass() != o.getClass()) return false; 52 | EH that = (EH) o; 53 | return arg.equals(that.arg); 54 | } 55 | 56 | @Override 57 | public int hashCode() { 58 | return hash; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/discourje/core/ctl/formulas/temporal/EP.java: -------------------------------------------------------------------------------- 1 | package discourje.core.ctl.formulas.temporal; 2 | 3 | import discourje.core.ctl.Formula; 4 | import discourje.core.ctl.Labels; 5 | import discourje.core.ctl.Model; 6 | import discourje.core.ctl.State; 7 | import discourje.core.ctl.formulas.Temporal; 8 | import discourje.core.ctl.formulas.atomic.True; 9 | import discourje.core.lts.Action; 10 | import java.util.Collections; 11 | import java.util.List; 12 | import java.util.Objects; 13 | 14 | public class EP extends Temporal { 15 | private final Formula arg; 16 | private final int hash; 17 | 18 | public EP(Formula arg) { 19 | this.arg = arg; 20 | hash = Objects.hash(this.arg); 21 | } 22 | 23 | @Override 24 | public List> extractWitness(Model model, State source) { 25 | if (model.hasLabel(source, this)) { 26 | throw new IllegalArgumentException(); 27 | } 28 | 29 | return Collections.emptyList(); 30 | } 31 | 32 | @Override 33 | public Labels label(Model model) { 34 | Formula ep = new ES(True.INSTANCE, arg); 35 | return model.calculateLabels(ep); 36 | } 37 | 38 | @Override 39 | public String toString() { 40 | return "EP(" + arg + ")"; 41 | } 42 | 43 | @Override 44 | public boolean equals(Object o) { 45 | if (this == o) return true; 46 | if (o == null || getClass() != o.getClass()) return false; 47 | EP that = (EP) o; 48 | return arg.equals(that.arg); 49 | } 50 | 51 | @Override 52 | public int hashCode() { 53 | return hash; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/discourje/core/ctl/formulas/temporal/ES.java: -------------------------------------------------------------------------------- 1 | package discourje.core.ctl.formulas.temporal; 2 | 3 | import discourje.core.ctl.Labels; 4 | import discourje.core.lts.Action; 5 | import discourje.core.ctl.State; 6 | import discourje.core.ctl.Model; 7 | import discourje.core.ctl.Formula; 8 | import discourje.core.ctl.formulas.Temporal; 9 | 10 | import java.util.*; 11 | 12 | public class ES extends Temporal { 13 | private final Formula lhs; 14 | private final Formula rhs; 15 | private final int hash; 16 | 17 | public ES(Formula lhs, Formula rhs) { 18 | this.lhs = lhs; 19 | this.rhs = rhs; 20 | hash = Objects.hash(this.lhs, this.rhs); 21 | } 22 | 23 | @Override 24 | public List> extractWitness(Model model, State source) { 25 | if (model.hasLabel(source, this)) { 26 | throw new IllegalArgumentException(); 27 | } 28 | 29 | return Collections.emptyList(); 30 | } 31 | 32 | @Override 33 | public Labels label(Model model) { 34 | Labels labels = new Labels(); 35 | Labels lhsLabels = model.calculateLabels(lhs); 36 | Labels rhsLabels = model.calculateLabels(rhs); 37 | 38 | Queue> states = new LinkedList<>(model.getStates()); 39 | while (!states.isEmpty()) { 40 | State state = states.remove(); 41 | if (rhsLabels.hasLabel(state) || 42 | (lhsLabels.hasLabel(state) && !state.getPreviousStates().isEmpty() && labels.anyHaveLabel(state.getPreviousStates()))) { 43 | if (labels.setLabel(state)) { 44 | states.addAll(state.getNextStates()); 45 | } 46 | } 47 | } 48 | return labels; 49 | } 50 | 51 | @Override 52 | public String toString() { 53 | return "ES(" + lhs + "," + rhs + ")"; 54 | } 55 | 56 | @Override 57 | public boolean equals(Object o) { 58 | if (this == o) return true; 59 | if (o == null || getClass() != o.getClass()) return false; 60 | ES as = (ES) o; 61 | return lhs.equals(as.lhs) && 62 | rhs.equals(as.rhs); 63 | } 64 | 65 | @Override 66 | public int hashCode() { 67 | return hash; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/discourje/core/ctl/formulas/temporal/EU.java: -------------------------------------------------------------------------------- 1 | package discourje.core.ctl.formulas.temporal; 2 | 3 | import discourje.core.ctl.Labels; 4 | import discourje.core.lts.Action; 5 | import discourje.core.ctl.State; 6 | import discourje.core.ctl.Model; 7 | import discourje.core.ctl.Formula; 8 | import discourje.core.ctl.formulas.Temporal; 9 | 10 | import java.util.*; 11 | 12 | public class EU extends Temporal { 13 | private final Formula lhs; 14 | private final Formula rhs; 15 | private final int hash; 16 | 17 | public EU(Formula lhs, Formula rhs) { 18 | this.lhs = lhs; 19 | this.rhs = rhs; 20 | hash = Objects.hash(this.lhs, this.rhs); 21 | } 22 | 23 | @Override 24 | public List> extractWitness(Model model, State source) { 25 | if (!model.hasLabel(source, this)) { 26 | return Collections.singletonList(Collections.emptyList()); 27 | } else { 28 | throw new IllegalArgumentException(); 29 | } 30 | } 31 | 32 | @Override 33 | public Labels label(Model model) { 34 | Labels labels = new Labels(); 35 | Labels lhsLabels = model.calculateLabels(lhs); 36 | Labels rhsLabels = model.calculateLabels(rhs); 37 | 38 | Queue> states = new LinkedList<>(model.getStates()); 39 | while (!states.isEmpty()) { 40 | State state = states.remove(); 41 | if (rhsLabels.hasLabel(state) || 42 | (lhsLabels.hasLabel(state) && !state.getNextStates().isEmpty() && labels.anyHaveLabel(state.getNextStates()))) { 43 | if (labels.setLabel(state)) { 44 | states.addAll(state.getPreviousStates()); 45 | } 46 | } 47 | } 48 | return labels; 49 | } 50 | 51 | @Override 52 | public String toString() { 53 | return "EU(" + lhs + "," + rhs + ")"; 54 | } 55 | 56 | @Override 57 | public boolean equals(Object o) { 58 | if (this == o) return true; 59 | if (o == null || getClass() != o.getClass()) return false; 60 | EU as = (EU) o; 61 | return lhs.equals(as.lhs) && 62 | rhs.equals(as.rhs); 63 | } 64 | 65 | @Override 66 | public int hashCode() { 67 | return hash; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/discourje/core/ctl/formulas/temporal/EX.java: -------------------------------------------------------------------------------- 1 | package discourje.core.ctl.formulas.temporal; 2 | 3 | import discourje.core.ctl.Labels; 4 | import discourje.core.lts.Action; 5 | import discourje.core.ctl.State; 6 | import discourje.core.ctl.Model; 7 | import discourje.core.ctl.Formula; 8 | import discourje.core.ctl.formulas.Temporal; 9 | 10 | import java.util.Collections; 11 | import java.util.List; 12 | import java.util.Objects; 13 | 14 | public class EX extends Temporal { 15 | private final Formula arg; 16 | private final int hash; 17 | 18 | public EX(Formula arg) { 19 | this.arg = arg; 20 | hash = Objects.hash(this.arg); 21 | } 22 | 23 | @Override 24 | public List> extractWitness(Model model, State source) { 25 | if (!model.hasLabel(source, this)) { 26 | return Collections.singletonList(Collections.emptyList()); 27 | } else { 28 | throw new IllegalArgumentException(); 29 | } 30 | } 31 | 32 | @Override 33 | public Labels label(Model model) { 34 | Labels labels = new Labels(); 35 | Labels argLabels = model.calculateLabels(arg); 36 | for (State state : model.getStates()) { 37 | if (!state.getNextStates().isEmpty() && argLabels.anyHaveLabel(state.getNextStates())) { 38 | labels.setLabel(state); 39 | } 40 | } 41 | return labels; 42 | } 43 | 44 | @Override 45 | public String toString() { 46 | return "EX(" + arg + ")"; 47 | } 48 | 49 | @Override 50 | public boolean equals(Object o) { 51 | if (this == o) return true; 52 | if (o == null || getClass() != o.getClass()) return false; 53 | EX that = (EX) o; 54 | return arg.equals(that.arg); 55 | } 56 | 57 | @Override 58 | public int hashCode() { 59 | return hash; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/discourje/core/ctl/formulas/temporal/EY.java: -------------------------------------------------------------------------------- 1 | package discourje.core.ctl.formulas.temporal; 2 | 3 | import discourje.core.ctl.Labels; 4 | import discourje.core.lts.Action; 5 | import discourje.core.ctl.State; 6 | import discourje.core.ctl.Model; 7 | import discourje.core.ctl.Formula; 8 | import discourje.core.ctl.formulas.Temporal; 9 | 10 | import java.util.Collections; 11 | import java.util.List; 12 | import java.util.Objects; 13 | 14 | public class EY extends Temporal { 15 | private final Formula arg; 16 | private final int hash; 17 | 18 | public EY(Formula arg) { 19 | this.arg = arg; 20 | hash = Objects.hash(this.arg); 21 | } 22 | 23 | @Override 24 | public List> extractWitness(Model model, State source) { 25 | if (model.hasLabel(source, this)) { 26 | throw new IllegalArgumentException(); 27 | } 28 | 29 | return Collections.emptyList(); 30 | } 31 | 32 | @Override 33 | public Labels label(Model model) { 34 | Labels labels = new Labels(); 35 | Labels argLabels = model.calculateLabels(arg); 36 | for (State state : model.getStates()) { 37 | if (!state.getPreviousStates().isEmpty() && argLabels.anyHaveLabel(state.getPreviousStates())) { 38 | labels.setLabel(state); 39 | } 40 | } 41 | return labels; 42 | } 43 | 44 | @Override 45 | public String toString() { 46 | return "EY(" + arg + ")"; 47 | } 48 | 49 | @Override 50 | public boolean equals(Object o) { 51 | if (this == o) return true; 52 | if (o == null || getClass() != o.getClass()) return false; 53 | EY that = (EY) o; 54 | return arg.equals(that.arg); 55 | } 56 | 57 | @Override 58 | public int hashCode() { 59 | return hash; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/discourje/core/ctl/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * This package contains code to validate {@link discourje.core.lts.LTS} objects against a set of rules. 3 | * The validation makes use of Computation Tree Logic (CTL) to check conformation to the rules. 4 | * A good explanation of this technique is given in 'Model Checking' by Madhavan Mukund (https://www.cmi.ac.in/~madhavan/papers/pdf/resonance-jul2009.pdf). 5 | *

6 | * Entrance of this package is {@link discourje.core.ctl.ModelChecker}. 7 | * The ModelChecker checks by default against the rules given in {@link discourje.core.ctl.ModelChecker#DEFAULT_RULES}. 8 | * This behaviour can be overruled by providing your own set of rules in {@link discourje.core.ctl.ModelChecker#ModelChecker(discourje.core.lts.LTS, java.util.Collection)}. 9 | *

10 | * You can provide your own rules. 11 | * They can be created by implementing {@link discourje.core.ctl.Rule}. 12 | * The actual rule can be constructed using the method on {@link discourje.core.ctl.Formulas}. 13 | */ 14 | package discourje.core.ctl; 15 | -------------------------------------------------------------------------------- /src/main/java/discourje/core/ctl/rules/Causality.java: -------------------------------------------------------------------------------- 1 | package discourje.core.ctl.rules; 2 | 3 | import discourje.core.ctl.Formula; 4 | import discourje.core.ctl.Rule; 5 | import static discourje.core.ctl.Formulas.EF; 6 | import static discourje.core.ctl.Formulas.EX; 7 | import static discourje.core.ctl.Formulas.and; 8 | import static discourje.core.ctl.Formulas.implies; 9 | import static discourje.core.ctl.Formulas.init; 10 | import static discourje.core.ctl.Formulas.or; 11 | import static discourje.core.ctl.Formulas.receiveOrHandshake; 12 | import static discourje.core.ctl.Formulas.sendOrHandshake; 13 | 14 | public class Causality extends Rule { 15 | 16 | @Override 17 | public String createErrorDescription(String r1, String r2) { 18 | return String.format("A message is sent from %s to %s for which no cause could be found.", r1, r2); 19 | } 20 | 21 | @Override 22 | public Formula createCtlFormula(String r1, String r2) { 23 | return implies(EF(sendOrHandshake(r1, r2)), EF(and(EX(sendOrHandshake(r1, r2)), or(init(), receiveOrHandshake(null, r1))))); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/discourje/core/ctl/rules/CloseChannelsOnlyOnce.java: -------------------------------------------------------------------------------- 1 | package discourje.core.ctl.rules; 2 | 3 | import discourje.core.ctl.Rule; 4 | import discourje.core.ctl.Formula; 5 | import static discourje.core.ctl.Formulas.AG; 6 | import static discourje.core.ctl.Formulas.EF; 7 | import static discourje.core.ctl.Formulas.EX; 8 | import static discourje.core.ctl.Formulas.close; 9 | import static discourje.core.ctl.Formulas.implies; 10 | import static discourje.core.ctl.Formulas.not; 11 | 12 | public class CloseChannelsOnlyOnce extends Rule { 13 | 14 | @Override 15 | public String createErrorDescription(String r1, String r2) { 16 | return String.format("A channel from %s to %s is closed, but this channel has already been closed before.", r1, r2); 17 | } 18 | 19 | @Override 20 | public Formula createCtlFormula(String r1, String r2) { 21 | return AG(implies(close(r1, r2), not(EX(EF(close(r1, r2)))))); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/discourje/core/ctl/rules/ClosedChannelMustBeUsedInPath.java: -------------------------------------------------------------------------------- 1 | package discourje.core.ctl.rules; 2 | 3 | import discourje.core.ctl.Formula; 4 | import discourje.core.ctl.Rule; 5 | import static discourje.core.ctl.Formulas.AG; 6 | import static discourje.core.ctl.Formulas.EP; 7 | import static discourje.core.ctl.Formulas.sendOrHandshake; 8 | import static discourje.core.ctl.Formulas.close; 9 | import static discourje.core.ctl.Formulas.implies; 10 | 11 | public class ClosedChannelMustBeUsedInPath extends Rule { 12 | 13 | @Override 14 | public String createErrorDescription(String r1, String r2) { 15 | return String.format("A channel from %s to %s is closed, but this channel is never used in the path.", r1, r2); 16 | } 17 | 18 | @Override 19 | public Formula createCtlFormula(String r1, String r2) { 20 | return AG(implies(close(r1, r2), EP(sendOrHandshake(r1, r2)))); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/discourje/core/ctl/rules/ClosedChannelMustBeUsedInProtocol.java: -------------------------------------------------------------------------------- 1 | package discourje.core.ctl.rules; 2 | 3 | import discourje.core.ctl.Formula; 4 | import discourje.core.ctl.Rule; 5 | import static discourje.core.ctl.Formulas.EF; 6 | import static discourje.core.ctl.Formulas.sendOrHandshake; 7 | import static discourje.core.ctl.Formulas.close; 8 | import static discourje.core.ctl.Formulas.implies; 9 | 10 | public class ClosedChannelMustBeUsedInProtocol extends Rule { 11 | 12 | @Override 13 | public String createErrorDescription(String r1, String r2) { 14 | return String.format("A channel from %s to %s is closed, but this channel is never used in the protocol.", r1, r2); 15 | } 16 | 17 | @Override 18 | public Formula createCtlFormula(String r1, String r2) { 19 | return implies(EF(close(r1, r2)), EF(sendOrHandshake(r1, r2))); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/discourje/core/ctl/rules/DoNotSendAfterClose.java: -------------------------------------------------------------------------------- 1 | package discourje.core.ctl.rules; 2 | 3 | import discourje.core.ctl.Formula; 4 | import discourje.core.ctl.Rule; 5 | import static discourje.core.ctl.Formulas.AG; 6 | import static discourje.core.ctl.Formulas.sendOrHandshake; 7 | import static discourje.core.ctl.Formulas.close; 8 | import static discourje.core.ctl.Formulas.implies; 9 | import static discourje.core.ctl.Formulas.not; 10 | 11 | public class DoNotSendAfterClose extends Rule { 12 | 13 | @Override 14 | public String createErrorDescription(String r1, String r2) { 15 | return String.format("A message is sent from %s to %s, after the channel between the two is closed.", r1, r2); 16 | } 17 | 18 | @Override 19 | public Formula createCtlFormula(String r1, String r2) { 20 | return AG(implies(close(r1, r2), AG(not(sendOrHandshake(r1, r2))))); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/discourje/core/ctl/rules/DoNotSendToSelf.java: -------------------------------------------------------------------------------- 1 | package discourje.core.ctl.rules; 2 | 3 | import discourje.core.ctl.Formula; 4 | import discourje.core.ctl.Rule; 5 | import static discourje.core.ctl.Formulas.AG; 6 | import static discourje.core.ctl.Formulas.sendOrHandshake; 7 | import static discourje.core.ctl.Formulas.not; 8 | 9 | public class DoNotSendToSelf extends Rule { 10 | 11 | @Override 12 | public String createErrorDescription(String r1, String r2) { 13 | return String.format("A message is sent from %s to %s.", r1, r1); 14 | } 15 | 16 | @Override 17 | public Formula createCtlFormula(String r1, String r2) { 18 | return AG(not(sendOrHandshake(r1, r1))); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/discourje/core/ctl/rules/UsedChannelsMustBeClosed.java: -------------------------------------------------------------------------------- 1 | package discourje.core.ctl.rules; 2 | 3 | import discourje.core.ctl.Formula; 4 | import discourje.core.ctl.Rule; 5 | import static discourje.core.ctl.Formulas.AF; 6 | import static discourje.core.ctl.Formulas.AG; 7 | import static discourje.core.ctl.Formulas.sendOrHandshake; 8 | import static discourje.core.ctl.Formulas.close; 9 | import static discourje.core.ctl.Formulas.implies; 10 | 11 | public class UsedChannelsMustBeClosed extends Rule { 12 | 13 | @Override 14 | public String createErrorDescription(String r1, String r2) { 15 | return String.format("A message is sent from %s to %s, but the channel is not closed afterwards.", r1, r2); 16 | } 17 | 18 | @Override 19 | public Formula createCtlFormula(String r1, String r2) { 20 | return AG(implies(sendOrHandshake(r1, r2), AF(close(r1, r2)))); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/discourje/core/lts/Action.java: -------------------------------------------------------------------------------- 1 | package discourje.core.lts; 2 | 3 | import java.util.Objects; 4 | import java.util.function.Predicate; 5 | 6 | public class Action { 7 | 8 | private String name; 9 | private Type type; 10 | private Predicate predicate; 11 | private String sender; 12 | private String receiver; 13 | 14 | public Action(String name, Type type, Predicate predicate, String sender, String receiver) { 15 | this.name = name; 16 | this.type = type; 17 | this.predicate = predicate; 18 | this.sender = sender; 19 | this.receiver = receiver; 20 | } 21 | 22 | @Override 23 | public boolean equals(Object o) { 24 | if (this == o) return true; 25 | if (o == null || getClass() != o.getClass()) return false; 26 | Action action = (Action) o; 27 | return Objects.equals(name, action.name); 28 | } 29 | 30 | @Override 31 | public int hashCode() { 32 | return Objects.hash(name); 33 | } 34 | 35 | @Override 36 | public String toString() { 37 | return name; 38 | } 39 | 40 | public String getName() { 41 | return name; 42 | } 43 | 44 | public Type getType() { 45 | return type; 46 | } 47 | 48 | public Predicate getPredicate() { 49 | return predicate; 50 | } 51 | 52 | public String getSender() { 53 | return sender; 54 | } 55 | 56 | public String getReceiver() { 57 | return receiver; 58 | } 59 | 60 | public enum Type { 61 | SYNC, SEND, RECEIVE, CLOSE; 62 | 63 | public T select(T sync, T send, T receive, T close) { 64 | switch (this) { 65 | case SYNC: 66 | return sync; 67 | case SEND: 68 | return send; 69 | case RECEIVE: 70 | return receive; 71 | case CLOSE: 72 | return close; 73 | default: 74 | throw new UnsupportedOperationException(); 75 | } 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/main/java/discourje/core/lts/State.java: -------------------------------------------------------------------------------- 1 | package discourje.core.lts; 2 | 3 | public interface State { 4 | 5 | default void expand() { 6 | expandRecursively(1); 7 | } 8 | 9 | default void expandRecursively() { 10 | expandRecursively(Integer.MAX_VALUE); 11 | } 12 | 13 | void expandRecursively(int bound); 14 | 15 | int getIdentifier(); 16 | 17 | Spec getSpec(); 18 | 19 | Transitions getTransitionsOrNull(); 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/discourje/core/lts/States.java: -------------------------------------------------------------------------------- 1 | package discourje.core.lts; 2 | 3 | import java.util.Collection; 4 | import java.util.LinkedHashSet; 5 | 6 | public class States { 7 | 8 | public static Collection> expandThenPerform(Collection> sources, 9 | Action.Type type, Object message, String sender, String receiver) { 10 | 11 | var targets = new LinkedHashSet>(); 12 | for (State source : sources) { 13 | source.expand(); 14 | var transitions = source.getTransitionsOrNull(); 15 | targets.addAll(transitions.perform(type, message, sender, receiver)); 16 | } 17 | 18 | return targets; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/discourje/examples/HelloWorld.java: -------------------------------------------------------------------------------- 1 | package discourje.examples; 2 | 3 | import discourje.core.AsyncJ; 4 | import discourje.core.SpecJ; 5 | 6 | public class HelloWorld { 7 | 8 | public static void main(String[] args) { 9 | AsyncJ.load(AsyncJ.Lib.DCJ); 10 | var c = AsyncJ.channel(); 11 | 12 | if (AsyncJ.dcj()) { 13 | SpecJ.defRole("::alice"); 14 | SpecJ.defRole("::bob"); 15 | SpecJ.defSession("::hello-world", new String[]{}, "(cat (--> ::alice ::bob) (close ::alice ::bob))"); 16 | 17 | var m = AsyncJ.monitor(SpecJ.session("::hello-world", new String[]{})); 18 | AsyncJ.link(c, SpecJ.role("::alice"), SpecJ.role("::bob"), m); 19 | } 20 | 21 | new Thread(() -> { 22 | AsyncJ.send(c, "hello, world"); 23 | AsyncJ.close(c); 24 | }).start(); 25 | 26 | new Thread(() -> { 27 | System.out.println(AsyncJ.receive(c)); 28 | }).start(); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/discourje/examples/clbg/Config.java: -------------------------------------------------------------------------------- 1 | package discourje.examples.clbg; 2 | 3 | import discourje.core.AsyncJ; 4 | 5 | import java.io.FileDescriptor; 6 | import java.io.FileOutputStream; 7 | import java.io.OutputStream; 8 | import java.io.PrintStream; 9 | 10 | public class Config { 11 | 12 | public static void clj() { 13 | AsyncJ.load(AsyncJ.Lib.CLJ); 14 | } 15 | 16 | public static void dcj() { 17 | AsyncJ.load(AsyncJ.Lib.DCJ); 18 | } 19 | 20 | public static void dcjNil() { 21 | AsyncJ.load(AsyncJ.Lib.DCJ_NIL); 22 | } 23 | 24 | public static void verbose(Boolean b) { 25 | if (b != null && b) { 26 | System.setOut(new PrintStream(new FileOutputStream(FileDescriptor.out))); 27 | } else { 28 | var devNull = new PrintStream(new OutputStream() { 29 | public void write(int b) { 30 | } 31 | }); 32 | System.setOut(devNull); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/discourje/examples/games/impl/chess/stockfish-linux: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/discourje/development/d98554dc0b7f922a31165d2e0270227cb005fd52/src/main/java/discourje/examples/games/impl/chess/stockfish-linux -------------------------------------------------------------------------------- /src/main/java/discourje/examples/games/impl/chess/stockfish-mac: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/discourje/development/d98554dc0b7f922a31165d2e0270227cb005fd52/src/main/java/discourje/examples/games/impl/chess/stockfish-mac -------------------------------------------------------------------------------- /src/main/java/discourje/examples/games/impl/chess/stockfish-win32.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/discourje/development/d98554dc0b7f922a31165d2e0270227cb005fd52/src/main/java/discourje/examples/games/impl/chess/stockfish-win32.exe -------------------------------------------------------------------------------- /src/main/java/discourje/examples/games/impl/chess/stockfish-win64.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/discourje/development/d98554dc0b7f922a31165d2e0270227cb005fd52/src/main/java/discourje/examples/games/impl/chess/stockfish-win64.exe -------------------------------------------------------------------------------- /src/main/java/discourje/examples/npb3/Config.java: -------------------------------------------------------------------------------- 1 | package discourje.examples.npb3; 2 | 3 | import discourje.core.AsyncJ; 4 | 5 | import java.io.FileDescriptor; 6 | import java.io.FileOutputStream; 7 | import java.io.OutputStream; 8 | import java.io.PrintStream; 9 | 10 | public class Config { 11 | 12 | public static void clj() { 13 | AsyncJ.load(AsyncJ.Lib.CLJ); 14 | } 15 | 16 | public static void dcj() { 17 | AsyncJ.load(AsyncJ.Lib.DCJ); 18 | } 19 | 20 | public static void dcjNil() { 21 | AsyncJ.load(AsyncJ.Lib.DCJ_NIL); 22 | } 23 | 24 | public static void verbose(Boolean b) { 25 | if (b != null && b) { 26 | System.setOut(new PrintStream(new FileOutputStream(FileDescriptor.out))); 27 | } else { 28 | var devNull = new PrintStream(new OutputStream() { 29 | public void write(int b) { 30 | } 31 | }); 32 | System.setOut(devNull); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/discourje/examples/npb3/impl/CGThreads/CGMessage.java: -------------------------------------------------------------------------------- 1 | package discourje.examples.npb3.impl.CGThreads; 2 | 3 | public class CGMessage { 4 | public final int OrderNum; 5 | public final double alpha; 6 | public final double beta; 7 | 8 | public CGMessage(int OrderNum, double alpha, double beta) { 9 | this.OrderNum = OrderNum; 10 | this.alpha = alpha; 11 | this.beta = beta; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/discourje/examples/npb3/impl/DoneMessage.java: -------------------------------------------------------------------------------- 1 | package discourje.examples.npb3.impl; 2 | 3 | public class DoneMessage { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/java/discourje/examples/npb3/impl/ExitMessage.java: -------------------------------------------------------------------------------- 1 | package discourje.examples.npb3.impl; 2 | 3 | public class ExitMessage { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/java/discourje/examples/npb3/impl/FTThreads/EvolveMessage.java: -------------------------------------------------------------------------------- 1 | package discourje.examples.npb3.impl.FTThreads; 2 | 3 | public class EvolveMessage { 4 | public final int kt; 5 | 6 | public EvolveMessage(int kt) { 7 | this.kt = kt; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/discourje/examples/npb3/impl/FTThreads/FFTMessage.java: -------------------------------------------------------------------------------- 1 | package discourje.examples.npb3.impl.FTThreads; 2 | 3 | public class FFTMessage { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/java/discourje/examples/npb3/impl/FTThreads/FFTSetVariablesMessage.java: -------------------------------------------------------------------------------- 1 | package discourje.examples.npb3.impl.FTThreads; 2 | 3 | public class FFTSetVariablesMessage { 4 | public final int sign1; 5 | public final boolean tr; 6 | public final double x1[]; 7 | public final double exp11[]; 8 | public final double exp21[]; 9 | public final double exp31[]; 10 | 11 | public FFTSetVariablesMessage(int sign1, boolean tr, double[] x1, double[] exp11, double[] exp21, double[] exp31) { 12 | this.sign1 = sign1; 13 | this.tr = tr; 14 | this.x1 = x1; 15 | this.exp11 = exp11; 16 | this.exp21 = exp21; 17 | this.exp31 = exp31; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/discourje/examples/npb3/impl/ISThreads/RankMessage.java: -------------------------------------------------------------------------------- 1 | package discourje.examples.npb3.impl.ISThreads; 2 | 3 | public class RankMessage { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/java/discourje/examples/npb3/impl/MGThreads/InterpMessage.java: -------------------------------------------------------------------------------- 1 | package discourje.examples.npb3.impl.MGThreads; 2 | 3 | public class InterpMessage { 4 | 5 | public final int wstart; 6 | public final int wend; 7 | public final int mm1; 8 | public final int mm2; 9 | public final int mm3; 10 | public final int n1; 11 | public final int n2; 12 | public final int n3; 13 | public final int zoff; 14 | public final int uoff; 15 | 16 | public InterpMessage(int wstart, int wend, int mm1, int mm2, int mm3, int n1, int n2, int n3, int zoff, int uoff) { 17 | this.wstart = wstart; 18 | this.wend = wend; 19 | this.mm1 = mm1; 20 | this.mm2 = mm2; 21 | this.mm3 = mm3; 22 | this.n1 = n1; 23 | this.n2 = n2; 24 | this.n3 = n3; 25 | this.zoff = zoff; 26 | this.uoff = uoff; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/discourje/examples/npb3/impl/MGThreads/PsinvMessage.java: -------------------------------------------------------------------------------- 1 | package discourje.examples.npb3.impl.MGThreads; 2 | 3 | public class PsinvMessage { 4 | 5 | public final int wstart; 6 | public final int wend; 7 | public final int n1; 8 | public final int n2; 9 | public final int n3; 10 | public final int roff; 11 | public final int uoff; 12 | 13 | public PsinvMessage(int wstart, int wend, int n1, int n2, int n3, int roff, int uoff) { 14 | this.wstart = wstart; 15 | this.wend = wend; 16 | this.n1 = n1; 17 | this.n2 = n2; 18 | this.n3 = n3; 19 | this.roff = roff; 20 | this.uoff = uoff; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/discourje/examples/npb3/impl/MGThreads/ResidMessage.java: -------------------------------------------------------------------------------- 1 | package discourje.examples.npb3.impl.MGThreads; 2 | 3 | public class ResidMessage { 4 | 5 | public final boolean visr; 6 | public final int wstart; 7 | public final int wend; 8 | public final int n1; 9 | public final int n2; 10 | public final int n3; 11 | public final int off; 12 | 13 | public ResidMessage(boolean visr, int wstart, int wend, int n1, int n2, int n3, int off) { 14 | this.visr = visr; 15 | this.wstart = wstart; 16 | this.wend = wend; 17 | this.n1 = n1; 18 | this.n2 = n2; 19 | this.n3 = n3; 20 | this.off = off; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/discourje/examples/npb3/impl/MGThreads/RprjMessage.java: -------------------------------------------------------------------------------- 1 | package discourje.examples.npb3.impl.MGThreads; 2 | 3 | public class RprjMessage { 4 | 5 | public final int wstart; 6 | public final int wend; 7 | public final int m1k; 8 | public final int m2k; 9 | public final int m3k; 10 | public final int m1j; 11 | public final int m2j; 12 | public final int m3j; 13 | public final int roff; 14 | public final int zoff; 15 | 16 | public RprjMessage(int wstart, int wend, int m1k, int m2k, int m3k, int m1j, int m2j, int m3j, int roff, int zoff) { 17 | this.wstart = wstart; 18 | this.wend = wend; 19 | this.m1k = m1k; 20 | this.m2k = m2k; 21 | this.m3k = m3k; 22 | this.m1j = m1j; 23 | this.m2j = m2j; 24 | this.m3j = m3j; 25 | this.roff = roff; 26 | this.zoff = zoff; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/discourje/examples/npb3/impl/Timer.java: -------------------------------------------------------------------------------- 1 | /* 2 | !-------------------------------------------------------------------------! 3 | ! ! 4 | ! N A S P A R A L L E L B E N C H M A R K S 3.0 ! 5 | ! ! 6 | ! J A V A V E R S I O N ! 7 | ! ! 8 | ! T I M E R ! 9 | ! ! 10 | !-------------------------------------------------------------------------! 11 | ! ! 12 | ! This benchmark is a serial version of the NPB3_0_JAV Timer code. ! ! ! 13 | ! Permission to use, copy, distribute and modify this software ! 14 | ! for any purpose with or without fee is hereby granted. We ! 15 | ! request, however, that all derived work reference the NAS ! 16 | ! Parallel Benchmarks 3.0. This software is provided "as is" ! 17 | ! without express or implied warranty. ! 18 | ! ! 19 | ! Information on NPB 3.0, including the Technical Report NAS-02-008 ! 20 | ! "Implementation of the NAS Parallel Benchmarks in Java", ! 21 | ! original specifications, source code, results and information ! 22 | ! on how to submit new results, is available at: ! 23 | ! ! 24 | ! http://www.nas.nasa.gov/Software/NPB/ ! 25 | ! ! 26 | ! Send comments or suggestions to npb@nas.nasa.gov ! 27 | ! ! 28 | ! NAS Parallel Benchmarks Group ! 29 | ! NASA Ames Research Center ! 30 | ! Mail Stop: T27A-1 ! 31 | ! Moffett Field, CA 94035-1000 ! 32 | ! ! 33 | ! E-mail: npb@nas.nasa.gov ! 34 | ! Fax: (650) 604-3957 ! 35 | ! ! 36 | !-------------------------------------------------------------------------! 37 | ! Translation to Java and to MultiThreaded Code: ! 38 | ! Michael A. Frumkin ! 39 | ! Mathew Schultz ! 40 | !-------------------------------------------------------------------------! 41 | */ 42 | package discourje.examples.npb3.impl; 43 | 44 | public class Timer{ 45 | public static final int max_counters=64; 46 | double start_time[]=new double[max_counters]; 47 | double elapsed_time[]=new double[max_counters]; 48 | double total_time[]=new double[max_counters]; 49 | 50 | public void Timer(){ 51 | for(int i=0;i> $OUT 2>> $ERR; 56 | done 57 | fi 58 | 59 | if [ "$GAMES_CHESS_40_30000_CLJ" -eq "1" ]; then 60 | echo games.chess/40/30000/clj 61 | for i in $(seq $I); do 62 | time $JAVA -jar $JAR {:run :clj :timeout $TIMEOUT} games.chess {:stockfish $STOCKFISH, :turns-per-player 40, :time-per-player 30000} 1>> $OUT 2>> $ERR; 63 | done 64 | fi 65 | 66 | if [ "$GAMES_CHESS_40_45000_CLJ" -eq "1" ]; then 67 | echo games.chess/40/45000/clj 68 | for i in $(seq $I); do 69 | time $JAVA -jar $JAR {:run :clj :timeout $TIMEOUT} games.chess {:stockfish $STOCKFISH, :turns-per-player 40, :time-per-player 45000} 1>> $OUT 2>> $ERR; 70 | done 71 | fi 72 | 73 | if [ "$GAMES_CHESS_40_60000_CLJ" -eq "1" ]; then 74 | echo games.chess/40/60000/clj 75 | for i in $(seq $I); do 76 | time $JAVA -jar $JAR {:run :clj :timeout $TIMEOUT} games.chess {:stockfish $STOCKFISH, :turns-per-player 40, :time-per-player 60000} 1>> $OUT 2>> $ERR; 77 | done 78 | fi 79 | 80 | # 81 | # Runs: dcj 82 | # 83 | 84 | if [ "$GAMES_CHESS_40_15000_DCJ" -eq "1" ]; then 85 | echo games.chess/40/15000/dcj 86 | for i in $(seq $I); do 87 | time $JAVA -jar $JAR {:run :dcj :timeout $TIMEOUT} games.chess {:stockfish $STOCKFISH, :turns-per-player 40, :time-per-player 15000} 1>> $OUT 2>> $ERR; 88 | done 89 | fi 90 | 91 | if [ "$GAMES_CHESS_40_30000_DCJ" -eq "1" ]; then 92 | echo games.chess/40/30000/dcj 93 | for i in $(seq $I); do 94 | time $JAVA -jar $JAR {:run :dcj :timeout $TIMEOUT} games.chess {:stockfish $STOCKFISH, :turns-per-player 40, :time-per-player 30000} 1>> $OUT 2>> $ERR; 95 | done 96 | fi 97 | 98 | if [ "$GAMES_CHESS_40_45000_DCJ" -eq "1" ]; then 99 | echo games.chess/40/45000/dcj 100 | for i in $(seq $I); do 101 | time $JAVA -jar $JAR {:run :dcj :timeout $TIMEOUT} games.chess {:stockfish $STOCKFISH, :turns-per-player 40, :time-per-player 45000} 1>> $OUT 2>> $ERR; 102 | done 103 | fi 104 | 105 | if [ "$GAMES_CHESS_40_60000_DCJ" -eq "1" ]; then 106 | echo games.chess/40/60000/dcj 107 | for i in $(seq $I); do 108 | time $JAVA -jar $JAR {:run :dcj :timeout $TIMEOUT} games.chess {:stockfish $STOCKFISH, :turns-per-player 40, :time-per-player 60000} 1>> $OUT 2>> $ERR; 109 | done 110 | fi 111 | 112 | # 113 | # Bookkeeping 114 | # 115 | 116 | cp -r $TMP . -------------------------------------------------------------------------------- /src/main/sh/npb3.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #SBATCH --nodes=1 3 | #SBATCH --ntasks=1 4 | #SBATCH --cpus-per-task=32 5 | #SBATCH --partition=thin 6 | #SBATCH --time=24:00:00 7 | 8 | # 9 | # Bookkeeping 10 | # 11 | 12 | DATE=$(date +%s) 13 | TMP=$(mktemp -d -t npb3-$DATE.XXX) 14 | OUT=$TMP"/out.txt" 15 | ERR=$TMP"/err.txt" 16 | echo $TMP 17 | 18 | # 19 | # Repetitions and programs 20 | # 21 | 22 | I=1 23 | 24 | NPB3_CG_CLJ=1 25 | NPB3_FT_CLJ=1 26 | NPB3_IS_CLJ=1 27 | NPB3_MG_CLJ=1 28 | NPB3_CG_DCJ=1 29 | NPB3_FT_DCJ=1 30 | NPB3_IS_DCJ=1 31 | NPB3_MG_DCJ=1 32 | 33 | # 34 | # Commands 35 | # 36 | 37 | JAVA=java 38 | JAR=target/discourje-examples.jar 39 | TIMEFORMAT='%3R' 40 | 41 | # 42 | # Settings and inputs 43 | # 44 | 45 | TIMEOUT=300 46 | CLASS=w 47 | VERBOSE=false 48 | 49 | # 50 | # Runs: clj 51 | # 52 | 53 | if [ "$NPB3_CG_CLJ" -eq "1" ]; then 54 | for k in 2 4 6 8 10 12 14 16; do 55 | echo npb3.cg/$k/clj 56 | for i in $(seq $I); do 57 | time $JAVA -jar $JAR {:run :clj :timeout $TIMEOUT} npb3.cg {:k $k, :class $CLASS, :verbose $VERBOSE} 1>> $OUT 2>> $ERR; 58 | done 59 | done 60 | fi 61 | 62 | if [ "$NPB3_FT_CLJ" -eq "1" ]; then 63 | for k in 2 4 6 8 10 12 14 16; do 64 | echo npb3.ft/$k/clj 65 | for i in $(seq $I); do 66 | time $JAVA -jar $JAR {:run :clj :timeout $TIMEOUT} npb3.ft {:k $k, :class $CLASS, :verbose $VERBOSE} 1>> $OUT 2>> $ERR; 67 | done 68 | done 69 | fi 70 | 71 | if [ "$NPB3_IS_CLJ" -eq "1" ]; then 72 | for k in 2 4 6 8 10 12 14 16; do 73 | echo npb3.is/$k/clj 74 | for i in $(seq $I); do 75 | time $JAVA -jar $JAR {:run :clj :timeout $TIMEOUT} npb3.is {:k $k, :class $CLASS, :verbose $VERBOSE} 1>> $OUT 2>> $ERR; 76 | done 77 | done 78 | fi 79 | 80 | if [ "$NPB3_MG_CLJ" -eq "1" ]; then 81 | for k in 2 4 6 8 10 12 14 16; do 82 | echo npb3.mg/$k/clj 83 | for i in $(seq $I); do 84 | time $JAVA -jar $JAR {:run :clj :timeout $TIMEOUT} npb3.mg {:k $k, :class $CLASS, :verbose $VERBOSE} 1>> $OUT 2>> $ERR; 85 | done 86 | done 87 | fi 88 | 89 | # 90 | # Runs: dcj 91 | # 92 | 93 | if [ "$NPB3_CG_DCJ" -eq "1" ]; then 94 | for k in 2 4 6 8 10 12 14 16; do 95 | echo npb3.cg/$k/dcj 96 | for i in $(seq $I); do 97 | time $JAVA -jar $JAR {:run :dcj :timeout $TIMEOUT} npb3.cg {:k $k, :class $CLASS, :verbose $VERBOSE} 1>> $OUT 2>> $ERR; 98 | done 99 | done 100 | fi 101 | 102 | if [ "$NPB3_FT_DCJ" -eq "1" ]; then 103 | for k in 2 4 6 8 10 12 14 16; do 104 | echo npb3.ft/$k/dcj 105 | for i in $(seq $I); do 106 | time $JAVA -jar $JAR {:run :dcj :timeout $TIMEOUT} npb3.ft {:k $k, :class $CLASS, :verbose $VERBOSE} 1>> $OUT 2>> $ERR; 107 | done 108 | done 109 | fi 110 | 111 | if [ "$NPB3_IS_DCJ" -eq "1" ]; then 112 | for k in 2 4 6 8 10 12 14 16; do 113 | echo npb3.is/$k/dcj 114 | for i in $(seq $I); do 115 | time $JAVA -jar $JAR {:run :dcj :timeout $TIMEOUT} npb3.is {:k $k, :class $CLASS, :verbose $VERBOSE} 1>> $OUT 2>> $ERR; 116 | done 117 | done 118 | fi 119 | 120 | if [ "$NPB3_MG_DCJ" -eq "1" ]; then 121 | for k in 2 4 6 8 10 12 14 16; do 122 | echo npb3.mg/$k/dcj 123 | for i in $(seq $I); do 124 | time $JAVA -jar $JAR {:run :dcj :timeout $TIMEOUT} npb3.mg {:k $k, :class $CLASS, :verbose $VERBOSE} 1>> $OUT 2>> $ERR; 125 | done 126 | done 127 | fi 128 | 129 | # 130 | # Bookkeeping 131 | # 132 | 133 | cp -r $TMP . -------------------------------------------------------------------------------- /src/test/clojure/discourje/core/ctl/causality.clj: -------------------------------------------------------------------------------- 1 | (ns discourje.core.ctl.causality 2 | (:require [discourje.core.spec :as s])) 3 | 4 | (s/defrole ::a) 5 | (s/defrole ::b) 6 | (s/defrole ::c) 7 | (s/defrole ::d) 8 | 9 | ;; All used messages have a clear cause 10 | (s/defsession ::protocol-trivial-correct [] 11 | [(s/--> ::a ::b) 12 | (s/--> ::b ::a) 13 | (s/close ::a ::b) 14 | (s/close ::b ::a) 15 | ]) 16 | 17 | ;; message c a has no cause 18 | (s/defsession ::protocol-trivial-incorrect [] 19 | [ 20 | (s/--> ::a ::b) 21 | (s/--> ::c ::a) 22 | (s/close ::a ::b) 23 | (s/close ::c ::a) 24 | ]) 25 | 26 | ;; the s/par keyword will lead to paths where some messages have no direct cause, but they have an indirect cause: 27 | ;; (--> a b) (--> a c) (--> b c) 28 | ;; (--> a c) (--> a b) (--> b c) 29 | (s/defsession ::protocol-non-trivial-correct [] 30 | (s/par 31 | [(s/--> ::a ::b) 32 | (s/--> ::b ::c) 33 | ] 34 | (s/--> ::a ::c)) 35 | (s/close ::a ::b) 36 | (s/close ::a ::c) 37 | (s/close ::b ::c) 38 | ) 39 | 40 | ;; (--> d a) has no cause, although in some paths it may come right after (--> c d). 41 | (s/defsession ::protocol-non-trivial-incorrect [] 42 | (s/par 43 | [(s/--> ::a ::b) 44 | (s/--> ::b ::c) 45 | (s/--> ::c ::d) 46 | ] 47 | [(s/--> ::a ::b) 48 | (s/--> ::b ::c) 49 | (s/--> ::d ::a) 50 | ]) 51 | (s/close ::a ::b) 52 | (s/close ::b ::c) 53 | (s/close ::c ::d) 54 | (s/close ::d ::a) 55 | ) 56 | 57 | (s/par [(s/--> ::a ::b) 58 | (s/close ::a ::b)] 59 | [(s/--> ::a ::c) 60 | (s/close ::a ::c)] 61 | ) -------------------------------------------------------------------------------- /src/test/clojure/discourje/core/ctl/causality_async.clj: -------------------------------------------------------------------------------- 1 | (ns discourje.core.ctl.causality-async 2 | (:require [discourje.core.spec :as s])) 3 | 4 | (s/defrole ::a) 5 | (s/defrole ::b) 6 | (s/defrole ::c) 7 | (s/defrole ::d) 8 | 9 | ;; All used messages have a clear cause 10 | (s/defsession ::protocol-trivial-correct [] 11 | [(s/-->> ::a ::b) 12 | (s/-->> ::b ::a) 13 | (s/close ::a ::b) 14 | (s/close ::b ::a) 15 | ]) 16 | 17 | ;; message c a has no cause 18 | (s/defsession ::protocol-trivial-incorrect [] 19 | [ 20 | (s/-->> ::a ::b) 21 | (s/-->> ::c ::a) 22 | (s/close ::a ::b) 23 | (s/close ::c ::a) 24 | ]) 25 | 26 | ;; the s/par keyword will lead to paths where some messages have no direct cause, but they have an indirect cause: 27 | ;; (--> a b) (--> a c) (--> b c) 28 | ;; (--> a c) (--> a b) (--> b c) 29 | (s/defsession ::protocol-non-trivial-correct [] 30 | (s/par 31 | [(s/-->> ::a ::b) 32 | (s/-->> ::b ::c) 33 | ] 34 | (s/-->> ::a ::c)) 35 | (s/close ::a ::b) 36 | (s/close ::a ::c) 37 | (s/close ::b ::c) 38 | ) 39 | 40 | ;; (--> d a) has no cause, although in some paths it may come right after (--> c d). 41 | (s/defsession ::protocol-non-trivial-incorrect [] 42 | (s/par 43 | [(s/-->> ::a ::b) 44 | (s/-->> ::b ::c) 45 | (s/-->> ::c ::d) 46 | ] 47 | [(s/-->> ::a ::b) 48 | (s/-->> ::b ::c) 49 | (s/-->> ::d ::a) 50 | ]) 51 | (s/close ::a ::b) 52 | (s/close ::b ::c) 53 | (s/close ::c ::d) 54 | (s/close ::d ::a) 55 | ) -------------------------------------------------------------------------------- /src/test/clojure/discourje/core/ctl/close_channels_only_once.clj: -------------------------------------------------------------------------------- 1 | (ns discourje.core.ctl.close-channels-only-once 2 | (:require [discourje.core.spec :as s])) 3 | 4 | (s/defrole ::a) 5 | (s/defrole ::b) 6 | (s/defrole ::c) 7 | (s/defrole ::d) 8 | 9 | ;; channels are only closed once 10 | (s/defsession ::protocol-trivial-correct [] 11 | [(s/--> ::a ::b) 12 | (s/--> ::b ::c) 13 | (s/close ::a ::b) 14 | (s/close ::b ::c) 15 | ]) 16 | 17 | ;; channel a b is closed twice 18 | (s/defsession ::protocol-trivial-incorrect [] 19 | [(s/--> ::a ::b) 20 | (s/--> ::b ::c) 21 | (s/close ::a ::b) 22 | (s/close ::b ::c) 23 | (s/close ::a ::b) 24 | ]) 25 | 26 | ;; channel a b is closed on both paths of an s/alt 27 | (s/defsession ::protocol-non-trivial-correct [] 28 | (s/alt 29 | [(s/--> ::a ::b) 30 | (s/--> ::b ::c) 31 | (s/close ::a ::b) 32 | (s/close ::b ::c) 33 | ] 34 | [(s/--> ::a ::b) 35 | (s/--> ::b ::d) 36 | (s/close ::a ::b) 37 | (s/close ::b ::d) 38 | ])) 39 | 40 | ;; channel a b is closed on both paths of an s/par 41 | (s/defsession ::protocol-non-trivial-incorrect [] 42 | (s/par 43 | [(s/--> ::a ::b) 44 | (s/--> ::b ::c) 45 | (s/close ::a ::b) 46 | (s/close ::b ::c) 47 | ] 48 | [(s/--> ::a ::b) 49 | (s/--> ::b ::d) 50 | (s/close ::a ::b) 51 | (s/close ::b ::d) 52 | ])) -------------------------------------------------------------------------------- /src/test/clojure/discourje/core/ctl/close_channels_only_once_async.clj: -------------------------------------------------------------------------------- 1 | (ns discourje.core.ctl.close-channels-only-once-async 2 | (:require [discourje.core.spec :as s])) 3 | 4 | (s/defrole ::a) 5 | (s/defrole ::b) 6 | (s/defrole ::c) 7 | (s/defrole ::d) 8 | 9 | ;; channels are only closed once 10 | (s/defsession ::protocol-trivial-correct [] 11 | [(s/-->> ::a ::b) 12 | (s/-->> ::b ::c) 13 | (s/close ::a ::b) 14 | (s/close ::b ::c) 15 | ]) 16 | 17 | ;; channel a b is closed twice 18 | (s/defsession ::protocol-trivial-incorrect [] 19 | [(s/-->> ::a ::b) 20 | (s/-->> ::b ::c) 21 | (s/close ::a ::b) 22 | (s/close ::b ::c) 23 | (s/close ::a ::b) 24 | ]) 25 | 26 | ;; channel a b is closed on both paths of an s/alt 27 | (s/defsession ::protocol-non-trivial-correct [] 28 | (s/alt 29 | [(s/-->> ::a ::b) 30 | (s/-->> ::b ::c) 31 | (s/close ::a ::b) 32 | (s/close ::b ::c) 33 | ] 34 | [(s/-->> ::a ::b) 35 | (s/-->> ::b ::d) 36 | (s/close ::a ::b) 37 | (s/close ::b ::d) 38 | ])) 39 | 40 | ;; channel a b is closed on both paths of an s/par 41 | (s/defsession ::protocol-non-trivial-incorrect [] 42 | (s/par 43 | [(s/-->> ::a ::b) 44 | (s/-->> ::b ::c) 45 | (s/close ::a ::b) 46 | (s/close ::b ::c) 47 | ] 48 | [(s/-->> ::a ::b) 49 | (s/-->> ::b ::d) 50 | (s/close ::a ::b) 51 | (s/close ::b ::d) 52 | ])) -------------------------------------------------------------------------------- /src/test/clojure/discourje/core/ctl/closed_channel_must_be_used_in_path.clj: -------------------------------------------------------------------------------- 1 | (ns discourje.core.ctl.closed-channel-must-be-used-in-path 2 | (:require [discourje.core.spec :as s])) 3 | 4 | (s/defrole ::a) 5 | (s/defrole ::b) 6 | (s/defrole ::c) 7 | (s/defrole ::d) 8 | 9 | ;; All closed channels are also used on that path 10 | (s/defsession ::protocol-trivial-correct [] 11 | (s/alt 12 | [(s/--> ::a ::b) 13 | (s/close ::a ::b)] 14 | [(s/--> ::a ::c) 15 | (s/close ::a ::c)])) 16 | 17 | ; Channel and a-->c is not used on the path. 18 | (s/defsession ::protocol-trivial-incorrect [] 19 | (s/--> ::a ::b) 20 | (s/close ::a ::b) 21 | (s/close ::a ::c)) 22 | 23 | ; Channels closed on parallel paths, just as messages. Every path should, however, contain close and send 24 | (s/defsession ::protocol-non-trivial-correct [] 25 | (s/par 26 | (s/--> ::a ::b) 27 | (s/--> ::b ::a)) 28 | (s/par 29 | (s/close ::a ::b) 30 | (s/close ::b ::a))) 31 | 32 | ; Closing channel a to c in the second branch of the first s/alt is not warranted. 33 | (s/defsession ::protocol-non-trivial-incorrect [] 34 | (s/alt 35 | [(s/alt 36 | (s/--> ::a ::b) 37 | (s/--> ::a ::c)) 38 | (s/close ::a ::b) 39 | (s/close ::a ::c)] 40 | [(s/alt 41 | (s/--> ::a ::b) 42 | (s/--> ::a ::d)) 43 | (s/close ::a ::b) 44 | (s/close ::a ::c) 45 | (s/close ::a ::d)] 46 | ) 47 | ) 48 | -------------------------------------------------------------------------------- /src/test/clojure/discourje/core/ctl/closed_channel_must_be_used_in_path_async.clj: -------------------------------------------------------------------------------- 1 | (ns discourje.core.ctl.closed-channel-must-be-used-in-path-async 2 | (:require [discourje.core.spec :as s])) 3 | 4 | (s/defrole ::a) 5 | (s/defrole ::b) 6 | (s/defrole ::c) 7 | (s/defrole ::d) 8 | 9 | ;; All closed channels are also used on that path 10 | (s/defsession ::protocol-trivial-correct [] 11 | (s/alt 12 | [(s/-->> ::a ::b) 13 | (s/close ::a ::b)] 14 | [(s/-->> ::a ::c) 15 | (s/close ::a ::c)])) 16 | 17 | ; Channel and a-->c is not used on the path. 18 | (s/defsession ::protocol-trivial-incorrect [] 19 | (s/-->> ::a ::b) 20 | (s/close ::a ::b) 21 | (s/close ::a ::c)) 22 | 23 | ; Channels closed on parallel paths, just as messages. Every path should, however, contain close and send 24 | (s/defsession ::protocol-non-trivial-correct [] 25 | (s/par 26 | (s/-->> ::a ::b) 27 | (s/-->> ::b ::a)) 28 | (s/par 29 | (s/close ::a ::b) 30 | (s/close ::b ::a))) 31 | 32 | ; Closing channel a to c in the second branch of the first s/alt is not warranted. 33 | (s/defsession ::protocol-non-trivial-incorrect [] 34 | (s/alt 35 | [(s/alt 36 | (s/--> ::a ::b) 37 | (s/--> ::a ::c)) 38 | (s/close ::a ::b) 39 | (s/close ::a ::c)] 40 | [(s/alt 41 | (s/--> ::a ::b) 42 | (s/--> ::a ::d)) 43 | (s/close ::a ::b) 44 | (s/close ::a ::c) 45 | (s/close ::a ::d)] 46 | ) 47 | ) 48 | -------------------------------------------------------------------------------- /src/test/clojure/discourje/core/ctl/closed_channel_must_be_used_in_protocol.clj: -------------------------------------------------------------------------------- 1 | (ns discourje.core.ctl.closed-channel-must-be-used-in-protocol 2 | (:require [discourje.core.spec :as s])) 3 | 4 | (s/defrole ::a) 5 | (s/defrole ::b) 6 | (s/defrole ::c) 7 | (s/defrole ::d) 8 | 9 | ;; All closed channels are also used 10 | (s/defsession ::protocol-trivial-correct [] 11 | [ 12 | (s/--> ::a ::b) 13 | (s/--> ::b ::a) 14 | (s/close ::a ::b) 15 | (s/close ::b ::a) 16 | ]) 17 | 18 | ;; Not all closed channels are also used 19 | (s/defsession ::protocol-trivial-incorrect [] 20 | [ 21 | (s/--> ::a ::b) 22 | (s/close ::a ::b) 23 | (s/close ::b ::a) 24 | ]) 25 | 26 | ;; Channels are closed on both paths, but used on only one 27 | (s/defsession ::protocol-non-trivial-correct [] 28 | (s/alt 29 | [(s/--> ::a ::b) 30 | (s/close ::a ::b) 31 | (s/close ::b ::a) 32 | ] 33 | [(s/--> ::b ::a) 34 | (s/close ::b ::a) 35 | (s/close ::a ::b) 36 | ] 37 | )) 38 | 39 | ;; channel b c is closed, but not used, not even on other paths 40 | (s/defsession ::protocol-non-trivial-incorrect [] 41 | (s/alt 42 | [(s/--> ::a ::b) 43 | (s/close ::a ::b) 44 | (s/close ::b ::c) 45 | ] 46 | [(s/--> ::b ::a) 47 | (s/close ::a ::b) 48 | (s/close ::b ::a) 49 | ] 50 | )) 51 | -------------------------------------------------------------------------------- /src/test/clojure/discourje/core/ctl/closed_channel_must_be_used_in_protocol_async.clj: -------------------------------------------------------------------------------- 1 | (ns discourje.core.ctl.closed-channel-must-be-used-in-protocol-async 2 | (:require [discourje.core.spec :as s])) 3 | 4 | (s/defrole ::a) 5 | (s/defrole ::b) 6 | (s/defrole ::c) 7 | (s/defrole ::d) 8 | 9 | ;; All closed channels are also used 10 | (s/defsession ::protocol-trivial-correct [] 11 | [ 12 | (s/-->> ::a ::b) 13 | (s/-->> ::b ::a) 14 | (s/close ::a ::b) 15 | (s/close ::b ::a) 16 | ]) 17 | 18 | ;; Not all closed channels are also used 19 | (s/defsession ::protocol-trivial-incorrect [] 20 | [ 21 | (s/-->> ::a ::b) 22 | (s/close ::a ::b) 23 | (s/close ::b ::a) 24 | ]) 25 | 26 | ;; Channels are closed on both paths, but used on only one 27 | (s/defsession ::protocol-non-trivial-correct [] 28 | (s/alt 29 | [(s/-->> ::a ::b) 30 | (s/close ::a ::b) 31 | (s/close ::b ::a) 32 | ] 33 | [(s/-->> ::b ::a) 34 | (s/close ::b ::a) 35 | (s/close ::a ::b) 36 | ] 37 | )) 38 | 39 | ;; channel b c is closed, but not used, not even on other paths 40 | (s/defsession ::protocol-non-trivial-incorrect [] 41 | (s/alt 42 | [(s/-->> ::a ::b) 43 | (s/close ::a ::b) 44 | (s/close ::b ::c) 45 | ] 46 | [(s/-->> ::b ::a) 47 | (s/close ::a ::b) 48 | (s/close ::b ::a) 49 | ] 50 | )) 51 | -------------------------------------------------------------------------------- /src/test/clojure/discourje/core/ctl/do_not_send_after_close.clj: -------------------------------------------------------------------------------- 1 | (ns discourje.core.ctl.do-not-send-after-close 2 | (:require [discourje.core.spec :as s])) 3 | 4 | (s/defrole ::a) 5 | (s/defrole ::b) 6 | (s/defrole ::c) 7 | (s/defrole ::d) 8 | 9 | ;; No channel usage after close 10 | (s/defsession ::protocol-trivial-correct [] 11 | [ 12 | (s/--> ::a ::b) 13 | (s/--> ::b ::a) 14 | (s/close ::a ::b) 15 | (s/close ::b ::a) 16 | ]) 17 | 18 | ;; channel a b is used after close 19 | (s/defsession ::protocol-trivial-incorrect [] 20 | [ 21 | (s/--> ::a ::b) 22 | (s/close ::a ::b) 23 | (s/--> ::b ::a) 24 | (s/close ::b ::a) 25 | (s/--> ::a ::b) 26 | ]) 27 | 28 | ;; the second (--> a b) is only sent if the first (close a b) is not executed 29 | (s/defsession ::protocol-non-trivial-correct 30 | [test] 31 | (s/if test 32 | [(s/--> ::a ::b) 33 | (s/close ::a ::b) 34 | ] 35 | [(s/--> ::a ::b) 36 | (s/close ::a ::b) 37 | ]) 38 | ) 39 | 40 | ;; (close a b) in one path is not guaranteed to happen before (--> a b) in the other path 41 | (s/defsession ::protocol-non-trivial-incorrect [] 42 | (s/par 43 | [(s/--> ::a ::b) 44 | (s/--> ::b ::c) 45 | (s/--> ::c ::a) 46 | (s/close ::a ::b) 47 | ] 48 | [(s/--> ::a ::b) 49 | (s/--> ::b ::d) 50 | (s/--> ::d ::a) 51 | (s/close ::a ::b) 52 | ]) 53 | (s/close ::b ::c) 54 | (s/close ::c ::a) 55 | (s/close ::d ::a) 56 | ) -------------------------------------------------------------------------------- /src/test/clojure/discourje/core/ctl/do_not_send_after_close_async.clj: -------------------------------------------------------------------------------- 1 | (ns discourje.core.ctl.do-not-send-after-close-async 2 | (:require [discourje.core.spec :as s])) 3 | 4 | (s/defrole ::a) 5 | (s/defrole ::b) 6 | (s/defrole ::c) 7 | (s/defrole ::d) 8 | 9 | ;; No channel usage after close 10 | (s/defsession ::protocol-trivial-correct [] 11 | [ 12 | (s/-->> ::a ::b) 13 | (s/-->> ::b ::a) 14 | (s/close ::a ::b) 15 | (s/close ::b ::a) 16 | ]) 17 | 18 | ;; channel a b is used after close 19 | (s/defsession ::protocol-trivial-incorrect [] 20 | [ 21 | (s/-->> ::a ::b) 22 | (s/close ::a ::b) 23 | (s/-->> ::b ::a) 24 | (s/close ::b ::a) 25 | (s/-->> ::a ::b) 26 | ]) 27 | 28 | ;; the second (--> a b) is only sent if the first (close a b) is not executed 29 | (s/defsession ::protocol-non-trivial-correct 30 | [test] 31 | (s/if test 32 | [(s/-->> ::a ::b) 33 | (s/close ::a ::b) 34 | ] 35 | [(s/-->> ::a ::b) 36 | (s/close ::a ::b) 37 | ]) 38 | ) 39 | 40 | ;; (close a b) in one path is not guaranteed to happen before (--> a b) in the other path 41 | (s/defsession ::protocol-non-trivial-incorrect [] 42 | (s/par 43 | [(s/-->> ::a ::b) 44 | (s/-->> ::b ::c) 45 | (s/-->> ::c ::a) 46 | (s/close ::a ::b) 47 | ] 48 | [(s/-->> ::a ::b) 49 | (s/-->> ::b ::d) 50 | (s/-->> ::d ::a) 51 | (s/close ::a ::b) 52 | ]) 53 | (s/close ::b ::c) 54 | (s/close ::c ::a) 55 | (s/close ::d ::a) 56 | ) -------------------------------------------------------------------------------- /src/test/clojure/discourje/core/ctl/do_not_send_to_self.clj: -------------------------------------------------------------------------------- 1 | (ns discourje.core.ctl.do-not-send-to-self 2 | (:require [discourje.core.spec :as s])) 3 | 4 | (s/defrole ::a) 5 | (s/defrole ::b) 6 | (s/defrole ::c) 7 | (s/defrole ::d) 8 | 9 | ;; No message to self 10 | (s/defsession ::protocol-trivial-correct [] 11 | [ 12 | (s/--> ::a ::b) 13 | (s/--> ::b ::a) 14 | (s/close ::a ::b) 15 | (s/close ::b ::a) 16 | ]) 17 | 18 | ;; Message to self 19 | (s/defsession ::protocol-trivial-incorrect [] 20 | [ 21 | (s/--> ::a ::b) 22 | (s/--> ::b ::b) 23 | (s/close ::a ::b) 24 | (s/close ::b ::b) 25 | ]) 26 | 27 | (defn send [r1 r2] 28 | (s/--> (r1) (r2)) 29 | ) 30 | 31 | ; Roles are not given as literals, but as variables passed as parameters 32 | (s/defsession ::protocol-non-trivial-correct [] 33 | (s/let 34 | [r1 ::a 35 | r2 ::b 36 | r3 ::c]) 37 | (s/cat (send ::a ::b) 38 | (send ::b ::a) 39 | (s/close ::a ::b) 40 | (s/close ::b ::a)) 41 | ) 42 | 43 | ;; Roles are not given as literals, but as variables passed as parameters 44 | (s/defsession ::protocol-non-trivial-incorrect [] 45 | (s/let 46 | [r1 ::a 47 | r2 ::b 48 | r3 ::a] 49 | [(send ::a ::b) 50 | (send ::a ::a) 51 | (s/close ::a ::b) 52 | (s/close ::a ::a)] 53 | ) 54 | ) 55 | -------------------------------------------------------------------------------- /src/test/clojure/discourje/core/ctl/do_not_send_to_self_async.clj: -------------------------------------------------------------------------------- 1 | (ns discourje.core.ctl.do-not-send-to-self-async 2 | (:require [discourje.core.spec :as s])) 3 | 4 | (s/defrole ::a) 5 | (s/defrole ::b) 6 | (s/defrole ::c) 7 | (s/defrole ::d) 8 | 9 | ;; No message to self 10 | (s/defsession ::protocol-trivial-correct [] 11 | [ 12 | (s/-->> ::a ::b) 13 | (s/-->> ::b ::a) 14 | (s/close ::a ::b) 15 | (s/close ::b ::a) 16 | ]) 17 | 18 | ;; Message to self 19 | (s/defsession ::protocol-trivial-incorrect [] 20 | [ 21 | (s/-->> ::a ::b) 22 | (s/-->> ::b ::b) 23 | (s/close ::a ::b) 24 | (s/close ::b ::b) 25 | ]) 26 | 27 | (defn send [r1 r2] 28 | (s/-->> (r1) (r2)) 29 | ) 30 | 31 | ; Roles are not given as literals, but as variables passed as parameters 32 | (s/defsession ::protocol-non-trivial-correct [] 33 | (s/let 34 | [r1 ::a 35 | r2 ::b 36 | r3 ::c]) 37 | (s/cat (send ::a ::b) 38 | (send ::b ::a) 39 | (s/close ::a ::b) 40 | (s/close ::b ::a)) 41 | ) 42 | 43 | ;; Roles are not given as literals, but as variables passed as parameters 44 | (s/defsession ::protocol-non-trivial-incorrect [] 45 | (s/let 46 | [r1 ::a 47 | r2 ::b 48 | r3 ::a] 49 | [(send ::a ::b) 50 | (send ::a ::a) 51 | (s/close ::a ::b) 52 | (s/close ::a ::a)] 53 | ) 54 | ) 55 | -------------------------------------------------------------------------------- /src/test/clojure/discourje/core/ctl/performance.clj: -------------------------------------------------------------------------------- 1 | (ns discourje.core.ctl.performance 2 | (:require [discourje.core.spec :as s] 3 | [discourje.core.spec.lts :as lts])) 4 | 5 | (s/defrole ::a) 6 | (s/defrole ::b) 7 | (s/defrole ::c) 8 | (s/defrole ::d) 9 | 10 | (s/defsession ::large-lts [size] 11 | (s/par 12 | (s/cat-every 13 | [i (range size)] 14 | [(s/--> String (::a i) (::a (+ i 1))) 15 | (s/close (::a i) (::a (+ i 1))) 16 | ]) 17 | (s/cat-every 18 | [i (range size)] 19 | [(s/--> String (::b i) (::b (+ i 1))) 20 | (s/close (::b i) (::b (+ i 1))) 21 | ]) 22 | (s/cat-every 23 | [i (range size)] 24 | [(s/--> String (::c i) (::c (+ i 1))) 25 | (s/close (::c i) (::c (+ i 1))) 26 | ]) 27 | )) 28 | 29 | (defn get-large-lts [size] 30 | (lts/lts (s/session ::large-lts [size]))) -------------------------------------------------------------------------------- /src/test/clojure/discourje/core/ctl/used_channels_must_be_closed.clj: -------------------------------------------------------------------------------- 1 | (ns discourje.core.ctl.used-channels-must-be-closed 2 | (:require [discourje.core.spec :as s])) 3 | 4 | (s/defrole ::a) 5 | (s/defrole ::b) 6 | (s/defrole ::c) 7 | (s/defrole ::d) 8 | 9 | ;; All used channels are closed 10 | (s/defsession ::protocol-trivial-correct [] 11 | [ 12 | (s/--> ::a ::b) 13 | (s/--> ::b ::a) 14 | (s/close ::a ::b) 15 | (s/close ::b ::a) 16 | ]) 17 | 18 | ;; channel b a is not closed 19 | (s/defsession ::protocol-trivial-incorrect [] 20 | [ 21 | (s/--> ::a ::b) 22 | (s/--> ::b ::a) 23 | (s/close ::a ::b) 24 | ]) 25 | 26 | ;; all used channels are closed, but only in the path they are used and after some other actions 27 | (s/defsession ::protocol-non-trivial-correct [] 28 | (s/alt 29 | [ 30 | (s/--> ::a ::b) 31 | (s/--> ::b ::c) 32 | (s/close ::b ::c) 33 | ] 34 | [ 35 | (s/--> ::a ::b) 36 | (s/--> ::b ::d) 37 | (s/close ::b ::d) 38 | ]) 39 | (s/close ::a ::b) 40 | ) 41 | 42 | ;; channel d a is not closed 43 | (s/defsession ::protocol-non-trivial-incorrect [] 44 | (s/alt 45 | [(s/--> ::a ::b) 46 | (s/--> ::b ::c) 47 | (s/--> ::c ::a) 48 | ] 49 | [(s/--> ::a ::c) 50 | (s/--> ::c ::d) 51 | (s/--> ::d ::a) 52 | ]) 53 | (s/close ::a ::b) 54 | (s/close ::a ::c) 55 | (s/close ::b ::c) 56 | (s/close ::c ::d) 57 | (s/close ::c ::a) 58 | ) -------------------------------------------------------------------------------- /src/test/clojure/discourje/core/ctl/used_channels_must_be_closed_async.clj: -------------------------------------------------------------------------------- 1 | (ns discourje.core.ctl.used-channels-must-be-closed-async 2 | (:require [discourje.core.spec :as s])) 3 | 4 | (s/defrole ::a) 5 | (s/defrole ::b) 6 | (s/defrole ::c) 7 | (s/defrole ::d) 8 | 9 | ;; All used channels are closed 10 | (s/defsession ::protocol-trivial-correct [] 11 | [ 12 | (s/-->> ::a ::b) 13 | (s/-->> ::b ::a) 14 | (s/close ::a ::b) 15 | (s/close ::b ::a) 16 | ]) 17 | 18 | ;; channel b a is not closed 19 | (s/defsession ::protocol-trivial-incorrect [] 20 | [ 21 | (s/-->> ::a ::b) 22 | (s/-->> ::b ::a) 23 | (s/close ::a ::b) 24 | ]) 25 | 26 | ;; all used channels are closed, but only in the path they are used and after some other actions 27 | (s/defsession ::protocol-non-trivial-correct [] 28 | (s/alt 29 | [ 30 | (s/-->> ::a ::b) 31 | (s/-->> ::b ::c) 32 | (s/close ::b ::c) 33 | ] 34 | [ 35 | (s/-->> ::a ::b) 36 | (s/-->> ::b ::d) 37 | (s/close ::b ::d) 38 | ]) 39 | (s/close ::a ::b) 40 | ) 41 | 42 | ;; channel d a is not closed 43 | (s/defsession ::protocol-non-trivial-incorrect [] 44 | (s/alt 45 | [(s/-->> ::a ::b) 46 | (s/-->> ::b ::c) 47 | (s/-->> ::c ::a) 48 | ] 49 | [(s/-->> ::a ::c) 50 | (s/-->> ::c ::d) 51 | (s/-->> ::d ::a) 52 | ]) 53 | (s/close ::a ::b) 54 | (s/close ::a ::c) 55 | (s/close ::b ::c) 56 | (s/close ::c ::d) 57 | (s/close ::c ::a) 58 | ) -------------------------------------------------------------------------------- /src/test/java/discourje/core/ctl/AbstractModelCheckerTest.java: -------------------------------------------------------------------------------- 1 | package discourje.core.ctl; 2 | 3 | import clojure.java.api.Clojure; 4 | import clojure.lang.IFn; 5 | import clojure.lang.Var; 6 | import discourje.core.lts.LTS; 7 | import java.util.List; 8 | import org.junit.jupiter.api.BeforeAll; 9 | 10 | public class AbstractModelCheckerTest { 11 | public static final String NS_VALIDATION = "discourje.core.ctl.validation-tests"; 12 | 13 | @BeforeAll 14 | public static void setUp() { 15 | IFn require = Clojure.var("clojure.core", "require"); 16 | require.invoke(Clojure.read("discourje.core.ctl.example-applications")); 17 | require.invoke(Clojure.read(NS_VALIDATION)); 18 | } 19 | 20 | protected List getModelCheckerResult(String name) { 21 | return getModelChecker(name).checkModel(); 22 | } 23 | 24 | private ModelChecker getModelChecker(String name) { 25 | return new ModelChecker(getLTS(name)); 26 | } 27 | 28 | LTS getLTS(String name) { 29 | IFn var = Clojure.var(NS_VALIDATION, name); 30 | @SuppressWarnings("unchecked") 31 | LTS lts = (LTS) ((Var) var).get(); 32 | return lts; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/test/java/discourje/core/ctl/ExampleApplicationsTest.java: -------------------------------------------------------------------------------- 1 | package discourje.core.ctl; 2 | 3 | import clojure.java.api.Clojure; 4 | import clojure.lang.IFn; 5 | import clojure.lang.Var; 6 | import discourje.core.lts.LTS; 7 | import java.util.List; 8 | import org.junit.jupiter.api.BeforeAll; 9 | import org.junit.jupiter.api.Disabled; 10 | import org.junit.jupiter.api.Test; 11 | 12 | class ExampleApplicationsTest { 13 | 14 | private static IFn require; 15 | 16 | @BeforeAll 17 | public static void setUp() { 18 | } 19 | 20 | @Test 21 | public void testProtocolChess() { 22 | List result = getModelCheckerResult("chess-protocol"); 23 | System.out.println(result); 24 | } 25 | 26 | @Test 27 | public void testProtocolGoFish() { 28 | List result = getModelCheckerResult("go-fish-protocol"); 29 | System.out.println(result); 30 | } 31 | 32 | @Test 33 | public void testProtocolRockPaperScissors() { 34 | List result = getModelCheckerResult("rock-paper-scissors-protocol"); 35 | System.out.println(result); 36 | } 37 | 38 | @Test 39 | public void testProtocolTicTacToe() { 40 | List result = getModelCheckerResult("tic-tac-toe-protocol"); 41 | System.out.println(result); 42 | } 43 | 44 | protected List getModelCheckerResult(String name) { 45 | require = Clojure.var("clojure.core", "require"); 46 | require.invoke(Clojure.read("discourje.core.async")); 47 | 48 | long t0 = System.currentTimeMillis(); 49 | require.invoke(Clojure.read("discourje.core.ctl.example-applications")); 50 | IFn var = Clojure.var("discourje.core.ctl.example-applications", name); 51 | @SuppressWarnings("unchecked") 52 | LTS lts = (LTS) ((Var) var).get(); 53 | lts.expandRecursively(); 54 | long t1 = System.currentTimeMillis(); 55 | ModelChecker modelChecker = new ModelChecker(lts); 56 | long t2 = System.currentTimeMillis(); 57 | List result = modelChecker.checkModel(); 58 | long t3 = System.currentTimeMillis(); 59 | System.out.println("#states;LTS; Model; Labelling"); 60 | System.out.println("" + lts.getStates().size() + ";" + (t1 - t0) / 1000.0 + ";" + (t2 - t1) / 1000.0 + ";" + (t3 - t2) / 1000.0); 61 | return result; 62 | } 63 | } -------------------------------------------------------------------------------- /src/test/java/discourje/core/ctl/formulas/ASTest.java: -------------------------------------------------------------------------------- 1 | package discourje.core.ctl.formulas; 2 | 3 | import discourje.core.ctl.Model; 4 | import discourje.core.ctl.State; 5 | import discourje.core.ctl.formulas.temporal.AS; 6 | import discourje.core.lts.Action; 7 | import org.junit.jupiter.api.Test; 8 | import static discourje.core.ctl.Formulas.close; 9 | import static discourje.core.ctl.Formulas.send; 10 | import static org.junit.jupiter.api.Assertions.assertFalse; 11 | import static org.junit.jupiter.api.Assertions.assertTrue; 12 | 13 | class ASTest extends AbstractCtlFormulaTest { 14 | 15 | @Test 16 | public void testValidOnAllPathsEarlySplit() { 17 | State s1 = createState(Action.Type.SEND, "a", "b"); 18 | State s2a = createState(Action.Type.SEND, "a", "b"); 19 | State s2b = createState(Action.Type.SEND, "a", "b"); 20 | State s3a = createState(Action.Type.CLOSE, "a", "b"); 21 | State s3b = createState(Action.Type.CLOSE, "a", "b"); 22 | 23 | s2a.addNextState(s1); 24 | s2b.addNextState(s1); 25 | s3a.addNextState(s2a); 26 | s3b.addNextState(s2b); 27 | 28 | Model model = createModel(s1, s2a, s2b, s3a, s3b); 29 | 30 | AS as = new AS(send("a", null), close("a", "b")); 31 | model.calculateLabels(as); 32 | 33 | assertTrue(model.hasLabel(s1, as)); 34 | } 35 | 36 | @Test 37 | public void testValidOnAllPathsLateSplit() { 38 | State s1 = createState(Action.Type.SEND, "a", "b"); 39 | State s2 = createState(Action.Type.SEND, "a", "b"); 40 | State s3a = createState(Action.Type.CLOSE, "a", "b"); 41 | State s3b = createState(Action.Type.CLOSE, "a", "b"); 42 | 43 | s2.addNextState(s1); 44 | s3a.addNextState(s2); 45 | s3b.addNextState(s2); 46 | 47 | Model model = createModel(s1, s2, s3a, s3b); 48 | 49 | AS as = new AS(send("a", null), close("a", "b")); 50 | model.calculateLabels(as); 51 | 52 | assertTrue(model.hasLabel(s1, as)); 53 | } 54 | 55 | @Test 56 | public void testValidOnOnePath() { 57 | State s1 = createState(Action.Type.SEND, "a", "b"); 58 | State s2a = createState(Action.Type.SEND, "a", "b"); 59 | State s2b = createState(Action.Type.SEND, "a", "b"); 60 | State s3a = createState(Action.Type.CLOSE, "a", "b"); 61 | State s3b = createState(Action.Type.CLOSE, "a", "c"); 62 | 63 | s2a.addNextState(s1); 64 | s2b.addNextState(s1); 65 | s3a.addNextState(s2a); 66 | s3b.addNextState(s2b); 67 | 68 | Model model = createModel(s1, s2a, s2b, s3a, s3b); 69 | 70 | AS as = new AS(send("a", null), close("a", "b")); 71 | model.calculateLabels(as); 72 | 73 | assertFalse(model.hasLabel(s1, as)); 74 | } 75 | 76 | @Test 77 | public void testValidOnNoPath() { 78 | State s1 = createState(Action.Type.SEND, "a", "b"); 79 | State s2a = createState(Action.Type.SEND, "a", "b"); 80 | State s2b = createState(Action.Type.SEND, "a", "b"); 81 | State s3a = createState(Action.Type.CLOSE, "a", "c"); 82 | State s3b = createState(Action.Type.CLOSE, "a", "c"); 83 | 84 | s2a.addNextState(s1); 85 | s2b.addNextState(s1); 86 | s3a.addNextState(s2a); 87 | s3b.addNextState(s2b); 88 | 89 | Model model = createModel(s1, s2a, s2b, s3a, s3b); 90 | 91 | AS as = new AS(send("a", null), close("a", "b")); 92 | model.calculateLabels(as); 93 | 94 | assertFalse(model.hasLabel(s1, as)); 95 | } 96 | } -------------------------------------------------------------------------------- /src/test/java/discourje/core/ctl/formulas/AXTest.java: -------------------------------------------------------------------------------- 1 | package discourje.core.ctl.formulas; 2 | 3 | import discourje.core.lts.Action; 4 | import discourje.core.ctl.State; 5 | import discourje.core.ctl.Model; 6 | import discourje.core.ctl.formulas.temporal.AX; 7 | import org.junit.jupiter.api.Test; 8 | import static discourje.core.ctl.Formulas.close; 9 | import static org.junit.jupiter.api.Assertions.*; 10 | 11 | class AXTest extends AbstractCtlFormulaTest { 12 | 13 | @Test 14 | public void testSelfAndAllSuccessors() { 15 | State s1 = createState(Action.Type.CLOSE, "a", "b"); 16 | State s2a = createState(Action.Type.CLOSE, "a", "b"); 17 | State s2b = createState(Action.Type.CLOSE, "a", "b"); 18 | 19 | s1.addNextState(s2a); 20 | s1.addNextState(s2b); 21 | 22 | Model model = createModel(s1, s2a, s2b); 23 | 24 | AX ax = new AX(close("a", "b")); 25 | model.calculateLabels(ax); 26 | 27 | assertTrue(model.hasLabel(s1, ax)); 28 | } 29 | 30 | @Test 31 | public void testNotSelfButAllSuccessors() { 32 | State s1 = createState(Action.Type.SEND, "a", "b"); 33 | State s2a = createState(Action.Type.CLOSE, "a", "b"); 34 | State s2b = createState(Action.Type.CLOSE, "a", "b"); 35 | 36 | s1.addNextState(s2a); 37 | s1.addNextState(s2b); 38 | 39 | Model model = createModel(s1, s2a, s2b); 40 | 41 | AX ax = new AX(close("a", "b")); 42 | model.calculateLabels(ax); 43 | 44 | assertTrue(model.hasLabel(s1, ax)); 45 | } 46 | 47 | @Test 48 | public void testNotAllSuccessors() { 49 | State s1 = createState(Action.Type.CLOSE, "a", "b"); 50 | State s2a = createState(Action.Type.SEND, "a", "b"); 51 | State s2b = createState(Action.Type.CLOSE, "a", "b"); 52 | 53 | s1.addNextState(s2a); 54 | s1.addNextState(s2b); 55 | 56 | Model model = createModel(s1, s2a, s2b); 57 | 58 | AX ax = new AX(close("a", "b")); 59 | model.calculateLabels(ax); 60 | 61 | assertFalse(model.hasLabel(s1, ax)); 62 | } 63 | 64 | @Test 65 | public void testNoSuccessors() { 66 | State s1 = createState(Action.Type.CLOSE, "a", "b"); 67 | State s2a = createState(Action.Type.SEND, "a", "b"); 68 | State s2b = createState(Action.Type.SEND, "a", "b"); 69 | 70 | s1.addNextState(s2a); 71 | s1.addNextState(s2b); 72 | 73 | Model model = createModel(s1, s2a, s2b); 74 | 75 | AX ax = new AX(close("a", "b")); 76 | model.calculateLabels(ax); 77 | 78 | assertFalse(model.hasLabel(s1, ax)); 79 | } 80 | } -------------------------------------------------------------------------------- /src/test/java/discourje/core/ctl/formulas/AYTest.java: -------------------------------------------------------------------------------- 1 | package discourje.core.ctl.formulas; 2 | 3 | import discourje.core.lts.Action; 4 | import discourje.core.ctl.State; 5 | import discourje.core.ctl.Model; 6 | import discourje.core.ctl.formulas.temporal.AY; 7 | import org.junit.jupiter.api.Test; 8 | import static discourje.core.ctl.Formulas.close; 9 | import static org.junit.jupiter.api.Assertions.assertFalse; 10 | import static org.junit.jupiter.api.Assertions.assertTrue; 11 | 12 | class AYTest extends AbstractCtlFormulaTest { 13 | 14 | @Test 15 | public void testSelfAndAllSuccessors() { 16 | State s1 = createState(Action.Type.CLOSE, "a", "b"); 17 | State s2a = createState(Action.Type.CLOSE, "a", "b"); 18 | State s2b = createState(Action.Type.CLOSE, "a", "b"); 19 | 20 | s2a.addNextState(s1); 21 | s2b.addNextState(s1); 22 | 23 | Model model = createModel(s1, s2a, s2b); 24 | 25 | AY ay = new AY(close("a", "b")); 26 | model.calculateLabels(ay); 27 | 28 | assertTrue(model.hasLabel(s1, ay)); 29 | } 30 | 31 | @Test 32 | public void testNotSelfButAllSuccessors() { 33 | State s1 = createState(Action.Type.SEND, "a", "b"); 34 | State s2a = createState(Action.Type.CLOSE, "a", "b"); 35 | State s2b = createState(Action.Type.CLOSE, "a", "b"); 36 | 37 | s2a.addNextState(s1); 38 | s2b.addNextState(s1); 39 | 40 | Model model = createModel(s1, s2a, s2b); 41 | 42 | AY ay = new AY(close("a", "b")); 43 | model.calculateLabels(ay); 44 | 45 | assertTrue(model.hasLabel(s1, ay)); 46 | } 47 | 48 | @Test 49 | public void testNotAllSuccessors() { 50 | State s1 = createState(Action.Type.CLOSE, "a", "b"); 51 | State s2a = createState(Action.Type.SEND, "a", "b"); 52 | State s2b = createState(Action.Type.CLOSE, "a", "b"); 53 | 54 | s2a.addNextState(s1); 55 | s2b.addNextState(s1); 56 | 57 | Model model = createModel(s1, s2a, s2b); 58 | 59 | AY ay = new AY(close("a", "b")); 60 | model.calculateLabels(ay); 61 | 62 | assertFalse(model.hasLabel(s1, ay)); 63 | } 64 | 65 | @Test 66 | public void testNoSuccessors() { 67 | State s1 = createState(Action.Type.CLOSE, "a", "b"); 68 | State s2a = createState(Action.Type.SEND, "a", "b"); 69 | State s2b = createState(Action.Type.SEND, "a", "b"); 70 | 71 | s2a.addNextState(s1); 72 | s2b.addNextState(s1); 73 | 74 | Model model = createModel(s1, s2a, s2b); 75 | 76 | AY ay = new AY(close("a", "b")); 77 | model.calculateLabels(ay); 78 | 79 | assertFalse(model.hasLabel(s1, ay)); 80 | } 81 | } -------------------------------------------------------------------------------- /src/test/java/discourje/core/ctl/formulas/AbstractCtlFormulaTest.java: -------------------------------------------------------------------------------- 1 | package discourje.core.ctl.formulas; 2 | 3 | import discourje.core.lts.Action; 4 | import discourje.core.ctl.State; 5 | import discourje.core.ctl.Model; 6 | import static org.mockito.Mockito.*; 7 | 8 | public class AbstractCtlFormulaTest { 9 | 10 | private int stateIndex = 0; 11 | 12 | @SuppressWarnings("unchecked") 13 | protected State createState(Action.Type type, String a, String a2) { 14 | Action action = new Action("name", type, null, a, a2); 15 | return new State(mock(discourje.core.lts.State.class), action, stateIndex++); 16 | } 17 | 18 | @SuppressWarnings("unchecked") 19 | protected State createState(Action action) { 20 | return new State(mock(discourje.core.lts.State.class), action, stateIndex++); 21 | } 22 | 23 | @SafeVarargs 24 | @SuppressWarnings("unchecked") 25 | protected final Model createModel(State... states) { 26 | return new Model(states); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/test/java/discourje/core/ctl/formulas/AndTest.java: -------------------------------------------------------------------------------- 1 | package discourje.core.ctl.formulas; 2 | 3 | import discourje.core.ctl.Model; 4 | import discourje.core.ctl.State; 5 | import discourje.core.lts.Action; 6 | import org.junit.jupiter.api.Test; 7 | import static discourje.core.ctl.Formulas.send; 8 | import static org.junit.jupiter.api.Assertions.assertFalse; 9 | import static org.junit.jupiter.api.Assertions.assertTrue; 10 | 11 | class AndTest extends AbstractCtlFormulaTest { 12 | 13 | @Test 14 | public void testAnd() { 15 | State s1 = createState(Action.Type.SEND, "a", "a"); 16 | State s2 = createState(Action.Type.SEND, "a", "b"); 17 | State s3 = createState(Action.Type.SEND, "b", "a"); 18 | State s4 = createState(Action.Type.SEND, "b", "b"); 19 | Model model = createModel(s1, s2, s3, s4); 20 | 21 | And and = new And(send("a", "a"), send("a", null), send(null, "a")); 22 | model.calculateLabels(and); 23 | 24 | // verify 25 | assertTrue(model.hasLabel(s1, and)); 26 | assertFalse(model.hasLabel(s2, and)); 27 | assertFalse(model.hasLabel(s3, and)); 28 | assertFalse(model.hasLabel(s4, and)); 29 | } 30 | 31 | } -------------------------------------------------------------------------------- /src/test/java/discourje/core/ctl/formulas/CloseTest.java: -------------------------------------------------------------------------------- 1 | package discourje.core.ctl.formulas; 2 | 3 | import discourje.core.lts.Action; 4 | import discourje.core.ctl.Formula; 5 | import discourje.core.ctl.State; 6 | import discourje.core.ctl.Model; 7 | import discourje.core.ctl.formulas.atomic.Close; 8 | import org.junit.jupiter.api.Test; 9 | import static org.junit.jupiter.api.Assertions.assertFalse; 10 | import static org.junit.jupiter.api.Assertions.assertTrue; 11 | 12 | class CloseTest extends AbstractCtlFormulaTest { 13 | 14 | @Test 15 | public void testClose() { 16 | // setup 17 | State s1 = createState(Action.Type.CLOSE, "a", "b"); 18 | State s2 = createState(Action.Type.CLOSE, "b", "a"); 19 | 20 | Model model = createModel(s1, s2); 21 | 22 | // execute 23 | Formula close = new Close("a", "b"); 24 | model.calculateLabels(close); 25 | 26 | // verify 27 | assertTrue(model.hasLabel(s1, close)); 28 | assertFalse(model.hasLabel(s2, close)); 29 | } 30 | 31 | } -------------------------------------------------------------------------------- /src/test/java/discourje/core/ctl/formulas/EXTest.java: -------------------------------------------------------------------------------- 1 | package discourje.core.ctl.formulas; 2 | 3 | import discourje.core.lts.Action; 4 | import discourje.core.ctl.State; 5 | import discourje.core.ctl.Model; 6 | import discourje.core.ctl.formulas.atomic.Close; 7 | import discourje.core.ctl.formulas.temporal.EX; 8 | import org.junit.jupiter.api.Test; 9 | import static org.junit.jupiter.api.Assertions.*; 10 | 11 | class EXTest extends AbstractCtlFormulaTest { 12 | 13 | @Test 14 | public void testEXLine() { 15 | State s1 = createState(Action.Type.SEND, "a", "b"); 16 | State s2 = createState(Action.Type.SEND, "b", "c"); 17 | State s3 = createState(Action.Type.CLOSE, "a", "b"); 18 | State s4 = createState(Action.Type.CLOSE, "b", "c"); 19 | s1.addNextState(s2); 20 | s2.addNextState(s3); 21 | s3.addNextState(s4); 22 | Model model = createModel(s1, s2, s3, s4); 23 | 24 | EX ex = new EX(new Close("a", "b")); 25 | model.calculateLabels(ex); 26 | 27 | assertFalse(model.hasLabel(s1, ex)); 28 | assertTrue(model.hasLabel(s2, ex)); 29 | assertFalse(model.hasLabel(s3, ex)); 30 | assertFalse(model.hasLabel(s4, ex)); 31 | } 32 | 33 | @Test 34 | public void testEXAllPaths() { 35 | State s1 = createState(Action.Type.SEND, "a", "b"); 36 | State s2a = createState(Action.Type.CLOSE, "a", "b"); 37 | State s2b = createState(Action.Type.CLOSE, "a", "b"); 38 | s1.addNextState(s2a); 39 | s1.addNextState(s2b); 40 | Model model = createModel(s1, s2a, s2b); 41 | 42 | EX ex = new EX(new Close("a", "b")); 43 | model.calculateLabels(ex); 44 | 45 | assertTrue(model.hasLabel(s1, ex)); 46 | assertFalse(model.hasLabel(s2a, ex)); 47 | assertFalse(model.hasLabel(s2a, ex)); 48 | } 49 | 50 | @Test 51 | public void testEXOnePath() { 52 | State s1 = createState(Action.Type.SEND, "a", "b"); 53 | State s2a = createState(Action.Type.CLOSE, "a", "b"); 54 | State s2b = createState(Action.Type.CLOSE, "b", "c"); 55 | s1.addNextState(s2a); 56 | s1.addNextState(s2b); 57 | Model model = createModel(s1, s2a, s2b); 58 | 59 | EX ex = new EX(new Close("a", "b")); 60 | model.calculateLabels(ex); 61 | 62 | assertTrue(model.hasLabel(s1, ex)); 63 | assertFalse(model.hasLabel(s2a, ex)); 64 | assertFalse(model.hasLabel(s2a, ex)); 65 | } 66 | 67 | @Test 68 | public void testEXNoPath() { 69 | State s1 = createState(Action.Type.SEND, "a", "b"); 70 | State s2a = createState(Action.Type.CLOSE, "b", "c"); 71 | State s2b = createState(Action.Type.CLOSE, "b", "c"); 72 | s1.addNextState(s2a); 73 | s1.addNextState(s2b); 74 | Model model = createModel(s1, s2a, s2b); 75 | 76 | EX ex = new EX(new Close("a", "b")); 77 | model.calculateLabels(ex); 78 | 79 | assertFalse(model.hasLabel(s1, ex)); 80 | assertFalse(model.hasLabel(s2a, ex)); 81 | assertFalse(model.hasLabel(s2a, ex)); 82 | } 83 | } -------------------------------------------------------------------------------- /src/test/java/discourje/core/ctl/formulas/EYTest.java: -------------------------------------------------------------------------------- 1 | package discourje.core.ctl.formulas; 2 | 3 | import discourje.core.lts.Action; 4 | import discourje.core.ctl.State; 5 | import discourje.core.ctl.Model; 6 | import discourje.core.ctl.formulas.atomic.Close; 7 | import discourje.core.ctl.formulas.temporal.EY; 8 | import org.junit.jupiter.api.Test; 9 | import static org.junit.jupiter.api.Assertions.assertFalse; 10 | import static org.junit.jupiter.api.Assertions.assertTrue; 11 | 12 | class EYTest extends AbstractCtlFormulaTest { 13 | 14 | @Test 15 | public void testEYLine() { 16 | State s1 = createState(Action.Type.SEND, "a", "b"); 17 | State s2 = createState(Action.Type.SEND, "b", "c"); 18 | State s3 = createState(Action.Type.CLOSE, "a", "b"); 19 | State s4 = createState(Action.Type.CLOSE, "b", "c"); 20 | s2.addNextState(s1); 21 | s3.addNextState(s2); 22 | s4.addNextState(s3); 23 | Model model = createModel(s1, s2, s3, s4); 24 | 25 | EY ey = new EY(new Close("a", "b")); 26 | model.calculateLabels(ey); 27 | 28 | assertFalse(model.hasLabel(s1, ey)); 29 | assertTrue(model.hasLabel(s2, ey)); 30 | assertFalse(model.hasLabel(s3, ey)); 31 | assertFalse(model.hasLabel(s4, ey)); 32 | } 33 | 34 | @Test 35 | public void testEYAllPaths() { 36 | State s1 = createState(Action.Type.SEND, "a", "b"); 37 | State s2a = createState(Action.Type.CLOSE, "a", "b"); 38 | State s2b = createState(Action.Type.CLOSE, "a", "b"); 39 | s2a.addNextState(s1); 40 | s2b.addNextState(s1); 41 | Model model = createModel(s1, s2a, s2b); 42 | 43 | EY ey = new EY(new Close("a", "b")); 44 | model.calculateLabels(ey); 45 | 46 | assertTrue(model.hasLabel(s1, ey)); 47 | assertFalse(model.hasLabel(s2a, ey)); 48 | assertFalse(model.hasLabel(s2b, ey)); 49 | } 50 | 51 | @Test 52 | public void testEYOnePath() { 53 | State s1 = createState(Action.Type.SEND, "a", "b"); 54 | State s2a = createState(Action.Type.CLOSE, "a", "b"); 55 | State s2b = createState(Action.Type.CLOSE, "b", "c"); 56 | s2a.addNextState(s1); 57 | s2b.addNextState(s1); 58 | Model model = createModel(s1, s2a, s2b); 59 | 60 | EY ey = new EY(new Close("a", "b")); 61 | model.calculateLabels(ey); 62 | 63 | assertTrue(model.hasLabel(s1, ey)); 64 | assertFalse(model.hasLabel(s2a, ey)); 65 | assertFalse(model.hasLabel(s2b, ey)); 66 | } 67 | 68 | @Test 69 | public void testEYNoPath() { 70 | State s1 = createState(Action.Type.SEND, "a", "b"); 71 | State s2a = createState(Action.Type.CLOSE, "b", "c"); 72 | State s2b = createState(Action.Type.CLOSE, "b", "c"); 73 | s2a.addNextState(s1); 74 | s2b.addNextState(s1); 75 | Model model = createModel(s1, s2a, s2b); 76 | 77 | EY ey = new EY(new Close("a", "b")); 78 | model.calculateLabels(ey); 79 | 80 | assertFalse(model.hasLabel(s1, ey)); 81 | assertFalse(model.hasLabel(s2a, ey)); 82 | assertFalse(model.hasLabel(s2b, ey)); 83 | } 84 | } -------------------------------------------------------------------------------- /src/test/java/discourje/core/ctl/formulas/ImpliesTest.java: -------------------------------------------------------------------------------- 1 | package discourje.core.ctl.formulas; 2 | 3 | import discourje.core.lts.Action; 4 | import discourje.core.ctl.State; 5 | import discourje.core.ctl.Model; 6 | import discourje.core.ctl.formulas.atomic.True; 7 | import org.junit.jupiter.api.Test; 8 | import static org.junit.jupiter.api.Assertions.*; 9 | 10 | class ImpliesTest extends AbstractCtlFormulaTest { 11 | 12 | @Test 13 | public void testTrueImpliesTrueIsTrue() { 14 | State s1 = createState(Action.Type.SEND, "a", "b"); 15 | Model model = createModel(s1); 16 | 17 | Implies implies = new Implies(True.INSTANCE, True.INSTANCE); 18 | model.calculateLabels(implies); 19 | 20 | assertTrue(model.hasLabel(s1, implies)); 21 | } 22 | 23 | @Test 24 | public void testTrueImpliesFalseIsFalse() { 25 | State s1 = createState(Action.Type.SEND, "a", "b"); 26 | Model model = createModel(s1); 27 | 28 | Implies implies = new Implies(True.INSTANCE, new Not(True.INSTANCE)); 29 | model.calculateLabels(implies); 30 | 31 | assertFalse(model.hasLabel(s1, implies)); 32 | } 33 | 34 | @Test 35 | public void testFalseImpliesTrueIsTrue() { 36 | State s1 = createState(Action.Type.SEND, "a", "b"); 37 | Model model = createModel(s1); 38 | 39 | Implies implies = new Implies(True.INSTANCE, True.INSTANCE); 40 | model.calculateLabels(implies); 41 | 42 | assertTrue(model.hasLabel(s1, implies)); 43 | } 44 | 45 | @Test 46 | public void testFalseImpliesFalseIsTrue() { 47 | State s1 = createState(Action.Type.SEND, "a", "b"); 48 | Model model = createModel(s1); 49 | 50 | Implies implies = new Implies(True.INSTANCE, True.INSTANCE); 51 | model.calculateLabels(implies); 52 | 53 | assertTrue(model.hasLabel(s1, implies)); 54 | } 55 | } -------------------------------------------------------------------------------- /src/test/java/discourje/core/ctl/formulas/InitTest.java: -------------------------------------------------------------------------------- 1 | package discourje.core.ctl.formulas; 2 | 3 | import discourje.core.lts.Action; 4 | import discourje.core.ctl.State; 5 | import discourje.core.ctl.Model; 6 | import discourje.core.ctl.formulas.atomic.Init; 7 | import org.junit.jupiter.api.Test; 8 | import static org.junit.jupiter.api.Assertions.*; 9 | import static org.mockito.Mockito.*; 10 | 11 | class InitTest extends AbstractCtlFormulaTest { 12 | 13 | @Test 14 | public void testFirst() { 15 | State firstState = createState(null); 16 | State secondState = createState(Action.Type.SEND, "a", "b"); 17 | Model model = createModel(firstState, secondState); 18 | 19 | Init init = Init.INSTANCE; 20 | model.calculateLabels(init); 21 | 22 | assertTrue(model.hasLabel(firstState, init)); 23 | assertFalse(model.hasLabel(secondState, init)); 24 | } 25 | } -------------------------------------------------------------------------------- /src/test/java/discourje/core/ctl/formulas/NotTest.java: -------------------------------------------------------------------------------- 1 | package discourje.core.ctl.formulas; 2 | 3 | import discourje.core.lts.Action; 4 | import discourje.core.ctl.State; 5 | import discourje.core.ctl.Model; 6 | import discourje.core.ctl.formulas.atomic.Send; 7 | import org.junit.jupiter.api.Test; 8 | import static org.junit.jupiter.api.Assertions.*; 9 | 10 | class NotTest extends AbstractCtlFormulaTest { 11 | 12 | @Test 13 | public void testNot() { 14 | State s1 = createState(Action.Type.SEND, "a", "b"); 15 | State s2 = createState(Action.Type.SEND, "b", "a"); 16 | Model model = createModel(s1, s2); 17 | 18 | Not not = new Not(new Send("a", null)); 19 | model.calculateLabels(not); 20 | 21 | assertFalse(model.hasLabel(s1, not)); 22 | assertTrue(model.hasLabel(s2, not)); 23 | } 24 | } -------------------------------------------------------------------------------- /src/test/java/discourje/core/ctl/formulas/OrTest.java: -------------------------------------------------------------------------------- 1 | package discourje.core.ctl.formulas; 2 | 3 | import discourje.core.lts.Action; 4 | import discourje.core.ctl.Formula; 5 | import discourje.core.ctl.State; 6 | import discourje.core.ctl.Model; 7 | import org.junit.jupiter.api.Test; 8 | import static discourje.core.ctl.Formulas.receive; 9 | import static discourje.core.ctl.Formulas.send; 10 | import static org.junit.jupiter.api.Assertions.assertFalse; 11 | import static org.junit.jupiter.api.Assertions.assertTrue; 12 | 13 | class OrTest extends AbstractCtlFormulaTest { 14 | 15 | @Test 16 | public void testOr() { 17 | State s1 = createState(Action.Type.SEND, "a", "a"); 18 | State s2 = createState(Action.Type.SEND, "a", "b"); 19 | State s3 = createState(Action.Type.SEND, "b", "a"); 20 | State s4 = createState(Action.Type.SEND, "b", "b"); 21 | Model model = createModel(s1, s2, s3, s4); 22 | 23 | Formula or = new Or(send("a", "a"), send("a", null), receive(null, "a")); 24 | model.calculateLabels(or); 25 | 26 | // verify 27 | assertTrue(model.hasLabel(s1, or)); 28 | assertTrue(model.hasLabel(s2, or)); 29 | assertFalse(model.hasLabel(s3, or)); 30 | assertFalse(model.hasLabel(s4, or)); 31 | } 32 | } -------------------------------------------------------------------------------- /src/test/java/discourje/core/ctl/formulas/ReceiveTest.java: -------------------------------------------------------------------------------- 1 | package discourje.core.ctl.formulas; 2 | 3 | import discourje.core.lts.Action; 4 | import discourje.core.ctl.State; 5 | import discourje.core.ctl.Model; 6 | import discourje.core.ctl.formulas.atomic.Receive; 7 | import org.junit.jupiter.api.Test; 8 | import static org.junit.jupiter.api.Assertions.*; 9 | 10 | class ReceiveTest extends AbstractCtlFormulaTest { 11 | 12 | @Test 13 | public void testReceive() { 14 | State s1 = createState(Action.Type.SYNC, "a", "b"); 15 | State s2 = createState(Action.Type.SEND, "a", "b"); 16 | State s3 = createState(Action.Type.RECEIVE, "a", "b"); 17 | State s4 = createState(Action.Type.CLOSE, "a", "b"); 18 | State s5 = createState(Action.Type.SYNC, "b", "a"); 19 | State s6 = createState(Action.Type.SEND, "b", "a"); 20 | State s7 = createState(Action.Type.RECEIVE, "b", "a"); 21 | State s8 = createState(Action.Type.CLOSE, "b", "a"); 22 | Model model = createModel(s1, s2, s3, s4, s5, s6, s7, s8); 23 | 24 | Receive rcv = new Receive(null, "a"); 25 | model.calculateLabels(rcv); 26 | 27 | assertFalse(model.hasLabel(s1, rcv)); 28 | assertFalse(model.hasLabel(s2, rcv)); 29 | assertFalse(model.hasLabel(s3, rcv)); 30 | assertFalse(model.hasLabel(s4, rcv)); 31 | assertFalse(model.hasLabel(s5, rcv)); 32 | assertFalse(model.hasLabel(s6, rcv)); 33 | assertTrue(model.hasLabel(s7, rcv)); 34 | assertFalse(model.hasLabel(s8, rcv)); 35 | } 36 | } -------------------------------------------------------------------------------- /src/test/java/discourje/core/ctl/formulas/SendTest.java: -------------------------------------------------------------------------------- 1 | package discourje.core.ctl.formulas; 2 | 3 | import discourje.core.lts.Action; 4 | import discourje.core.ctl.State; 5 | import discourje.core.ctl.Model; 6 | import discourje.core.ctl.formulas.atomic.Send; 7 | import org.junit.jupiter.api.Test; 8 | import static org.junit.jupiter.api.Assertions.assertFalse; 9 | import static org.junit.jupiter.api.Assertions.assertTrue; 10 | 11 | class SendTest extends AbstractCtlFormulaTest { 12 | 13 | @Test 14 | public void testSend() { 15 | State s1 = createState(Action.Type.SYNC, "a", "b"); 16 | State s2 = createState(Action.Type.SEND, "a", "b"); 17 | State s3 = createState(Action.Type.RECEIVE, "a", "b"); 18 | State s4 = createState(Action.Type.CLOSE, "a", "b"); 19 | State s5 = createState(Action.Type.SYNC, "b", "a"); 20 | State s6 = createState(Action.Type.SEND, "b", "a"); 21 | State s7 = createState(Action.Type.RECEIVE, "b", "a"); 22 | State s8 = createState(Action.Type.CLOSE, "b", "a"); 23 | Model model = createModel(s1, s2, s3, s4, s5, s6, s7, s8); 24 | 25 | Send snd = new Send("a", null); 26 | model.calculateLabels(snd); 27 | 28 | assertFalse(model.hasLabel(s1, snd)); 29 | assertTrue(model.hasLabel(s2, snd)); 30 | assertFalse(model.hasLabel(s3, snd)); 31 | assertFalse(model.hasLabel(s4, snd)); 32 | assertFalse(model.hasLabel(s5, snd)); 33 | assertFalse(model.hasLabel(s6, snd)); 34 | assertFalse(model.hasLabel(s7, snd)); 35 | assertFalse(model.hasLabel(s8, snd)); 36 | } 37 | } -------------------------------------------------------------------------------- /src/test/java/discourje/core/ctl/formulas/TrueTest.java: -------------------------------------------------------------------------------- 1 | package discourje.core.ctl.formulas; 2 | 3 | import discourje.core.ctl.formulas.atomic.True; 4 | import discourje.core.lts.Action; 5 | import discourje.core.ctl.State; 6 | import discourje.core.ctl.Model; 7 | import org.junit.jupiter.api.Test; 8 | import static org.junit.jupiter.api.Assertions.*; 9 | 10 | class TrueTest extends AbstractCtlFormulaTest { 11 | 12 | @Test 13 | public void testTrue() { 14 | State s1 = createState(Action.Type.SYNC, "a", "b"); 15 | Model model = createModel(s1); 16 | 17 | True _true = True.INSTANCE; 18 | model.calculateLabels(_true); 19 | 20 | assertTrue(model.hasLabel(s1, _true)); 21 | } 22 | } --------------------------------------------------------------------------------