From bd2594fe626a8239698e79bebba6fb428fe9dc46 Mon Sep 17 00:00:00 2001 From: Michael Leuschel <leuschel@uni-duesseldorf.de> Date: Tue, 3 Sep 2024 15:32:37 +0200 Subject: [PATCH] add TLA+ version of Jars puzzle --- Jars/DieHard.tla | 141 ++++++++++++++++++++++++++++++++++ Jars/DieHard_tla.json | 172 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 313 insertions(+) create mode 100644 Jars/DieHard.tla create mode 100644 Jars/DieHard_tla.json diff --git a/Jars/DieHard.tla b/Jars/DieHard.tla new file mode 100644 index 0000000..bedfe7d --- /dev/null +++ b/Jars/DieHard.tla @@ -0,0 +1,141 @@ +------------------------------ MODULE DieHard ------------------------------- +(* File from TLC distribution; minor change for ProB and VisB *) +(***************************************************************************) +(* In the movie Die Hard 3, the heros must obtain exactly 4 gallons of *) +(* water using a 5 gallon jug, a 3 gallon jug, and a water faucet. Our *) +(* goal: to get TLC to solve the problem for us. *) +(* *) +(* First, we write a spec that describes all allowable behaviors of our *) +(* heros. *) +(***************************************************************************) +EXTENDS Integers + (*************************************************************************) + (* This statement imports the definitions of the ordinary operators on *) + (* natural numbers, such as +. *) + (*************************************************************************) + + +(***************************************************************************) +(* We next declare the specification's variables. *) +(***************************************************************************) +VARIABLES big, \* The number of gallons of water in the 5 gallon jug. + small \* The number of gallons of water in the 3 gallon jug. + + +VISB_JSON_FILE == "DieHard_tla.json" \* addition for ProB-VisB +GOAL == (big=4) \* for ProB; not really required; config file has invariant + +(***************************************************************************) +(* We now define TypeOK to be the type invariant, asserting that the value *) +(* of each variable is an element of the appropriate set. A type *) +(* invariant like this is not part of the specification, but it's *) +(* generally a good idea to include it because it helps the reader *) +(* understand the spec. Moreover, having TLC check that it is an *) +(* invariant of the spec catches errors that, in a typed language, are *) +(* caught by type checking. *) +(* *) +(* Note: TLA+ uses the convention that a list of formulas bulleted by /\ *) +(* or \/ denotes the conjunction or disjunction of those formulas. *) +(* Indentation of subitems is significant, allowing one to eliminate lots *) +(* of parentheses. This makes a large formula much easier to read. *) +(* However, it does mean that you have to be careful with your indentation.*) +(***************************************************************************) +TypeOK == /\ small \in 0..3 + /\ big \in 0..5 + + +(***************************************************************************) +(* Now we define of the initial predicate, that specifies the initial *) +(* values of the variables. I like to name this predicate Init, but the *) +(* name doesn't matter. *) +(***************************************************************************) +Init == /\ big = 0 + /\ small = 0 + +(***************************************************************************) +(* Now we define the actions that our hero can perform. There are three *) +(* things they can do: *) +(* *) +(* - Pour water from the faucet into a jug. *) +(* *) +(* - Pour water from a jug onto the ground. *) +(* *) +(* - Pour water from one jug into another *) +(* *) +(* We now consider the first two. Since the jugs are not calibrated, *) +(* partially filling or partially emptying a jug accomplishes nothing. *) +(* So, the first two possibilities yield the following four possible *) +(* actions. *) +(***************************************************************************) +FillSmallJug == /\ small' = 3 + /\ big' = big + +FillBigJug == /\ big' = 5 + /\ small' = small + +EmptySmallJug == /\ small' = 0 + /\ big' = big + +EmptyBigJug == /\ big' = 0 + /\ small' = small + +(***************************************************************************) +(* We now consider pouring water from one jug into another. Again, since *) +(* the jugs are not callibrated, when pouring from jug A to jug B, it *) +(* makes sense only to either fill B or empty A. And there's no point in *) +(* emptying A if this will cause B to overflow, since that could be *) +(* accomplished by the two actions of first filling B and then emptying A. *) +(* So, pouring water from A to B leaves B with the lesser of (i) the water *) +(* contained in both jugs and (ii) the volume of B. To express this *) +(* mathematically, we first define Min(m,n) to equal the minimum of the *) +(* numbers m and n. *) +(***************************************************************************) +Min(m,n) == IF m < n THEN m ELSE n + +(***************************************************************************) +(* Now we define the last two pouring actions. From the observation *) +(* above, these definitions should be clear. *) +(***************************************************************************) +SmallToBig == /\ big' = Min(big + small, 5) + /\ small' = small - (big' - big) + +BigToSmall == /\ small' = Min(big + small, 3) + /\ big' = big - (small' - small) + +(***************************************************************************) +(* We define the next-state relation, which I like to call Next. A Next *) +(* step is a step of one of the six actions defined above. Hence, Next is *) +(* the disjunction of those actions. *) +(***************************************************************************) +Next == \/ FillSmallJug + \/ FillBigJug + \/ EmptySmallJug + \/ EmptyBigJug + \/ SmallToBig + \/ BigToSmall + +(***************************************************************************) +(* We define the formula Spec to be the complete specification, asserting *) +(* of a behavior that it begins in a state satisfying Init, and that every *) +(* step either satisfies Next or else leaves the pair <<big, small>> *) +(* unchanged. *) +(***************************************************************************) +Spec == Init /\ [][Next]_<<big, small>> +----------------------------------------------------------------------------- + +(***************************************************************************) +(* Remember that our heros must measure out 4 gallons of water. *) +(* Obviously, those 4 gallons must be in the 5 gallon jug. So, they have *) +(* solved their problem when they reach a state with big = 4. So, we *) +(* define NotSolved to be the predicate asserting that big # 4. *) +(***************************************************************************) +NotSolved == big # 4 + +(***************************************************************************) +(* We find a solution by having TLC check if NotSolved is an invariant, *) +(* which will cause it to print out an "error trace" consisting of a *) +(* behavior ending in a states where NotSolved is false. Such a *) +(* behavior is the desired solution. (Because TLC uses a breadth-first *) +(* search, it will find the shortest solution.) *) +(***************************************************************************) +============================================================================= diff --git a/Jars/DieHard_tla.json b/Jars/DieHard_tla.json new file mode 100644 index 0000000..7671df9 --- /dev/null +++ b/Jars/DieHard_tla.json @@ -0,0 +1,172 @@ +{ + "svg":"Jars.svg", + "comment": "VisB Visualization for Jars by Jonas Erdmann", + "definitions":[ + {"name":"level", + "value": "{3|->small, 5|->big}", + "comment":"simulating the level variable from the classical B model" + }, + {"name":"maxf", + "value": "{3|->3, 5|->5}", + "comment":"simulating the level variable from the classical B model" + } + ], + "items": [ + { + "id": "jar_%0_full", + "attr": "height", + "value": "level(%0) * 20", + "repeat": [ + ["3"], ["5"] + ] + }, + { + "id": "jar_%0_text", + "attr": "text", + "value": "level(%0)", + "repeat": [ + ["3"], ["5"] + ] + }, + { + "id": "jar_%0_svg", + "attr": "height", + "value": "maxf(%0) * 20", + "repeat": [ + ["3"], ["5"] + ] + }, + { + "id": "jar_%0_svg", + "attr": "y", + "value": "0 -(max({maxf(3), maxf(5)}) * 20 - 100)", + "repeat": [ + ["3"], ["5"] + ] + }, + { + "id": "jar_%0_empty", + "attr": "height", + "value": "maxf(%0) * 20", + "repeat": [ + ["3"], ["5"] + ] + }, + { + "id": "left_%0", + "attr": "y2", + "value": "maxf(%0) * 20", + "repeat": [ + ["3"], ["5"] + ] + }, + { + "id": "right_%0", + "attr": "y2", + "value": "maxf(%0) * 20", + "repeat": [ + ["3"], ["5"] + ] + }, + { + "id": "goal_achieved", + "attr": "opacity", + "value": "IF max({level(3), level(5)}) = max({maxf(3), maxf(5)}) -1 THEN 1 ELSE 0 END" + }, + { + "id": "transfer_left", + "attr": "opacity", + "value": "IF level(3) = maxf(3) THEN 0 ELSE IF level(5) = 0 THEN 0 ELSE 1 END END" + }, + { + "id": "transfer_right", + "attr": "opacity", + "value": "IF level(5) = maxf(5) THEN 0 ELSE IF level(3) = 0 THEN 0 ELSE 1 END END" + }, + { + "id": "transfer_sym3", + "attr": "opacity", + "value": "IF level(3) = 0 & level(5) = 0 THEN 0 ELSE IF level(3) = maxf(3) & level(5) = maxf(5) THEN 0 ELSE 1 END END" + }, + { + "id": "goal", + "attr": "x1", + "value": "IF maxf(3) > maxf(5) THEN 2 ELSE 107 END" + }, + { + "id": "goal", + "attr": "x2", + "value": "IF maxf(3) > maxf(5) THEN 48 ELSE 153 END" + } + +], + "events": [ + { + "id": "fill_3", + "event": "FillSmallJug", + "hovers": [{ "attr":"stroke-width", "enter":"6", "leave":"1"}, + { "attr":"opacity", "enter":"0.8", "leave":"1.0"}] + }, + { + "id": "fill_5", + "event": "FillBigJug", + "hovers": [{ "attr":"stroke-width", "enter":"6", "leave":"1"}, + { "attr":"opacity", "enter":"0.8", "leave":"1.0"}] + }, + { + "id": "fill_3_sym", + "event": "FillSmallJug" + }, + { + "id": "fill_5_sym", + "event": "FillBigJug" + }, + { + "id": "empty_3", + "event": "EmptySmallJug", + "hovers": [{ "attr":"stroke-width", "enter":"6", "leave":"1"}, + { "attr":"opacity", "enter":"0.8", "leave":"1.0"}] + }, + { + "id": "empty_5", + "event": "EmptyBigJug", + "hovers": [{ "attr":"stroke-width", "enter":"6", "leave":"1"}, + { "attr":"opacity", "enter":"0.8", "leave":"1.0"}] + }, + { + "id": "empty_3_sym", + "event": "EmptySmallJug" + }, + { + "id": "empty_5_sym", + "event": "EmptyBigJug" + }, + { + "id": "transfer", + "event": "BigToSmall", + "hovers": [{ "attr":"stroke-width", "enter":"6", "leave":"1"}, + { "attr":"opacity", "enter":"0.8", "leave":"1.0"}] + }, + { + "id": "transfer", + "event": "SmallToBig" + }, + { + "id": "transfer_left", + "event": "BigToSmall" + }, + { + "id": "transfer_right", + "event": "SmallToBig" + }, + { + "id": "transfer_sym3", + "event": "BigToSmall" + }, + { + "id": "transfer_sym3", + "event": "SmallToBig" + } + ] +} + -- GitLab