diff --git a/.gitignore b/.gitignore index a40cd7472b0fb88382dbda47b54906dfe7f9de31..133e971bdcf8c70942e6eb5d1e807165158de17a 100644 --- a/.gitignore +++ b/.gitignore @@ -29,3 +29,6 @@ tlatools/build !**/gradle/wrapper/gradle-wrapper.jar ajcore.*.txt tlatools/test-model/CodePlexBug08/checkpoint/ +tlatools/test-model/CallGotoUnlabeledTest.old +junit[0-9]*.properties +junitvmwatcher[0-9]*.properties diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index dc9368190c43f6820a01bb5c76680d7a3aaf6a6d..bf1254715d67626b6d7bd44bf486d99855782ced 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,4 +1,6 @@ -We welcome contributions from volunteers. A number of [improvements we'd like to see implemented](https://github.com/tlaplus/tlaplus/blob/master/general/docs/contributions.md) are listed at [general/docs/contributions.md](https://github.com/tlaplus/tlaplus/blob/master/general/docs/contributions.md) in addition to the [issues tagged with "helpwanted"](https://github.com/tlaplus/tlaplus/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22). But we're happy to consider anything you'd like to contribute. However, some parts of the tlaplus repository follow a very strict contribution policy. So before you start working on anything, please [discuss with us](https://github.com/tlaplus/tlaplus/issues) what you want to do. You can do that on the [issues page](https://github.com/tlaplus/tlaplus/issues). We do not want to reject your 1k LOC patch because the actual change is not considered sensible by us. +Is this your first contribution to Open Source? If yes, please read the excellent first time contributor guide at [https://opensource.guide/how-to-contribute/](https://opensource.guide/how-to-contribute/). + +Generally, we welcome contributions from volunteers. A number of [improvements we'd like to see implemented](https://github.com/tlaplus/tlaplus/blob/master/general/docs/contributions.md) are listed at [general/docs/contributions.md](https://github.com/tlaplus/tlaplus/blob/master/general/docs/contributions.md) in addition to the [issues tagged with "helpwanted"](https://github.com/tlaplus/tlaplus/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22). But we're happy to consider anything you'd like to contribute. However, some parts of the tlaplus repository follow a very strict contribution policy. So before you start working on anything, please [discuss with us](https://github.com/tlaplus/tlaplus/issues) what you want to do. You can do that on the [issues page](https://github.com/tlaplus/tlaplus/issues). We do not want to reject your 1k LOC patch because the actual change is not considered sensible by us. diff --git a/general/docs/changelogs/ch1_5_7.md b/general/docs/changelogs/ch1_5_7.md new file mode 100644 index 0000000000000000000000000000000000000000..e4e09e2575bb1cd4f08f9061e7e6c2fb60e6af52 --- /dev/null +++ b/general/docs/changelogs/ch1_5_7.md @@ -0,0 +1,46 @@ +### Changelog +The high level changelog is available at http://research.microsoft.com/en-us/um/people/lamport/tla/toolbox.html#release. The [1.5.7 milestone](https://github.com/tlaplus/tlaplus/issues?q=is%3Aissue+milestone%3A1.5.7+is%3Aclosed) lists all completed issues. + +### Additional noteworthy changes + +#### TLC +* Reword and complete comments of TLA<sup>+</sup> standard modules d2f54a1a5e3b7d9a9ac397046e147c7ef63c2f9d +* IsABag inconsistent with Bags.tla when parameter is not a bag 5d15bde33891d34cdf07eaaf94845db665c59c72 +* BagsUnion operator of TLA<sup>+</sup> standard module for `BagUnion({b,b})` produces incorrect `b (+) b` as result bc0f7dbf89a703a5899689b98232f1fe02241918 +* [Correctly handle sequences as input to Bags operators](https://github.com/tlaplus/tlaplus/issues/139) +* [Provisional Randomization standard module] +* tlc2.Generator refactored into tlc2.TLC 6141aed0c680f6b3257527e91d6652fc5adedaa6 +* Correctly recreate error trace in BFS mode with RandomElement 3a618d7dc566dd1fbae90d2ebbe5066d2c300fe2 +* Minimize the number of duplicate states that are generated as part of the initial predicate f3a98cec010b63a4d0fb6fa122e6bd4e675ff3ae +* Minimize the number of duplicate states that are generated as part of the next-state predicate fba43190b2aa1ab58fecbddd1b878aaad0d3de1a +* Indicate name of action which does not completely specified the successor state fddcdd48b8d7ab402be887d484a2d6d2198cdb56 +* Speed-up Cloud TLC by skipping instance provisioning 2bc248848d89b094b74810c808f50eaa04506ddd +* Colorize and label actions (arcs) in state graph visualization 7e80f1d6301c42c5381ef63c2ed26166c35f12bc ([Screenshot](https://user-images.githubusercontent.com/6131840/35131485-64933ddc-fc94-11e7-9b71-04f543877abe.png)) Contributor: [will62794](https://github.com/will62794) +* Fix broken error traces with views 5a629454ed5286076f5f6012b382e852448d165c + +#### PlusCal +* Allow no intervening label between call and goto in PlusCal 188e1fd65788f5499030da53b6481351d4564b8c + +#### Specification Editor +* Show errors in PlusCal algorithm for assignments to undeclared variables 1e3f8fae00d12e5d1e755ad47e95dacaaa5c46af +* Editor command "Goto declaration" now also goes to declarations of TLA+ standard modules 103204a62dabae2e68b8f728a11af50a64205dcf ([Screencast](https://user-images.githubusercontent.com/88777/42322087-a7e0946a-804a-11e8-9ee7-fa4be54aa7b2.gif)) +* Mouse hover help shows BNF and help for PlusCal statements dbeafb64c395c6bd936a1bf0026c5780032e34ed +* Show operation definition and comment in mouse hover help ad36f390a22f24ebef23cd3d387e3a371fb90c2b +* Code completion for PlusCal statements triggered by Ctrl+Space 13c772ff44b494d00a9dc95d429c5ec7cfb0e494 ([Screencast](https://user-images.githubusercontent.com/88777/42321184-930decf2-8047-11e8-9f92-2447695504f8.gif)) +* Code completion for operator definitions and declarations triggered by Ctrl+Space c31c2bd2b6ed9cf66dc733b7e39639b8837a516f ([Screencast](https://user-images.githubusercontent.com/88777/42320885-7b2a4ef6-8046-11e8-846d-5f9340c445fe.gif)) +* Automatically transpile PlusCal to TLA+ on editor save 642b540e0d479867ec73c202795106ed5ed9454a ([Screencast](https://user-images.githubusercontent.com/88777/42319531-cc8d9afa-8041-11e8-91e9-3b4656243e4f.gif)) + +#### Model Editor +* Collapse, disable and annotate "Generals" and "Statistics" sections with "No behavior spec" 43d207d0b3368401900a927ffea790ce041bde55 +* Add undo and redo support to constant expression source viewer ff03c664b0ed4bf435df216c3b6fec758a3b95be +* Add TLA+ syntax highlighting to constant expression source viewer fd93b56ced23a1e15c1e2f24ad67303c88a0cb09 +* Report the number of initial states as first item reported in the ResultPage's statistic table (with diameter of 0) 076f0c78635fe29ff1cfd6c68f3109fb6f04b191 +* Show output/progress of remotely running Cloud TLC in Toolbox 593fc822e89d84ffbb586a3a73f0d143af502f1d + +#### Misc +* [Add a mechanism to inform Toolbox users about important news](https://github.com/tlaplus/tlaplus/issues/100) ([Screencast](https://user-images.githubusercontent.com/88777/42326534-f1987984-8058-11e8-8dfb-afe2333d9ff2.gif)) Contributor: [quaeler](https://github.com/quaeler) +* Update Eclipse Foundation to Oxygen SR3 ed931d03fe4e33135f80f5957b0d2d76f815ab7f + +### 32 bits +32 bit (x86) variants of the TLA Toolbox have been discontinued with this release. fb680446557e92229a059ef9f93fd48a29c5bb2f + diff --git a/general/docs/changelogs/gh-1_5_7.jq b/general/docs/changelogs/gh-1_5_7.jq new file mode 100644 index 0000000000000000000000000000000000000000..5969954252d800930bfb35e9d7442f09976f3eaf --- /dev/null +++ b/general/docs/changelogs/gh-1_5_7.jq @@ -0,0 +1,7 @@ +{ + "tag_name": "v1.5.6", + "name": "The Xenophon release", + "draft": true, + "prerelease": false, + "body": $changelog +} \ No newline at end of file diff --git a/general/docs/contributions.md b/general/docs/contributions.md index 03e1ac8003413b8250e64f36f0f89a6f506c65eb..38a438978a1f9f8d9db9447f1997b410bfeaba0a 100644 --- a/general/docs/contributions.md +++ b/general/docs/contributions.md @@ -6,7 +6,7 @@ Please also consult the [issues tracker](https://github.com/tlaplus/tlaplus/issu TLC model checker ----------------- #### Concurrent search for strongly connected components (difficulty: high) (skills: Java, TLA+) -One part of TLC's procedure to check liveness properties, is to find the liveness graph's [strongly connected components](https://en.wikipedia.org/wiki/Strongly_connected_component) (SCC). TLC's implementation uses [Tarjan's](https://en.wikipedia.org/wiki/Strongly_connected_component) canonical solution to this problem. Tarjan's algorithm is a sequential algorithm that runs in linear time. While the time complexity is acceptable, its sequential nature causes TLC's liveness checking not to scale. Recently, concurrent variants of the algorithm have been proposed and [studied in the scope of other model checkers](https://github.com/utwente-fmt/ppopp16). This work will require writing a TLA+ specification and ideally a formal proof of the algorithm's correctness. +One part of TLC's procedure to check liveness properties, is to find the liveness graph's [strongly connected components](https://en.wikipedia.org/wiki/Strongly_connected_component) (SCC). TLC's implementation uses [Tarjan's](https://en.wikipedia.org/wiki/Strongly_connected_component) canonical solution to this problem. Tarjan's algorithm is a sequential algorithm that runs in linear time. While the time complexity is acceptable, its sequential nature causes TLC's liveness checking not to scale. Recently, concurrent variants of the algorithm have been proposed and studied in the scope of other model checkers ([Multi-Core On-The-Fly SCC Decomposition](https://github.com/utwente-fmt/ppopp16) & [Concurrent On-the-Fly SCC Detection for Automata-Based Model Checking with Fairness Assumption](http://ieeexplore.ieee.org/document/7816578/)). This work will require writing a TLA+ specification and ideally a formal proof of the algorithm's correctness. #### Liveness checking under symmetry (difficulty: high) (skills: Java, TLA+) [Symmetry reduction](http://www.cs.cmu.edu/~emc/papers/Conference%20Papers/Symmetry%20Reductions%20in%20Model%20Checking.pdf) techniques can significantly reduce the size of the state graph generated and checked by TLC. For safety checking, symmetry reduction is well studied and has long been implemented in TLC. TLC's liveness checking procedure however, can fail to find property violations if symmetry is declared. Yet, there is no reason why symmetry reduction cannot be applied to liveness checking. This work will require writing a TLA+ specification and ideally a formal proof of the algorithm's correctness. @@ -45,9 +45,6 @@ TLA Toolbox #### Port Toolbox to e4 (difficulty: easy) (skills: Java, Eclipse) [e4](http://www.vogella.com/tutorials/EclipseRCP/article.html) represents the newest programming model for Eclipse RCP applications. e4 provides higher flexibility while simultaneously reducing boilerplate code. The TLA Toolbox has been implemented on top of Eclipse RCP 3.x and thus is more complex than it has to. -#### Package Toolbox for Debian and Fedora based Linux distributions (difficulty: easy) (skills: Eclipse, Linux) -The current Toolbox installation requires Linux users to download a zip file, to extract it and manually integrate the Toolbox into the System. Packaging the Toolbox for Debian (.deb) and Fedora (.rpm) based Linux distributions would not only simplify the installation procedure, it would also create more visible for TLA+ within the Linux community. - #### Add support for Google Compute to Cloud TLC (difficulty: easy) (skills: jclouds, Linux) The Toolbox can launch Azure and Amazon EC2 instances to run model checking in the cloud. The Toolbox interfaces with clouds via the [jclouds](https://jclouds.apache.org/) toolkit. jclouds has support for Google Compute, but https://github.com/tlaplus/tlaplus/blob/master/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/CloudDistributedTLCJob.java has to be enhanced to support Google Compute. diff --git a/general/performance/Ghostferry/MC.cfg b/general/performance/Ghostferry/MC.cfg new file mode 100644 index 0000000000000000000000000000000000000000..3be413a1ca6efb5f287716c02cdba396c82b27c9 --- /dev/null +++ b/general/performance/Ghostferry/MC.cfg @@ -0,0 +1,43 @@ +\* MV CONSTANT declarations +CONSTANTS +r0 = r0 +r1 = r1 +r2 = r2 +\* CONSTANT declarations +CONSTANT defaultInitValue = defaultInitValue +\* MV CONSTANT definitions +CONSTANT +Records <- const_152748923762611000 +\* CONSTANT declarations +CONSTANT Ferry = Ferry +\* CONSTANT declarations +CONSTANT Application = Application +\* CONSTANT declarations +CONSTANT BinlogStreamer = BinlogStreamer +\* CONSTANT declarations +CONSTANT TableIterator = TableIterator +\* CONSTANT definitions +CONSTANT +MaxPrimaryKey <- const_152748923762612000 +\* CONSTANT definitions +CONSTANT +InitialTable <- const_152748923762613000 +\* CONSTANT definitions +CONSTANT +MaxBinlogSize <- const_152748923762614000 +\* CONSTANT definition +CONSTANT +NoRecordHere = NoRecordHere +\* ACTION_CONSTRAINT definition +ACTION_CONSTRAINT +action_constr_152748923762616000 +\* SPECIFICATION definition +SPECIFICATION +spec_152748923762617000 +\* INVARIANT definition +INVARIANT +inv_152748923762618000 +\* PROPERTY definition +PROPERTY +prop_152748923762619000 +\* Generated on Mon May 28 08:33:57 CEST 2018 \ No newline at end of file diff --git a/general/performance/Ghostferry/MC.tla b/general/performance/Ghostferry/MC.tla new file mode 100644 index 0000000000000000000000000000000000000000..b46d44025ede36082aae1a35fa202d0f29d25a0c --- /dev/null +++ b/general/performance/Ghostferry/MC.tla @@ -0,0 +1,47 @@ +---- MODULE MC ---- +EXTENDS ghostferry, TLC + +\* MV CONSTANT declarations@modelParameterConstants +CONSTANTS +r0, r1, r2 +---- + +\* MV CONSTANT definitions Records +const_152748923762611000 == +{r0, r1, r2} +---- + +\* CONSTANT definitions @modelParameterConstants:2MaxPrimaryKey +const_152748923762612000 == +3 +---- + +\* CONSTANT definitions @modelParameterConstants:4InitialTable +const_152748923762613000 == +<<r0, r1, r2, NoRecordHere>> +---- + +\* CONSTANT definitions @modelParameterConstants:8MaxBinlogSize +const_152748923762614000 == +4 +---- + +\* ACTION_CONSTRAINT definition @modelParameterActionConstraint:0 +action_constr_152748923762616000 == +BinlogSizeActionConstraint +---- +\* SPECIFICATION definition @modelBehaviorSpec:0 +spec_152748923762617000 == +Spec +---- +\* INVARIANT definition @modelCorrectnessInvariants:0 +inv_152748923762618000 == +SourceTargetEquality +---- +\* PROPERTY definition @modelCorrectnessProperties:0 +prop_152748923762619000 == +Termination +---- +============================================================================= +\* Modification History +\* Created Mon May 28 08:33:57 CEST 2018 by markus diff --git a/general/performance/Ghostferry/README.md b/general/performance/Ghostferry/README.md new file mode 100644 index 0000000000000000000000000000000000000000..ec6d946836a35a03a9ab542fc7c2adb7470229c4 --- /dev/null +++ b/general/performance/Ghostferry/README.md @@ -0,0 +1 @@ +# This is a snapshot of the tlaplus folder of the repository at https://github.com/Shopify/ghostferry/ - released under the MIT license - from which we copied the spec for TLC performance testing! We claim no authorship of this specification. diff --git a/general/performance/Ghostferry/ghostferry.tla b/general/performance/Ghostferry/ghostferry.tla new file mode 100644 index 0000000000000000000000000000000000000000..bbf4169e96f7fb7f4beda12ade27f7090e9bedbc --- /dev/null +++ b/general/performance/Ghostferry/ghostferry.tla @@ -0,0 +1,631 @@ +----------------------------- MODULE ghostferry ----------------------------- + +(*************************************************************************** + This is the model of the primary Ghostferry algorithm of copying data. Note + that this is a model that has many simplifying assumptions and thus it will + have a lot of differences with the actual implementation. + + The comment here describes this model and justify how it is applicable to + to the real world. + + ## Process Model ## + + A standard, parallel Ghostferry run is something along the following lines: + + 1. Ghostferry begins to tail and apply the binlogs via the BinlogStreamer. + 2. Ghostferry begins to iterate through the tables, applying the rows in + batches via the DataIterator. Ghostferry will find the current minimum + and maximum primary key for each source table and copies all rows within + the ranges. + 3. The API consumer of Ghostferry (e.g. copydb) waits until the data copying + is completed. + 4. The application/source database is locked/set as read only and copydb wait + until all writes are completed (cutover stage). + 5. The binlog streaming is instructed to stop. A target binlog position is set + to be the current binlog position of the master. The binlog streamer will + catch up to that position and then quit. + 6. At this point, the source and target database are expected to be identical. + + Note that until the source database is set to read only, something + (the application/dba/whatever) will perform INSERT/UPDATE/DELETEs on the source + database concurrently with respect to Ghostferry. + + This whole process is modeled as four separate processes: + 1. TableIterator: Performs the job of the DataIterator, but only on one table + (see Data Model for justification). + 2. BinlogStreamer: Tails and applies the binlog of the source database. + 3. Application: Perform INSERT/UPDATE/DELETE on the source database and record + the action into the source database binlog. Essentially + combines both the database itself and the client of the + database (app/dba/whatever). + 4. Ferry: Coordinates the entire run by waiting for the data copy to complete, + performing the cut over stage, and stopping the binlog streamer. + + ## Data Model ## + + In the real world, each database contains many schemas, each with many tables. + Each table can have millions/billions of rows, each of which has many values + associated with many columns. This is a very difficult to replicate in a just a + simple mental model, never mind a formal, checkable model. The present data + model makes simplifying assumptions and reduces the source and target databases + down to its very essense: + + 1. Each database only contains a single table as opposed to many tables. + 2. A table is modeled as a finite sequence of `PossibleRecords`. Each element + in the sequence is a row and the index of that element is the primary key of + the row + - Hence, primary keys are in the set of natural numbers. + 3. `PossibleRecords` is a set of all possible records. There's a special + element called `NoRecordHere` that indicate that row does not exist. In + other words, if the i-th entry of the table sequence is `NoRecordHere`, it + is the equivalent of saying that row does not exist. + - INSERT into the database is just an UPDATE of a row with `NoRecordHere` + to another record. + - DELETE is just an UPDATE to a row with a record with `NoRecordHere`. + - Thus, the table sequence will always be filled to its maximum capacity. + - The initial table layout should be something like + <<record, record, ..., record, NoRecordHere, ... NoRecordHere>> + - The minimum primary key will always be 1. + - The maximum primary key will initially be the last entry that is not + NoRecordHere. This number is manually specified because it will complicate + the model. + - The table length is defined by the last entry of record before + NoRecordHere. The table length is increased everytime when an INSERT + occurs at a primary key above the current length. + - The table capacity is defined by the size of the sequence, including the + NoRecordHere elements. + 4. The Binlog is modeled as a sequence of log entries. + - The sequence starts empty and are appended to every time the source table + is changed. + - To ensure the binlog does not grow to infinity and checking with TLC stays + feasible, a maximum size is constrained on it. + + Currently, the simplifications made here are not inductively proven to be + applicable to the real dataset. However, some prose arguments are made that + is convincing that the simplifications will be applicable to the real, larger + (possibly infinite) dataset. + + ### Hand waving for: Finite table = Infinite tables ### + + Note that this is not a proof by any sense of the word, merely a hand-wavy + justification of correctness. + + Since TLC can only check a finite model (and only a small one is feasible), + the size of the source and target database must be kept as low as possible. + If we modeled a database with 100 rows, the possible states for TLC to verify + will explode to an astronomical amount and will not complete in a reasonable + time. Thus, we have to choose the size of the initial databases and this is + done via the concept of "super rows". + + Super rows are simply the idea that we can combine multiple rows into a single + row and not change the semantics of the operation. For example, we can define + a super row to be a combination of 100 regular rows. If we have a table + with n regular rows, it would also thus have n/100 super rows. + + Suppose that the super row j maps to regular rows [i, i+100) and suppose that + the DataIterator atomically copies 100 regular rows [i, i+100) in a batch. + This would be the equivalent of copying a single super row j: + + ROW_COPY([i, i+100)) = SUPER_ROW_COPY(j) + + As long as ROW_COPY is atomic, the ROW_COPY is the equivalent to + SUPER_ROW_COPY. + + A more complex case is if we copy 150 rows, which would imply it is copying + two super rows. Thus: + + ROW_COPY([i, i+150)) = SUPER_ROW_COPY(j) /\ SUPER_ROW_COPY(j+1) + + We can make similar arguments for the binlog streamer, where instead of row + copy, we are performing operations that mirrows INSERT/UPDATE/DELETE. + + Philosophically, we can also think of the entire table as one giant super row. + This would imply the table only needs a size of 1. However, without an actual + proof of correness, the finite table size is chosen to be 2. To be more + cautious: The capacity of the table is 3 so we can INSERT a row. + + An alternative way to think about this: + + - We can either: app update a row OR copy the row OR binlog to apply the update. + - For any particular row, the copy phase can only occur once. update and binlog + can occur any number of times in any order. + - Binlog respects the ordering of the update + - There are only three cases that we really care about: + - copy -> update -> binlog: copy before update and binlog + - update -> copy -> binlog: copy in between the update and binlog + - update -> binlog -> copy: copy after update and binlog. + - Logically, the copy operate can only happen within those time. + - This means copy \/ update \/ binlog. + - No where did we need to involve the size of the table, thus copy and update + can be their super equivalent, which means we only need 1 record to prove + that this works. + + ### Hand waving for: finite set of possible records to be inserted = infinite set of possible records ### + + There are an infinite amount of possible Records we can insert in real life. + The TLA+ spec reflects that by not assuming a size in the Record set. However, + since TLC can only check a small, finite model, the number of records in this + set must be restricted to a finite amount and we need to inductively proof + that the behaviours with this finite Record set is equivalent to the infinite + set. However, this proof is not yet available and a brief "justification" is + given below: + + Since we ever only care about the transition of a row from containing one + Record to another, we only need to have two records in this set. + + ### Hand waving for: restricting maximum binlog size is ok ### + + If we do not restrict the maximum binlog size, it will grow unbounded. We + need to limit it in TLC otherwise the state checking will not complete. + + The intuitive amount to bound this at is the maximum of the capacity of the + tables and the number of different types of operations we model. The reason is + this allows at least one branch of the state tree to update each of the entries + in the table with a different operation. + + ***************************************************************************) + +EXTENDS Integers, Sequences, TLC + +\* Helper Methods +\* ============== + +SetMin(S) == CHOOSE i \in S: \A j \in S : i <= j + +\* Constant Declarations +\* ===================== + +(*************************************************************************** +This defines the initial layout of the source table. The source table should +be defined as a sequence with a bunch of Records. It is possible to be +NoRecordHere as that is the placeholder for an non-existent row. + +Example: InitialTable = <<r0, r1, NoRecordHere>> + MaxPrimaryKey = 2 + +The example table will also have a TableCapacity of 3 and a CurrentMaxPrimaryKey +of 2. The CurrentMaxPrimaryKey can be increased when the third element is +updated to an element \in Records. + ***************************************************************************) +CONSTANT InitialTable +CONSTANT MaxPrimaryKey + +(*************************************************************************** +This defines the set of possible records that can be written to the +database. + +Example: {r0, r1} + ***************************************************************************) +CONSTANT Records + +(*************************************************************************** +These are defined as ModelValues that will serve as the identifier to the +different processes running. + ***************************************************************************) +CONSTANTS TableIterator, BinlogStreamer, Application, Ferry + +\* Maximum table capacity +TableCapacity == Len(InitialTable) + +\* The set of all possible primary key +PrimaryKeys == 1..TableCapacity + +\* This value cannot be computed by the TLC. Use the Model to override it to be +\* a model value instead. +NoRecordHere == CHOOSE r : r \notin Records + +\* A set of possible records for TypeOK +PossibleRecords == Records \cup {NoRecordHere} + +(*************************************************************************** +--algorithm ghostferry { + variables + \* CurrentMaxPrimaryKey indicates the length of the table as opposed to the + \* capacity of the table. + CurrentMaxPrimaryKey = MaxPrimaryKey, + + \* The source table is initialized with the given InitialTable. + \* The target table is initialized with the same capacity but has no records + \* associated with any of the primary key (in the real world: no rows exists) + SourceTable = InitialTable, + TargetTable = [k \in PrimaryKeys |-> NoRecordHere], + + \* The binlogs are modeled as a list of binlog events. + \* The size of the binlog is constrainted to MaxBinlogSize via + \* ActionConstraint. This serves to ensure that the binlog do not increase + \* infinitely. In essense, this assumes that Ghostferry is fast enough to + \* tail and apply binlogs. + SourceBinlog = <<>>, + + \* Set to TRUE when the cutover operation is started to prevent the + \* application from writing more data into the database. This is equivalent + \* to either setting the database to read only or use some method to set + \* the application to read only. + ApplicationReadonly = FALSE, + + \* This is the index of the binlog position we want to stream to when the + \* application is set to read only during the cutover. + TargetBinlogPos = 0, + + \* This is set to TRUE to stop all components of Ghostferry and Ghostferry + \* should terminate after finishing streaming all the binlog events. + BinlogStreamingStopRequested = FALSE; + + fair process (ProcTableIterator = TableIterator) + variables + lastSuccessfulPK = 0, \* Last PK successfully applied to the target db. + currentRow; \* The current row's data + { + \* Note that tblit_rw is an atomic step. If the read and write steps are + \* two distinct steps, this could cause a race condition that will cause + \* data corruption. + \* TODO: offer a way to see this data corruption with TLC. + \* + \* In order to do this in the real work, this could be done via something + \* like SELECT FOR UPDATE, which would block the Application from being + \* to change currentRow while currentRow is being written to the target + \* database. + \* + \* It may be possible to perform some sort of locking between the + \* BinlogStreamer and the TableIterator. + \* TODO: model this with TLA+ and validate its correctness. + \* + \* It may be possible to perform some sort of locking via the Application, + \* but this seems cumbersome and prone to implementation level error. + \* TODO: model this with TLA+ and validate its correctness. + tblit_loop: while (lastSuccessfulPK < MaxPrimaryKey) { + tblit_rw: currentRow := SourceTable[lastSuccessfulPK + 1]; + if (currentRow # NoRecordHere) { + TargetTable[lastSuccessfulPK + 1] := currentRow; + }; + tblit_upkey: lastSuccessfulPK := lastSuccessfulPK + 1; + }; + } + + fair process (ProcBinlogStreamer = BinlogStreamer) + variables + lastSuccessfulBinlogPos = 0, \* Last binlog pos successfully applied on the target db + currentBinlogEntry; \* The binlog event that is currently being read + { + binlog_loop: while (BinlogStreamingStopRequested = FALSE \/ (BinlogStreamingStopRequested = TRUE /\ lastSuccessfulBinlogPos < TargetBinlogPos)) { + \* We cannot use an await as there could be a deadlock for + \* when the application is set to read only and thus nothing + \* else writes to the database. + \* + \* This also means in the real implementation we need a + \* non-blocking read for the binlog. + binlog_read: if (lastSuccessfulBinlogPos < Len(SourceBinlog)) { + currentBinlogEntry := SourceBinlog[lastSuccessfulBinlogPos + 1]; + binlog_write: if (TargetTable[currentBinlogEntry.pk] = currentBinlogEntry.oldr) { + TargetTable[currentBinlogEntry.pk] := currentBinlogEntry.newr; + }; + binlog_upkey: lastSuccessfulBinlogPos := lastSuccessfulBinlogPos + 1; + }; + } + } + + (*********************************************************************** + The application modeled here encompasses both the real application as + well as the database itself. It is modeled as a process that is always + issuing INSERT/UPDATE/DELETEs. The model also appends the record into + the binlogs. + + The model here also models setting the database/application as read only. + It will stop writing to the database when ApplicationReadonly = TRUE. + + The model combines the act of picking the row to update, writing to it, + and recording the action into the binlog as one big atomic step. This + ASSUMPTION relies upon the fact that MySQL's updates atomically writes + to the binlog and the actual data with respect to Ghostferry. + ***********************************************************************) + fair process (ProcApplication = Application) + variables + oldRecord, + newRecord, + chosenPK, + { + app_loop: while (ApplicationReadonly = FALSE) { + \* Choose a "random" PK to update. + app_write: with (pk \in 1..SetMin({TableCapacity, CurrentMaxPrimaryKey + 1})) { + chosenPK := pk; + }; + oldRecord := SourceTable[chosenPK]; + + \* Choose a "random" record to update the chosen row, except + \* the current value of the chosen row (oldRecord), as that + \* would be a pointless update and we don't need to make TLC + \* check that. + with (r \in PossibleRecords \ {oldRecord}) { + newRecord := r; + }; + + SourceBinlog := Append( + SourceBinlog, + [ + pk |-> chosenPK, + oldr |-> oldRecord, + newr |-> newRecord + ] + ); + SourceTable[chosenPK] := newRecord; + + \* The following essentially implements auto_increment. We + \* might not necessarily need this, but there's no proof + \* saying that we can, thus it is included. + if (oldRecord = NoRecordHere /\ chosenPK > CurrentMaxPrimaryKey) { + assert (chosenPK - 1 = CurrentMaxPrimaryKey); + CurrentMaxPrimaryKey := chosenPK; + } + } + } + + (*********************************************************************** + In the actual code, the Ferry class would have started all of the above. + This is unnecessary here as it is done via the Next definition in TLA+ + (automatically generated from PlusCal). Thus, the Ferry here is really + the Ferry that each application must implement: + + 1. Waiting until the DataITerator is finished copying data. + 2. Perform the cutover operation (setting the source to be read only). + 3. Instruct the BinlogStreamer to quit after streaming. + + Note that setting the target binlog position and requesting binlog + streaming to stop are two distinct steps. Making them one atomic step + is not realistic unless we implement a lock. With two distinct steps, + if the steps are reversed, a race condition will be present. + ***********************************************************************) + fair process (ProcFerry = Ferry) { + ferry_setro: await pc[TableIterator] = "Done"; + ApplicationReadonly := TRUE; + ferry_waitro: await pc[Application] = "Done"; + ferry_binlogpos: TargetBinlogPos := Len(SourceBinlog); + ferry_binlogstop: BinlogStreamingStopRequested := TRUE; + } +} + + ***************************************************************************) +\* BEGIN TRANSLATION +CONSTANT defaultInitValue +VARIABLES CurrentMaxPrimaryKey, SourceTable, TargetTable, SourceBinlog, + ApplicationReadonly, TargetBinlogPos, BinlogStreamingStopRequested, + pc, lastSuccessfulPK, currentRow, lastSuccessfulBinlogPos, + currentBinlogEntry, oldRecord, newRecord, chosenPK + +vars == << CurrentMaxPrimaryKey, SourceTable, TargetTable, SourceBinlog, + ApplicationReadonly, TargetBinlogPos, BinlogStreamingStopRequested, + pc, lastSuccessfulPK, currentRow, lastSuccessfulBinlogPos, + currentBinlogEntry, oldRecord, newRecord, chosenPK >> + +ProcSet == {TableIterator} \cup {BinlogStreamer} \cup {Application} \cup {Ferry} + +Init == (* Global variables *) + /\ CurrentMaxPrimaryKey = MaxPrimaryKey + /\ SourceTable = InitialTable + /\ TargetTable = [k \in PrimaryKeys |-> NoRecordHere] + /\ SourceBinlog = <<>> + /\ ApplicationReadonly = FALSE + /\ TargetBinlogPos = 0 + /\ BinlogStreamingStopRequested = FALSE + (* Process ProcTableIterator *) + /\ lastSuccessfulPK = 0 + /\ currentRow = defaultInitValue + (* Process ProcBinlogStreamer *) + /\ lastSuccessfulBinlogPos = 0 + /\ currentBinlogEntry = defaultInitValue + (* Process ProcApplication *) + /\ oldRecord = defaultInitValue + /\ newRecord = defaultInitValue + /\ chosenPK = defaultInitValue + /\ pc = [self \in ProcSet |-> CASE self = TableIterator -> "tblit_loop" + [] self = BinlogStreamer -> "binlog_loop" + [] self = Application -> "app_loop" + [] self = Ferry -> "ferry_setro"] + +tblit_loop == /\ pc[TableIterator] = "tblit_loop" + /\ IF lastSuccessfulPK < MaxPrimaryKey + THEN /\ pc' = [pc EXCEPT ![TableIterator] = "tblit_rw"] + ELSE /\ pc' = [pc EXCEPT ![TableIterator] = "Done"] + /\ UNCHANGED << CurrentMaxPrimaryKey, SourceTable, TargetTable, + SourceBinlog, ApplicationReadonly, + TargetBinlogPos, BinlogStreamingStopRequested, + lastSuccessfulPK, currentRow, + lastSuccessfulBinlogPos, currentBinlogEntry, + oldRecord, newRecord, chosenPK >> + +tblit_rw == /\ pc[TableIterator] = "tblit_rw" + /\ currentRow' = SourceTable[lastSuccessfulPK + 1] + /\ IF currentRow' # NoRecordHere + THEN /\ TargetTable' = [TargetTable EXCEPT ![lastSuccessfulPK + 1] = currentRow'] + ELSE /\ TRUE + /\ UNCHANGED TargetTable + /\ pc' = [pc EXCEPT ![TableIterator] = "tblit_upkey"] + /\ UNCHANGED << CurrentMaxPrimaryKey, SourceTable, SourceBinlog, + ApplicationReadonly, TargetBinlogPos, + BinlogStreamingStopRequested, lastSuccessfulPK, + lastSuccessfulBinlogPos, currentBinlogEntry, + oldRecord, newRecord, chosenPK >> + +tblit_upkey == /\ pc[TableIterator] = "tblit_upkey" + /\ lastSuccessfulPK' = lastSuccessfulPK + 1 + /\ pc' = [pc EXCEPT ![TableIterator] = "tblit_loop"] + /\ UNCHANGED << CurrentMaxPrimaryKey, SourceTable, TargetTable, + SourceBinlog, ApplicationReadonly, + TargetBinlogPos, BinlogStreamingStopRequested, + currentRow, lastSuccessfulBinlogPos, + currentBinlogEntry, oldRecord, newRecord, + chosenPK >> + +ProcTableIterator == tblit_loop \/ tblit_rw \/ tblit_upkey + +binlog_loop == /\ pc[BinlogStreamer] = "binlog_loop" + /\ IF BinlogStreamingStopRequested = FALSE \/ (BinlogStreamingStopRequested = TRUE /\ lastSuccessfulBinlogPos < TargetBinlogPos) + THEN /\ pc' = [pc EXCEPT ![BinlogStreamer] = "binlog_read"] + ELSE /\ pc' = [pc EXCEPT ![BinlogStreamer] = "Done"] + /\ UNCHANGED << CurrentMaxPrimaryKey, SourceTable, TargetTable, + SourceBinlog, ApplicationReadonly, + TargetBinlogPos, BinlogStreamingStopRequested, + lastSuccessfulPK, currentRow, + lastSuccessfulBinlogPos, currentBinlogEntry, + oldRecord, newRecord, chosenPK >> + +binlog_read == /\ pc[BinlogStreamer] = "binlog_read" + /\ IF lastSuccessfulBinlogPos < Len(SourceBinlog) + THEN /\ currentBinlogEntry' = SourceBinlog[lastSuccessfulBinlogPos + 1] + /\ pc' = [pc EXCEPT ![BinlogStreamer] = "binlog_write"] + ELSE /\ pc' = [pc EXCEPT ![BinlogStreamer] = "binlog_loop"] + /\ UNCHANGED currentBinlogEntry + /\ UNCHANGED << CurrentMaxPrimaryKey, SourceTable, TargetTable, + SourceBinlog, ApplicationReadonly, + TargetBinlogPos, BinlogStreamingStopRequested, + lastSuccessfulPK, currentRow, + lastSuccessfulBinlogPos, oldRecord, newRecord, + chosenPK >> + +binlog_write == /\ pc[BinlogStreamer] = "binlog_write" + /\ IF TargetTable[currentBinlogEntry.pk] = currentBinlogEntry.oldr + THEN /\ TargetTable' = [TargetTable EXCEPT ![currentBinlogEntry.pk] = currentBinlogEntry.newr] + ELSE /\ TRUE + /\ UNCHANGED TargetTable + /\ pc' = [pc EXCEPT ![BinlogStreamer] = "binlog_upkey"] + /\ UNCHANGED << CurrentMaxPrimaryKey, SourceTable, + SourceBinlog, ApplicationReadonly, + TargetBinlogPos, BinlogStreamingStopRequested, + lastSuccessfulPK, currentRow, + lastSuccessfulBinlogPos, currentBinlogEntry, + oldRecord, newRecord, chosenPK >> + +binlog_upkey == /\ pc[BinlogStreamer] = "binlog_upkey" + /\ lastSuccessfulBinlogPos' = lastSuccessfulBinlogPos + 1 + /\ pc' = [pc EXCEPT ![BinlogStreamer] = "binlog_loop"] + /\ UNCHANGED << CurrentMaxPrimaryKey, SourceTable, TargetTable, + SourceBinlog, ApplicationReadonly, + TargetBinlogPos, BinlogStreamingStopRequested, + lastSuccessfulPK, currentRow, + currentBinlogEntry, oldRecord, newRecord, + chosenPK >> + +ProcBinlogStreamer == binlog_loop \/ binlog_read \/ binlog_write + \/ binlog_upkey + +app_loop == /\ pc[Application] = "app_loop" + /\ IF ApplicationReadonly = FALSE + THEN /\ pc' = [pc EXCEPT ![Application] = "app_write"] + ELSE /\ pc' = [pc EXCEPT ![Application] = "Done"] + /\ UNCHANGED << CurrentMaxPrimaryKey, SourceTable, TargetTable, + SourceBinlog, ApplicationReadonly, TargetBinlogPos, + BinlogStreamingStopRequested, lastSuccessfulPK, + currentRow, lastSuccessfulBinlogPos, + currentBinlogEntry, oldRecord, newRecord, chosenPK >> + +app_write == /\ pc[Application] = "app_write" + /\ \E pk \in 1..SetMin({TableCapacity, CurrentMaxPrimaryKey + 1}): + chosenPK' = pk + /\ oldRecord' = SourceTable[chosenPK'] + /\ \E r \in PossibleRecords \ {oldRecord'}: + newRecord' = r + /\ SourceBinlog' = Append( + SourceBinlog, + [ + pk |-> chosenPK', + oldr |-> oldRecord', + newr |-> newRecord' + ] + ) + /\ SourceTable' = [SourceTable EXCEPT ![chosenPK'] = newRecord'] + /\ IF oldRecord' = NoRecordHere /\ chosenPK' > CurrentMaxPrimaryKey + THEN /\ Assert((chosenPK' - 1 = CurrentMaxPrimaryKey), + "Failure of assertion at line 230, column 21.") + /\ CurrentMaxPrimaryKey' = chosenPK' + ELSE /\ TRUE + /\ UNCHANGED CurrentMaxPrimaryKey + /\ pc' = [pc EXCEPT ![Application] = "app_loop"] + /\ UNCHANGED << TargetTable, ApplicationReadonly, TargetBinlogPos, + BinlogStreamingStopRequested, lastSuccessfulPK, + currentRow, lastSuccessfulBinlogPos, + currentBinlogEntry >> + +ProcApplication == app_loop \/ app_write + +ferry_setro == /\ pc[Ferry] = "ferry_setro" + /\ pc[TableIterator] = "Done" + /\ ApplicationReadonly' = TRUE + /\ pc' = [pc EXCEPT ![Ferry] = "ferry_waitro"] + /\ UNCHANGED << CurrentMaxPrimaryKey, SourceTable, TargetTable, + SourceBinlog, TargetBinlogPos, + BinlogStreamingStopRequested, lastSuccessfulPK, + currentRow, lastSuccessfulBinlogPos, + currentBinlogEntry, oldRecord, newRecord, + chosenPK >> + +ferry_waitro == /\ pc[Ferry] = "ferry_waitro" + /\ pc[Application] = "Done" + /\ pc' = [pc EXCEPT ![Ferry] = "ferry_binlogpos"] + /\ UNCHANGED << CurrentMaxPrimaryKey, SourceTable, TargetTable, + SourceBinlog, ApplicationReadonly, + TargetBinlogPos, BinlogStreamingStopRequested, + lastSuccessfulPK, currentRow, + lastSuccessfulBinlogPos, currentBinlogEntry, + oldRecord, newRecord, chosenPK >> + +ferry_binlogpos == /\ pc[Ferry] = "ferry_binlogpos" + /\ TargetBinlogPos' = Len(SourceBinlog) + /\ pc' = [pc EXCEPT ![Ferry] = "ferry_binlogstop"] + /\ UNCHANGED << CurrentMaxPrimaryKey, SourceTable, + TargetTable, SourceBinlog, + ApplicationReadonly, + BinlogStreamingStopRequested, + lastSuccessfulPK, currentRow, + lastSuccessfulBinlogPos, currentBinlogEntry, + oldRecord, newRecord, chosenPK >> + +ferry_binlogstop == /\ pc[Ferry] = "ferry_binlogstop" + /\ BinlogStreamingStopRequested' = TRUE + /\ pc' = [pc EXCEPT ![Ferry] = "Done"] + /\ UNCHANGED << CurrentMaxPrimaryKey, SourceTable, + TargetTable, SourceBinlog, + ApplicationReadonly, TargetBinlogPos, + lastSuccessfulPK, currentRow, + lastSuccessfulBinlogPos, + currentBinlogEntry, oldRecord, newRecord, + chosenPK >> + +ProcFerry == ferry_setro \/ ferry_waitro \/ ferry_binlogpos + \/ ferry_binlogstop + +Next == ProcTableIterator \/ ProcBinlogStreamer \/ ProcApplication + \/ ProcFerry + \/ (* Disjunct to prevent deadlock on termination *) + ((\A self \in ProcSet: pc[self] = "Done") /\ UNCHANGED vars) + +Spec == /\ Init /\ [][Next]_vars + /\ WF_vars(ProcTableIterator) + /\ WF_vars(ProcBinlogStreamer) + /\ WF_vars(ProcApplication) + /\ WF_vars(ProcFerry) + +Termination == <>(\A self \in ProcSet: pc[self] = "Done") + +\* END TRANSLATION + +\* Safety Constraints +\* ================== + +SourceTargetEquality == (\A self \in ProcSet: pc[self] = "Done") => (SourceTable = TargetTable)\* /\ PrintT(<<"Source", SourceTable, "Target", TargetTable>>) + +\* Action Constraints +\* ================== + +\* It is possible that the binlog infinitely grows. If it becomes too big it +\* becomes infeasible to check the behaviour of the ghostferry algorithm. Thus +\* we limit it. +\* +\* Usually we can pick a MaxBinlogSize == 3. +CONSTANT MaxBinlogSize + +BinlogSizeActionConstraint == Len(SourceBinlog) <= MaxBinlogSize + +============================================================================= +\* Modification History +\* Last modified Mon May 28 08:10:14 CEST 2018 by markus +\* Last modified Thu Jan 25 10:09:10 EST 2018 by shuhao +\* Created Thu Jan 18 11:35:40 EST 2018 by shuhao diff --git a/general/performance/Grid5k/Grid5k.tla b/general/performance/Grid5k/Grid5k.tla new file mode 100644 index 0000000000000000000000000000000000000000..ec2532584f1cb21a3b990c049cfa4d8a6c7ee357 --- /dev/null +++ b/general/performance/Grid5k/Grid5k.tla @@ -0,0 +1,32 @@ +-------------------------------- MODULE Grid5k -------------------------------- +\* This spec executes +\* variable x = [i \in 1..N |-> 0]; +\* while (TRUE) { +\* with (i \in 1..N) { +\* x[i] := (x[i] + 1) % K ; +\* \* SUBSET 1..L causes TLC to generate the power set of the set 1..L. +\* \* For each set in the power set, TLC evaluates if the set's +\* \* cardinality is L... KaBOOM! +\* await \E s \in SUBSET (1..L): Cardinality(s) = L +\* } +\* } +\* Thus, - N is the number of states computed for each evaluation of the +\* next-state action +\* - K^N is the total number of distinct states +\* - The time to compute a single state is asymptotically +\* proportional to 2^L. +\* - C defines the number of initial states. Let C=n +\* then the state graph has n isomorphic disjunct subgraphs. +EXTENDS Integers, FiniteSets + +CONSTANTS N, K, L, C +VARIABLE x, y + +Init == /\ x = [i \in 1..N |-> 0] + /\ y \in 1..C + +Next == /\ UNCHANGED y + /\ \E i \in 1..N : /\ x' = [x EXCEPT ![i] = (@ + 1) % K] + /\ \E s \in SUBSET (1..L): Cardinality(s) = L + +============================================================================= diff --git a/general/performance/Grid5k/MC.cfg b/general/performance/Grid5k/MC.cfg new file mode 100644 index 0000000000000000000000000000000000000000..b2f09f38c7d11fadb042152debf53ce2aed5e68f --- /dev/null +++ b/general/performance/Grid5k/MC.cfg @@ -0,0 +1,7 @@ +CONSTANT K=05 +CONSTANT L=01 +CONSTANT N=10 +CONSTANT C=32 +INIT Init +NEXT Next + diff --git a/general/performance/Grid5k/MC.tla b/general/performance/Grid5k/MC.tla new file mode 100644 index 0000000000000000000000000000000000000000..2ca72e177fdfb735be6916729901e9863d2fe510 --- /dev/null +++ b/general/performance/Grid5k/MC.tla @@ -0,0 +1,4 @@ +-------- MODULE MC --------- +EXTENDS Grid5k +=================== + diff --git a/general/performance/MongoRepl/MC.cfg b/general/performance/MongoRepl/MC.cfg new file mode 100644 index 0000000000000000000000000000000000000000..d46e9c2fe872e157de15dd5be456fa0f2b08236f --- /dev/null +++ b/general/performance/MongoRepl/MC.cfg @@ -0,0 +1,33 @@ +\* MV CONSTANT declarations +CONSTANTS +v1 = v1 +\* MV CONSTANT declarations +CONSTANTS +s1 = s1 +s2 = s2 +s3 = s3 +\* CONSTANT declarations +CONSTANT Nil = Nil +\* CONSTANT declarations +CONSTANT Follower = Follower +\* MV CONSTANT definitions +CONSTANT +Value <- const_1518107340940126000 +\* CONSTANT declarations +CONSTANT Leader = Leader +\* MV CONSTANT definitions +CONSTANT +Server <- const_1518107340940127000 +\* CONSTANT declarations +CONSTANT Candidate = Candidate +\* SYMMETRY definition +SYMMETRY symm_1518107340940128000 +\* CONSTRAINT definition +CONSTRAINT +constr_1518107340940129000 +\* SPECIFICATION definition +SPECIFICATION +spec_1518107340940130000 +\* INVARIANT definition +INVARIANT +inv_1518107340940131000 diff --git a/general/performance/MongoRepl/MC.tla b/general/performance/MongoRepl/MC.tla new file mode 100644 index 0000000000000000000000000000000000000000..181e0863f4eb1e00b628496005bcee60729de8c5 --- /dev/null +++ b/general/performance/MongoRepl/MC.tla @@ -0,0 +1,42 @@ +---- MODULE MC ---- +EXTENDS RaftMongo, TLC + +\* MV CONSTANT declarations@modelParameterConstants +CONSTANTS +v1 +---- + +\* MV CONSTANT declarations@modelParameterConstants +CONSTANTS +s1, s2, s3 +---- + +\* MV CONSTANT definitions Value +const_1518107340940126000 == +{v1} +---- + +\* MV CONSTANT definitions Server +const_1518107340940127000 == +{s1, s2, s3} +---- + +\* SYMMETRY definition +symm_1518107340940128000 == +Permutations(const_1518107340940127000) +---- + +\* CONSTRAINT definition @modelParameterContraint:0 +constr_1518107340940129000 == +/\ \forall i \in Server: globalCurrentTerm <= 6 +/\ \forall i \in Server: Len(log[i]) <= 15 +---- +\* SPECIFICATION definition @modelBehaviorSpec:0 +spec_1518107340940130000 == +Spec +---- +\* INVARIANT definition @modelCorrectnessInvariants:0 +inv_1518107340940131000 == +NeverRollbackCommitted +---- +============================================================================= diff --git a/general/performance/MongoRepl/README.md b/general/performance/MongoRepl/README.md new file mode 100644 index 0000000000000000000000000000000000000000..ff54adfba5cfe823bf25c2fa8fe549cca4d758ee --- /dev/null +++ b/general/performance/MongoRepl/README.md @@ -0,0 +1,38 @@ +# This is a snapshot of the repository at https://github.com/visualzhou/mongo-repl-tla from which we copied the spec for TLC performance testing! We claim no authorship of this specification. +--------------------------- + + +This is an attempt to model a simplified part of the replication system of MongoDB in TLA+. + +## Spec +MongoDB secondaries pull oplogs from any nodes that have more up-to-date oplogs, which is different than the push model in Raft. This spec models the gossip protocol with two synchronized actions: AppendOplog and RollbackOplog. + +The spec also simplifies the election protocol. Every election will succeed in one shot, including sending and replying vote requests and learning the new term. + +## Model Checking +I have successfully run model checker on the spec with a small model that has: +- 3 nodes (symmetrical model value) +- Term up to 3 +- # of logs up to 10 + +State constraint: +``` +/\ \forall i \in Server: globalCurrentTerm <= 3 +/\ \forall i \in Server: Len(log[i]) <= 10 +``` +Invarients to check: +- NeverRollbackCommitted + +The model checker generates 7778 distinct states and passes. + +## Play with the Spec +To play with the spec, you may comment out Line 112 in RollbackCommitted action, which specifies that an oplog entry replicated to the majority nodes only **in the current term** can be considered as "committed". Otherwise, secondaries syncing from the the old primary will report the commit level to the old primary even though they have voted for the new primary. This differs from the Raft protocol. In Raft, voting for a new primary implies not accepting any logs from old leaders. + +Commenting out Line 112 will cause the model checker to fail, giving a simple concrete failure case. + +1. Node 1 becomes the primary in term 2 and writes [index: 1, term: 2] to its oplog. +2. Node 3 wins an election in term 3 without the oplog on Node 1 and writes [index: 1, term: 3]. +3. Node 2 replicates [index: 1, term: 2] from Node 1, making this oplog entry replicated on the majority nodes, but it will be rolled back after syncing from Node 3. + +## Conclusion +We have found the exact same issue in MongoDB code. [SERVER-22136](https://jira.mongodb.org/browse/SERVER-22136) tracks the fix to notify the old primary of the new term. We've never encountered this issue in testing or in the field and only found it by reasoning about the edge cases. This shows writing and model checking TLA+ specs is an excellent alternative way to find and verify edge cases. diff --git a/general/performance/MongoRepl/RaftMongo.tla b/general/performance/MongoRepl/RaftMongo.tla new file mode 100644 index 0000000000000000000000000000000000000000..cb4b32841867e2ad102fdd187f371a2e2b9c2d72 --- /dev/null +++ b/general/performance/MongoRepl/RaftMongo.tla @@ -0,0 +1,154 @@ +--------------------------------- MODULE RaftMongo --------------------------------- +\* This is the formal specification for the Raft consensus algorithm in MongoDB + +EXTENDS Naturals, FiniteSets, Sequences, TLC + +\* The set of server IDs +CONSTANTS Server + +\* The set of requests that can go into the log +CONSTANTS Value + +\* Server states. +\* Candidate is not used, but this is fine. +CONSTANTS Follower, Candidate, Leader + +\* A reserved value. +CONSTANTS Nil + +---- +\* Global variables + +\* The server's term number. +VARIABLE globalCurrentTerm + +---- +\* The following variables are all per server (functions with domain Server). + +\* The server's state (Follower, Candidate, or Leader). +VARIABLE state +serverVars == <<globalCurrentTerm, state>> + +\* A Sequence of log entries. The index into this sequence is the index of the +\* log entry. Unfortunately, the Sequence module defines Head(s) as the entry +\* with index 1, so be careful not to use that! +VARIABLE log +logVars == <<log>> + +\* End of per server variables. +---- + +\* All variables; used for stuttering (asserting state hasn't changed). +vars == <<serverVars, logVars>> + +---- +\* Helpers + +\* The set of all quorums. This just calculates simple majorities, but the only +\* important property is that every quorum overlaps with every other. +Quorum == {i \in SUBSET(Server) : Cardinality(i) * 2 > Cardinality(Server)} + +\* The term of the last entry in a log, or 0 if the log is empty. +LogTerm(i, index) == IF index = 0 THEN 0 ELSE log[i][index].term +LastTerm(xlog) == IF Len(xlog) = 0 THEN 0 ELSE xlog[Len(xlog)].term + +\* Return the minimum value from a set, or undefined if the set is empty. +Min(s) == CHOOSE x \in s : \A y \in s : x <= y +\* Return the maximum value from a set, or undefined if the set is empty. +Max(s) == CHOOSE x \in s : \A y \in s : x >= y + +---- +\* Define initial values for all variables + +InitServerVars == /\ globalCurrentTerm = 1 + /\ state = [i \in Server |-> Follower] +InitLogVars == /\ log = [i \in Server |-> << >>] +Init == /\ InitServerVars + /\ InitLogVars + +---- +\* Message handlers +\* i = recipient, j = sender, m = message + +AppendOplog(i, j) == + /\ Len(log[i]) < Len(log[j]) + /\ LastTerm(log[i]) = LogTerm(j, Len(log[i])) + /\ log' = [log EXCEPT ![i] = Append(log[i], log[j][Len(log[i]) + 1])] + /\ UNCHANGED <<serverVars>> + +CanRollbackOplog(i, j) == + /\ Len(log[i]) > 0 + /\ \* The log with later term is more up-to-date + LastTerm(log[i]) < LastTerm(log[j]) + /\ + \/ Len(log[i]) > Len(log[j]) + \* There seems no short-cut of OR clauses, so I have to specify the negative case + \/ /\ Len(log[i]) <= Len(log[j]) + /\ LastTerm(log[i]) /= LogTerm(j, Len(log[i])) + +RollbackOplog(i, j) == + /\ CanRollbackOplog(i, j) + \* Rollback 1 oplog entry + /\ LET new == [index2 \in 1..(Len(log[i]) - 1) |-> log[i][index2]] + IN log' = [log EXCEPT ![i] = new] + /\ UNCHANGED <<serverVars>> + + +\* RollbackCommitted and NeverRollbackCommitted are not actions. +\* They are used for verification. +RollbackCommitted(i) == + LET + \* The set of nodes that has log[me][logIndex] in their oplog + Agree(me, logIndex) == + { node \in Server : + /\ Len(log[node]) >= logIndex + /\ LogTerm(me, logIndex) = LogTerm(node, logIndex) } + IsCommitted(me, logIndex) == + /\ Agree(me, logIndex) \in Quorum + \* If we comment out the following line, a replicated log entry from old primary will voilate the safety. + \* [ P (2), S (), S ()] + \* [ S (2), S (), P (3)] + \* [ S (2), S (2), P (3)] !!! the log from term 2 shouldn't be considered as committed. + /\ LogTerm(me, logIndex) = globalCurrentTerm + IN \E j \in Server: + /\ CanRollbackOplog(i, j) + /\ IsCommitted(i, Len(log[i])) + +NeverRollbackCommitted == + \A i \in Server: ~RollbackCommitted(i) + +\* i = the new primary node. +BecomePrimaryByMagic(i) == + LET notBehind(me, j) == + \/ LastTerm(log[me]) > LastTerm(log[j]) + \/ /\ LastTerm(log[me]) = LastTerm(log[j]) + /\ Len(log[me]) >= Len(log[j]) + ayeVoters(me) == + { index \in Server : notBehind(me, index) } + IN /\ ayeVoters(i) \in Quorum + /\ state' = [index \in Server |-> IF index = i THEN Leader ELSE Follower] + /\ globalCurrentTerm' = globalCurrentTerm + 1 + /\ UNCHANGED <<logVars>> + +\* Leader i receives a client request to add v to the log. +ClientWrite(i, v) == + /\ state[i] = Leader + /\ LET entry == [term |-> globalCurrentTerm, + value |-> v] + newLog == Append(log[i], entry) + IN log' = [log EXCEPT ![i] = newLog] + /\ UNCHANGED <<serverVars>> + +---- +\* Defines how the variables may transition. +Next == /\ + \/ \E i,j \in Server : AppendOplog(i, j) + \/ \E i,j \in Server : RollbackOplog(i, j) + \/ \E i \in Server : BecomePrimaryByMagic(i) + \/ \E i \in Server, v \in Value : ClientWrite(i, v) + +\* The specification must start with the initial state and transition according +\* to Next. +Spec == Init /\ [][Next]_vars + +=============================================================================== diff --git a/general/performance/SwarmKit/EventCounter.tla b/general/performance/SwarmKit/EventCounter.tla new file mode 100644 index 0000000000000000000000000000000000000000..59daf1731d9eaa2763cc69130ec950d99083af30 --- /dev/null +++ b/general/performance/SwarmKit/EventCounter.tla @@ -0,0 +1,25 @@ +---------------------------- MODULE EventCounter ---------------------------- + +EXTENDS Integers + +\* The number of ``events'' that have occurred (always 0 if we're not keeping track). +VARIABLE nEvents + +\* The maximum number of events to allow, or ``-1'' for unlimited. +maxEvents == -1 + +InitEvents == + nEvents = 0 \* Start with the counter at zero + +(* If we're counting events, increment the event counter. + We don't increment the counter when we don't have a maximum because that + would make the model infinite. + Actions tagged with CountEvent cannot happen once nEvents = maxEvents. *) +CountEvent == + IF maxEvents = -1 THEN + UNCHANGED nEvents + ELSE + /\ nEvents < maxEvents + /\ nEvents' = nEvents + 1 + +============================================================================= \ No newline at end of file diff --git a/general/performance/SwarmKit/MC.cfg b/general/performance/SwarmKit/MC.cfg new file mode 100644 index 0000000000000000000000000000000000000000..65520b1b3c5a40887c6eb7a96ab44ad1bb22ffaf --- /dev/null +++ b/general/performance/SwarmKit/MC.cfg @@ -0,0 +1,15 @@ +SPECIFICATION Spec + +CONSTANT TaskId = {t1, t2} +CONSTANT ServiceId = {s1, s1} +CONSTANT Node = {n1, n2} +CONSTANT maxTerminated = 1 +CONSTANT maxReplicas = 1 +CONSTANT unassigned = unassigned +CONSTANT global = global + +INVARIANT TypeOK +INVARIANT Inv + +PROPERTY TransitionsOK +PROPERTY EventuallyAsDesired diff --git a/general/performance/SwarmKit/MC.tla b/general/performance/SwarmKit/MC.tla new file mode 100644 index 0000000000000000000000000000000000000000..0ea2dcbe326e570f38bc930ae986f549f7682d55 --- /dev/null +++ b/general/performance/SwarmKit/MC.tla @@ -0,0 +1,4 @@ +----------- MODULE MC ----------- +EXTENDS SwarmKit + +================================= diff --git a/general/performance/SwarmKit/README.md b/general/performance/SwarmKit/README.md new file mode 100644 index 0000000000000000000000000000000000000000..1abf9f67906d38dc9f5a9b6dc6f0e4b4b4462bd3 --- /dev/null +++ b/general/performance/SwarmKit/README.md @@ -0,0 +1 @@ +# This is a snapshot of the tlaplus folder of the repository at https://github.com/talex5/swarmkit/tree/c43c5852be355dae2e32328c17b8885cfc86600f/design/tla/ - released under the Apache 2 license - from which we copied the spec for TLC performance testing! We claim no authorship of this specification. diff --git a/general/performance/SwarmKit/SwarmKit.tla b/general/performance/SwarmKit/SwarmKit.tla new file mode 100644 index 0000000000000000000000000000000000000000..1cf23f10c93c9727073eca79c0853c28aaf84a8f --- /dev/null +++ b/general/performance/SwarmKit/SwarmKit.tla @@ -0,0 +1,633 @@ +This is a TLA+ model of SwarmKit. Even if you don't know TLA+, you should be able to +get the general idea. This section gives a very brief overview of the syntax. + +Declare `x' to be something that changes as the system runs: + + VARIABLE x + +Define `Init' to be a state predicate (== means ``is defined to be''): + + Init == + x = 0 + +`Init' is true for states in which `x = 0'. This can be used to define +the possible initial states of the system. For example, the state +[ x |-> 0, y |-> 2, ... ] satisfies this. + +Define `Next' to be an action: + + Next == + /\ x' \in Nat + /\ x' > x + +An action takes a pair of states, representing an atomic step of the system. +Unprimed expressions (e.g. `x') refer to the old state, and primed ones to +the new state. This example says that a step is a `Next' step iff the new +value of `x' is a natural number and greater than the previous value. +For example, [ x |-> 3, ... ] -> [x |-> 10, ... ] is a `Next' step. + +/\ is logical ``and''. This example uses TLA's ``bulleted-list'' syntax, which makes +writing these easier. It is indentation-sensitive. TLA also has \/ lists (``or''). + +See `.http://lamport.azurewebsites.net/tla/summary.pdf.' for a more complete summary +of the syntax. + +This specification can be read as documentation, but it can also be executed by the TLC +model checker. See the model checking section below for details about that. + +The rest of the document is organised as follows: + +1. Parameters to the model +2. Types and definitions +3. How to run the model checker +4. Actions performed by the user +5. Actions performed by the components of SwarmKit +6. The complete system +7. Properties of the system + +-------------------------------- MODULE SwarmKit -------------------------------- + +(* Import some libraries we use. + Common SwarmKit types are defined in Types.tla. You should probably read that before continuing. *) +EXTENDS Integers, TLC, FiniteSets, \* From the TLA+ standard library + Types, \* SwarmKit types + Tasks, \* The `tasks' variable + WorkerSpec, \* High-level spec for worker nodes + EventCounter \* Event limiting, for modelling purposes + +(* The maximum number of terminated tasks to keep for each slot. *) +CONSTANT maxTerminated +ASSUME maxTerminated \in Nat + +(* In the model, we share taskIDs (see ModelTaskId), which means that + we can cover most behaviours with only enough task IDs + for one running task and maxTerminated finished ones. *) +ASSUME Cardinality(TaskId) >= 1 + maxTerminated + +------------------------------------------------------------------------------- +\* Services + +VARIABLE services \* A map of currently-allocated services, indexed by ServiceId + +(* A replicated service is one that specifies some number of replicas it wants. *) +IsReplicated(sid) == + services[sid].replicas \in Nat + +(* A global service is one that wants one task running on each node. *) +IsGlobal(sid) == + services[sid].replicas = global + +(* TasksOf(sid) is the set of tasks for service `sid'. *) +TasksOf(sid) == + { t \in tasks : t.service = sid } + +(* All tasks of service `sid' in `vslot'. *) +TasksOfVSlot(sid, vslot) == + { t \in TasksOf(sid) : VSlot(t) = vslot } + +(* All vslots of service `sid'. *) +VSlotsOf(sid) == + { VSlot(t) : t \in TasksOf(sid) } + +------------------------------------------------------------------------------- +\* Types + +(* The expected type of each variable. TLA+ is an untyped language, but the model checker + can check that TypeOK is true for every reachable state. *) +TypeOK == + \* `services' is a mapping from service IDs to ServiceSpecs: + /\ DOMAIN services \subseteq ServiceId + /\ services \in [ DOMAIN services -> ServiceSpec ] + /\ TasksTypeOK \* Defined in Types.tla + /\ WorkerTypeOK \* Defined in WorkerSpec.tla + +------------------------------------------------------------------------------- +(* +`^ \textbf{Model checking} ^' + + You can test this specification using the TLC model checker. + This section describes how to do that. If you don't want to run TLC, + you can skip this section. + + To use TLC, load this specification file in the TLA+ toolbox (``Open Spec'') + and create a new model using the menu. + + You will be prompted to enter values for the various CONSTANTS. + A suitable set of initial values is: + + `. + Node <- [ model value ] {n1} + ServiceId <- [ model value ] {s1} + TaskId <- [ model value ] {t1, t2} + maxReplicas <- 1 + maxTerminated <- 1 + .' + + For the [ model value ] ones, select `Set of model values'. + + This says that we have one node, `n1', at most one service, and at most + two tasks per vslot. TLC can explore all possible behaviours of this system + in a couple of seconds on my laptop. + + You should also specify some things to check (under ``What to check?''): + + - Add `TypeOK' and `Inv' under ``Invariants'' + - Add `TransitionsOK' and `EventuallyAsDesired' under ``Properties'' + + Running the model should report ``No errors''. + + If the model fails, TLC will show you an example sequence of actions that lead to + the failure and you can inspect the state at each step. You can try this out by + commenting out any important-looking condition in the model (e.g. the requirement + in UpdateService that you can't change the mode of an existing service). + + Although the above model is very small, it should detect most errors that you might + accidentally introduce when modifying the specification. Increasing the number of nodes, + services, replicas or terminated tasks will check more behaviours of the system, + but will be MUCH slower. + + The rest of this section describes techniques to make model checking faster by reducing + the number of states that must be considered in various ways. Feel free to skip it. + +`^ \textbf{Symmetry sets} ^' + + You should configure any model sets (e.g. `TaskId') as `symmetry sets'. + For example, if you have a model with two nodes {n1, n2} then this tells TLC that + two states which are the same except that n1 and n2 are swapped are equivalent + and it only needs to continue exploring from one of them. + TLC will warn that checking temporal properties may not work correctly, + but it's much faster and I haven't had any problems with it. + +`^ \textbf{Limiting the maximum number of setbacks to consider} ^' + + Another way to speed things up is to reduce the number of failures that TLC must consider. + By default, it checks every possible combination of failures at every point, which + is very expensive. + In the `Advanced Options' panel of the model, add a ``Definition Override'' of e.g. + `maxEvents = 2'. Actions that represent unnecessary extra work (such as the user + changing the configuration or a worker node going down) are tagged with `CountEvent'. + Any run of the system cannot have more than `maxEvents' such events. + + See `EventCounter.tla' for details. + +`^ \textbf{Preventing certain failures} ^' + + If you're not interested in some actions then you can block them. For example, + adding these two constraints in the ``Action Constraint'' box of the + ``Advanced Options'' tab tells TLC not to consider workers going down or + workers rejecting tasks as possible actions: + + /\ ~WorkerDown + /\ ~RejectTask +*) + +(* +`^ \textbf{Combining task states} ^' + + A finished task can be either in the `complete' or `failed' state, depending on + its exit status. If we have 4 finished tasks, that's 16 different states. For + modelling, we might not care about exit codes and we can treat this as a single + state with another definition override: + + `.failed <- complete.' + + In a similar way, we can combine { assigned, accepted, preparing, ready } into a single + state: + + `.accepted <- assigned + preparing <- assigned + ready <- assigned.' +*) + +---------------------------- MODULE User -------------------------------------------- +\* Actions performed by users + +(* Create a new service with any ServiceSpec. + + This says that a single atomic step of the system from an old state + to a new one is a CreateService step iff `tasks', `nodes' and `nEvents' don't change + and the new value of `services' is the same as before except that some + service ID that wasn't used in the old state is now mapped to some + ServiceSpec. + + Note: A \ B means { x \in A : x \notin B } -- + i.e. the set A with all elements in B removed. + *) +CreateService == + /\ UNCHANGED << tasks, nodes, nEvents >> + /\ \E sid \in ServiceId \ DOMAIN services, \* `sid' is an unused ServiceId + spec \in ServiceSpec : \* `spec' is any ServiceSpec + /\ spec.remove = FALSE \* (not flagged for removal) + /\ services' = services @@ sid :> spec \* Add `sid |-> spec' to `services' + +(* Update an existing service's spec. *) +UpdateService == + /\ UNCHANGED << tasks, nodes >> + /\ CountEvent \* Flag as an event for model-checking purposes + /\ \E sid \in DOMAIN services, \* `sid' is an existing ServiceId + newSpec \in ServiceSpec : \* `newSpec' is any `ServiceSpec' + /\ services[sid].remove = FALSE \* We weren't trying to remove sid + /\ newSpec.remove = FALSE \* and we still aren't. + \* You can't change a service's mode: + /\ (services[sid].replicas = global) <=> (newSpec.replicas = global) + /\ services' = [ services EXCEPT ![sid] = newSpec ] + +(* The user removes a service. + + Note: Currently, SwarmKit deletes the service from its records immediately. + However, this isn't right because we need to wait for service-level resources + such as Virtual IPs to be freed. + Here we model the proposed fix, in which we just flag the service for removal. *) +RemoveService == + /\ UNCHANGED << nodes >> + /\ CountEvent + /\ \E sid \in DOMAIN services : \* sid is some existing service + \* Flag service for removal: + /\ services' = [services EXCEPT ![sid].remove = TRUE] + \* Flag every task of the service for removal: + /\ UpdateTasks([ t \in TasksOf(sid) |-> + [t EXCEPT !.desired_state = remove] ]) + +(* A user action is one of these. *) +User == + \/ CreateService + \/ UpdateService + \/ RemoveService + +============================================================================= + +---------------------------- MODULE Orchestrator ---------------------------- + +\* Actions performed the orchestrator + +\* Note: This is by far the most complicated component in the model. +\* You might want to read this section last... + +(* The set of tasks for service `sid' that should be considered as active. + This is any task that is running or on its way to running. *) +RunnableTasks(sid) == + { t \in TasksOf(sid) : Runnable(t) } + +(* Candidates for shutting down when we have too many. We don't want to count tasks that are shutting down + towards the total count when deciding whether we need to kill anything. *) +RunnableWantedTasks(sid) == + { t \in RunnableTasks(sid) : t.desired_state \preceq running } + +(* The set of possible new vslots for `sid'. *) +UnusedVSlot(sid) == + IF IsReplicated(sid) THEN Slot \ VSlotsOf(sid) + ELSE Node \ VSlotsOf(sid) + +(* The set of possible IDs for a new task in a vslot. + + The complexity here is just a side-effect of the modelling (where we need to + share and reuse task IDs for performance). + In the real system, choosing an unused ID is easy. *) +UnusedId(sid, vslot) == + LET swarmTaskIds == { t.id : t \in TasksOfVSlot(sid, vslot) } + IN TaskId \ swarmTaskIds + +(* Create a new task/slot if the number of runnable tasks is less than the number requested. *) +CreateSlot == + /\ UNCHANGED << services, nodes, nEvents >> + /\ \E sid \in DOMAIN services : \* `sid' is an existing service + /\ ~services[sid].remove \* that we're not trying to remove + (* For replicated tasks, only create as many slots as we need. + For global tasks, we want all possible vslots (nodes). *) + /\ IsReplicated(sid) => + services[sid].replicas > Cardinality(VSlotsOf(sid)) \* Desired > actual + /\ \E slot \in UnusedVSlot(sid) : + \E id \in UnusedId(sid, slot) : + tasks' = tasks \union { NewTask(sid, slot, id, running) } + +(* Add a task if a slot exists, contains no runnable tasks, and we weren't trying to remove it. + Note: if we are trying to remove it, the slot will eventually disappear and CreateSlot will + then make a new one if we later need it again. + + Currently in SwarmKit, slots do not actually exist as objects in the store. + Instead, we just infer that a slot exists because there exists a task with that slot ID. + This has the odd effect that if `maxTerminated = 0' then we may create new slots rather than reusing + existing ones, depending on exactly when the reaper runs. + *) +ReplaceTask == + /\ UNCHANGED << services, nodes, nEvents >> + /\ \E sid \in DOMAIN services : + \E slot \in VSlotsOf(sid) : + /\ \A task \in TasksOfVSlot(sid, slot) : \* If all tasks in `slot' are + ~Runnable(task) \* dead (not runnable) and + /\ \E task \in TasksOfVSlot(sid, slot) : \* there is some task that + task.desired_state # remove \* we're not trying to remove, + /\ \E id \in UnusedId(sid, slot) : \* then create a replacement task: + tasks' = tasks \union { NewTask(sid, slot, id, running) } + +(* If we have more replicas than the spec asks for, remove one of them. *) +RequestRemoval == + /\ UNCHANGED << services, nodes, nEvents >> + /\ \E sid \in DOMAIN services : + LET current == RunnableWantedTasks(sid) + IN \* Note: `current' excludes tasks we're already trying to kill + /\ IsReplicated(sid) + /\ services[sid].replicas < Cardinality(current) \* We have too many replicas + /\ \E slot \in { t.slot : t \in current } : \* Choose an allocated slot + \* Mark all tasks for that slot for removal: + UpdateTasks( [ t \in TasksOfVSlot(sid, slot) |-> + [t EXCEPT !.desired_state = remove] ] ) + +(* Mark a terminated task for removal if we already have `maxTerminated' terminated tasks for this slot. *) +CleanupTerminated == + /\ UNCHANGED << services, nodes, nEvents >> + /\ \E sid \in DOMAIN services : + \E slot \in VSlotsOf(sid) : + LET termTasksInSlot == { t \in TasksOfVSlot(sid, slot) : + State(t) \in { complete, shutdown, failed, rejected } } + IN + /\ Cardinality(termTasksInSlot) > maxTerminated \* Too many tasks for slot + /\ \E t \in termTasksInSlot : \* Pick a victim to remove + UpdateTasks(t :> [t EXCEPT !.desired_state = remove]) + +(* We don't model the updater explicitly, but we allow any task to be restarted (perhaps with + a different image) at any time, which should cover the behaviours of the restart supervisor. + + TODO: SwarmKit also allows ``start-first'' mode updates where we first get the new task to + `running' and then mark the old task for shutdown. Add this to the model. *) +RestartTask == + /\ UNCHANGED << services, nodes >> + /\ CountEvent + /\ \E oldT \in tasks : + \E newId \in UnusedId(oldT.service, VSlot(oldT)) : + /\ Runnable(oldT) \* Victim must be runnable + /\ oldT.desired_state \prec shutdown \* and we're not trying to kill it + \* Create the new task in the `ready' state (see ReleaseReady below): + /\ LET replacement == NewTask(oldT.service, VSlot(oldT), newId, ready) + IN tasks' = + (tasks \ {oldT}) \union { + [oldT EXCEPT !.desired_state = shutdown], + replacement + } + +(* A task is set to wait at `ready' and the previous task for that slot has now finished. + Allow it to proceed to `running'. *) +ReleaseReady == + /\ UNCHANGED << services, nodes, nEvents >> + /\ \E t \in tasks : + /\ t.desired_state = ready \* (and not e.g. `remove') + /\ State(t) = ready + /\ \A other \in TasksOfVSlot(t.service, VSlot(t)) \ {t} : + ~Runnable(other) \* All other tasks have finished + /\ UpdateTasks(t :> [t EXCEPT !.desired_state = running]) + +(* The user asked to remove a service, and now all its tasks have been cleaned up. *) +CleanupService == + /\ UNCHANGED << tasks, nodes, nEvents >> + /\ \E sid \in DOMAIN services : + /\ services[sid].remove = TRUE + /\ TasksOf(sid) = {} + /\ services' = [ i \in DOMAIN services \ {sid} |-> services[i] ] + +(* Tasks that the orchestrator must always do eventually if it can: *) +OrchestratorProgress == + \/ CreateSlot + \/ ReplaceTask + \/ RequestRemoval + \/ CleanupTerminated + \/ ReleaseReady + \/ CleanupService + +(* All actions that the orchestrator can perform *) +Orchestrator == + \/ OrchestratorProgress + \/ RestartTask + +============================================================================= + +---------------------------- MODULE Allocator ------------------------------- +\* Actions performed the allocator + +(* Pick a `new' task and move it to `pending'. + + The spec says the allocator will ``allocate resources such as network attachments + which are necessary for the tasks to run''. However, we don't model any resources here. *) +AllocateTask == + /\ UNCHANGED << services, nodes, nEvents >> + /\ \E t \in tasks : + /\ State(t) = new + /\ UpdateTasks(t :> [t EXCEPT !.status.state = pending]) + +AllocatorProgress == + \/ AllocateTask + +Allocator == + \/ AllocatorProgress + +============================================================================= + +---------------------------- MODULE Scheduler ------------------------------- + +\* Actions performed by the scheduler + +(* The scheduler assigns a node to a `pending' task and moves it to `assigned' + once sufficient resources are available (we don't model resources here). *) +Scheduler == + /\ UNCHANGED << services, nodes, nEvents >> + /\ \E t \in tasks : + /\ State(t) = pending + /\ LET candidateNodes == IF t.node = unassigned + THEN Node \* (all nodes) + ELSE { t.node } + IN + \E node \in candidateNodes : + UpdateTasks(t :> [t EXCEPT !.status.state = assigned, + !.node = node ]) + +============================================================================= + +---------------------------- MODULE Reaper ---------------------------------- + +\* Actions performed by the reaper + +(* Forget about tasks in remove or orphan states. + + Orphaned tasks belong to nodes that we are assuming are lost forever (or have crashed + and will come up with nothing running, which is an equally fine outcome). *) +Reaper == + /\ UNCHANGED << services, nodes, nEvents >> + /\ \E t \in tasks : + /\ \/ /\ t.desired_state = remove + /\ (State(t) \prec assigned \/ ~Runnable(t)) \* Not owned by agent + \/ State(t) = orphaned + /\ tasks' = tasks \ {t} + +============================================================================= + +\* The complete system + +\* Import definitions from the various modules +INSTANCE User +INSTANCE Orchestrator +INSTANCE Allocator +INSTANCE Scheduler +INSTANCE Reaper + +\* All the variables +vars == << tasks, services, nodes, nEvents >> + +\* Initially there are no tasks and no services, and all nodes are up. +Init == + /\ tasks = {} + /\ services = << >> + /\ nodes = [ n \in Node |-> nodeUp ] + /\ InitEvents + +(* WorkerSpec doesn't mention `services'. To combine it with this spec, we need to say + that every action of the agent leaves `services' unchanged. *) +AgentReal == + Agent /\ UNCHANGED services + +(* Unfortunately, `AgentReal' causes TLC to report all problems of the agent + as simply `AgentReal' steps, which isn't very helpful. We can get better + diagnostics by expanding it, like this: *) +AgentTLC == + \/ (ProgressTask /\ UNCHANGED services) + \/ (ShutdownComplete /\ UNCHANGED services) + \/ (OrphanTasks /\ UNCHANGED services) + \/ (WorkerUp /\ UNCHANGED services) + \/ (RejectTask /\ UNCHANGED services) + \/ (ContainerExit /\ UNCHANGED services) + \/ (WorkerDown /\ UNCHANGED services) + +(* To avoid the risk of `AgentTLC' getting out of sync, + TLAPS can check that the definitions are equivalent. *) +THEOREM AgentTLC = AgentReal +BY DEF AgentTLC, AgentReal, Agent, AgentProgress + +(* A next step is one in which any of these sub-components takes a step: *) +Next == + \/ User + \/ Orchestrator + \/ Allocator + \/ Scheduler + \/ AgentTLC + \/ Reaper + \* For model checking: don't report deadlock if we're limiting events + \/ (nEvents = maxEvents /\ UNCHANGED vars) + +(* This is a ``temporal formula''. It takes a sequence of states representing the + changing state of the world and evaluates to TRUE if that sequences of states is + a possible behaviour of SwarmKit. *) +Spec == + \* The first state in the behaviour must satisfy Init: + /\ Init + \* All consecutive pairs of states must satisfy Next or leave `vars' unchanged: + /\ [][Next]_vars + (* Some actions are required to happen eventually. For example, a behaviour in + which SwarmKit stops doing anything forever, even though it could advance some task + from the `new' state, isn't a valid behaviour of the system. + This property is called ``weak fairness''. *) + /\ WF_vars(OrchestratorProgress) + /\ WF_vars(AllocatorProgress) + /\ WF_vars(Scheduler) + /\ WF_vars(AgentProgress /\ UNCHANGED services) + /\ WF_vars(Reaper) + /\ WF_vars(WorkerUp /\ UNCHANGED services) + (* We don't require fairness of: + - User (we don't control them), + - RestartTask (services aren't required to be updated), + - RejectTask (tasks aren't required to be rejected), + - ContainerExit (we don't specify image behaviour) or + - WorkerDown (workers aren't required to fail). *) + +------------------------------------------------------------------------------- +\* Properties to verify + +(* These are properties that should follow automatically if the system behaves as + described by `Spec' in the previous section. *) + +\* A state invariant (things that should be true in every state). +Inv == + \A t \in tasks : + (* Every task has a service: + + TODO: The spec says: ``In some cases, there are tasks that exist independent of any service. + These do not have a value set in service_id.''. Add an example of one. *) + /\ t.service \in DOMAIN services + \* Tasks have nodes once they reach `assigned', except maybe if rejected: + /\ assigned \preceq State(t) => t.node \in Node \/ State(t) = rejected + \* `remove' is only used as a desired state, not an actual one: + /\ State(t) # remove + \* Task IDs are unique + /\ \A t2 \in tasks : Id(t) = Id(t2) => t = t2 + +(* The state of task `i' in `S', or `null' if it doesn't exist *) +Get(S, i) == + LET cand == { x \in S : Id(x) = i } + IN IF cand = {} THEN null + ELSE State(CHOOSE x \in cand : TRUE) + +(* An action in which all transitions were valid. *) +StepTransitionsOK == + LET permitted == { << x, x >> : x \in TaskState } \union \* No change is always OK + CASE Orchestrator -> Transitions.orchestrator + [] Allocator -> Transitions.allocator + [] Scheduler -> Transitions.scheduler + [] Agent -> Transitions.agent + [] Reaper -> Transitions.reaper + [] OTHER -> {} + oldIds == IdSet(tasks) + newIds == IdSet(tasks') + IN + \A id \in newIds \union oldIds : + << Get(tasks, id), Get(tasks', id) >> \in permitted + +(* Some of the expressions below are ``temporal formulas''. Unlike state expressions and actions, + these look at a complete behaviour (sequence of states). Summary of notation: + + [] means ``always''. e.g. []x=3 means that `x = 3' in all states. + + <> means ``eventually''. e.g. <>x=3 means that `x = 3' in some state. + + `x=3' on its own means that `x=3' in the initial state. +*) + +\* A temporal formula that checks every step satisfies StepTransitionsOK (or `vars' is unchanged) +TransitionsOK == + [][StepTransitionsOK]_vars + +(* Every service has the right number of running tasks (the system is in the desired state). *) +InDesiredState == + \A sid \in DOMAIN services : + \* We're not trying to remove the service: + /\ ~services[sid].remove + \* The service has the correct set of running replicas: + /\ LET runningTasks == { t \in TasksOf(sid) : State(t) = running } + nRunning == Cardinality(runningTasks) + IN + CASE IsReplicated(sid) -> + /\ nRunning = services[sid].replicas + [] IsGlobal(sid) -> + \* We have as many tasks as nodes: + /\ nRunning = Cardinality(Node) + \* We have a task for every node: + /\ { t.node : t \in runningTasks } = Node + \* The service does not have too many terminated tasks + /\ \A slot \in VSlotsOf(sid) : + LET terminated == { t \in TasksOfVSlot(sid, slot) : ~Runnable(t) } + IN Cardinality(terminated) <= maxTerminated + +(* The main property we want to check. + + []<> means ``always eventually'' (``infinitely-often'') + + <>[] means ``eventually always'' (always true after some point) + + This temporal formula says that if we only experience a finite number of + problems then the system will eventually settle on InDesiredState. +*) +EventuallyAsDesired == + \/ []<> <<User>>_vars \* Either the user keeps changing the configuration, + \/ []<> <<RestartTask>>_vars \* or restarting/updating tasks, + \/ []<> <<WorkerDown>>_vars \* or workers keep failing, + \/ []<> <<RejectTask>>_vars \* or workers keep rejecting tasks, + \/ []<> <<ContainerExit>>_vars \* or the containers keep exiting, + \/ <>[] InDesiredState \* or we eventually get to the desired state and stay there. + +============================================================================= diff --git a/general/performance/SwarmKit/Tasks.tla b/general/performance/SwarmKit/Tasks.tla new file mode 100644 index 0000000000000000000000000000000000000000..f0b1569659c75d43601f7e598a6aa0f414556baa --- /dev/null +++ b/general/performance/SwarmKit/Tasks.tla @@ -0,0 +1,112 @@ +---------------------------- MODULE Tasks ---------------------------------- + +EXTENDS TLC, Types + +VARIABLE tasks \* The set of currently-allocated tasks + +(* The expected type of each variable. TLA+ is an untyped language, but the model checker + can check that TasksTypeOK is true for every reachable state. *) +TasksTypeOK == + \* `tasks' is a subset of the set of all possible tasks + /\ tasks \in SUBSET Task + +(* Update `tasks' by performing each update in `f', which is a function + mapping old tasks to new ones. *) +UpdateTasks(f) == + /\ Assert(\A t \in DOMAIN f : t \in tasks, "An old task does not exist!") + /\ Assert(\A t \in DOMAIN f : + LET t2 == f[t] + IN \* The updated version of `t' must have + /\ t.id = t2.id \* the same task ID, + /\ t.service = t2.service \* the same service ID, + /\ VSlot(t) = VSlot(t2), \* and the same vslot. + "An update changes a task's identity!") + \* Remove all the old tasks and add the new ones: + /\ tasks' = (tasks \ DOMAIN f) \union Range(f) + +(* A `new' task belonging to service `sid' with the given slot, id, and desired state. *) +NewTask(sid, vslot, id, desired_state) == + [ + id |-> id, + service |-> sid, + status |-> [ state |-> new ], + desired_state |-> desired_state, + node |-> IF vslot \in Node THEN vslot ELSE unassigned, + slot |-> IF vslot \in Slot THEN vslot ELSE global + ] + + +\* A special ``state'' used when a task doesn't exist. +null == "null" + +(* All the possible transitions, grouped by the component that performs them. *) +Transitions == [ + orchestrator |-> { + << null, new >> + }, + + allocator |-> { + << new, pending >> + }, + + scheduler |-> { + << pending, assigned >> + }, + + agent |-> { + << assigned, accepted >>, + << accepted, preparing >>, + << preparing, ready >>, + << ready, starting >>, + << starting, running >>, + + << assigned, rejected >>, + << accepted, rejected >>, + << preparing, rejected >>, + << ready, rejected >>, + << starting, rejected >>, + + << running, complete >>, + << running, failed >>, + + << running, shutdown >>, + + << assigned, orphaned >>, + << accepted, orphaned >>, + << preparing, orphaned >>, + << ready, orphaned >>, + << starting, orphaned >>, + << running, orphaned >> + }, + + reaper |-> { + << new, null >>, + << pending, null >>, + << rejected, null >>, + << complete, null >>, + << failed, null >>, + << shutdown, null >>, + << orphaned, null >> + } +] + +(* Check that `Transitions' itself is OK. *) +TransitionTableOK == + \* No transition moves to a lower-ranked state: + /\ \A actor \in DOMAIN Transitions : + \A trans \in Transitions[actor] : + \/ trans[1] = null + \/ trans[2] = null + \/ trans[1] \preceq trans[2] + (* Every source state has exactly one component which handles transitions out of that state. + Except for the case of the reaper removing `new' and `pending' tasks that are flagged + for removal. *) + /\ \A a1, a2 \in DOMAIN Transitions : + LET exceptions == { << new, null >>, << pending, null >> } + Source(a) == { s[1] : s \in Transitions[a] \ exceptions} + IN a1 # a2 => + Source(a1) \intersect Source(a2) = {} + +ASSUME TransitionTableOK \* Note: ASSUME means ``check'' to TLC + +============================================================================= \ No newline at end of file diff --git a/general/performance/SwarmKit/Types.tla b/general/performance/SwarmKit/Types.tla new file mode 100644 index 0000000000000000000000000000000000000000..555ad4c68f4c4bd474cc3849ce1dd8a1bc10b1ea --- /dev/null +++ b/general/performance/SwarmKit/Types.tla @@ -0,0 +1,124 @@ +------------------------------- MODULE Types ------------------------------- + +EXTENDS Naturals, FiniteSets + +(* A generic operator to get the range of a function (the set of values in a map): *) +Range(S) == { S[i] : i \in DOMAIN S } + +(* The set of worker nodes. + + Note: a CONSTANT is an input to the model. The model should work with any set of nodes you provide. + + TODO: should cope with this changing at runtime, and with draining nodes. *) +CONSTANT Node + +(* A special value indicating that a task is not yet assigned to a node. + + Note: this TLA+ CHOOSE idiom just says to pick some value that isn't a Node (e.g. `null'). *) +unassigned == CHOOSE n : n \notin Node + +(* The type (set) of service IDs (e.g. `Int' or `String'). + When model checking, this will be some small set (e.g. {"s1", "s2"}). *) +CONSTANT ServiceId + +(* The type of task IDs. *) +CONSTANT TaskId + +(* The maximum possible value for `replicas' in ServiceSpec. *) +CONSTANT maxReplicas +ASSUME maxReplicas \in Nat +Slot == 1..maxReplicas \* Possible slot numbers + +(* A special value (e.g. `-1') indicating that we want one replica running on each node: *) +global == CHOOSE x : x \notin Nat + +(* The type of a description of a service (a struct/record). + This is provided by, and only changed by, the user. *) +ServiceSpec == [ + (* The replicas field is either a count giving the desired number of replicas, + or the special value `global'. *) + replicas : 0..maxReplicas \union {global}, + remove : BOOLEAN \* The user wants to remove this service +] + +(* The possible states for a task: *) +new == "new" +pending == "pending" +assigned == "assigned" +accepted == "accepted" +preparing == "preparing" +ready == "ready" +starting == "starting" +running == "running" +complete == "complete" +shutdown == "shutdown" +failed == "failed" +rejected == "rejected" +remove == "remove" \* Only used as a ``desired state'', not an actual state +orphaned == "orphaned" + +(* Every state has a rank. It is only possible for a task to change + state to a state with a higher rank (later in this sequence). *) +order == << new, pending, assigned, accepted, + preparing, ready, starting, + running, + complete, shutdown, failed, rejected, + remove, orphaned >> + +(* Maps a state to its position in `order' (e.g. StateRank(new) = 1): *) +StateRank(s) == CHOOSE i \in DOMAIN order : order[i] = s + +(* Convenient notation for comparing states: *) +s1 \prec s2 == StateRank(s1) < StateRank(s2) +s1 \preceq s2 == StateRank(s1) <= StateRank(s2) + +(* The set of possible states ({new, pending, ...}): *) +TaskState == Range(order) \ {remove} + +(* Possibly this doesn't need to be a record, but we might want to add extra fields later. *) +TaskStatus == [ + state : TaskState +] + +(* The state that SwarmKit wants to the task to be in. *) +DesiredState == { ready, running, shutdown, remove } + +(* This has every field mentioned in `task_model.md' except for `spec', which + it doesn't seem to use for anything. + + `desired_state' can be any state, although currently we only ever set it to one of + {ready, running, shutdown, remove}. *) +Task == [ + id : TaskId, \* To uniquely identify this task + service : ServiceId, \* The service that owns the task + status : TaskStatus, \* The current state + desired_state : DesiredState, \* The state requested by the orchestrator + node : Node \union {unassigned}, \* The node on which the task should be run + slot : Slot \union {global} \* A way of tracking related tasks +] + +(* The current state of task `t'. *) +State(t) == t.status.state + +(* A task is runnable if it is running or could become running in the future. *) +Runnable(t) == State(t) \preceq running + +(* A task's ``virtual slot'' is its actual slot for replicated services, + but its node for global ones. *) +VSlot(t) == + IF t.slot = global THEN t.node ELSE t.slot + +(* In the real SwarmKit, a task's ID is just its taskId field. + However, this requires lots of IDs, which is expensive for model checking. + So instead, we will identify tasks by their << serviceId, vSlot, taskId >> + triple, and only require taskId to be unique within its vslot. *) +ModelTaskId == ServiceId \X (Slot \union Node) \X TaskId + +(* A unique identifier for a task, which never changes. *) +Id(t) == + << t.service, VSlot(t), t.id >> \* A ModelTaskId + +(* The ModelTaskIds of a set of tasks. *) +IdSet(S) == { Id(t) : t \in S } + +============================================================================= diff --git a/general/performance/SwarmKit/WorkerImpl.tla b/general/performance/SwarmKit/WorkerImpl.tla new file mode 100644 index 0000000000000000000000000000000000000000..03bf39bf3296d0cd25b443da5a7c4db10e41f4a6 --- /dev/null +++ b/general/performance/SwarmKit/WorkerImpl.tla @@ -0,0 +1,321 @@ +---------------------------- MODULE WorkerImpl ---------------------------------- + +EXTENDS TLC, Types, Tasks, EventCounter + +(* +`WorkerSpec' provides a high-level specification of worker nodes that only refers to +the state of the tasks recorded in SwarmKit's store. This specification (WorkerImpl) +refines WorkerSpec by also modelling the state of the containers running on a node. +It should be easier to see that this lower-level specification corresponds to what +actually happens on worker nodes. + +The reason for having this in a separate specification is that including the container +state greatly increases the number of states to be considered and so slows down model +checking. Instead of checking + + SwarmKit /\ WorkerImpl => EventuallyAsDesired + +(which is very slow), we check two separate expressions: + + SwarmKit /\ WorkerSpec => EventuallyAsDesired + WorkerImpl => WorkerSpec + +TLAPS can check that separating the specification in this way makes sense: *) +THEOREM ASSUME TEMPORAL SwarmKit, TEMPORAL WorkerSpec, + TEMPORAL WorkerImpl, TEMPORAL EventuallyAsDesired, + TEMPORAL Env, \* A simplified version of SwarmKit + SwarmKit /\ WorkerSpec => EventuallyAsDesired, + Env /\ WorkerImpl => WorkerSpec, + SwarmKit => Env + PROVE SwarmKit /\ WorkerImpl => EventuallyAsDesired +OBVIOUS + +\* This worker's node ID +CONSTANT node +ASSUME node \in Node + +VARIABLES nodes \* Defined in WorkerSpec.tla +VARIABLE containers \* The actual container state on the node, indexed by ModelTaskId + +(* The high-level specification of worker nodes. + This module should be a refinement of `WS'. *) +WS == INSTANCE WorkerSpec + +terminating == "terminating" \* A container which we're trying to stop + +(* The state of an actual container on a worker node. *) +ContainerState == { running, terminating, complete, failed } + +(* A running container finishes running on its own (or crashes). *) +ContainerExit == + /\ UNCHANGED << nodes, tasks >> + /\ CountEvent + /\ \E id \in DOMAIN containers, + s2 \in {failed, complete} : \* Either a successful or failed exit status + /\ containers[id] = running + /\ containers' = [containers EXCEPT ![id] = s2] + +(* A running container finishes because we stopped it. *) +ShutdownComplete == + /\ UNCHANGED << nodes, tasks, nEvents >> + /\ \E id \in DOMAIN containers : + /\ containers[id] = terminating + /\ containers' = [containers EXCEPT ![id] = failed] + +(* SwarmKit thinks the node is up. i.e. the agent is connected to a manager. *) +IsUp(n) == WS!IsUp(n) + +(* The new value that `containers' should take after getting an update from the + managers. If the managers asked us to run a container and then stop mentioning + that task, we shut the container down and (once stopped) remove it. *) +DesiredContainers == + LET WantShutdown(id) == + \* The managers stop mentioning the task, or ask for it to be stopped. + \/ id \notin IdSet(tasks) + \/ running \prec (CHOOSE t \in tasks : Id(t) = id).desired_state + (* Remove containers that no longer have tasks, once they've stopped. *) + rm == { id \in DOMAIN containers : + /\ containers[id] \in { complete, failed } + /\ id \notin IdSet(tasks) } + IN [ id \in DOMAIN containers \ rm |-> + IF containers[id] = running /\ WantShutdown(id) THEN terminating + ELSE containers[id] + ] + +(* The updates that SwarmKit should apply to its store to bring it up-to-date + with the real state of the containers. *) +RequiredTaskUpdates == + LET \* Tasks the manager is expecting news about: + oldTasks == { t \in tasks : t.node = node /\ State(t) = running } + \* The state to report for task `t': + ReportFor(t) == + IF Id(t) \notin DOMAIN containers THEN \* We were asked to forget about this container. + shutdown \* SwarmKit doesn't care which terminal state we finish in. + ELSE IF /\ containers[Id(t)] = failed \* It's terminated and + /\ t.desired_state = shutdown THEN \* we wanted to shut it down, + shutdown \* Report a successful shutdown + ELSE IF containers[Id(t)] = terminating THEN + running \* SwarmKit doesn't record progress of the shutdown + ELSE + containers[Id(t)] \* Report the actual state + IN [ t \in oldTasks |-> [ t EXCEPT !.status.state = ReportFor(t) ]] + +(* Our node synchronises its state with a manager. *) +DoSync == + /\ containers' = DesiredContainers + /\ UpdateTasks(RequiredTaskUpdates) + +(* Try to advance containers towards `desired_state' if we're not there yet. + + XXX: do we need a connection to the manager to do this, or can we make progress + while disconnected and just report the final state? +*) +ProgressTask == + /\ UNCHANGED << nodes, nEvents >> + /\ \E t \in tasks, + s2 \in TaskState : \* The state we want to move to + LET t2 == [t EXCEPT !.status.state = s2] + IN + /\ s2 \preceq t.desired_state \* Can't be after the desired state + /\ << State(t), State(t2) >> \in { \* Possible ``progress'' (desirable) transitions + << assigned, accepted >>, + << accepted, preparing >>, + << preparing, ready >>, + << ready, starting >>, + << starting, running >> + } + /\ IsUp(t.node) \* Node must be connected to SwarmKit + /\ IF s2 = running THEN + \* The container started running + containers' = Id(t) :> running @@ containers + ELSE + UNCHANGED containers + /\ UpdateTasks(t :> t2) + +(* The agent on the node synchronises with a manager. *) +SyncWithManager == + /\ UNCHANGED << nodes, nEvents >> + /\ IsUp(node) + /\ DoSync + +(* We can reject a task once we're responsible for it (it has reached `assigned') + until it reaches the `running' state. + Note that an ``accepted'' task can still be rejected. *) +RejectTask == + /\ UNCHANGED << nodes, containers >> + /\ CountEvent + /\ \E t \in tasks : + /\ State(t) \in { assigned, accepted, preparing, ready, starting } + /\ t.node = node + /\ IsUp(node) + /\ UpdateTasks(t :> [t EXCEPT !.status.state = rejected]) + +(* The dispatcher notices that the worker is down (the connection is lost). *) +WorkerDown == + /\ UNCHANGED << tasks, containers >> + /\ CountEvent + /\ \E n \in Node : + /\ IsUp(n) + /\ nodes' = [nodes EXCEPT ![n] = WS!nodeDown] + +(* When the node reconnects to the cluster, it gets an assignment set from the dispatcher + which does not include any tasks that have been marked orphaned and then deleted. + Any time an agent gets an assignment set that does not include some task it has running, + it shuts down those tasks. + + We model this separately with the `SyncWithManager' action. *) +WorkerUp == + /\ UNCHANGED << nEvents, containers, tasks >> + /\ \E n \in Node : + /\ ~IsUp(n) + /\ nodes' = [nodes EXCEPT ![n] = WS!nodeUp] + +(* Tasks assigned to a node and for which the node is responsible. *) +TasksOwnedByNode(n) == { t \in tasks : + /\ t.node = n + /\ assigned \preceq State(t) + /\ State(t) \prec remove +} + +(* If SwarmKit sees a node as down for a long time (48 hours or so) then + it marks all the node's tasks as orphaned. + Note that this sets the actual state, not the desired state. + + ``Moving a task to the Orphaned state is not desirable, + because it's the one case where we break the otherwise invariant + that the agent sets all states past ASSIGNED.'' +*) +OrphanTasks == + /\ UNCHANGED << nodes, containers, nEvents >> + /\ LET affected == { t \in TasksOwnedByNode(node) : Runnable(t) } + IN + /\ ~IsUp(node) \* Our connection to the agent is down + /\ UpdateTasks([ t \in affected |-> + [t EXCEPT !.status.state = orphaned] ]) + +(* The worker reboots. All containers are terminated. *) +WorkerReboot == + /\ UNCHANGED << nodes, tasks >> + /\ CountEvent + /\ containers' = [ id \in DOMAIN containers |-> + LET state == containers[id] + IN CASE state \in {running, terminating} -> failed + [] state \in {complete, failed} -> state + ] + +(* Actions we require to happen eventually when possible. *) +AgentProgress == + \/ ProgressTask + \/ OrphanTasks + \/ WorkerUp + \/ ShutdownComplete + \/ SyncWithManager + +(* All actions of the agent/worker. *) +Agent == + \/ AgentProgress + \/ RejectTask + \/ WorkerDown + \/ ContainerExit + \/ WorkerReboot + +------------------------------------------------------------------------------- +\* A simplified model of the rest of the system + +(* A new task is created. *) +CreateTask == + /\ UNCHANGED << containers, nEvents, nodes >> + /\ \E t \in Task : \* `t' is the new task + \* Don't reuse IDs (only really an issue for model checking) + /\ Id(t) \notin IdSet(tasks) + /\ Id(t) \notin DOMAIN containers + /\ State(t) = new + /\ t.desired_state \in { ready, running } + /\ \/ /\ t.node = unassigned \* A task for a replicated service + /\ t.slot \in Slot + \/ /\ t.node \in Node \* A task for a global service + /\ t.slot = global + /\ ~\E t2 \in tasks : \* All tasks of a service have the same mode + /\ t.service = t2.service + /\ (t.slot = global) # (t2.slot = global) + /\ tasks' = tasks \union {t} + +(* States before `assigned' aren't shared with worker nodes, so modelling them + isn't very useful. You can use this in a model to override `CreateTask' to + speed things up a bit. It creates tasks directly in the `assigned' state. *) +CreateTaskQuick == + /\ UNCHANGED << containers, nEvents, nodes >> + /\ \E t \in Task : + /\ Id(t) \notin IdSet(tasks) + /\ Id(t) \notin DOMAIN containers + /\ State(t) = assigned + /\ t.desired_state \in { ready, running } + /\ t.node \in Node + /\ t.slot \in Slot \union {global} + /\ ~\E t2 \in tasks : \* All tasks of a service have the same mode + /\ t.service = t2.service + /\ (t.slot = global) # (t2.slot = global) + /\ tasks' = tasks \union {t} + +(* The state or desired_state of a task is updated. *) +UpdateTask == + /\ UNCHANGED << containers, nEvents, nodes >> + /\ \E t \in tasks, t2 \in Task : \* `t' becomes `t2' + /\ Id(t) = Id(t2) \* The ID can't change + /\ State(t) # State(t2) => \* If the state changes then + \E actor \in DOMAIN Transitions : \* it is a legal transition + /\ actor = "agent" => t.node # node \* and not one our worker does + /\ << State(t), State(t2) >> \in Transitions[actor] + \* When tasks reach the `assigned' state, they must have a node + /\ IF State(t2) = assigned /\ t.node = unassigned THEN t2.node \in Node + ELSE t2.node = t.node + /\ UpdateTasks(t :> t2) + +(* The reaper removes a task. *) +RemoveTask == + /\ UNCHANGED << containers, nEvents, nodes >> + /\ \E t \in tasks : + /\ << State(t), null >> \in Transitions.reaper + /\ tasks' = tasks \ {t} + +(* Actions of our worker's environment (i.e. SwarmKit and other workers). *) +OtherComponent == + \/ CreateTask + \/ UpdateTask + \/ RemoveTask + +------------------------------------------------------------------------------- +\* A complete system + +vars == << tasks, nEvents, nodes, containers >> + +Init == + /\ tasks = {} + /\ containers = << >> + /\ nodes = [ n \in Node |-> WS!nodeUp ] + /\ InitEvents + +Next == + \/ OtherComponent + \/ Agent + +(* The specification for our worker node. *) +Impl == Init /\ [][Next]_vars /\ WF_vars(AgentProgress) + +------------------------------------------------------------------------------- + +TypeOK == + /\ TasksTypeOK + \* The node's container map maps IDs to states + /\ DOMAIN containers \in SUBSET ModelTaskId + /\ containers \in [ DOMAIN containers -> ContainerState ] + +wsVars == << tasks, nEvents, nodes >> + +(* We want to check that a worker implementing `Impl' is also implementing + `WorkerSpec'. i.e. we need to check that Impl => WSSpec. *) +WSSpec == + /\ [][WS!Agent \/ OtherComponent]_wsVars + /\ WF_wsVars(WS!AgentProgress) + +============================================================================= diff --git a/general/performance/SwarmKit/WorkerSpec.tla b/general/performance/SwarmKit/WorkerSpec.tla new file mode 100644 index 0000000000000000000000000000000000000000..e56b8009b3fbfca9ef251a941f65c9a9f7a80322 --- /dev/null +++ b/general/performance/SwarmKit/WorkerSpec.tla @@ -0,0 +1,133 @@ +----------------------------- MODULE WorkerSpec ----------------------------- + +EXTENDS Types, Tasks, EventCounter + +VARIABLE nodes \* Maps nodes to SwarmKit's view of their NodeState + +(* The possible states of a node, as recorded by SwarmKit. *) +nodeUp == "up" +nodeDown == "down" +NodeState == { nodeUp, nodeDown } + +WorkerTypeOK == + \* Nodes are up or down + /\ nodes \in [ Node -> NodeState ] + +----------------------------------------------------------------------------- + +\* Actions performed by worker nodes (actually, by the dispatcher on their behalf) + +(* SwarmKit thinks the node is up. i.e. the agent is connected to a manager. *) +IsUp(n) == nodes[n] = nodeUp + +(* Try to advance containers towards `desired_state' if we're not there yet. *) +ProgressTask == + /\ UNCHANGED << nodes, nEvents >> + /\ \E t \in tasks, + s2 \in TaskState : \* The state we want to move to + LET t2 == [t EXCEPT !.status.state = s2] + IN + /\ s2 \preceq t.desired_state \* Can't be after the desired state + /\ << State(t), State(t2) >> \in { \* Possible ``progress'' (desirable) transitions + << assigned, accepted >>, + << accepted, preparing >>, + << preparing, ready >>, + << ready, starting >>, + << starting, running >> + } + /\ IsUp(t.node) \* Node must be connected to SwarmKit + /\ UpdateTasks(t :> t2) + +(* A running container finishes because we stopped it. *) +ShutdownComplete == + /\ UNCHANGED << nodes, nEvents >> + /\ \E t \in tasks : + /\ t.desired_state \in {shutdown, remove} \* We are trying to stop it + /\ State(t) = running \* It is currently running + /\ IsUp(t.node) + /\ UpdateTasks(t :> [t EXCEPT !.status.state = shutdown]) \* It becomes shutdown + +(* A node can reject a task once it's responsible for it (it has reached `assigned') + until it reaches the `running' state. + Note that an ``accepted'' task can still be rejected. *) +RejectTask == + /\ UNCHANGED << nodes >> + /\ CountEvent + /\ \E t \in tasks : + /\ State(t) \in { assigned, accepted, preparing, ready, starting } + /\ IsUp(t.node) + /\ UpdateTasks(t :> [t EXCEPT !.status.state = rejected]) + +(* We notify the managers that some running containers have finished. + There might be several updates at once (e.g. if we're reconnecting). *) +ContainerExit == + /\ UNCHANGED << nodes >> + /\ CountEvent + /\ \E n \in Node : + /\ IsUp(n) + /\ \E ts \in SUBSET { t \in tasks : t.node = n /\ State(t) = running } : + \* Each container could have ended in either state: + \E s2 \in [ ts -> { failed, complete } ] : + UpdateTasks( [ t \in ts |-> + [t EXCEPT !.status.state = + \* Report `failed' as `shutdown' if we wanted to shut down + IF s2[t] = failed /\ t.desired_state = shutdown THEN shutdown + ELSE s2[t]] + ] ) + +(* Tasks assigned to a node and for which the node is responsible. *) +TasksOwnedByNode(n) == { t \in tasks : + /\ t.node = n + /\ assigned \preceq State(t) + /\ State(t) \prec remove +} + +(* The dispatcher notices that the worker is down (the connection is lost). *) +WorkerDown == + /\ UNCHANGED << tasks >> + /\ CountEvent + /\ \E n \in Node : + /\ IsUp(n) + /\ nodes' = [nodes EXCEPT ![n] = nodeDown] + +(* When the node reconnects to the cluster, it gets an assignment set from the dispatcher + which does not include any tasks that have been marked orphaned and then deleted. + Any time an agent gets an assignment set that does not include some task it has running, + it shuts down those tasks. *) +WorkerUp == + /\ UNCHANGED << tasks, nEvents >> + /\ \E n \in Node : + /\ ~IsUp(n) + /\ nodes' = [nodes EXCEPT ![n] = nodeUp] + +(* If SwarmKit sees a node as down for a long time (48 hours or so) then + it marks all the node's tasks as orphaned. + + ``Moving a task to the Orphaned state is not desirable, + because it's the one case where we break the otherwise invariant + that the agent sets all states past ASSIGNED.'' +*) +OrphanTasks == + /\ UNCHANGED << nodes, nEvents >> + /\ \E n \in Node : + LET affected == { t \in TasksOwnedByNode(n) : Runnable(t) } + IN + /\ ~IsUp(n) \* Node `n' is still detected as down + /\ UpdateTasks([ t \in affected |-> + [t EXCEPT !.status.state = orphaned] ]) + +(* Actions we require to happen eventually when possible. *) +AgentProgress == + \/ ProgressTask + \/ ShutdownComplete + \/ OrphanTasks + \/ WorkerUp + +(* All actions of the agent/worker. *) +Agent == + \/ AgentProgress + \/ RejectTask + \/ ContainerExit + \/ WorkerDown + +============================================================================= diff --git a/org.lamport.tla.toolbox.editor.basic/.classpath b/org.lamport.tla.toolbox.editor.basic/.classpath index 64c5e31b7a264082f4c1dfdabb8097de820e66ce..eca7bdba8f03f22510b7980a94dbfe10c16c0901 100644 --- a/org.lamport.tla.toolbox.editor.basic/.classpath +++ b/org.lamport.tla.toolbox.editor.basic/.classpath @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <classpath> - <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/> + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/> <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/> <classpathentry kind="src" path="src"/> <classpathentry kind="output" path="bin"/> diff --git a/org.lamport.tla.toolbox.editor.basic/.settings/org.eclipse.jdt.core.prefs b/org.lamport.tla.toolbox.editor.basic/.settings/org.eclipse.jdt.core.prefs index 57cc0af172cd6eba242c7ffe3fe185354d6dbba3..0c68a61dca867ceb49e79d2402935261ec3e3809 100644 --- a/org.lamport.tla.toolbox.editor.basic/.settings/org.eclipse.jdt.core.prefs +++ b/org.lamport.tla.toolbox.editor.basic/.settings/org.eclipse.jdt.core.prefs @@ -1,8 +1,7 @@ -#Mon May 09 12:19:15 CEST 2011 eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 -org.eclipse.jdt.core.compiler.compliance=1.5 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.compliance=1.8 org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -org.eclipse.jdt.core.compiler.source=1.5 +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/org.lamport.tla.toolbox.editor.basic/META-INF/MANIFEST.MF b/org.lamport.tla.toolbox.editor.basic/META-INF/MANIFEST.MF index 59ba740b364815ba7c7d69c62d02b1a8c67e448a..7a7b1296b4369582b97ee1c1e728b391a83cb532 100644 --- a/org.lamport.tla.toolbox.editor.basic/META-INF/MANIFEST.MF +++ b/org.lamport.tla.toolbox.editor.basic/META-INF/MANIFEST.MF @@ -14,10 +14,15 @@ Require-Bundle: org.eclipse.ui, org.eclipse.core.resources, org.eclipse.ui.workbench.texteditor, org.eclipse.ui.views, - org.eclipse.ui.forms -Bundle-RequiredExecutionEnvironment: J2SE-1.5 + org.eclipse.ui.forms, + org.eclipse.core.filesystem +Bundle-RequiredExecutionEnvironment: JavaSE-1.8 Bundle-ActivationPolicy: lazy -Import-Package: org.eclipse.e4.core.services.events, - org.eclipse.ui.forms +Import-Package: org.eclipse.e4.core.di.annotations;version="1.6.0", + org.eclipse.e4.core.services.events, + org.eclipse.ui.forms, + org.osgi.service.event;version="1.3.1" Export-Package: org.lamport.tla.toolbox.editor.basic, + org.lamport.tla.toolbox.editor.basic.handlers;x-friends:="org.lamport.tla.toolbox", + org.lamport.tla.toolbox.editor.basic.tla, org.lamport.tla.toolbox.editor.basic.util diff --git a/org.lamport.tla.toolbox.editor.basic/plugin.xml b/org.lamport.tla.toolbox.editor.basic/plugin.xml index 325e83d46edca84ad547cc349dda249d7e19770c..9ddc50fef808c322c7b7bcc07f9c68d0bf6589ca 100644 --- a/org.lamport.tla.toolbox.editor.basic/plugin.xml +++ b/org.lamport.tla.toolbox.editor.basic/plugin.xml @@ -307,6 +307,24 @@ id="org.lamport.tla.toolbox.editor.basic.DecomposeProof" name="Decompose Proof"> </command> + <command + categoryId="org.eclipse.ui.category.textEditor" + defaultHandler="org.lamport.tla.toolbox.util.e4.E4HandlerWrapper:org.lamport.tla.toolbox.editor.basic.handlers.PCalTranslateAutomaticallyHandler" + description="Automatically translate PlusCal to TLA+ on TLA+ editor save." + id="toolbox.command.module.translate.automatially" + name="Translate PlusCal automatically"> + <state + class="org.eclipse.ui.handlers.RegistryToggleState:false" + id="org.eclipse.ui.commands.toggleState"> + </state> + </command> + <command + categoryId="toolbox.command.category.module" + defaultHandler="org.lamport.tla.toolbox.editor.basic.handlers.PCalTranslateModuleHandler" + description="Translates PCal in the active editor" + id="toolbox.command.module.translate.active" + name="Translate module"> + </command> </extension> <extension @@ -629,6 +647,14 @@ commandId="org.lamport.tla.toolbox.editor.basic.gotoMatchingParen" style="push"> </command> + <separator + name="org.lamport.tla.toolbox.editor.basic.commentseparator" + visible="true"> + </separator> + <command + commandId="toolbox.command.module.translate.automatially" + style="toggle"> + </command> </menuContribution> </extension> diff --git a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/TLADocumentSetupParticipant.java b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/TLADocumentSetupParticipant.java index e3ac3c80c2c0ada4d1086ef24ca5c4e28cee558d..c625feb0bb33083118813fc2431a832a08962d04 100644 --- a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/TLADocumentSetupParticipant.java +++ b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/TLADocumentSetupParticipant.java @@ -4,7 +4,6 @@ import org.eclipse.core.filebuffers.IDocumentSetupParticipant; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IDocumentExtension3; import org.eclipse.jface.text.IDocumentPartitioner; -import org.eclipse.jface.text.rules.FastPartitioner; /** * Responsible for document setup diff --git a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/TLAEditor.java b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/TLAEditor.java index 5cb02aee43ce8df59e8e24b6c51826de767469a7..36e1abb01464f4b8a80be36974a4999c1a168aaf 100644 --- a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/TLAEditor.java +++ b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/TLAEditor.java @@ -37,6 +37,7 @@ import org.eclipse.jface.action.Separator; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.FindReplaceDocumentAdapter; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.ITextSelection; @@ -80,6 +81,7 @@ import org.eclipse.ui.texteditor.ITextEditorActionConstants; import org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds; import org.eclipse.ui.texteditor.TextOperationAction; import org.lamport.tla.toolbox.editor.basic.actions.ToggleCommentAction; +import org.lamport.tla.toolbox.editor.basic.pcal.IPCalReservedWords; import org.lamport.tla.toolbox.editor.basic.proof.IProofFoldCommandIds; import org.lamport.tla.toolbox.editor.basic.proof.TLAProofFoldingStructureProvider; import org.lamport.tla.toolbox.editor.basic.proof.TLAProofPosition; @@ -99,7 +101,6 @@ import pcal.TLAtoPCalMapping; * Basic editor for TLA+ * * @author Simon Zambrovski - * @version $Id$ */ public class TLAEditor extends TextEditor { @@ -108,6 +109,11 @@ public class TLAEditor extends TextEditor * saved. */ public static final String SAVE_EVENT = "TLAEditor/save"; + /** + * The IEventBroker topic identifying the event sent out while the editor is + * being saved. + */ + public static final String PRE_SAVE_EVENT = "TLAEditor/presave"; public static final String ID = "org.lamport.tla.toolbox.editor.basic.TLAEditor"; private IContextService contextService = null; @@ -445,6 +451,8 @@ public class TLAEditor extends TextEditor */ public void doSave(IProgressMonitor progressMonitor) { + service.send(PRE_SAVE_EVENT, this); + final IEditorInput editorInput = this.getEditorInput(); IDocument doc = this.getDocumentProvider().getDocument(editorInput); String text = doc.get(); @@ -545,6 +553,7 @@ public class TLAEditor extends TextEditor } // end if (historyStart > -1) + super.doSave(progressMonitor); // Send out a save event through the event bus. There might be parties // interested in this, e.g. to regenerate the pretty printed pdf. @@ -554,8 +563,6 @@ public class TLAEditor extends TextEditor final IFile spec = fei.getFile(); service.post(SAVE_EVENT, spec); } - - super.doSave(progressMonitor); } /** @@ -742,7 +749,8 @@ public class TLAEditor extends TextEditor } } - public Object getAdapter(@SuppressWarnings("rawtypes") Class required) + @SuppressWarnings("unchecked") + public Object getAdapter(@SuppressWarnings("rawtypes") Class required) { /* adapt to projection support */ if (projectionSupport != null) @@ -902,6 +910,25 @@ public class TLAEditor extends TextEditor return this.getSourceViewer(); } + + public boolean hasPlusCal() { + try { + // Search the document for the string "--algorithm" or "--fair". + final IDocument doc = this.getDocumentProvider().getDocument(this.getEditorInput()); + final FindReplaceDocumentAdapter search = new FindReplaceDocumentAdapter(doc); + IRegion find = search.find(0, IPCalReservedWords.ALGORITHM, true, true, false, false); + if (find != null) { + return true; + } + find = search.find(0, "--" + IPCalReservedWords.FAIR, true, true, false, false); + if (find != null) { + return true; + } + } catch (BadLocationException e) { + } + return false; + } + /** * Simon's comments, explaining exactly what this class is doing: * The class is located here, because editor does not expose the source viewer (method protected) diff --git a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/TLAReconcilingStrategy.java b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/TLAReconcilingStrategy.java index c23bb9f0be814a1bde383631f2fc5e6f13f974a3..bfdae3df3fecfd3aa57c6fe8e756a7f220e99e6e 100644 --- a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/TLAReconcilingStrategy.java +++ b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/TLAReconcilingStrategy.java @@ -65,13 +65,14 @@ public class TLAReconcilingStrategy implements IReconcilingStrategy, IReconcilin calculatePositions(); // update the editor - Display.getDefault().asyncExec(new Runnable() { - public void run() - { - editor.updateFoldingStructure(positions); - } - }); - + if (editor != null) { + Display.getDefault().asyncExec(new Runnable() { + public void run() + { + editor.updateFoldingStructure(positions); + } + }); + } } /* (non-Javadoc) diff --git a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/TLASourceViewerConfiguration.java b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/TLASourceViewerConfiguration.java index 492b251086647b0527e95049ff629101357aa727..00b75ee62929785a81cca345c0b6aba3b2928e53 100644 --- a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/TLASourceViewerConfiguration.java +++ b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/TLASourceViewerConfiguration.java @@ -1,9 +1,18 @@ package org.lamport.tla.toolbox.editor.basic; +import java.lang.reflect.Field; + import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.jface.resource.JFaceResources; +import org.eclipse.jface.text.DefaultInformationControl; import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.IInformationControl; +import org.eclipse.jface.text.IInformationControlCreator; +import org.eclipse.jface.text.ITextHover; import org.eclipse.jface.text.TextAttribute; import org.eclipse.jface.text.contentassist.ContentAssistant; +import org.eclipse.jface.text.contentassist.ICompletionProposal; +import org.eclipse.jface.text.contentassist.ICompletionProposalSorter; import org.eclipse.jface.text.contentassist.IContentAssistant; import org.eclipse.jface.text.presentation.IPresentationReconciler; import org.eclipse.jface.text.presentation.PresentationReconciler; @@ -14,20 +23,29 @@ import org.eclipse.jface.text.rules.DefaultDamagerRepairer; import org.eclipse.jface.text.rules.Token; import org.eclipse.jface.text.source.IAnnotationHover; import org.eclipse.jface.text.source.ISourceViewer; +import org.eclipse.swt.custom.StyledText; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.editors.text.TextSourceViewerConfiguration; +import org.lamport.tla.toolbox.editor.basic.pcal.PCalCompletionProcessor; +import org.lamport.tla.toolbox.editor.basic.pcal.PCalHover; import org.lamport.tla.toolbox.editor.basic.tla.TLAAnnotationHover; import org.lamport.tla.toolbox.editor.basic.tla.TLACompletionProcessor; /** * Configuration of the source viewer for TLA+ editor * @author Simon Zambrovski - * @version $Id$ */ public class TLASourceViewerConfiguration extends TextSourceViewerConfiguration { private final TLAEditor editor; + public TLASourceViewerConfiguration() { + super(); + this.editor = null; + } + /** * Constructs configuration based on a preference store * @param preferenceStore @@ -108,12 +126,23 @@ public class TLASourceViewerConfiguration extends TextSourceViewerConfiguration */ public IContentAssistant getContentAssistant(ISourceViewer sourceViewer) { - ContentAssistant assistant = new ContentAssistant(); assistant.setDocumentPartitioning(getConfiguredDocumentPartitioning(sourceViewer)); assistant.setContentAssistProcessor(new TLACompletionProcessor(), IDocument.DEFAULT_CONTENT_TYPE); + assistant.setContentAssistProcessor(new PCalCompletionProcessor(), TLAPartitionScanner.TLA_PCAL); + assistant.enableColoredLabels(true); assistant.enableAutoActivation(true); assistant.setAutoActivationDelay(500); + assistant.setInformationControlCreator(new IInformationControlCreator() { + public IInformationControl createInformationControl(final Shell parent) { + return new DefaultInformationControl(parent, (DefaultInformationControl.IInformationPresenter) null); + } + }); + assistant.setSorter(new ICompletionProposalSorter() { + public int compare(ICompletionProposal p1, ICompletionProposal p2) { + return 0; + } + }); assistant.setProposalPopupOrientation(IContentAssistant.PROPOSAL_OVERLAY); assistant.setContextInformationPopupOrientation(IContentAssistant.CONTEXT_INFO_ABOVE); assistant.setContextInformationPopupBackground(TLAEditorActivator.getDefault().getTLAColorProvider().getColor( @@ -121,6 +150,30 @@ public class TLASourceViewerConfiguration extends TextSourceViewerConfiguration return assistant; } + /* (non-Javadoc) + * @see org.eclipse.ui.editors.text.TextSourceViewerConfiguration#getTextHover(org.eclipse.jface.text.source.ISourceViewer, java.lang.String) + */ + @Override + public ITextHover getTextHover(ISourceViewer sourceViewer, String contentType) { + if (TLAPartitionScanner.TLA_PCAL.equals(contentType)) { + return new PCalHover(); + } + return new ToolboxHover(); + } + + /* (non-Javadoc) + * @see org.eclipse.jface.text.source.SourceViewerConfiguration#getInformationControlCreator(org.eclipse.jface.text.source.ISourceViewer) + */ + @Override + public IInformationControlCreator getInformationControlCreator(ISourceViewer sourceViewer) { + // We want the hover popup to use a monospaced font. + return new IInformationControlCreator() { + public IInformationControl createInformationControl(final Shell parent) { + return new MonospacedDefaultInformationControl(parent); + } + }; + } + /** * Ruler annotation */ @@ -156,4 +209,25 @@ public class TLASourceViewerConfiguration extends TextSourceViewerConfiguration return new String[] { "\\*", "" }; } + public static class MonospacedDefaultInformationControl extends DefaultInformationControl { + public MonospacedDefaultInformationControl(final Shell parent) { + super(parent, (DefaultInformationControl.IInformationPresenter) null); + } + + @Override + protected void createContent(Composite parent) { + super.createContent(parent); + try { + final Field f = DefaultInformationControl.class.getDeclaredField("fText"); + f.setAccessible(true); + final StyledText fText = (StyledText) f.get(this); // IllegalAccessException + + fText.setFont(JFaceResources.getFont(JFaceResources.TEXT_FONT)); + } catch (NoSuchFieldException e) { + } catch (SecurityException e) { + } catch (IllegalArgumentException e) { + } catch (IllegalAccessException e) { + } + } + } } diff --git a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/ToolboxCompletionProcessor.java b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/ToolboxCompletionProcessor.java new file mode 100644 index 0000000000000000000000000000000000000000..6ab17df5a4571d469e91c7596b7d1abda784ebba --- /dev/null +++ b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/ToolboxCompletionProcessor.java @@ -0,0 +1,360 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package org.lamport.tla.toolbox.editor.basic; + +import java.nio.CharBuffer; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.SortedMap; +import java.util.TreeMap; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.IRegion; +import org.eclipse.jface.text.ITextViewer; +import org.eclipse.jface.text.contentassist.BoldStylerProvider; +import org.eclipse.jface.text.contentassist.ContextInformation; +import org.eclipse.jface.text.contentassist.ICompletionProposal; +import org.eclipse.jface.text.contentassist.ICompletionProposalExtension5; +import org.eclipse.jface.text.contentassist.ICompletionProposalExtension7; +import org.eclipse.jface.text.contentassist.IContextInformation; +import org.eclipse.jface.text.contentassist.IContextInformationValidator; +import org.eclipse.jface.viewers.StyledString; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.Point; +import org.lamport.tla.toolbox.editor.basic.tla.ITLAReserveredWords; +import org.lamport.tla.toolbox.editor.basic.util.DocumentHelper; +import org.lamport.tla.toolbox.tool.ToolboxHandle; + +import tla2sany.modanalyzer.SpecObj; +import tla2sany.semantic.ModuleNode; +import tla2sany.semantic.SymbolMatcher; +import tla2sany.semantic.SymbolNode; +import util.UniqueString; + +public abstract class ToolboxCompletionProcessor { + + protected final SortedMap<String, List<CompletionProposalTemplate>> proposals = new TreeMap<String, List<CompletionProposalTemplate>>(); + + protected final SymbolMatcher.NameAndTypeMatcher matcher = new SymbolMatcher.NameAndTypeMatcher(); + + public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int offset) { + final IDocument document = viewer.getDocument(); + // get the selection range + final Point selectedRange = viewer.getSelectedRange(); + + final List<ICompletionProposal> propList = new ArrayList<ICompletionProposal>(); + try { + // The zero-based row index of the caret. + final int caretRowIndex = document.getLineOfOffset(offset); + // The zero-based column index of the caret. + final int carretColumnIndex = offset - document.getLineOffset(caretRowIndex); + if (selectedRange.y > 0) { + // the range is non-empty + final String text = document.get(selectedRange.x, selectedRange.y); + computeWordProposals(text, offset, carretColumnIndex, propList); + } else { + // the range is empty, no selection in the editor + + // get the region + final IRegion wordRegion = DocumentHelper.getRegionExpandedBackwards(document, offset, + DocumentHelper.getDefaultWordDetector()); + final String word = document.get(wordRegion.getOffset(), wordRegion.getLength()); + computeWordProposals(word, offset, carretColumnIndex, propList); + } + } catch (final BadLocationException ignore) { + } + return propList.toArray(new ICompletionProposal[propList.size()]); + } + + /** + * Syntax-based proposal based for word beginning + */ + private void computeWordProposals(final String word, final int offset, final int carretColumnIndex, final List<ICompletionProposal> propositionList) { + final int qualifierLength = word.length(); + final int replacementOffset = offset - qualifierLength; + + // keyword and other static proposals + for (List<CompletionProposalTemplate> list : filterPrefix(proposals, word).values()) { + // and add to result list + for (CompletionProposalTemplate template : list) { + propositionList.add(template.getProposal(replacementOffset, carretColumnIndex - qualifierLength, qualifierLength)); + } + } + + // Try to find matches among the spec's set of symbols (e.g. operators definitions and declarations). + final SpecObj specObj = ToolboxHandle.getSpecObj(); + if (specObj != null && specObj.getRootModule() != null) { // null if spec hasn't been parsed. + final ModuleNode rootModule = specObj.getRootModule(); + + final Collection<SymbolNode> symbols = rootModule.getSymbols(matcher.setPrefix(word)); + for (final SymbolNode symbolNode : symbols) { + propositionList.add(new CompletionProposalTemplate(symbolNode.getSignature(), symbolNode.getName(), + symbolNode.getHumanReadableImage()).getProposal(replacementOffset, carretColumnIndex - qualifierLength, qualifierLength)); + } + } + } + + public static SortedMap<String, List<CompletionProposalTemplate>> filterPrefix(SortedMap<String, List<CompletionProposalTemplate>> baseMap, String prefix) { + if (prefix.length() > 0) { + final char nextLetter = (char) (prefix.charAt(prefix.length() - 1) + 1); + final String end = prefix.substring(0, prefix.length() - 1) + nextLetter; + return baseMap.subMap(prefix, end); + } + return baseMap; + } + + public IContextInformation[] computeContextInformation(ITextViewer viewer, int offset) { + // Retrieve selected range + final Point selectedRange = viewer.getSelectedRange(); + if (selectedRange.y > 0) { + // Text is selected. Create a context information array. + final IContextInformation[] contextInfos = new ContextInformation[ITLAReserveredWords.ALL_WORDS_ARRAY.length]; + + // Create one context information item for each style + for (int i = 0; i < ITLAReserveredWords.ALL_WORDS_ARRAY.length; i++) { + contextInfos[i] = new ContextInformation(null, ITLAReserveredWords.ALL_WORDS_ARRAY[i] + " Style"); + } + return contextInfos; + } + return new ContextInformation[0]; + } + + /* (non-Javadoc) + * @see org.eclipse.jface.text.contentassist.IContentAssistProcessor#getCompletionProposalAutoActivationCharacters() + */ + public char[] getCompletionProposalAutoActivationCharacters() { + return null; + } + + /* (non-Javadoc) + * @see org.eclipse.jface.text.contentassist.IContentAssistProcessor#getContextInformationAutoActivationCharacters() + */ + public char[] getContextInformationAutoActivationCharacters() { + return null; + } + + /* (non-Javadoc) + * @see org.eclipse.jface.text.contentassist.IContentAssistProcessor#getContextInformationValidator() + */ + public IContextInformationValidator getContextInformationValidator() { + return null; + } + + /* (non-Javadoc) + * @see org.eclipse.jface.text.contentassist.IContentAssistProcessor#getErrorMessage() + */ + public String getErrorMessage() { + return null; + } + + protected static class CompletionProposalTemplate { + private final String fReplacementString; + private final Image fImage; + private final IContextInformation fContextInformation; + private final String fAdditionalProposalInfo; + private final String fDisplayString; + + public CompletionProposalTemplate(String replacementString, Image image, String dipslayString, + IContextInformation contextInformation, String additionalProposalInfo) { + this.fReplacementString = replacementString; + this.fImage = image; + this.fDisplayString = dipslayString; + this.fContextInformation = contextInformation; + this.fAdditionalProposalInfo = additionalProposalInfo; + } + + public CompletionProposalTemplate(String replacementString, Image image, String dipslayString, + String additionalProposalInfo) { + this.fReplacementString = replacementString; + this.fImage = image; + this.fDisplayString = dipslayString; + this.fContextInformation = null; + this.fAdditionalProposalInfo = additionalProposalInfo; + } + + public CompletionProposalTemplate(UniqueString replacementString, UniqueString dipslayString, + String additionalProposalInfo) { + this(replacementString.toString(), dipslayString.toString(), additionalProposalInfo); + } + + public CompletionProposalTemplate(String replacementString, UniqueString dipslayString, + String additionalProposalInfo) { + this(replacementString, dipslayString.toString(), additionalProposalInfo); + } + + public CompletionProposalTemplate(String replacementString, String dipslayString, + String additionalProposalInfo) { + this.fReplacementString = replacementString; + this.fImage = null; + this.fDisplayString = dipslayString; + this.fContextInformation = null; + this.fAdditionalProposalInfo = additionalProposalInfo; + } + + public CompletionProposalTemplate(String replacementString) { + this.fReplacementString = replacementString; + this.fImage = null; // Image for keywords?! + this.fContextInformation = null; + this.fAdditionalProposalInfo = null; + this.fDisplayString = null; + } + + public ICompletionProposal getProposal(final int replacementOffset, final int wordStartColumnIndex, final int qualifierLength) { + final String indent = CharBuffer.allocate(wordStartColumnIndex).toString().replace( '\0', ' ' ); + final String indentedReplacementString = fReplacementString.replace("\n", "\n" + indent); + return new ToolboxCompletionProposal(indentedReplacementString, replacementOffset, qualifierLength, + indentedReplacementString.length(), fImage, fDisplayString, fContextInformation, + fAdditionalProposalInfo); + } + } + + public static class ToolboxCompletionProposal implements ICompletionProposal, ICompletionProposalExtension5, ICompletionProposalExtension7 { + + /** The string to be displayed in the completion proposal popup. */ + private String fDisplayString; + /** The replacement string. */ + private String fReplacementString; + /** The replacement offset. */ + private int fReplacementOffset; + /** The replacement length. */ + private int fReplacementLength; + /** The cursor position after this proposal has been applied. */ + private int fCursorPosition; + /** The image to be displayed in the completion proposal popup. */ + private Image fImage; + /** The context information of this proposal. */ + private IContextInformation fContextInformation; + /** The additional info of this proposal. */ + private String fAdditionalProposalInfo; + + /** + * Creates a new completion proposal based on the provided information. The + * replacement string is considered being the display string too. All remaining + * fields are set to <code>null</code>. + * + * @param replacementString + * the actual string to be inserted into the document + * @param replacementOffset + * the offset of the text to be replaced + * @param replacementLength + * the length of the text to be replaced + * @param cursorPosition + * the position of the cursor following the insert relative to + * replacementOffset + */ + public ToolboxCompletionProposal(String replacementString, int replacementOffset, int replacementLength, + int cursorPosition) { + this(replacementString, replacementOffset, replacementLength, cursorPosition, null, null, null, null); + } + + /** + * Creates a new completion proposal. All fields are initialized based on the + * provided information. + * + * @param replacementString + * the actual string to be inserted into the document + * @param replacementOffset + * the offset of the text to be replaced + * @param replacementLength + * the length of the text to be replaced + * @param cursorPosition + * the position of the cursor following the insert relative to + * replacementOffset + * @param image + * the image to display for this proposal + * @param displayString + * the string to be displayed for the proposal + * @param contextInformation + * the context information associated with this proposal + * @param additionalProposalInfo + * the additional information associated with this proposal + */ + public ToolboxCompletionProposal(String replacementString, int replacementOffset, int replacementLength, + int cursorPosition, Image image, String displayString, IContextInformation contextInformation, + String additionalProposalInfo) { + Assert.isNotNull(replacementString); + Assert.isTrue(replacementOffset >= 0); + Assert.isTrue(replacementLength >= 0); + Assert.isTrue(cursorPosition >= 0); + + fReplacementString = replacementString; + fReplacementOffset = replacementOffset; + fReplacementLength = replacementLength; + fCursorPosition = cursorPosition; + fImage = image; + fDisplayString = displayString; + fContextInformation = contextInformation; + fAdditionalProposalInfo = additionalProposalInfo; + } + + public void apply(IDocument document) { + try { + document.replace(fReplacementOffset, fReplacementLength, fReplacementString); + } catch (BadLocationException x) { + // ignore + } + } + + public Point getSelection(IDocument document) { + return new Point(fReplacementOffset + fCursorPosition, 0); + } + + public IContextInformation getContextInformation() { + return fContextInformation; + } + + public Image getImage() { + return fImage; + } + + public String getDisplayString() { + if (fDisplayString != null) + return fDisplayString; + return fReplacementString; + } + + public String getAdditionalProposalInfo() { + return fAdditionalProposalInfo; + } + + public Object getAdditionalProposalInfo(IProgressMonitor monitor) { + return getAdditionalProposalInfo(); + } + + public StyledString getStyledDisplayString(IDocument document, int offset, + BoldStylerProvider boldStylerProvider) { + final StyledString styledString = new StyledString(); + styledString.append(getDisplayString()); + styledString.append(": "); + styledString.append(fReplacementString.replaceAll("\n[ ]*", " "), StyledString.COUNTER_STYLER); + return styledString; + } + } +} diff --git a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/ToolboxHover.java b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/ToolboxHover.java new file mode 100644 index 0000000000000000000000000000000000000000..3082821537850278ddc69b8b3d26cc042be7ed27 --- /dev/null +++ b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/ToolboxHover.java @@ -0,0 +1,87 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package org.lamport.tla.toolbox.editor.basic; + +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.IRegion; +import org.eclipse.jface.text.ITextHover; +import org.eclipse.jface.text.ITextViewer; +import org.eclipse.jface.text.Region; +import org.lamport.tla.toolbox.editor.basic.pcal.PCalWordDetector; +import org.lamport.tla.toolbox.editor.basic.util.DocumentHelper; +import org.lamport.tla.toolbox.editor.basic.util.EditorUtil; +import org.lamport.tla.toolbox.editor.basic.util.DocumentHelper.WordRegion; +import org.lamport.tla.toolbox.tool.ToolboxHandle; + +import tla2sany.modanalyzer.SpecObj; +import tla2sany.semantic.SymbolNode; + +public class ToolboxHover implements ITextHover { + + /* (non-Javadoc) + * @see org.eclipse.jface.text.ITextHover#getHoverInfo(org.eclipse.jface.text.ITextViewer, org.eclipse.jface.text.IRegion) + */ + public String getHoverInfo(ITextViewer textViewer, IRegion hoverRegion) { + // Expand the given region to word (token) and get the token. If it can't get + // the token, no hover help is provided. + final WordRegion wordRegion; + try { + wordRegion = DocumentHelper.getRegionExpandedBoth(textViewer.getDocument(), + hoverRegion.getOffset(), new PCalWordDetector()); + } catch (BadLocationException ignore) { + return null; + } + + final String hoverInfo = getHoverInfo(textViewer.getDocument(), wordRegion); + if (hoverInfo != null) { + return hoverInfo; + } + + // No keywords, lets look for operator definitions. For that, the spec has to be + // in parsed state. + final SpecObj spec = ToolboxHandle.getSpecObj(); + if (spec != null) { // null if spec hasn't been parsed. + final SymbolNode symbol = EditorUtil.lookupSymbol(spec, textViewer.getDocument(), wordRegion); + if (symbol == null) { + return null; + } + return symbol.getHumanReadableImage(); + } + return null; + } + + protected String getHoverInfo(IDocument document, WordRegion wordRegion) { + return null; + } + + /* (non-Javadoc) + * @see org.eclipse.jface.text.ITextHover#getHoverRegion(org.eclipse.jface.text.ITextViewer, int) + */ + public IRegion getHoverRegion(ITextViewer textViewer, int offset) { + return new Region(offset, 0); + } +} diff --git a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/actions/ExampleEditorAction.java b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/actions/ExampleEditorAction.java index 836bc0b89f0727cc4f6cfddb53274fa1da61d486..fed2356892b3f37716f648e36f19325dc33b526c 100644 --- a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/actions/ExampleEditorAction.java +++ b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/actions/ExampleEditorAction.java @@ -67,10 +67,9 @@ public class ExampleEditorAction extends TextEditorAction implements VerifyKeyLi // retrieve the region describing the word containing // the caret - IRegion region = DocumentHelper.getRegionExpandedBoth(document, textSelection.getOffset(), - DocumentHelper.getDefaultWordDetector()); try { + IRegion region = DocumentHelper.getRegionExpandedBoth(document, textSelection.getOffset()); // generate the insertion string String insertionText = " " + document.get(region.getOffset(), region.getLength()); diff --git a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/actions/OpenDeclarationAction.java b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/actions/OpenDeclarationAction.java index 3448f3b48c9b6643b093662dbba7864043f4e6c5..6d43928f89ef5ba597b6237c4c823ff886046940 100644 --- a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/actions/OpenDeclarationAction.java +++ b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/actions/OpenDeclarationAction.java @@ -1,21 +1,13 @@ package org.lamport.tla.toolbox.editor.basic.actions; -import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Status; import org.eclipse.jface.action.Action; import org.eclipse.jface.text.IRegion; -import org.eclipse.jface.text.ITextSelection; import org.eclipse.jface.text.hyperlink.IHyperlink; -import org.eclipse.jface.viewers.ISelection; -import org.eclipse.ui.part.FileEditorInput; +import org.eclipse.ui.IEditorInput; +import org.eclipse.ui.IEditorPart; import org.lamport.tla.toolbox.editor.basic.TLAEditor; -import org.lamport.tla.toolbox.editor.basic.TLAEditorActivator; import org.lamport.tla.toolbox.editor.basic.TLAEditorAndPDFViewer; import org.lamport.tla.toolbox.editor.basic.util.EditorUtil; -import org.lamport.tla.toolbox.spec.Spec; -import org.lamport.tla.toolbox.tool.ToolboxHandle; import org.lamport.tla.toolbox.util.UIHelper; /** @@ -29,58 +21,38 @@ import org.lamport.tla.toolbox.util.UIHelper; * nested class. * * @author Simon Zambrovski - * @version $Id$ */ public class OpenDeclarationAction extends Action implements IHyperlink { - private IResource resource; - private IRegion location; - private String label; + private final IEditorInput editorInput; + private final IRegion location; + private final String label; private final IRegion hyperlinkLocation; + private final String editorId; - /** - * Constructs the action - * @param targetResource resource to link - * @param targetLocation location in the resource - * @param hyperlinkLabel label of the hyperlink - * @param hyperlinkLocation location of the hyperlink - */ - public OpenDeclarationAction(IResource targetResource, IRegion targetLocation, String hyperlinkLabel, + public OpenDeclarationAction(String editorId, IEditorInput editorInput, IRegion targetLocation, String hyperlinkLabel, IRegion hyperlinkLocation) { super(); - this.resource = targetResource; + this.editorId = editorId; + this.editorInput = editorInput; this.location = targetLocation; this.label = hyperlinkLabel; this.hyperlinkLocation = hyperlinkLocation; } - /** - * Action method + /* (non-Javadoc) + * @see org.eclipse.jface.action.Action#run() */ public void run() { - TLAEditorActivator - .getDefault() - .getLog() - .log(new Status(IStatus.INFO, TLAEditorActivator.PLUGIN_ID, - "Opening " + label + "(" + resource.getName() + " at " - + location + ")")); EditorUtil.setReturnFromOpenDecl(); -// // Find current location and store as a property of the spec for the -// // Return from Goto Declaration command. -// TLAEditor srcEditor = EditorUtil.getTLAEditorWithFocus(); -// if (srcEditor != null) -// { -// Spec spec = ToolboxHandle.getCurrentSpec(); -// spec.setOpenDeclModuleName(srcEditor.getEditorInput().getName()); -// spec.setOpenDeclSelection((ITextSelection) srcEditor.getSelectionProvider().getSelection()); -// } - - TLAEditorAndPDFViewer editor = (TLAEditorAndPDFViewer) UIHelper.openEditor(TLAEditorAndPDFViewer.ID, - new FileEditorInput((IFile) resource)); - editor.getTLAEditor().selectAndReveal(location.getOffset(), location.getLength()); - + final IEditorPart editor = UIHelper.openEditor(editorId, editorInput); + if (editor instanceof TLAEditorAndPDFViewer) { + ((TLAEditorAndPDFViewer) editor).getTLAEditor().selectAndReveal(location.getOffset(), location.getLength()); + } else if (editor instanceof TLAEditor) { + ((TLAEditor) editor).selectAndReveal(location.getOffset(), location.getLength()); + } } /* (non-Javadoc) @@ -114,5 +86,4 @@ public class OpenDeclarationAction extends Action implements IHyperlink { run(); } - } diff --git a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/handlers/ExampleEditCommandHandler.java b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/handlers/ExampleEditCommandHandler.java index 0ba1a8bd6bbfa3b5c537c3b828cce8d20d789736..d3383c71bc855c67545326b10bbedf1a26d4ae36 100644 --- a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/handlers/ExampleEditCommandHandler.java +++ b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/handlers/ExampleEditCommandHandler.java @@ -16,7 +16,6 @@ import org.eclipse.swt.events.VerifyEvent; import org.lamport.tla.toolbox.Activator; import org.lamport.tla.toolbox.editor.basic.TLAEditor; import org.lamport.tla.toolbox.editor.basic.util.DocumentHelper; -import org.lamport.tla.toolbox.editor.basic.util.EditorUtil; /** * Performs a useless command to illustrate how to get keyboard input @@ -125,10 +124,9 @@ public class ExampleEditCommandHandler extends AbstractHandler implements Verify // retrieve the region describing the word containing // the caret - IRegion region = DocumentHelper.getRegionExpandedBoth(document, textSelection.getOffset(), - DocumentHelper.getDefaultWordDetector()); try { + IRegion region = DocumentHelper.getRegionExpandedBoth(document, textSelection.getOffset()); // generate the insertion string String insertionText = " " + document.get(region.getOffset(), region.getLength()); @@ -186,7 +184,7 @@ public class ExampleEditCommandHandler extends AbstractHandler implements Verify * This is added as a focus listener so that it can uninstall() * itself if focus is lost. */ - private void install() + public void install() { editor.getViewer().prependVerifyKeyListener(this); editor.getViewer().getTextWidget().addFocusListener(this); diff --git a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/handlers/PCalTranslateAutomaticallyHandler.java b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/handlers/PCalTranslateAutomaticallyHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..6163864d52ae9f2b2657adaa2ffb69e8b6730265 --- /dev/null +++ b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/handlers/PCalTranslateAutomaticallyHandler.java @@ -0,0 +1,98 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package org.lamport.tla.toolbox.editor.basic.handlers; + +import java.lang.reflect.InvocationTargetException; + +import javax.inject.Inject; + +import org.eclipse.core.commands.Command; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.core.commands.State; +import org.eclipse.core.runtime.Assert; +import org.eclipse.e4.core.di.annotations.Execute; +import org.eclipse.e4.core.services.events.IEventBroker; +import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.commands.ICommandService; +import org.eclipse.ui.handlers.HandlerUtil; +import org.eclipse.ui.handlers.RegistryToggleState; +import org.lamport.tla.toolbox.editor.basic.TLAEditor; +import org.lamport.tla.toolbox.editor.basic.pcal.PCalTranslator; +import org.osgi.service.event.Event; +import org.osgi.service.event.EventHandler; + +public class PCalTranslateAutomaticallyHandler extends PCalTranslator implements EventHandler { + + @Inject + public void initializeAtStartup(final IWorkbench workbench, final ICommandService commandService) { + /* + * Check the UI state of the IHandler/Command which indicates if the user + * enabled automatic PlusCal conversion. + */ + final Command command = commandService.getCommand("toolbox.command.module.translate.automatially"); + final State state = command.getState(RegistryToggleState.STATE_ID); + if (!((Boolean) state.getValue()).booleanValue()) { + return; + } + // This IHander is stateful even across Toolbox restarts. In other words, if the + // user enables automatic PlusCal translation, it will remain enabled even after + // a Toolbox restart. This means we have to register this EventHandler at the + // IEventBroker during Toolbox startup. + // It is vital that we use the Workbench's IEventBroker instance. If e.g. we + // would use an IEventBroker from higher up the IEclipseContext hierarchy, the + // broker would be disposed when a new spec gets opened while the IHandler's state + // remains enabled. + workbench.getService(IEventBroker.class).unsubscribe(this); + Assert.isTrue(workbench.getService(IEventBroker.class).subscribe(TLAEditor.PRE_SAVE_EVENT, this)); + } + + @Execute + public void execute(final ExecutionEvent event, final IWorkbench workbench) throws ExecutionException { + // Toggle the IHandler's state at the UI level (check mark on/off) and + // unsubscribe/subscribe the EventHandler. + final IEventBroker eventBroker = workbench.getService(IEventBroker.class); + if (HandlerUtil.toggleCommandState(event.getCommand())) { + eventBroker.unsubscribe(this); + } else { + eventBroker.unsubscribe(this); + Assert.isTrue(eventBroker.subscribe(TLAEditor.PRE_SAVE_EVENT, this)); + } + } + + /* (non-Javadoc) + * @see org.osgi.service.event.EventHandler#handleEvent(org.osgi.service.event.Event) + */ + @Override + public void handleEvent(final Event event) { + try { + final TLAEditor editor = (TLAEditor) event.getProperty(IEventBroker.DATA); + translate(editor, editor.getSite().getShell(), false); + } catch (InvocationTargetException | InterruptedException e) { + throw new RuntimeException(e); + } + } +} diff --git a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/handlers/PCalTranslateModuleHandler.java b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/handlers/PCalTranslateModuleHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..75d05c5df82b9b1dc3cec0387b34998ec5db9afc --- /dev/null +++ b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/handlers/PCalTranslateModuleHandler.java @@ -0,0 +1,76 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Simon Zambrowski - initial API and implementation + * Markus Alexander Kuppe - Refactoring + ******************************************************************************/ +package org.lamport.tla.toolbox.editor.basic.handlers; + +import java.lang.reflect.InvocationTargetException; + +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.handlers.HandlerUtil; +import org.lamport.tla.toolbox.editor.basic.TLAEditor; +import org.lamport.tla.toolbox.editor.basic.TLAEditorAndPDFViewer; +import org.lamport.tla.toolbox.editor.basic.pcal.PCalTranslator; +import org.lamport.tla.toolbox.ui.handler.SaveDirtyEditorAbstractHandler; + +/** + * Triggers the PCal translation of the module + * + * @author Simon Zambrovski + */ +public class PCalTranslateModuleHandler extends SaveDirtyEditorAbstractHandler { + + public Object execute(final ExecutionEvent event) throws ExecutionException { + if (!saveDirtyEditor(event)) { + // Cannot translate a dirty editor. + return null; + } + final TLAEditor tlaEditor = getTLAEditor(activeEditor); + if (tlaEditor == null || !tlaEditor.hasPlusCal()) { + // If it's not a TLAEditor, it can't have PlusCal code. + return null; + } + + try { + new PCalTranslator().translate(tlaEditor, HandlerUtil.getActiveShell(event)); + } catch (InvocationTargetException | InterruptedException e) { + throw new ExecutionException(e.getMessage(), e); + } + return null; + } + + private static TLAEditor getTLAEditor(IEditorPart anEditor) { + if (anEditor instanceof TLAEditorAndPDFViewer) { + final TLAEditorAndPDFViewer editor = (TLAEditorAndPDFViewer) anEditor; + return editor.getTLAEditor(); + } + if (anEditor instanceof TLAEditor) { + return (TLAEditor) anEditor; + } + return null; + } +} diff --git a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/handlers/ShowDeclarationsHandler.java b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/handlers/ShowDeclarationsHandler.java index 0698c9eac42a449df515200ffb116f18d7c1fcd4..2e5d34062f868adc7f92279158b9d25a7f4450b4 100644 --- a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/handlers/ShowDeclarationsHandler.java +++ b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/handlers/ShowDeclarationsHandler.java @@ -3,8 +3,9 @@ */ package org.lamport.tla.toolbox.editor.basic.handlers; -import java.util.Arrays; -import java.util.Vector; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; import org.eclipse.core.commands.AbstractHandler; import org.eclipse.core.commands.ExecutionEvent; @@ -25,8 +26,13 @@ import org.lamport.tla.toolbox.editor.basic.util.EditorUtil; import org.lamport.tla.toolbox.util.ResourceHelper; import org.lamport.tla.toolbox.util.UIHelper; +import tla2sany.semantic.ASTConstants; +import tla2sany.semantic.AnyDefNode; import tla2sany.semantic.ModuleNode; +import tla2sany.semantic.OpDeclNode; import tla2sany.semantic.OpDefNode; +import tla2sany.semantic.SemanticNode; +import tla2sany.semantic.SymbolMatcher; import tla2sany.semantic.SymbolNode; import tla2sany.semantic.ThmOrAssumpDefNode; @@ -118,6 +124,48 @@ public class ShowDeclarationsHandler extends AbstractHandler implements IHandler // int curSelection; // The currently selected item. + private final SymbolMatcher.NameAndTypeMatcher matcher = new SymbolMatcher.NameAndTypeMatcher() { + + /* (non-Javadoc) + * @see tla2sany.semantic.SymbolMatcher.NameAndTypeMatcher#matchTypes() + */ + @Override + public Set<Class<? extends SymbolNode>> matchTypes() { + final Set<Class<? extends SymbolNode>> set = new HashSet<Class<? extends SymbolNode>>(); + set.add(OpDefNode.class); + set.add(OpDeclNode.class); + set.add(ThmOrAssumpDefNode.class); + return set; + } + + /* (non-Javadoc) + * @see tla2sany.semantic.SymbolMatcher.NameAndTypeMatcher#matches(tla2sany.semantic.SymbolNode) + */ + @Override + public boolean matches(SymbolNode aSymbol) { + if (aSymbol instanceof ThmOrAssumpDefNode || aSymbol instanceof OpDefNode) { + if (aSymbol.getKind() == ASTConstants.ModuleInstanceKind) { + // Do not match INSTANCE symbols, e.g.: "InChan" defined as: + // InChan == INSTANCE Channel WITH ... + return false; + } + if (aSymbol.getKind() == ASTConstants.BuiltInKind) { + // Do not match built-in operators. + return false; + } + if (!ResourceHelper.isFromUserModule((SemanticNode) ((AnyDefNode) aSymbol).getSource())) { + // Do not match symbols of the Standard Modules such as Sequences, FiniteSets... + return false; + } + if (!showAll && (((AnyDefNode) aSymbol).getSource() != aSymbol)) { + // Unless showAll, do not match symbols defined or declared by extended modules. + return false; + } + } + return super.matches(aSymbol); + } + }; + /** * Constructs a new Show Declarations popup with indicated parent and * with showAll determining if instantiated definitions should be shown. @@ -142,8 +190,6 @@ public class ShowDeclarationsHandler extends AbstractHandler implements IHandler { module = ResourceHelper.getModuleNode(editor.getModuleName()); } - System.out.println("Created new popup with showAll = " + showAll); - } /** @@ -173,72 +219,21 @@ public class ShowDeclarationsHandler extends AbstractHandler implements IHandler */ protected void setList() { - // Get the list of SymbolNodes to be displayed. They - // come from the module's constant decls, variable decls, - // opdef nodes, ThmOrAssumpDefNodes. - - String lcFilterPrefix = filterPrefix.toLowerCase(); list.removeAll(); // Get the current module. if (module == null) { return; } - Vector symVec = new Vector(40); - SymbolNode[] syms = module.getConstantDecls(); - for (int i = 0; i < syms.length; i++) - { - if (syms[i].getName().toString().toLowerCase().startsWith(lcFilterPrefix)) - { - symVec.add(syms[i]); - } - } - - syms = module.getVariableDecls(); - for (int i = 0; i < syms.length; i++) - { - if (syms[i].getName().toString().toLowerCase().toLowerCase().startsWith(lcFilterPrefix)) - { - symVec.add(syms[i]); - } - } - - OpDefNode[] symsOpD = module.getOpDefs(); - for (int i = 0; i < symsOpD.length; i++) - { - if (ResourceHelper.isFromUserModule(symsOpD[i].getSource()) - && (showAll || (symsOpD[i].getSource() == symsOpD[i])) - && symsOpD[i].getName().toString().toLowerCase().startsWith(lcFilterPrefix)) - { - symVec.add(symsOpD[i]); - } - } - - ThmOrAssumpDefNode[] symsTAD = module.getThmOrAssDefs(); - for (int i = 0; i < symsTAD.length; i++) - { - if (ResourceHelper.isFromUserModule(symsTAD[i].getSource()) - && (showAll || (symsTAD[i].getSource() == symsTAD[i])) - && symsTAD[i].getName().toString().toLowerCase().startsWith(lcFilterPrefix)) - { - symVec.add(symsTAD[i]); - } - } - - SymbolNode[] symbols = new SymbolNode[symVec.size()]; - - for (int i = 0; i < symbols.length; i++) - { - symbols[i] = (SymbolNode) symVec.get(i); - } - - Arrays.sort(symbols); - - for (int i = 0; i < symbols.length; i++) - { - list.add(symbols[i].getName().toString()); - list.setData(symbols[i].getName().toString(), symbols[i]); - } + + // Get the list of SymbolNodes to be displayed. They + // come from the module's constant decls, variable decls, + // opdef nodes, ThmOrAssumpDefNodes. + final Collection<SymbolNode> symbols = module.getSymbols(matcher.setPrefix(filterPrefix.toLowerCase())); + for (SymbolNode symbolNode : symbols) { + list.add(symbolNode.getName().toString()); + list.setData(symbolNode.getName().toString(), symbolNode); + } } /** diff --git a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/pcal/IPCalReservedWords.java b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/pcal/IPCalReservedWords.java index 7a3fe81853e1a02dd3bc22026914f549a2670859..d54ff40eed61b0df7bc222d232271b01c621f64d 100644 --- a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/pcal/IPCalReservedWords.java +++ b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/pcal/IPCalReservedWords.java @@ -1,41 +1,308 @@ package org.lamport.tla.toolbox.editor.basic.pcal; +import org.lamport.tla.toolbox.editor.basic.tla.ITLAReserveredWords; + /** * @author Simon Zambrovski * @version $Id$ */ -public interface IPCalReservedWords -{ - public final static String ALGORITHM = "--algorithm"; +public interface IPCalReservedWords { + public final static String ALGORITHM = "--algorithm"; + + public final static String ASSERT = "assert"; + public final static String AWAIT = "await"; + public final static String BEGIN = "begin"; + public final static String CALL = "call"; + public final static String DEFINE = ITLAReserveredWords.PDEFINE; + public final static String DO = "do"; + public final static String EITHER = "either"; + public final static String ELSE = "else"; + public final static String ELSEIF = "elseif"; + public final static String END = "end"; + public final static String GOTO = "goto"; + public final static String IF = "if"; + public final static String MACRO = "macro"; + public final static String OR = "or"; + public final static String PRINT = "print"; + public final static String PROCEDURE = "procedure"; + public final static String PROCESS = "process"; + public final static String FAIR = "fair"; + public final static String RETURN = "return"; + public final static String SKIP = "skip"; + public final static String THEN = "then"; + public final static String VARIABLE = "variable"; + public final static String VARIABLES = "variables"; + public final static String WHILE = "while"; + public final static String WITH = "with"; + // public final static String WHEN = ""; - public final static String ASSERT = "assert"; - // public final static String AWAIT = ""; - public final static String BEGIN = "begin"; - public final static String CALL = "call"; - // public final static String DEFINE = "define"; - public final static String DO = "do"; - public final static String EITHER = "either"; - public final static String ELSE = "else"; - public final static String ELSEIF = "elseif"; - public final static String END = "end"; - public final static String GOTO = "goto"; - public final static String IF = "if"; - public final static String MACRO = "macro"; - public final static String OR = "or"; - public final static String PRINT = "print"; - public final static String PROCEDURE = "procedure"; - public final static String PROCESS = "process"; - public final static String FAIR = "fair"; - public final static String RETURN = "return"; - public final static String SKIP = "skip"; - public final static String THEN = "then"; - public final static String VARIABLE = "variable"; - public final static String VARIABLES = "variables"; - public final static String WHILE = "while"; - public final static String WITH = "with"; - // public final static String WHEN = ""; + public final static String[] ALL_WORDS_ARRAY = new String[] { ASSERT, BEGIN, CALL, DO, EITHER, ELSE, ELSEIF, END, + GOTO, IF, MACRO, OR, PRINT, PROCEDURE, PROCESS, FAIR, RETURN, SKIP, THEN, VARIABLE, VARIABLES, WHILE, + WITH }; - public final static String[] ALL_WORDS_ARRAY = new String[] { ASSERT, BEGIN, CALL, DO, EITHER, ELSE, ELSEIF, END, - GOTO, IF, MACRO, OR, PRINT, PROCEDURE, PROCESS, FAIR, RETURN, SKIP, THEN, VARIABLE, VARIABLES, WHILE, WITH }; + // Just the complete PlusCal BNF + public static final String ALGORITHM_HELP = "<Algorithm> ::= [--algorithm | --fair algorithm] <name>\r\n" + + " {<VarDecls>{0,1}\r\n" + " <Definitions>{0,1}\r\n" + " <Macro>*\r\n" + + " <Procedure>*\r\n" + " [<CompoundStmt> | [fair [+]{0,1}]{0,1}<Process>+] }\r\n" + "\r\n" + + "<Definitions> ::= define { <Defs> } [;]{0,1}\r\n" + "\r\n" + + "<Macro> ::= macro<Name> ( [ <Variable>[, <Variable>]* ]{0,1} )\r\n" + " <CompoundStmt> [;]{0,1}\r\n" + + "\r\n" + "<Procedure> ::= procedure<Name> ( [<PVarDecl> [,<PVarDecl>]*]{0,1} )\r\n" + + " <PVarDecls>{0,1}\r\n" + " <CompoundStmt> [;]{0,1}\r\n" + "\r\n" + + "<Process> ::= [fair [+]{0,1}]{0,1} process (<Name> [=|\\in] <Expr> )\r\n" + " <VarDecls>{0,1}\r\n" + + " <CompoundStmt> [;]{0,1}\r\n" + "\r\n" + "<VarDecls> ::= [variable | variables] <VarDecl>+\r\n" + + "<VarDecl> ::=<Variable> [[=|\\in] <Expr>]{0,1} [;|,]\r\n" + "\r\n" + + "<PVarDecls> ::= [variable | variables] [hPVarDecl> [;|,]]+\r\n" + + "<PVarDecl> ::=<Variable> [=<Expr>]{0,1}\r\n" + "\r\n" + + "<CompoundStmt> ::= {<Stmt> [;<Stmt>]* [;]{0,1} }\r\n" + + "<Stmt> ::= [<Label> : [+|-]{0,1}]{0,1} [<UnlabeledStmt> |<CompoundStmt>]\r\n" + + "<UnlabeledStmt> ::=<Assign> |<If> |<While> |<Either> |<With> | <Await> |<Print> |<Assert> |<Skip> |<Return> | <Goto> |<Call> |<MacroCall>\r\n" + + "\r\n" + "<Assign> ::=<LHS> := <Expr> [||<LHS> :=<Expr>]*\r\n" + + "<LHS> ::=<Variable> [[<Expr> [,<Expr>]*] | .<Field>]*\r\n" + "\r\n" + + "<If> ::=>f (<Expr> )<Stmt> [else<Stmt>]{0,1}\r\n" + "\r\n" + "<While> ::= while (<Expr>)<Stmt>\r\n" + + "\r\n" + "<Either> ::= either<Stmt> [or<Stmt>]+\r\n" + "<With> ::= with (<Variable> [=|\\in] <Expr>\r\n" + + " [[; | ,]<Variable> [=|\\in] <Expr>]* [; | ,]{0,1}\r\n" + " )<Stmt>\r\n" + "\r\n" + + "<Await> ::= [await | when]<Expr>\r\n" + "\r\n" + "<Print> ::= print<Expr>\r\n" + "\r\n" + + "<Assert> ::= assert<Expr>\r\n" + "\r\n" + "<Skip> ::= skip\r\n" + "\r\n" + "<Return> ::= return\r\n" + + "\r\n" + "<Goto> ::= goto<Label>\r\n" + "\r\n" + "<Call> ::= call<MacroCall>\r\n" + "\r\n" + + "<MacroCall> ::=<Name> ( [<Expr> [,<Expr>]*]{0,1} )\r\n" + "\r\n" + + "<Variable> ::= A TLA+ identifier that is not a PlusCal reserved word and\r\n" + + "is not pc, stack, or self.\r\n" + "\r\n" + "<Field> ::= A TLA+ record-component label.\r\n" + "\r\n" + + "<Name> ::= A TLA+ identifier that is not a PlusCal reserved word.\r\n" + "\r\n" + + "<Label> ::= A TLA+ identifier that is not a PlusCal reserved word and\r\n" + "is not Done or Error.\r\n" + + "\r\n" + "<Expr> ::= A TLA+ expression not containing a PlusCal reserved word\r\n" + "or symbol.\r\n" + + "\r\n" + "<Defs> ::= A sequence of TLA+ definitions not containing a PlusCal\r\n" + + "reserved word or symbol."; + public static final String ASSIGN_HELP = "<Assign> ::= <LHS> := <Expr> [ || <LHS> := <Expr>]*\r\n" + + "\t<LHS> ::= <Variable> [[ <Expr> [, <Expr>]* ] | . <Field>]*\n\n" + + "An assignment is either an assignment to a variable such as\r\n" + "\ty := A + B\r\n" + + "or else an assignment to a component, such as\r\n" + "\tx.foo[i+1] := y+3\r\n" + + "If the current value of x is a record with a foo component that is a function\r\n" + + "(array), then this assignment sets the component x.foo[i+1] to the current\r\n" + + "value of y+3. The value of this assignment is undefined if the value of x is not\r\n" + + "a record with a foo component, or if x.foo is not a function. Therefore, if\r\n" + + "such an assignment appears in the code, then x will usually be initialized to\r\n" + + "an element of the correct “type”, or to be a member of some set of elements\r\n" + + "of the correct type. For example, the declaration\r\n" + "\tvariable x \\in [bar : BOOLEAN,\r\n" + + "\t\tfoo : [1..N |-> {\"on\", \"off\"}] ] ;\r\n" + + "asserts that initially x is a record with a bar component that is a Boolean\r\n" + + "(equal to TRUE or FALSE) and a foo component that is a function with\r\n" + + "domain 1.. N such that x.foo[i] equals either “on” or “off” for each i in\r\n" + "1.. N.\r\n" + + "An assignment statement consists of one or more assignments, separated\r\n" + + "by “||” tokens, ending with a semicolon. An assignment statement contain-\r\n" + + "ing more than one assignment is called a multiple assignment. A multiple\r\n" + + "assignment is executed by first evaluating the right-hand sides of all its as-\r\n" + + "signments, and then performing those assignments from left to right. For\r\n" + + "example, if i = j = 3, then executing\r\n" + "\tx[i] := 1 || x[j] := 2\r\n" + "sets x[3] to 2.\r\n" + + "Assignments to the same variable cannot be made in two different as-\r\n" + + "signment statements within the same step. In other words, in any control\r\n" + + "path, a label must come between two statements that assign to the same\r\n" + + "variable. However, assignments to components of the same variable may\r\n" + + "appear in a single multiple assignment, as in\r\n" + "\tx.foo[7] := 13 || y := 27 || x.bar := x.foo"; + public static final String MULTI_ASSIGN_HELP = "A multiple\r\n" + + "assignment is executed by first evaluating the right-hand sides of all its as-\r\n" + + "signments, and then performing those assignments from left to right. For\r\n" + + "example, if i = j = 3, then executing\r\n" + "\tx[i] := 1 || x[j] := 2\r\n" + "sets x[3] to 2.\r\n" + + "Assignments to the same variable cannot be made in two different as-\r\n" + + "signment statements within the same step. In other words, in any control\r\n" + + "path, a label must come between two statements that assign to the same\r\n" + + "variable. However, assignments to components of the same variable may\r\n" + + "appear in a single multiple assignment, as in\r\n" + "\tx.foo[7] := 13 || y := 27 || x.bar := x.foo"; + public static final String DEFINE_HELP = "<Definitions> ::= define { <Defs> }[;]{0,1}\n\n" + + "An algorithm’s expressions can use any operators defined in the TLA + mod-\r\n" + + "ule before the “BEGIN TRANSLATION” line. Since the TLA + declaration of\r\n" + + "the algorithm’s variables follows that line, the definitions of those opera-\r\n" + + "tors can’t mention any algorithm variables. The PlusCal define statement\r\n" + + "allows you to write TLA + definitions of operators that depend on the algo-\r\n" + + "rithm’s global variables. For example, suppose the algorithm begins:\r\n" + "\t--algorithm Test {\r\n" + + "\tvariables x \\in 1..N ; y ;\r\n" + "\tdefine { zy == y*(x+y)\r\n" + "\t\tzx(a) == x*(y-a) }\r\n" + + "\t...\r\n" + "The operators zy and zx can then be\r\n" + + "used in expressions anywhere in the remainder of the algorithm. Observe\r\n" + + "that there is no semicolon or other separator between the two definitions.\r\n" + + "Section 5.11 on page 55 describes how to write TLA + definitions.\r\n" + + "The variables that may appear within the define statement are the ones\r\n" + + "declared in the variable statement that immediately precedes it and that\r\n" + + "follows the algorithm name, as well as the variable pc and, if there is a pro-\r\n" + + "cedure, the variable stack . Local process and procedure variables may not\r\n" + + "appear in the define statement. The define statement’s definitions need\r\n" + + "not mention the algorithm’s variables. You might prefer to put definitions\r\n" + + "in the define statement even when they don’t have to go there. However,\r\n" + + "remember that the define statement cannot mention any symbols defined\r\n" + + "or declared after the “END TRANSLATION” line; and the symbols it defines\r\n" + + "cannot be used before the “BEGIN TRANSLATION” line.\r\n" + + "Definitions, including ones in a define statement, are not expanded\r\n" + + "in the PlusCal to TLA + translation. All defined symbols appear in the\r\n" + + "translation exactly as they appear in the PlusCal code."; + public static final String MACRO_HELP = "<Macro> ::= macro <Name> ( [<Variable>[, <Variable>]∗]{0,1})\n" + + "\t<CompoundStmt>[;]{0,1}\n\n" + + "A macro is like a procedure, except that a call of a macro is expanded at\r\n" + + "translation time. You can think of a macro as a procedure that is executed\r\n" + + "within the step from which it is called.\r\n" + + "A macro definition looks much like a procedure declaration - for example:\r\n" + + "\tmacro P(s, i) { await s ≥ i ;\r\n" + "\t\ts := s - i }\r\n" + + "The difference is that the body of the macro may contain no labels, no\r\n" + + "while, call, return, or goto statement. It may contain a call of a previously\r\n" + + "defined macro. Macro definitions come right after any global variable\r\n" + + "declarations and define section.\r\n" + + "A macro call is like a procedure call, except with the call omitted—for\r\n" + "example:\r\n" + + "\tP(sem, y + 17) ;\r\n" + + "The translation replaces the macro call with the sequence of statements ob-\r\n" + + "tained from the body of the macro definition by substituting the arguments\r\n" + + "of the call for the definition’s parameters. Thus, this call of the P macro\r\n" + "expands to:\r\n" + + "\tawait sem ≥ (y + 17) ;\r\n" + "\tsem := sem - (y + 17) ;\n" + + "When translating a macro call, substitution is syntactic in the sense that\r\n" + + "the meaning of any symbol in the macro definition other than a parameter\r\n" + + "is the meaning it has in the context of the call. For example, if the body of\r\n" + + "the macro definition contains a symbol q and the macro is called within a\r\n" + + "\"with ( q \\in ... )\" statement, then the q in the macro expansion is the q\r\n" + + "introduced by the with statement.\r\n" + + "When replacing a macro by its definition, the translation replaces every\r\n" + + "instance of a macro parameter id in an expression within the macro body\r\n" + + "by the corresponding expression. Every instance includes any uses of id as\r\n" + + "a bound variable, as in the expression\r\n" + "\t[id \\id 1..N |-> false]\r\n" + + "The substitution of an expression like y + 17 for id here will cause a mys-\r\n" + + "terious error when the translation is parsed. When using PlusCal, obey the\r\n" + + "TLA+ convention of never assigning a new meaning to any identifier that\r\n" + "already has a meaning."; + public static final String GOTO_HELP = "<Goto> ::= goto <Label>\n\nExecuting the statement\r\n" + "\tgoto lab ;\r\n" + + "ends the execution of the current step and causes control to go to the state-\r\n" + + "ment labeled lab. In any control path, a goto must be immediately followed\r\n" + + "by a label. (Remember that the control path by definition ignores the mean-\r\n" + + "ing of the goto and continues to what is syntactically the next statement.)\r\n" + + "It is legal for a goto to jump into the middle of a while or if statement,\r\n" + + "but this sort of trickery should be avoided."; + public static final String SKIP_HELP = "<Skip> ::= skip\n\nThe statement skip; does nothing."; + public static final String ASSERT_HELP = "<Assert> ::= assert <Expr>\n\n" + "The statement" + "\tassert expr;" + + "is equivalent to skip if expression expr equals true. If expr equals false,\r\n" + + "executing the statement causes TLC to produce an error message saying\r\n" + + "that the assertion failed and giving the location of the assert statement.\r\n" + + "TLC may report a failed assertion even if the step containing the assert\r\n" + + "statement is not executed because of an await statement that appears later\r\n" + "in the step.\r\n" + + "An algorithm containing an assert statement must be in a module that\r\n" + "extends the TLC module."; + public static final String PRINT_HELP = "<Print> ::= print <Expr>\n\n" + "Execution of the statement\r\n" + + "\tprint expr;\r\n" + + "is equivalent to skip, except it causes TLC to print the current value of expr.\r\n" + + "TLC may print the value even if the step containing the print statement is\r\n" + + "not executed because of an await statement that appears later in the step.\r\n" + + "An algorithm containing a print statement must be in a module that\r\n" + "extends the TLC module."; + public static final String RETURN_HELP = "<Return> ::= return\n\nSee procedure!"; + public static final String AWAIT_HELP = "<Await> ::= [ await | when ] <Expr>\n\nA step containing the statement await expr can be executed only when the\r\n" + + "value of the Boolean expression expr is TRUE. Although it usually appears\r\n" + + "at the beginning of a step, an await statement can appear anywhere within\r\n" + "the step.\r\n" + + "\ta : x := y + 1 ;\r\n" + "\tb: ...\r\n" + + "The step from a to b can be executed only when the current value of y+1\r\n" + + "is positive. (Remember that an entire step must be executed; part of a step\r\n" + + "cannot be executed by itself.) The keyword when can be used instead of\r\n" + "await."; + public static final String WITH_HELP = "<With> ::= with ( <Variable> [=|\\in] <Expr>\r\n" + + "\t[ [;|,] <Variable> [=|\\\\in] <Expr> ]* [;|,]{0,1}\r\n" + "\t) <Stmt>\n\n" + "The statement\r\n" + + "\twith ( id \\in S ) body\r\n" + + "is executed by executing the (possibly compound) statement body with identifier\r\n" + + " id equal to a nondeterministically chosen element of S.\r\n" + "Execution is impossible if S is empty."; + public static final String EITHEROR_HELP = "<Either> ::= either <Stmt> [or <Stmt> ]+\n\n" + + "The either statement has the form:\r\n" + "\teither clause 1\r\n" + "\tor clause 2\r\n" + "\t.\r\n" + + "\t.\r\n" + "\tor clause n\r\n" + + "where each clause i is a (possibly compound) statement. It is executed by\r\n" + + "nondeterministically choosing any clause i that is executable and executing\r\n" + + "it. The either statement can be executed iff at least one of those clauses can\r\n" + + "be executed. If any clause i contains a call, return, or goto statement or a\r\n" + + "label, then the either statement must be followed by a labeled statement.\r\n" + "The statement\r\n" + + "\tif (test) t clause else e clause\r\n" + "is equivalent to the following statement.\r\n" + + "\teither { await test ; t clause }\r\n" + "\tor { await ¬test ; e clause }"; + public static final String IFTHENELSE_HELP = "<If> ::= if ( <Expr> ) <Stmt> [else <Stmt>]{0,1}\n\n" + + "The if statement has its usual meaning. The statement\r\n" + "\tif ( test ) t clause else e clause\r\n" + + "is executed by evaluating the expression test and then executing the (pos-\r\n" + + "sibly compound) statement t clause or e clause depending on whether test\r\n" + + "equals true or false. The else clause is optional. An if statement must\r\n" + + "have a non-empty then clause. An if statement that contains a call,\r\n" + + "return, or goto statement or a label within it must be followed by a\r\n" + + "labeled statement. (A label on the if statement itself is not considered to be\r\n" + + "within the statement.)"; + public static final String VARIABLE_HELP = "<VarDecls> ::= [variable|variables] <VarDecl>+\r\n" + + "\t<VarDecl> ::= <Variable> [ [= |\\in] <Expr> ]{0,1} [;|,]\n\n"; + public static final String WHILE_HELP = "<While> ::= while ( <Expr> ) <Stmt>\n\n" + + "The while statement has its usual meaning. The statement\r\n" + "\tlb : while ( test ) body\r\n" + + "where body is a (possibly compound) statement, is executed like the following\r\n" + "if statement.\r\n" + + "\tlb : if ( test ) { body ; goto lb }\r\n" + + "A while statement must be labeled. However, the statement following a\r\n" + + "while statement need not be labeled, even if there is a label in body."; + public static final String PROCESS_HELP = "<Process> ::= [ fair [+]{0,1} ]{0,1} process ( <Name> [=|\\in] <Expr> )\r\n" + + "\t<VarDecls>{0,1}\r\n" + "\t<CompoundStmt> [;]{0,1}\n\n" + + "A multiprocess algorithm contains one or more processes. A process begins\r\n" + + "in one of two ways:\r\n" + "\tprocess ( ProcName \\in IdSet )\r\n" + "\tprocess ( ProcName = Id )\r\n" + + "The first form begins a process set, the second an individual process. The\r\n" + + "identifier ProcName is the process or process set’s name. The elements of\r\n" + + "the set IdSet and the element Id are called process identifiers. The process\r\n" + + "identifiers of different processes in the same algorithm must all be different.\r\n" + + "This means that the semantics of TLA + must imply that they are different,\r\n" + + "which intuitively usually means that they must be of the same “type”. (For\r\n" + + "example, the semantics of TLA + does not specify whether or not a string\r\n" + + "may equal a number.) For execution by TLC, this means that all process\r\n" + + "identifiers must be comparable values, as defined in Specifying\r\n" + "Systems.\r\n" + + "The name ProcName has no significance; changing it does not change\r\n" + + "the meaning of the process statement in any way. The name appears\r\n" + + "in the TLA + translation, and it should be different for different process\r\n" + "statements\r\n" + + "As explained above in Section 2.6 on page 11, the process statement is\r\n" + + "optionally followed by declarations of local variables. The process body is a\r\n" + + "sequence of statements enclosed by braces ({ }). Its first statement must be\r\n" + + "labeled. Within the body of a process set, self equals the current process’s\r\n" + "identifier.\r\n" + + "A multiprocess algorithm is executed by repeatedly choosing an arbitrary\r\n" + + "process and executing one step of that process, if that step’s execution is\r\n" + + "possible. Execution of the process’s next step is impossible if the process has\r\n" + + "terminated, if its next step contains an await statement whose expression\r\n" + + "equals false, or if that step contains a statement of the form “await x ∈ S ”\r\n" + + "and S equals the empty set. Fairness conditions may be specified on the choice\r\n" + + "of which processes’ steps are to be executed."; + public static final String CALL_HELP = "<Call> ::= call <MacroCall>\r\n" + + "\t<MacroCall> ::= <Name> ( [ <Expr>[, <Expr>]* ]{0,1} )\n\nSee procedure!"; + public static final String PROCEDURE_HELP = "<Procedure> ::= procedure <Name> ( [<PVarDecl> [, <PVarDecl>]* ]{0,1} )\r\n" + + "\t<PVarDecls>{0,1}\r\n" + "\t<CompoundStmt> [;]{0,1}\n\n" + + "An algorithm may have one or more procedures. If it does, the algorithm\r\n" + + "must be in a TLA + module that extends the Sequences module.\r\n" + + "The algorithm’s procedures follow its global variable declarations and\r\n" + + "define section (if any) and precede the “{” that begins the body of a\r\n" + + "uniprocess algorithm or the first process of a multiprocess algorithm. A\r\n" + + "procedure named PName begins\r\n" + "\tprocedure PName ( param 1 , . . . , param n )\r\n" + + "where the identifiers param i are the formal parameters of the procedure.\r\n" + + "These parameters are treated as variables and may be assigned to. As ex-\r\n" + + "plained in Section 4.5 on page 37, there may also be initial-value assignments\r\n" + + "of the parameters.\r\n" + "The procedure statement is optionally followed by declarations of vari-\r\n" + + "ables local to the procedure. These have the same form as the declara-\r\n" + + "tions of global variables, except that initializations may only have the form\r\n" + + "“variable = expression”. The procedure’s local variables are initialized on\r\n" + + "each entry to the procedure.\r\n" + + "Any variable declarations are followed by the procedure’s body, which\r\n" + + "is a sequence of statements enclosed by braces ({ }). The body must begin\r\n" + + "with a labeled statement. There is an implicit label Error immediately\r\n" + + "after the body. If control ever reaches that point, then execution of either\r\n" + + "the process (multiprocess algorithm) or the complete algorithm (uniprocess\r\n" + "algorithm) halts.\r\n" + + "A procedure PName can be called by the statement\r\n" + "\tcall PName ( expr 1 , . . . , expr n )\r\n" + + "Executing this call assigns the current values of the expressions expr i to the\r\n" + + "corresponding parameters param i , initializes the procedure’s local variables,\r\n" + + "and puts control at the beginning of the procedure body.\r\n" + + "A return statement assigns to the parameters and local procedure vari-\r\n" + + "ables their previous values—that is, the values they had before the procedure\r\n" + + "was last called—and returns control to the point immediately following the\r\n" + "call statement.\r\n" + + "The call and return statements are considered to be assignments to the\r\n" + + "procedure’s parameters and local variables. In particular, they are included\r\n" + + "in the rule that a variable can be assigned a value by at most one assignment\r\n" + + "statement in a step. For example, if x is a local variable of procedure P ,\r\n" + + "then a step within the body of P that (recursively) calls P cannot also assign\r\n" + "a value to x.\r\n" + + "For a multiprocess algorithm, the identifier self in the body of a proce-\r\n" + + "dure equals the process identifier of the process within which the procedure\r\n" + "is executing.\r\n" + + "The return statement has no argument. A PlusCal procedure does not\r\n" + + "explicitly return a value. A value can be returned by having the procedure\r\n" + + "set a global variable and having the code immediately following the call\r\n" + + "read that variable. For example, in a multiprocess algorithm, procedure P\r\n" + + "might use a global variable rVal to return a value by executing\r\n" + "\trVal[self] := ... ;\r\n" + + "\treturn ;\r\n" + "From within a process in a process set, the code that calls P might look like\r\n" + + "this:\r\n" + "call P(17) ;\r\n" + "lab: x := ... rVal[self] ... ;\r\n" + + "For a call from within a single process, the code would contain the process’s\r\n" + + "identifier instead of self.\r\n" + + "In any control path, a return statement must be immediately followed\r\n" + + "by a label. A call statement must either be followed in the control path by\r\n" + + "a label or else it must appear immediately before a return statement in a\r\n" + + "statement sequence.\r\n" + "When a call P statement is followed immediately by a return, the\r\n" + + "return from procedure P and the return performed by the return statement\r\n" + + "are both executed as part of a single execution step. When these statements\r\n" + + "are in the (recursive) procedure P , this combining of the two returns is\r\n" + + "essentially the standard optimization of replacing tail recursion by a loop."; } diff --git a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/pcal/PCalCompletionProcessor.java b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/pcal/PCalCompletionProcessor.java new file mode 100644 index 0000000000000000000000000000000000000000..fb5839abed4d712905152950e1848669b43e7139 --- /dev/null +++ b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/pcal/PCalCompletionProcessor.java @@ -0,0 +1,91 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package org.lamport.tla.toolbox.editor.basic.pcal; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jface.text.contentassist.IContentAssistProcessor; +import org.lamport.tla.toolbox.editor.basic.ToolboxCompletionProcessor; + +public class PCalCompletionProcessor extends ToolboxCompletionProcessor implements IContentAssistProcessor { + + public PCalCompletionProcessor() { + // No sense to add "--algorithm" because the 'PCalCompletionProcessor is only + // hot when cursor/caret inside a PCal algorithm. Thus "--algorithm" is part of + // TLACompletionProcessor. +// proposals.put(IPCalReservedWords.ALGORITHM, "--algorithm AName {\n}"); + + List<CompletionProposalTemplate> templates = new ArrayList<CompletionProposalTemplate>(); + templates.add(new CompletionProposalTemplate("process (ProcName \\in S) {\n label: skip;\n}", + IPCalReservedWords.PROCESS, IPCalReservedWords.PROCESS_HELP)); + templates.add(new CompletionProposalTemplate("process (ProcName = Id) {\n label: skip;\n}", + IPCalReservedWords.PROCESS, IPCalReservedWords.PROCESS_HELP)); + proposals.put(IPCalReservedWords.PROCESS, templates); + + templates = new ArrayList<ToolboxCompletionProcessor.CompletionProposalTemplate>(); + templates.add( + new CompletionProposalTemplate("if (TRUE) {\n skip;\n};", "if-then", IPCalReservedWords.IFTHENELSE_HELP)); + templates.add(new CompletionProposalTemplate("if (TRUE) {\n skip;\n} else {\n skip;\n};", "if-then-else", + IPCalReservedWords.IFTHENELSE_HELP)); + templates.add(new CompletionProposalTemplate("if (TRUE) {\n skip;\n} else if (FALSE) {\n skip;\n} else {\n skip;\n};", "if-then-elseif", + IPCalReservedWords.IFTHENELSE_HELP)); + proposals.put(IPCalReservedWords.IF, templates); + + proposals.put(IPCalReservedWords.VARIABLE, + getSingleProposal("variable x = TRUE;", IPCalReservedWords.VARIABLE, IPCalReservedWords.VARIABLE_HELP)); + proposals.put(IPCalReservedWords.VARIABLES, getSingleProposal("variables x = TRUE;\n y \\in {1,2,3};\n z;", + IPCalReservedWords.VARIABLES, IPCalReservedWords.VARIABLE_HELP)); + proposals.put(IPCalReservedWords.PROCEDURE, + getSingleProposal("procedure PName (param1, ..., paramN) {\n label: skip;\n}", IPCalReservedWords.PROCEDURE, + IPCalReservedWords.PROCEDURE_HELP)); + proposals.put(IPCalReservedWords.CALL, getSingleProposal("call PName (expr1, ..., exprN)", + IPCalReservedWords.CALL, IPCalReservedWords.PROCEDURE_HELP)); + proposals.put(IPCalReservedWords.WHILE, getSingleProposal("label: while (TRUE) {\n skip;\n};", + IPCalReservedWords.WHILE, IPCalReservedWords.WHILE_HELP)); + proposals.put(IPCalReservedWords.EITHER, getSingleProposal("either { skip; } or { skip; } or { skip; };", + IPCalReservedWords.EITHER, IPCalReservedWords.EITHEROR_HELP)); + proposals.put(IPCalReservedWords.ASSERT, + getSingleProposal("assert TRUE;", IPCalReservedWords.ASSERT, IPCalReservedWords.ASSERT_HELP)); + proposals.put(IPCalReservedWords.GOTO, + getSingleProposal("goto label;", IPCalReservedWords.GOTO, IPCalReservedWords.GOTO_HELP)); + proposals.put(IPCalReservedWords.PRINT, + getSingleProposal("print \"msg\";", IPCalReservedWords.PRINT, IPCalReservedWords.PRINT_HELP)); + proposals.put(IPCalReservedWords.WITH, getSingleProposal("with ( i \\in S ) {\n skip;\n}", + IPCalReservedWords.WITH, IPCalReservedWords.WITH_HELP)); + proposals.put(IPCalReservedWords.MACRO, getSingleProposal("macro P(param1, ... , paramN) {\n skip;\n}", + IPCalReservedWords.MACRO, IPCalReservedWords.MACRO_HELP)); + proposals.put(IPCalReservedWords.DEFINE, + getSingleProposal("define {\n Op1(param1, ... , paramN) == TRUE\n Op2(...) == TRUE\n}", + IPCalReservedWords.DEFINE, IPCalReservedWords.DEFINE_HELP)); + } + + private static List<CompletionProposalTemplate> getSingleProposal(String replacementString, String displayString, String additionalInformation) { + final List<CompletionProposalTemplate> proposal = new ArrayList<CompletionProposalTemplate>(); + proposal.add(new CompletionProposalTemplate(replacementString, displayString, additionalInformation)); + return proposal; + } +} diff --git a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/pcal/PCalHover.java b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/pcal/PCalHover.java new file mode 100644 index 0000000000000000000000000000000000000000..9f025b651630bf44f1e08f1c52ad2e0861a2ae09 --- /dev/null +++ b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/pcal/PCalHover.java @@ -0,0 +1,78 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package org.lamport.tla.toolbox.editor.basic.pcal; + +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.jface.text.IDocument; +import org.lamport.tla.toolbox.editor.basic.ToolboxHover; +import org.lamport.tla.toolbox.editor.basic.util.DocumentHelper.WordRegion; + +public class PCalHover extends ToolboxHover implements IPCalReservedWords { + + private final Map<String, String> keywordHover = new HashMap<String, String>(); + + public PCalHover() { + keywordHover.put(ALGORITHM, ALGORITHM_HELP); + keywordHover.put("algorithm", ALGORITHM_HELP); + keywordHover.put(DEFINE, DEFINE_HELP); + keywordHover.put(MACRO, MACRO_HELP); + keywordHover.put(PROCEDURE, PROCEDURE_HELP); + keywordHover.put(RETURN, RETURN_HELP); + keywordHover.put(CALL, CALL_HELP); + keywordHover.put(PROCESS, PROCESS_HELP); + keywordHover.put(WHILE, WHILE_HELP); + keywordHover.put("variable", VARIABLE_HELP); + keywordHover.put("variables", VARIABLE_HELP); + keywordHover.put(IF, IFTHENELSE_HELP); + keywordHover.put(THEN, IFTHENELSE_HELP); + keywordHover.put(ELSE, IFTHENELSE_HELP); + keywordHover.put(ELSEIF, IFTHENELSE_HELP); + keywordHover.put(EITHER, EITHEROR_HELP); + keywordHover.put(OR, EITHEROR_HELP); + keywordHover.put(WITH, WITH_HELP); + keywordHover.put(AWAIT, AWAIT_HELP); + keywordHover.put(PRINT, PRINT_HELP); + keywordHover.put(ASSERT, ASSERT_HELP); + keywordHover.put(SKIP, SKIP_HELP); + keywordHover.put(GOTO, GOTO_HELP); + keywordHover.put(":=", ASSIGN_HELP); + keywordHover.put("||", MULTI_ASSIGN_HELP); + } + + /* (non-Javadoc) + * @see org.lamport.tla.toolbox.editor.basic.ToolboxHover#getHoverInfo(org.eclipse.jface.text.IDocument, org.lamport.tla.toolbox.editor.basic.util.DocumentHelper.WordRegion) + */ + @Override + protected String getHoverInfo(final IDocument document, final WordRegion wordRegion) { + // Check if word matches any keywords. + if (keywordHover.containsKey(wordRegion.getWord())) { + return keywordHover.get(wordRegion.getWord()); + } + return null; + } +} diff --git a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/pcal/PCalTranslator.java b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/pcal/PCalTranslator.java new file mode 100644 index 0000000000000000000000000000000000000000..0feca318b3392364a8317bed20625fc9bc005747 --- /dev/null +++ b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/pcal/PCalTranslator.java @@ -0,0 +1,125 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package org.lamport.tla.toolbox.editor.basic.pcal; + +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IMarker; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.jface.dialogs.ProgressMonitorDialog; +import org.eclipse.jface.operation.IRunnableContext; +import org.eclipse.jface.operation.IRunnableWithProgress; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.IEditorInput; +import org.eclipse.ui.part.FileEditorInput; +import org.lamport.tla.toolbox.editor.basic.TLAEditor; +import org.lamport.tla.toolbox.spec.Spec; +import org.lamport.tla.toolbox.tool.ToolboxHandle; +import org.lamport.tla.toolbox.util.TLAMarkerHelper; +import org.lamport.tla.toolbox.util.UIHelper; +import org.lamport.tla.toolbox.util.pref.IPreferenceConstants; +import org.lamport.tla.toolbox.util.pref.PreferenceStoreHelper; + +import pcal.Translator; + +public class PCalTranslator { + + public void translate(final TLAEditor tlaEditor, final Shell shell) throws InvocationTargetException, InterruptedException { + translate(tlaEditor, shell, true); + } + + public void translate(final TLAEditor tlaEditor, final Shell shell, final boolean saveEditor) throws InvocationTargetException, InterruptedException { + // Running the PlusCal translator takes too long for the UI thread. Thus, the + // call to the PlusCal translator call is forked off into a non-UI thread. + // However, we use a ProgressMonitorDialog to lock the UI from further + // modifications. + final IRunnableContext context = new ProgressMonitorDialog(tlaEditor.getEditorSite().getShell()); + context.run(true, false, new IRunnableWithProgress() { + public void run(final IProgressMonitor progressMonitor) throws InvocationTargetException, InterruptedException { + final IEditorInput editorInput = tlaEditor.getEditorInput(); + final IDocument doc = tlaEditor.getDocumentProvider().getDocument(editorInput); + final IFile file = ((FileEditorInput) editorInput).getFile(); + + final Spec spec = ToolboxHandle.getCurrentSpec(); + + // Remove all old markers that indicated parser problems in the previous version + // of the editor. + TLAMarkerHelper.removeProblemMarkers(file, progressMonitor, + TLAMarkerHelper.TOOLBOX_MARKERS_TRANSLATOR_MARKER_ID); + + // Get the user-defined, per spec translator arguments. In almost all cases this + // is "-nocfg". + final List<String> asList = new ArrayList<String>( + Arrays.asList(PreferenceStoreHelper.getStringArray(spec, + IPreferenceConstants.PCAL_CAL_PARAMS, new String[] { "-nocfg" }))); + // Add the name of the current file to the arguments. The Translator expects + // this even though we invoke the translator in a way that it doesn't write files. + asList.add(file.getLocation().toOSString()); + + // Run the Translator on the input and check if it succeeded. If it didn't + // succeed, we know there are parser problems which we will use to marker the + // editor. + final Translator translator = new Translator(doc.get(), asList); + if (translator.translate()) { + // Update the mapping to/from TLA+ to PlusCal. + spec.setTpMapping(translator.getMapping(), file.getName(), progressMonitor); + + // User might have edited a non-PlusCal part of the editor. In this case, don't + // change the editor to not create a superfluous undo operation. + if (translator.hasChanged()) { + // Join the UI thread to modify the editor's content. + UIHelper.runUISync(new Runnable() { + public void run() { + // Replace the documents content while preserving the current caret position. + final ISelection selection = tlaEditor.getViewer().getSelection(); + doc.set(translator.getOutput()); + tlaEditor.getViewer().setSelection(selection); + + // Finally save the editor. + if (tlaEditor.isDirty() && saveEditor) { + tlaEditor.doSave(progressMonitor); + } + } + }); + } + } else { + // Add parser problem markers to the editor. + for (Translator.Error anError : translator.getErrors()) { + TLAMarkerHelper.installProblemMarker(file, file.getName(), IMarker.SEVERITY_ERROR, + anError.getLocation(), anError.toString(), progressMonitor, + TLAMarkerHelper.TOOLBOX_MARKERS_TRANSLATOR_MARKER_ID); + } + } + } + }); + } +} diff --git a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/pcal/PCalWordDetector.java b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/pcal/PCalWordDetector.java new file mode 100644 index 0000000000000000000000000000000000000000..ad4a0356542cc683700cd729154bc0eaad6ea1e9 --- /dev/null +++ b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/pcal/PCalWordDetector.java @@ -0,0 +1,22 @@ +package org.lamport.tla.toolbox.editor.basic.pcal; + +import org.eclipse.jface.text.rules.IWordDetector; +import org.lamport.tla.toolbox.editor.basic.tla.TLAWordDetector; + +public class PCalWordDetector extends TLAWordDetector implements IWordDetector { + + /* (non-Javadoc) + * @see org.lamport.tla.toolbox.editor.basic.tla.TLAWordDetector#isWordPart(char) + */ + @Override + public boolean isWordPart(final char character) { + if (character == ':' || character == '=') { + // Detect assignment ":=" as word. + return true; + } else if (character == '|') { + // Detect multi-assignment "||" as word. + return true; + } + return super.isWordPart(character); + } +} diff --git a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/tla/PCALCodeScanner.java b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/tla/PCALCodeScanner.java index dac3f85651860817b487b15db77f0a8c64a66208..98509d28ed91c5388786b39fa9f61a52d5d8dee0 100644 --- a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/tla/PCALCodeScanner.java +++ b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/tla/PCALCodeScanner.java @@ -37,7 +37,7 @@ public class PCALCodeScanner extends RuleBasedScanner IToken other = new Token(new TextAttribute(provider.getColor(TLAColorProvider.TLA_DEFAULT))); IToken pcal = new Token(new TextAttribute(provider.getColor(TLAColorProvider.PCAL_KEYWORD))); - List rules = new ArrayList(); + List<WordRule> rules = new ArrayList<WordRule>(); // Add generic whitespace rule. // rules.add(new WhitespaceRule(DocumentHelper.getDefaultWhitespaceDetector())); diff --git a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/tla/TLACompletionProcessor.java b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/tla/TLACompletionProcessor.java index 152ad29d648527a71d17d89c60ec93effcd14dc8..ff3de00067466baa925588658e35068bd9476283 100644 --- a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/tla/TLACompletionProcessor.java +++ b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/tla/TLACompletionProcessor.java @@ -1,169 +1,58 @@ package org.lamport.tla.toolbox.editor.basic.tla; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; -import org.eclipse.jface.text.BadLocationException; -import org.eclipse.jface.text.IDocument; -import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.ITextViewer; -import org.eclipse.jface.text.contentassist.CompletionProposal; import org.eclipse.jface.text.contentassist.ContextInformation; -import org.eclipse.jface.text.contentassist.ICompletionProposal; import org.eclipse.jface.text.contentassist.IContentAssistProcessor; import org.eclipse.jface.text.contentassist.IContextInformation; -import org.eclipse.jface.text.contentassist.IContextInformationValidator; import org.eclipse.swt.graphics.Point; -import org.lamport.tla.toolbox.editor.basic.TLAEditorActivator; -import org.lamport.tla.toolbox.editor.basic.util.DocumentHelper; +import org.lamport.tla.toolbox.editor.basic.ToolboxCompletionProcessor; +import org.lamport.tla.toolbox.editor.basic.pcal.IPCalReservedWords; /** * Syntactic auto-completion processor * @author Simon Zambrovski - * @version $Id$ */ -public class TLACompletionProcessor implements IContentAssistProcessor +public class TLACompletionProcessor extends ToolboxCompletionProcessor implements IContentAssistProcessor { - private String[] proposals = ITLAReserveredWords.ALL_WORDS_ARRAY; - - /* (non-Javadoc) - * @see org.eclipse.jface.text.contentassist.IContentAssistProcessor#computeCompletionProposals(org.eclipse.jface.text.ITextViewer, int) - */ - public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int offset) - { - /* - // show all proposals without checking the context - ICompletionProposal[] result = new ICompletionProposal[fgProposals.length]; - for (int i = 0; i < fgProposals.length; i++) - { - IContextInformation info = new ContextInformation(fgProposals[i], ""); - result[i] = new CompletionProposal(fgProposals[i], offset, 0, fgProposals[i].length(), null, - fgProposals[i], info, ""); - } - return result; - */ - - IDocument document = viewer.getDocument(); - // get the selection range - Point selectedRange = viewer.getSelectedRange(); - - List propList = new ArrayList(); - try - { - if (selectedRange.y > 0) - { - // the range is non-empty - String text = document.get(selectedRange.x, selectedRange.y); - computeWordProposals(text, offset, propList); - } else - { - // the range is empty, no selection in the editor - - // get the region - IRegion wordRegion = DocumentHelper.getRegionExpandedBackwards(document, offset, DocumentHelper - .getDefaultWordDetector()); - String word = document.get(wordRegion.getOffset(), wordRegion.getLength()); - TLAEditorActivator.getDefault().logDebug("Content assist for '" + word + "'" + wordRegion ); - computeWordProposals(word, offset, propList); - } - } catch (BadLocationException e) - { - // TODO Auto-generated catch block - e.printStackTrace(); - } - - ICompletionProposal[] proposals = new ICompletionProposal[propList.size()]; - propList.toArray(proposals); - - return proposals; - - } - - /** - * Syntax-based proposal based for word beginning - * @param word - * @param offset - * @param propositionList - */ - private void computeWordProposals(String word, int offset, List propositionList) - { - int qualifierLength = word.length(); - - // Loop through all proposals - for (int i = 0; i < proposals.length; i++) - { - String proposalText = proposals[i]; - - // Check if proposal matches qualifier - if (proposalText.startsWith(word)) - { - // compute whole proposal text - String text = proposalText + " "; - - // Derive cursor position - int cursor = proposalText.length(); - - // Construct proposal - CompletionProposal proposal = new CompletionProposal(text, offset - qualifierLength, qualifierLength, - cursor); - - // and add to result list - propositionList.add(proposal); - } - } - + public TLACompletionProcessor() { + final List<String> asList = Arrays.asList(ITLAReserveredWords.ALL_WORDS_ARRAY); + for (String string : asList) { + final List<CompletionProposalTemplate> proposal = new ArrayList<CompletionProposalTemplate>(1); + proposal.add(new CompletionProposalTemplate(string + " ")); + proposals.put(string, proposal); + } + + // Define PCal "algorithm" here because the PCalCompletionProcessor is only + // active inside an algorithm definition (chicken or egg problem). + final List<CompletionProposalTemplate> l = new ArrayList<CompletionProposalTemplate>(1); + l.add(new CompletionProposalTemplate( + "(***************************************************************************\r\n" + + "--algorithm AlgorithmName {\r\n}\r\n" + + " ***************************************************************************)\r\n", + IPCalReservedWords.ALGORITHM, IPCalReservedWords.ALGORITHM_HELP)); + proposals.put(ITLAReserveredWords.ALGORITHM, l); } /* (non-Javadoc) * @see org.eclipse.jface.text.contentassist.IContentAssistProcessor#computeContextInformation(org.eclipse.jface.text.ITextViewer, int) */ - public IContextInformation[] computeContextInformation(ITextViewer viewer, int offset) - { - // Retrieve selected range - Point selectedRange = viewer.getSelectedRange(); - if (selectedRange.y > 0) - { - // Text is selected. Create a context information array. - ContextInformation[] contextInfos = new ContextInformation[ITLAReserveredWords.ALL_WORDS_ARRAY.length]; - - // Create one context information item for each style - for (int i = 0; i < ITLAReserveredWords.ALL_WORDS_ARRAY.length; i++) - contextInfos[i] = new ContextInformation(null, ITLAReserveredWords.ALL_WORDS_ARRAY[i] + " Style"); - return contextInfos; - } - return new ContextInformation[0]; - } - - /* (non-Javadoc) - * @see org.eclipse.jface.text.contentassist.IContentAssistProcessor#getCompletionProposalAutoActivationCharacters() - */ - public char[] getCompletionProposalAutoActivationCharacters() - { - return null; - } - - /* (non-Javadoc) - * @see org.eclipse.jface.text.contentassist.IContentAssistProcessor#getContextInformationAutoActivationCharacters() - */ - public char[] getContextInformationAutoActivationCharacters() - { - return null; - } - - /* (non-Javadoc) - * @see org.eclipse.jface.text.contentassist.IContentAssistProcessor#getContextInformationValidator() - */ - public IContextInformationValidator getContextInformationValidator() - { - return null; - } - - /* (non-Javadoc) - * @see org.eclipse.jface.text.contentassist.IContentAssistProcessor#getErrorMessage() - */ - public String getErrorMessage() - { - return null; - } - + public IContextInformation[] computeContextInformation(ITextViewer viewer, int offset) { + // Retrieve selected range + final Point selectedRange = viewer.getSelectedRange(); + if (selectedRange.y > 0) { + // Text is selected. Create a context information array. + final IContextInformation[] contextInfos = new ContextInformation[ITLAReserveredWords.ALL_WORDS_ARRAY.length]; + + // Create one context information item for each style + for (int i = 0; i < ITLAReserveredWords.ALL_WORDS_ARRAY.length; i++) { + contextInfos[i] = new ContextInformation(null, ITLAReserveredWords.ALL_WORDS_ARRAY[i] + " Style"); + } + return contextInfos; + } + return new ContextInformation[0]; + } } diff --git a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/tla/TLAHyperlinkDetector.java b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/tla/TLAHyperlinkDetector.java index 40bc69738e30602652627f77f0052b753024b3e0..1d045fa2ed7d2346a65c901c64a6380b17ba0f5b 100644 --- a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/tla/TLAHyperlinkDetector.java +++ b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/tla/TLAHyperlinkDetector.java @@ -1,8 +1,12 @@ package org.lamport.tla.toolbox.editor.basic.tla; +import java.io.File; + +import org.eclipse.core.filesystem.EFS; +import org.eclipse.core.filesystem.IFileStore; import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.Path; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IRegion; @@ -10,29 +14,26 @@ import org.eclipse.jface.text.ITextViewer; import org.eclipse.jface.text.Region; import org.eclipse.jface.text.hyperlink.AbstractHyperlinkDetector; import org.eclipse.jface.text.hyperlink.IHyperlink; +import org.eclipse.ui.IEditorInput; import org.eclipse.ui.editors.text.FileDocumentProvider; +import org.eclipse.ui.editors.text.TextFileDocumentProvider; +import org.eclipse.ui.ide.FileStoreEditorInput; import org.eclipse.ui.part.FileEditorInput; -import org.lamport.tla.toolbox.editor.basic.TLAEditor; +import org.eclipse.ui.texteditor.IDocumentProvider; import org.lamport.tla.toolbox.editor.basic.TLAEditorActivator; +import org.lamport.tla.toolbox.editor.basic.TLAEditorAndPDFViewer; +import org.lamport.tla.toolbox.editor.basic.TLAEditorReadOnly; import org.lamport.tla.toolbox.editor.basic.actions.OpenDeclarationAction; -import org.lamport.tla.toolbox.editor.basic.util.DocumentHelper; -import org.lamport.tla.toolbox.editor.basic.util.EditorUtil; -import org.lamport.tla.toolbox.editor.basic.util.EditorUtil.StringAndLocation; import org.lamport.tla.toolbox.tool.ToolboxHandle; -import org.lamport.tla.toolbox.ui.handler.OpenModuleHandler; import org.lamport.tla.toolbox.util.ResourceHelper; -import tla2sany.modanalyzer.SpecObj; import tla2sany.parser.SyntaxTreeNode; -import tla2sany.parser.TLAplusParserConstants; -import tla2sany.semantic.Context; import tla2sany.semantic.ModuleNode; import tla2sany.semantic.OpDefNode; import tla2sany.semantic.SymbolNode; import tla2sany.semantic.ThmOrAssumpDefNode; -import tla2sany.st.Location; import tla2sany.st.SyntaxTreeConstants; -import util.UniqueString; +import util.FilenameToStream; /** * Detects hyperlinks in TLA+ code @@ -50,10 +51,6 @@ import util.UniqueString; public class TLAHyperlinkDetector extends AbstractHyperlinkDetector { - public TLAHyperlinkDetector() - { - } - /** * This method first sets label to the token at the position indicated by the * region. If the module is parsed and unmodified, it uses EditorUtil.getTokenAt @@ -100,6 +97,7 @@ public class TLAHyperlinkDetector extends AbstractHyperlinkDetector { return null; } + // Set region to the Region of the document described by currentTokenSpec // (this ugly re-use of a parameter name is kept from Simon's original @@ -141,25 +139,40 @@ public class TLAHyperlinkDetector extends AbstractHyperlinkDetector TLAEditorActivator.getDefault().logDebug(csNode.getAttachedComments()[i]); } - IResource resource = null; - // - if (ToolboxHandle.isUserModule(ResourceHelper.getModuleFileName(csNode.getFilename()))) - { - // resource - resource = ResourceHelper.getResourceByModuleName(csNode.getFilename()); - } else - { - // TLAEditorActivator.getDefault().logDebug("A StandardModule '" + csNode.getFilename() + "' is requested..."); - return null; - } + IDocumentProvider documentProvider = null; + IEditorInput editorInput = null; + String editorId = ""; + // + final FilenameToStream resolver = ToolboxHandle.getSpecObj().getResolver(); + if (ToolboxHandle.isUserModule(ResourceHelper.getModuleFileName(csNode.getFilename()))) { + editorId = TLAEditorAndPDFViewer.ID; + editorInput = new FileEditorInput( + (IFile) ResourceHelper.getResourceByModuleName(csNode.getFilename())); + documentProvider = new FileDocumentProvider(); + } else if (resolver.isStandardModule(csNode.getFilename())) { + // No point editing standard modules. + editorId = TLAEditorReadOnly.ID; + + // Resolve the file via the FilenameToStream resolver in case a user has + // provided its own standard module definition. + final File resolved = resolver.resolve(csNode.getFilename(), true); + + // Standard modules live outside the workspace which is why they have to be + // opened with EFS and read with a TextFileDocumentProvider. + final IFileStore fileStore = EFS.getLocalFileSystem() + .getStore(new Path(resolved.getAbsolutePath())); + editorInput = new FileStoreEditorInput(fileStore); + documentProvider = new TextFileDocumentProvider(); + } else { + // A TLA+ built-in module. + return null; + } // connect to the resource - FileEditorInput fileEditorInput = new FileEditorInput((IFile) resource); - FileDocumentProvider fileDocumentProvider = new FileDocumentProvider(); try { - fileDocumentProvider.connect(fileEditorInput); - document = fileDocumentProvider.getDocument(fileEditorInput); + documentProvider.connect(editorInput); + document = documentProvider.getDocument(editorInput); } finally { /* @@ -169,7 +182,7 @@ public class TLAHyperlinkDetector extends AbstractHyperlinkDetector * Keeping it connected only seems to provide synchronization of * the document with file changes. That is not necessary in this context. */ - fileDocumentProvider.disconnect(fileEditorInput); + documentProvider.disconnect(editorInput); } try @@ -178,7 +191,7 @@ public class TLAHyperlinkDetector extends AbstractHyperlinkDetector // to get just the symbol from the left-hand side. (Otherwise, // the user can't execute Goto Declaration immediately followed // by Show Uses.) - if (resolvedSymbol instanceof OpDefNode) + if (resolvedSymbol instanceof OpDefNode && csNode.getHeirs().length >= 1) { // Need to pick out the symbol from the left-hand side of // the definition. @@ -194,7 +207,7 @@ public class TLAHyperlinkDetector extends AbstractHyperlinkDetector csNode = csNode.getHeirs()[1]; } } - } else if ((resolvedSymbol instanceof ThmOrAssumpDefNode) + } else if ((resolvedSymbol instanceof ThmOrAssumpDefNode && csNode.getHeirs().length >= 2) && ((csNode.getKind() == SyntaxTreeConstants.N_Theorem) || (csNode.getKind() == SyntaxTreeConstants.N_Assumption))) { csNode = csNode.getHeirs()[1]; @@ -206,7 +219,7 @@ public class TLAHyperlinkDetector extends AbstractHyperlinkDetector int startOffset = startLineRegion.getOffset() + csNode.getLocation().beginColumn() - 1; int endOffset = endLineRegion.getOffset() + csNode.getLocation().endColumn(); - return new IHyperlink[] { new OpenDeclarationAction(resource, new Region(startOffset, endOffset + return new IHyperlink[] { new OpenDeclarationAction(editorId, editorInput, new Region(startOffset, endOffset - startOffset), label, region) }; } catch (BadLocationException e) diff --git a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/tla/TokenSpec.java b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/tla/TokenSpec.java index b63ccff6df9f843f0cf9814411c465bc4995a062..8b1e5ecd8ba437580e28fd27415b1fa921aad1bd 100644 --- a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/tla/TokenSpec.java +++ b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/tla/TokenSpec.java @@ -148,9 +148,15 @@ public class TokenSpec int rightPos = tokenSpecs[i].rightPos; tokenSpecs[i].leftPos = leftPos + offsetOfLine; tokenSpecs[i].rightPos = rightPos + offsetOfLine; + + String indiceAdjustedToken = tokenSpecs[i].token; Location location = EditorUtil.getLocationAt(document, tokenSpecs[i].leftPos, rightPos - leftPos); - symbol = EditorUtil.lookupOriginalSymbol(UniqueString.uniqueStringOf(tokenSpecs[i].token), moduleNode, - location, null); + + if ((indiceAdjustedToken != null) && (indiceAdjustedToken.length() > 1) && (indiceAdjustedToken.charAt(0) == '_')) { + indiceAdjustedToken = indiceAdjustedToken.substring(1); + } + + symbol = EditorUtil.lookupOriginalSymbol(UniqueString.uniqueStringOf(indiceAdjustedToken), moduleNode, location, null); if (symbol != null) { goodIndex = i; diff --git a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/util/DocumentHelper.java b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/util/DocumentHelper.java index f35f3bf968cb72a1e079d577a40bad6508952a10..3175ed6918c7cdd266b5be9077b2af34e251c1d4 100644 --- a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/util/DocumentHelper.java +++ b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/util/DocumentHelper.java @@ -15,7 +15,6 @@ import tla2sany.st.Location; /** * Toolkit for document helper methods * @author Simon Zambrovski - * @version $Id$ */ public class DocumentHelper { @@ -109,19 +108,29 @@ public class DocumentHelper return new Region(documentOffset - charCounter, charCounter + 1); } + + /** + * @see DocumentHelper#getRegionExpandedBoth(IDocument, int, IWordDetector) + */ + public static WordRegion getRegionExpandedBoth(IDocument document, int documentOffset) throws BadLocationException + { + return getRegionExpandedBoth(document, documentOffset, getDefaultWordDetector()); + } /** * Combines the effect of backwards and forwards region expansion * @param document * @param offset * @param defaultWordDetector - * @return + * @return A {@link WordRegion} or null if no region could be found. + * @throws BadLocationException */ - public static IRegion getRegionExpandedBoth(IDocument document, int documentOffset, IWordDetector detector) + public static WordRegion getRegionExpandedBoth(IDocument document, int documentOffset, IWordDetector detector) throws BadLocationException { - IRegion backwards = getRegionExpandedBackwards(document, documentOffset, detector); - IRegion forwards = getRegionExpandedForwards(document, documentOffset, detector); - return new Region(backwards.getOffset(), backwards.getLength() + forwards.getLength()); + final IRegion backwards = getRegionExpandedBackwards(document, documentOffset, detector); + final IRegion forwards = getRegionExpandedForwards(document, documentOffset, detector); + final String word = document.get(backwards.getOffset(), backwards.getLength() + forwards.getLength()); + return new WordRegion(backwards.getOffset(), backwards.getLength() + forwards.getLength(), word); } /** @@ -187,6 +196,19 @@ public class DocumentHelper // no previous line so do nothing return region; } - + } + + public static class WordRegion extends Region implements IRegion { + + private final String word; + + public WordRegion(int offset, int length, String word) { + super(offset, length); + this.word = word; + } + + public String getWord() { + return word; + } } } diff --git a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/util/EditorUtil.java b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/util/EditorUtil.java index 6a244a84153cb56a4780ddff1bbde9850e80e292..e43401a392eaad0d705efc99d723f1d03685b120 100644 --- a/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/util/EditorUtil.java +++ b/org.lamport.tla.toolbox.editor.basic/src/org/lamport/tla/toolbox/editor/basic/util/EditorUtil.java @@ -21,6 +21,7 @@ import org.lamport.tla.toolbox.Activator; import org.lamport.tla.toolbox.editor.basic.TLAEditor; import org.lamport.tla.toolbox.editor.basic.TLAEditorActivator; import org.lamport.tla.toolbox.editor.basic.TLAEditorAndPDFViewer; +import org.lamport.tla.toolbox.editor.basic.util.DocumentHelper.WordRegion; import org.lamport.tla.toolbox.spec.Spec; import org.lamport.tla.toolbox.spec.parser.IParseConstants; import org.lamport.tla.toolbox.spec.parser.ParseResult; @@ -30,6 +31,7 @@ import org.lamport.tla.toolbox.util.ResourceHelper; import org.lamport.tla.toolbox.util.UIHelper; import pcal.TLAtoPCalMapping; +import tla2sany.modanalyzer.SpecObj; import tla2sany.parser.Operators; import tla2sany.parser.SyntaxTreeNode; import tla2sany.semantic.AssumeProveNode; @@ -446,6 +448,24 @@ public class EditorUtil } return loc; } + + /** + * @see EditorUtil#lookupSymbol(UniqueString, SemanticNode, Location, SymbolNode) + */ + public static SymbolNode lookupSymbol(SpecObj specObj, IDocument document, WordRegion region) { + final Location location = getLocationAt(document, region.getOffset(), region.getLength()); + final ModuleNode rootModule = specObj.getExternalModuleTable().getRootModule(); + return lookupSymbol(UniqueString.uniqueStringOf(region.getWord()), rootModule, location, null); + } + + /** + * @see EditorUtil#lookupSymbol(UniqueString, SemanticNode, Location, SymbolNode) + */ + public static SymbolNode lookupSymbol(String name, SymbolNode curNode, IDocument document, IRegion region, + SymbolNode defaultResult) { + final Location location = getLocationAt(document, region.getOffset(), region.getLength()); + return lookupSymbol(UniqueString.uniqueStringOf(name), curNode, location, defaultResult); + } /** * This method is called externally with <code>curNode</code> equal to diff --git a/org.lamport.tla.toolbox.feature.branding/feature.xml b/org.lamport.tla.toolbox.feature.branding/feature.xml index 55faf058868a23e8e7cd8334aed060e028055e08..83cbb60c1f0615fb8c97541319ff4bd1f8da5eca 100644 --- a/org.lamport.tla.toolbox.feature.branding/feature.xml +++ b/org.lamport.tla.toolbox.feature.branding/feature.xml @@ -5,78 +5,28 @@ version="1.0.0.qualifier" provider-name="Leslie Lamport, Markus Alexander Kuppe"> - <description url="http://www.example.com/description"> - [Enter Feature Description here.] - </description> - - <copyright> - This feature contains branding¹ information like the License Agreement. - -¹ "branding" is an Eclipse specific term. - </copyright> - <license url=""> - Unless otherwise indicated, the TLA Toolbox is made available by Microsoft Corporation under the terms and conditions of the Microsoft Research License Agreement provided below. The Compaq Corporation license below governs some of the code located in subdirectories tla2sany, tla2tex, tlc2, and util of the file tla2tools.jar. - -IT IS YOUR OBLIGATION TO READ AND ACCEPT ALL SUCH TERMS AND CONDITIONS PRIOR TO USE -Microsoft Research License Agreement -TLA Toolbox - -This Microsoft Research License Agreement ("MSR-LA") is a legal agreement between you and Microsoft Corporation (Microsoft or we) for the software or data identified above, which may include source code, and any associated materials, text or speech files, associated media and "online" or electronic documentation and any updates we provide in our discretion (together, the "Software"). - -By installing, copying, or otherwise using this Software, found at http://research.microsoft.com/downloads, you agree to be bound by the terms of this MSR-LA. If you do not agree, do not install copy or use the Software. The Software is protected by copyright and other intellectual property laws and is licensed, not sold. -SCOPE OF RIGHTS: -You may use, copy, reproduce, and distribute this Software for any non-commercial purpose, subject to the restrictions in this MSR-LA. Some purposes which can be non-commercial are teaching, academic research, public demonstrations and personal experimentation. You may also distribute this Software with books or other teaching materials, or publish the Software on websites, that are intended to teach the use of the Software for academic or other non-commercial purposes. -You may not use or distribute this Software or any derivative works in any form for commercial purposes. Examples of commercial purposes would be running business operations, licensing, leasing, or selling the Software, distributing the Software for use with commercial products, or any other activity which purpose is to procure a commercial gain to you or others. Notwithstanding the foregoing, if you are a commercial entity, you may use this software solely for your own internal use. -If the Software includes source code or data, you may create derivative works of such portions of the Software and distribute the modified Software for non-commercial purposes, as provided herein. -If you distribute the Software or any derivative works of the Software, you will distribute them under the same terms and conditions as in this license, and you will not grant other rights to the Software or derivative works that are different from those provided by this MSR-LA. -If you have created derivative works of the Software, and distribute such derivative works, you will cause the modified files to carry prominent notices so that recipients know that they are not receiving the original Software. Such notices must state: (i) that you have changed the Software; and (ii) the date of any changes. -In return, we simply require that you agree: -1. That you will not remove any copyright or other notices from the Software. -2. That if any of the Software is in binary format, you will not attempt to modify such portions of the Software, or to reverse engineer or decompile them, except and only to the extent authorized by applicable law. -3. That you will not use the Software in a live operating environment where it may be relied upon to perform in the same manner as a commercially released product, or with data that has not been sufficiently backed up. -4. That Microsoft is granted back, without any restrictions or limitations, a non-exclusive, perpetual, irrevocable, royalty-free, assignable and sub-licensable license, to reproduce, publicly perform or display, install, use, modify, post, distribute, make and have made, sell and transfer your modifications to and/or derivative works of the Software source code or data, for any purpose. -5. That any feedback about the Software provided by you to us is voluntarily given, and Microsoft shall be free to use the feedback as it sees fit without obligation or restriction of any kind, even if the feedback is designated by you as confidential. -6. THAT THE SOFTWARE COMES "AS IS", WITH NO WARRANTIES. THIS MEANS NO EXPRESS, IMPLIED OR STATUTORY WARRANTY, INCLUDING WITHOUT LIMITATION, WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, ANY WARRANTY AGAINST INTERFERENCE WITH YOUR ENJOYMENT OF THE SOFTWARE OR ANY WARRANTY OF TITLE OR NON-INFRINGEMENT. THERE IS NO WARRANTY THAT THIS SOFTWARE WILL FULFILL ANY OF YOUR PARTICULAR PURPOSES OR NEEDS. ALSO, YOU MUST PASS THIS DISCLAIMER ON WHENEVER YOU DISTRIBUTE THE SOFTWARE OR DERIVATIVE WORKS. -7. THAT NEITHER MICROSOFT NOR ANY CONTRIBUTOR TO THE SOFTWARE WILL BE LIABLE FOR ANY DAMAGES RELATED TO THE SOFTWARE OR THIS MSR-LA, INCLUDING DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL OR INCIDENTAL DAMAGES, TO THE MAXIMUM EXTENT THE LAW PERMITS, NO MATTER WHAT LEGAL THEORY IT IS BASED ON. ALSO, YOU MUST PASS THIS LIMITATION OF LIABILITY ON WHENEVER YOU DISTRIBUTE THE SOFTWARE OR DERIVATIVE WORKS. -8. That we have no duty of reasonable care or lack of negligence, and we are not obligated to (and will not) provide technical support for the Software. -9. That if you breach this MSR-LA or if you sue anyone over patents that you think may apply to or read on the Software or anyone's use of the Software, this MSR-LA (and your license and rights obtained herein) terminate automatically. Upon any such termination, you shall destroy all of your copies of the Software immediately. Sections 4, 5, 6, 7, 8, 9, 12 and 13 of this MSR-LA shall survive any termination of this MSR-LA. -10. That the patent rights, if any, granted to you in this MSR-LA only apply to the Software, not to any derivative works you make. -11. That the Software may be subject to U.S. export jurisdiction at the time it is licensed to you, and it may be subject to additional export or import laws in other places. You agree to comply with all such laws and regulations that may apply to the Software after delivery of the software to you. -12. That all rights not expressly granted to you in this MSR-LA are reserved. -13. That this MSR-LA shall be construed and controlled by the laws of the State of Washington, USA, without regard to conflicts of law. If any provision of this MSR-LA shall be deemed unenforceable or contrary to law, the rest of this MSR-LA shall remain in full effect and interpreted in an enforceable manner that most nearly captures the intent of the original language. - -The following license applies to code marked with the following notice: -Copyright (c) 2003 -Compaq Corporation. All rights reserved. - -Compaq Computer Corporation, a Delaware corporation with offices at -20555 SH 249, Houston, TX, (COMPAQ) and you the CUSTOMER agree as -follows: - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL COMPAQ BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR -THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -Except as contained in this notice, the name of COMPAQ shall not be -used in advertising or otherwise to promote the sale, use or other -dealings in this Software without prior written authorization from -COMPAQ. + MIT License + +Copyright (c) 2018 Microsoft Corporation + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. </license> </feature> diff --git a/org.lamport.tla.toolbox.feature.standalone/feature.xml b/org.lamport.tla.toolbox.feature.standalone/feature.xml index 5913e4911e890fac5d85c1507d524941dc3c0fbe..c47aa9a2b731d5c3fd6a55cf2c1e73e9dfe7bd43 100644 --- a/org.lamport.tla.toolbox.feature.standalone/feature.xml +++ b/org.lamport.tla.toolbox.feature.standalone/feature.xml @@ -110,6 +110,10 @@ id="com.abstratt.eclipsegraphviz.feature" version="0.0.0"/> + <includes + id="org.eclipse.recommenders.news.rcp.feature" + version="0.0.0"/> + <plugin id="org.lamport.tla.toolbox.product.standalone" download-size="0" @@ -127,16 +131,6 @@ fragment="true" unpack="false"/> - <plugin - id="org.eclipse.core.filesystem.win32.x86" - os="win32" - arch="x86" - download-size="0" - install-size="0" - version="0.0.0" - fragment="true" - unpack="false"/> - <plugin id="org.eclipse.core.filesystem.linux.x86_64" os="linux" @@ -147,16 +141,6 @@ fragment="true" unpack="false"/> - <plugin - id="org.eclipse.core.filesystem.linux.x86" - os="linux" - arch="x86" - download-size="0" - install-size="0" - version="0.0.0" - fragment="true" - unpack="false"/> - <plugin id="org.eclipse.core.filesystem.macosx" os="macosx" @@ -233,9 +217,9 @@ unpack="false"/> <plugin - id="org.eclipse.core.net.linux.x86" - os="linux" - arch="x86" + id="org.eclipse.core.net.win32.x86_64" + os="win32" + arch="x86_64" download-size="0" install-size="0" version="0.0.0" @@ -243,37 +227,101 @@ unpack="false"/> <plugin - id="org.eclipse.core.net.win32.x86_64" - os="win32" - arch="x86_64" + id="org.eclipse.equinox.p2.director" download-size="0" install-size="0" version="0.0.0" - fragment="true" unpack="false"/> <plugin - id="org.eclipse.core.net.win32.x86" - os="win32" - arch="x86" + id="org.eclipse.equinox.p2.director.app" download-size="0" install-size="0" version="0.0.0" - fragment="true" unpack="false"/> <plugin - id="org.eclipse.equinox.p2.director" + id="org.apache.commons.lang3" download-size="0" install-size="0" version="0.0.0" unpack="false"/> <plugin - id="org.eclipse.equinox.p2.director.app" + id="org.eclipse.mylyn.commons.notifications.core" download-size="0" install-size="0" version="0.0.0" unpack="false"/> + <plugin + id="org.eclipse.mylyn.commons.notifications.feed" + download-size="0" + install-size="0" + version="0.0.0" + unpack="false"/> + + <plugin + id="org.eclipse.mylyn.commons.notifications.ui" + download-size="0" + install-size="0" + version="0.0.0" + unpack="false"/> + + <plugin + id="org.eclipse.mylyn.commons.workbench" + download-size="0" + install-size="0" + version="0.0.0" + unpack="false"/> + + <plugin + id="org.apache.commons.lang" + download-size="0" + install-size="0" + version="0.0.0" + unpack="false"/> + + <plugin + id="org.eclipse.mylyn.commons.screenshots" + download-size="0" + install-size="0" + version="0.0.0" + unpack="false"/> + + <plugin + id="com.google.guava" + download-size="0" + install-size="0" + version="15.0.0.v201403281430" + unpack="false"/> + + <plugin + id="org.eclipse.mylyn.commons.ui" + download-size="0" + install-size="0" + version="0.0.0" + unpack="false"/> + + <plugin + id="org.eclipse.mylyn.commons.core" + download-size="0" + install-size="0" + version="0.0.0" + unpack="false"/> + + <plugin + id="org.eclipse.ui.browser" + download-size="0" + install-size="0" + version="0.0.0" + unpack="false"/> + + <plugin + id="org.eclipse.jdt.annotation" + download-size="0" + install-size="0" + version="1.1.150.v20180322-1206" + unpack="false"/> + </feature> diff --git a/org.lamport.tla.toolbox.jclouds/META-INF/MANIFEST.MF b/org.lamport.tla.toolbox.jclouds/META-INF/MANIFEST.MF index 479158e7d497873bd7e06c5bb47a8aeebb7e9d67..06936e2a86f5845f5fc12d5b442efce877066d23 100644 --- a/org.lamport.tla.toolbox.jclouds/META-INF/MANIFEST.MF +++ b/org.lamport.tla.toolbox.jclouds/META-INF/MANIFEST.MF @@ -11,7 +11,7 @@ Require-Bundle: org.eclipse.core.runtime, jclouds-scriptbuilder;bundle-version="1.7.3", jclouds-slf4j;bundle-version="1.7.3", jclouds-sshj;bundle-version="1.7.3", - com.google.guava;bundle-version="15.0.0", + com.google.guava;bundle-version="[15.0.0,21.0.0)", com.google.inject;bundle-version="3.0.0", org.apache.commons.io;bundle-version="2.0.1", org.lamport.tlatools;bundle-version="1.0.0" diff --git a/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/AzureARMCloudTLCInstanceParameters.java b/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/AzureARMCloudTLCInstanceParameters.java new file mode 100644 index 0000000000000000000000000000000000000000..a5b1e835e7790815c16f12f6c1e823109d5ab243 --- /dev/null +++ b/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/AzureARMCloudTLCInstanceParameters.java @@ -0,0 +1,161 @@ +/******************************************************************************* + * Copyright (c) 2015 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ + +package org.lamport.tla.toolbox.jcloud; + +import java.util.Properties; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.jclouds.ContextBuilder; +import org.jclouds.location.reference.LocationConstants; + +public class AzureARMCloudTLCInstanceParameters extends AzureCloudTLCInstanceParameters { + + public AzureARMCloudTLCInstanceParameters(final String tlcParams, int numberOfWorkers) { + super(tlcParams.trim(), numberOfWorkers); + } + + /* (non-Javadoc) + * @see org.lamport.tla.toolbox.jcloud.CloudTLCInstanceParameters#getCloudProvier() + */ + @Override + public String getCloudProvider() { + return "azurecompute-arm"; + } + + /* (non-Javadoc) + * @see org.lamport.tla.toolbox.jcloud.CloudTLCInstanceParameters#getRegion() + */ + @Override + public String getRegion() { + return System.getProperty("azure.region", "eastus"); + } + + /* (non-Javadoc) + * @see org.lamport.tla.toolbox.jcloud.CloudTLCInstanceParameters#getImageId() + */ + @Override + public String getImageId() { + // With azure-cli v2 (based on Python) extract name from 'az vm image list --all --publisher Canonical'. + return System.getProperty("azure.image", "eastus/Canonical/UbuntuServer/18.04-LTS"); } + + /* (non-Javadoc) + * @see org.lamport.tla.toolbox.jcloud.CloudTLCInstanceParameters#getHardwareId() + */ + @Override + public String getHardwareId() { + // STANDARD_D14: 16 cores, 112GB + return System.getProperty("azure.instanceType", "eastus/Standard_D14"); + } + + /* (non-Javadoc) + * @see org.lamport.tla.toolbox.jcloud.CloudTLCInstanceParameters#getIdentity() + */ + @Override + public String getIdentity() { + final String identity = System.getenv("AZURE_COMPUTE_SERVICE_PRINCIPAL"); + Assert.isNotNull(identity); + return identity; + } + + /* (non-Javadoc) + * @see org.lamport.tla.toolbox.jcloud.CloudTLCInstanceParameters#getCredentials() + */ + @Override + public String getCredentials() { + final String credential = System.getenv("AZURE_COMPUTE_SERVICE_PRINCIPAL_PASSWORD"); + Assert.isNotNull(credential); + return credential; + } + + private String getSubscriptionId() { + final String subscription = System.getenv("AZURE_COMPUTE_SUBSCRIPTION"); + Assert.isNotNull(subscription); + return subscription; + } + + /* (non-Javadoc) + * @see org.lamport.tla.toolbox.jcloud.CloudTLCInstanceParameters#validateCredentials() + */ + @Override + public IStatus validateCredentials() { + final String credential = System.getenv("AZURE_COMPUTE_SERVICE_PRINCIPAL_PASSWORD"); + final String identity = System.getenv("AZURE_COMPUTE_SERVICE_PRINCIPAL"); + final String subscription = System.getenv("AZURE_COMPUTE_SUBSCRIPTION"); + final String tenantId = System.getenv("AZURE_COMPUTE_TENANT"); + if (credential == null || identity == null || subscription == null || tenantId == null) { + return new Status(Status.ERROR, "org.lamport.tla.toolbox.jcloud", + "Invalid credentials, please check the environment variables " + + "(AZURE_COMPUTE_SERVICE_PRINCIPAL_PASSWORD & AZURE_COMPUTE_SERVICE_PRINCIPAL " + + "& AZURE_COMPUTE_TENANT and AZURE_COMPUTE_SUBSCRIPTION) are correctly " + + "set up and picked up by the Toolbox." + + "\n\nPlease visit the Toolbox help and read section 4 " + + "of \"Cloud based distributed TLC\" on how to setup authentication."); + } + return Status.OK_STATUS; + } + + /* (non-Javadoc) + * @see org.lamport.tla.toolbox.jcloud.CloudTLCInstanceParameters#mungeProperties(java.util.Properties) + */ + @Override + public void mungeProperties(final Properties properties) { + properties.setProperty("azurecompute-arm.tenantId", System.getenv("AZURE_COMPUTE_TENANT")); + // Minimize back and forth with Azure API by limiting images to those provided + // by Canoncial. Also only talk to Azure in US east. Both properties reduce + // startup time. + // org/jclouds/azurecompute/arm/config/AzureComputeProperties.IMAGE_PUBLISHERS + properties.setProperty("jclouds.azurecompute.arm.publishers", "Canonical"); + properties.setProperty(LocationConstants.PROPERTY_REGIONS, "eastus"); + super.mungeProperties(properties); + } + + /* (non-Javadoc) + * @see org.lamport.tla.toolbox.jcloud.CloudTLCInstanceParameters#mungeBuilder(org.jclouds.ContextBuilder) + */ + @Override + public void mungeBuilder(ContextBuilder builder) { + builder.endpoint("https://management.azure.com/subscriptions/" + getSubscriptionId()); + } + + /* (non-Javadoc) + * @see org.lamport.tla.toolbox.jcloud.CloudTLCInstanceParameters#getHostnameSetup() + */ + @Override + public String getHostnameSetup() { + // Append ".cloudapp.net" to automatically set hostname and add a mapping from + // public ip (obtained via third party service ifconfig.co) to hostname in + // /etc/hosts. Results in FQDN being used my MailSender and thus less likely + // to be classified or rejected as spam. + // The suffix ".cloudapp.net" is something that might change on the Azure end in + // the future. It will then break this statement (suffix can be found in portal). + // It would also be nice for Azure to offer a public API to query the hostname + // (similar to EC2CloudTLCInstanceParameters#getHostnameSetup. + return "hostname \"$(hostname).cloudapp.net\" && echo \"$(curl -s ifconfig.co) $(hostname)\" >> /etc/hosts"; + } +} diff --git a/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/AzureCloudTLCInstanceParameters.java b/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/AzureCloudTLCInstanceParameters.java index b817c193dc56b61804c68ee705d494a867af85a4..a90a821ab5a0da23d1ab7c383d0942409941846e 100644 --- a/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/AzureCloudTLCInstanceParameters.java +++ b/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/AzureCloudTLCInstanceParameters.java @@ -89,7 +89,7 @@ public class AzureCloudTLCInstanceParameters extends CloudTLCInstanceParameters public String getImageId() { // 'azure vm image list eastus canonical' (manually lookup image release date from output) // With azure-cli v2 (based on Python) extract date from 'az vm image list --all --publisher Canonical'. - return System.getProperty("azure.image", "b39f27a8b8c64d52b05eac6a62ebad85__Ubuntu-16_04-LTS-amd64-server-20180112-en-us-30GB"); + return System.getProperty("azure.image", "b39f27a8b8c64d52b05eac6a62ebad85__Ubuntu-18_04-LTS-amd64-server-20180426.2-en-us-30GB"); } /* (non-Javadoc) @@ -140,7 +140,9 @@ public class AzureCloudTLCInstanceParameters extends CloudTLCInstanceParameters "Invalid credentials, please check the environment variables " + "(AZURE_COMPUTE_CREDENTIALS & AZURE_COMPUTE_IDENTITY " + "and AZURE_COMPUTE_SUBSCRIPTION) are correctly " - + "set up and picked up by the Toolbox."); + + "set up and picked up by the Toolbox." + + "\n\nPlease visit the Toolbox help and read section 4 " + + "of \"Cloud based distributed TLC\" on how to setup authentication."); } // Verify that the identity file exists. final File file = new File(identity); @@ -158,24 +160,6 @@ public class AzureCloudTLCInstanceParameters extends CloudTLCInstanceParameters public void mungeBuilder(ContextBuilder builder) { builder.endpoint("https://management.core.windows.net/" + getSubscriptionId()); } - - /* (non-Javadoc) - * @see org.lamport.tla.toolbox.jcloud.CloudTLCInstanceParameters#getExtraRepositories() - */ - @Override - public String getExtraRepositories() { - return "echo \"deb [arch=amd64] https://packages.microsoft.com/repos/azure-cli/ wheezy main\" | sudo tee /etc/apt/sources.list.d/azure-cli.list && apt-key adv --keyserver packages.microsoft.com --recv-keys 417A0893"; - } - - /* (non-Javadoc) - * @see org.lamport.tla.toolbox.jcloud.CloudTLCInstanceParameters#getExtraPackages() - */ - @Override - public String getExtraPackages() { - // https://docs.microsoft.com/en-us/cli/azure/install-azure-cli?view=azure-cli-latest#install-on-debianubuntu-with-apt-get - // see getExtraRepositories too. - return "azure-cli"; - } /* (non-Javadoc) * @see org.lamport.tla.toolbox.jcloud.CloudTLCInstanceParameters#getHostnameSetup() @@ -192,47 +176,4 @@ public class AzureCloudTLCInstanceParameters extends CloudTLCInstanceParameters // (similar to EC2CloudTLCInstanceParameters#getHostnameSetup. return "hostname \"$(hostname).cloudapp.net\" && echo \"$(curl -s ifconfig.co) $(hostname)\" >> /etc/hosts"; } - - /* (non-Javadoc) - * @see org.lamport.tla.toolbox.jcloud.CloudTLCInstanceParameters#getCleanup() - */ - @Override - public String getCloudAPIShutdown() { - final String servicePrincipal = System.getenv("AZURE_COMPUTE_SERVICE_PRINCIPAL"); - final String password = System.getenv("AZURE_COMPUTE_SERVICE_PRINCIPAL_PASSWORD"); - final String tenant = System.getenv("AZURE_COMPUTE_SERVICE_PRINCIPAL_TENANT"); - if (servicePrincipal == null || password == null || tenant == null) { - // Missing credentials. - return super.getCloudAPIShutdown(); - } - // What we try to accomplish is to purge the complete Azure Resource Group (a RG - // combines all Azure resources associated with the VM (storage, networking, - // ips, ...). - // The way we do it, is to use the azure CLI to deploy the template in - // /tmp/rg.json created by the printf statement under the same resource group - // identify we wish to purge. The trick is, that the template defines no - // resources whatsoever. This effectively purges the old resources in the - // resource group. Idea taken from - // http://www.codeisahighway.com/effective-ways-to-delete-resources-in-a-resource-group-on-azure/ - // bash/screen/ssh apparently fiddle with quotes and which is why the json is base64 encoded - // and decoded on the instance: - // { "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": {}, "variables": {}, "resources": [], "outputs": {} } | base64 - // - // Unfortunately, the azure CLI needs credentials to talk to the Azure API. For - // that, one manually creates a service principal once as described in - // https://docs.microsoft.com/en-us/cli/azure/create-an-azure-service-principal-azure-cli?view=azure-cli-latest - // and uses it to log into Azure as described in - // https://docs.microsoft.com/en-us/cli/azure/authenticate-azure-cli?view=azure-cli-latest. - // Using AZURE_COMPUTE_CREDENTIALS and AZURE_COMPUTE_IDENTITY to login with azure CLI - // would trigger a two-factor auth for Microsoft FTEs. Not something we want. - // - // An alternative might be to use an auth.properties file, but this doesn't seem - // supported by azure CLI yet. Read "File based authentication" at - // https://docs.microsoft.com/en-us/java/azure/java-sdk-azure-authenticate#mgmt-file - return "echo eyAiJHNjaGVtYSI6ICJodHRwczovL3NjaGVtYS5tYW5hZ2VtZW50LmF6dXJlLmNvbS9zY2hlbWFzLzIwMTUtMDEtMDEvZGVwbG95bWVudFRlbXBsYXRlLmpzb24jIiwgImNvbnRlbnRWZXJzaW9uIjogIjEuMC4wLjAiLCAicGFyYW1ldGVycyI6IHt9LCAidmFyaWFibGVzIjoge30sICJyZXNvdXJjZXMiOiBbXSwgIm91dHB1dHMiOiB7fSB9Cg== | base64 -d > /tmp/rg.json" - + " && " + "az login --service-principal -u \"" + servicePrincipal + "\" -p " + password + " --tenant " - // $(hostname -s) only works iff hostname is correctly setup with getHostnameSetup() above. - + tenant + " && " + "az group deployment create --resource-group $(hostname -s)" - + " --template-file /tmp/rg.json --mode Complete"; - } } diff --git a/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/CloudDistributedTLCJob.java b/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/CloudDistributedTLCJob.java index 2a23604b20bdd7ebf2040dc38e40a41e332a8271..6c23c9d0ea168cc98adfd26d5c63a23e5d25a926 100644 --- a/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/CloudDistributedTLCJob.java +++ b/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/CloudDistributedTLCJob.java @@ -38,11 +38,17 @@ import java.io.InputStream; import java.net.URL; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Arrays; +import java.util.HashSet; import java.util.Map; import java.util.NoSuchElementException; import java.util.Properties; import java.util.Set; import java.util.UUID; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; @@ -53,11 +59,14 @@ import org.jclouds.compute.ComputeService; import org.jclouds.compute.ComputeServiceContext; import org.jclouds.compute.RunNodesException; import org.jclouds.compute.RunScriptOnNodesException; +import org.jclouds.compute.domain.ComputeMetadata; import org.jclouds.compute.domain.ExecChannel; import org.jclouds.compute.domain.ExecResponse; import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.domain.TemplateBuilder; +import org.jclouds.compute.domain.internal.NodeMetadataImpl; import org.jclouds.compute.options.TemplateOptions; +import org.jclouds.domain.LoginCredentials; import org.jclouds.io.Payload; import org.jclouds.logging.config.ConsoleLoggingModule; import org.jclouds.logging.slf4j.config.SLF4JLoggingModule; @@ -69,11 +78,13 @@ import org.jclouds.sshj.config.SshjSshClientModule; import org.lamport.tla.toolbox.tool.tlc.job.ITLCJobStatus; import org.lamport.tla.toolbox.tool.tlc.job.TLCJobFactory; +import com.google.common.base.Charsets; import com.google.common.base.Predicate; import com.google.common.base.Predicates; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; import com.google.common.io.ByteStreams; +import com.google.common.io.Files; import com.google.inject.AbstractModule; /* @@ -81,16 +92,20 @@ import com.google.inject.AbstractModule; * ==== * - Reverse PTR records in DNS to make it less likely that emails coming out of the VM are classified as SPAM * -- Azure has only support for it in its service API but not in JClouds + * --- Also see https://docs.microsoft.com/en-us/azure/dns/dns-reverse-dns-for-azure-services * -- AWS just has a form where users can request a PTR record * - Send test mail during instance startup and communicate back to user on failure */ public class CloudDistributedTLCJob extends Job { + private static final String SHUTDOWN_AFTER = System + .getProperty(CloudDistributedTLCJob.class.getName() + ".shutdownMinutes", "10"); /** * The groupName has to be unique per job. This is how cloud instances are * associated to this job. If two jobs use the same groupName, they will talk * to the same set of nodes. */ + private final String providerName; private final String groupNameUUID; private final Path modelPath; private final int nodes; @@ -102,6 +117,7 @@ public class CloudDistributedTLCJob extends Job { public CloudDistributedTLCJob(String aName, File aModelFolder, int numberOfWorkers, final Properties properties, CloudTLCInstanceParameters params) { super(aName); + this.providerName = aName; this.nodes = numberOfWorkers; this.params = params; //TODO groupNameUUID is used by some providers (azure) as a hostname/DNS name. Thus, format. @@ -112,9 +128,7 @@ public class CloudDistributedTLCJob extends Job { @Override protected IStatus run(final IProgressMonitor monitor) { - final long startUp = System.currentTimeMillis(); - - monitor.beginTask("Starting TLC model checker in the cloud", 85 + (nodes > 1 ? 20 : 0)); + monitor.beginTask("Starting TLC model checker in the cloud", 90 + (nodes > 1 ? 20 : 0)); // Validate credentials and fail fast if null or syntactically incorrect if (!params.validateCredentials().equals(Status.OK_STATUS)) { return params.validateCredentials(); @@ -122,10 +136,18 @@ public class CloudDistributedTLCJob extends Job { ComputeServiceContext context = null; try { - final Payload jarPayLoad = PayloadHelper - .appendModel2Jar(modelPath, - props.getProperty(TLCJobFactory.MAIN_CLASS), props, - monitor); + // Tweak tla2tools in a background thread. It takes a couple of seconds to run + // pack200 to shrink the files size but we can lookup or launch a cloud instance + // in the meantime. + monitor.subTask("Tweaking tla2tools.jar to contain the spec & model (in background)"); + final ExecutorService executor = Executors.newSingleThreadExecutor(); + final Future<Payload> future = executor.submit(() -> { + return PayloadHelper + .appendModel2Jar(modelPath, + props.getProperty(TLCJobFactory.MAIN_CLASS), props, + monitor); + }); + executor.shutdown(); // User has canceled the job, thus stop it (there will be more // cancelled checks down below). if (monitor.isCanceled()) { @@ -156,149 +178,23 @@ public class CloudDistributedTLCJob extends Job { return Status.CANCEL_STATUS; } - // start a node, but first configure it - final TemplateOptions templateOptions = compute.templateOptions(); - - // Open up node's firewall to allow http traffic in. This allows users to - // look at the munin/ stats generated for the OS as well as TLC specifically. - // (See below where munin gets installed manually) - // This now makes us dependent on EC2 (for now) - templateOptions.inboundPorts(22, 80, 443); - - // note this will create a user with the same name as you on the - // node. ex. you can connect via ssh public IP - templateOptions.runScript(AdminAccess.standard()); - - final TemplateBuilder templateBuilder = compute.templateBuilder(); - templateBuilder.options(templateOptions); - templateBuilder.imageId(params.getImageId()); - templateBuilder.hardwareId(params.getHardwareId()); - - // Everything configured, now launch node - monitor.subTask(String.format("Starting %s %s instance%s in region %s.", nodes > 1 ? nodes : "a", - params.getHardwareId(), nodes > 1 ? "s" : "", params.getRegion())); - final Set<? extends NodeMetadata> createNodesInGroup; - createNodesInGroup = compute.createNodesInGroup(groupNameUUID, - nodes, templateBuilder.build()); - monitor.worked(20); - if (monitor.isCanceled()) { - return Status.CANCEL_STATUS; - } - final long spinUp = System.currentTimeMillis(); - - // Install custom tailored jmx2munin to monitor the TLC process. Can - // either monitor standalone tlc2.TLC or TLCServer. - monitor.subTask("Provisioning TLC environment on all node(s)"); - final String email = props.getProperty(TLCJobFactory.MAIL_ADDRESS); - Map<? extends NodeMetadata, ExecResponse> execResponse = compute.runScriptOnNodesMatching( - inGroup(groupNameUUID), - // Creating an entry in /etc/alias that makes sure system email sent - // to root ends up at the address given by the user. Note that this - // has to be done before postfix gets installed later. postfix - // re-generates the aliases file for us. - exec( "echo root: " + email + " >> /etc/aliases" - + " && " - // OS tuning parameters for (distributed) TLC: - // - Disable hugepage defragmentation (especially important on highmem instances) - + "echo never > /sys/kernel/mm/transparent_hugepage/defrag" - + " && " - // - Turn off NUMA balancing - + "echo 0 > /proc/sys/kernel/numa_balancing" - + " && " - // Don't want dpkg to require user interaction. - + "export DEBIAN_FRONTEND=noninteractive" - + " && " - + params.getHostnameSetup() - + " && " - // Oracle Java 8 - + "add-apt-repository ppa:webupd8team/java -y && " - // Accept license before apt (dpkg) tries to present it to us (which fails due to 'noninteractive' mode below) - // see http://stackoverflow.com/a/19391042 - + "echo debconf shared/accepted-oracle-license-v1-1 select true | sudo debconf-set-selections && " - + "echo debconf shared/accepted-oracle-license-v1-1 seen true | sudo debconf-set-selections && " - + params.getExtraRepositories() - + " && " - // Update Ubuntu's package index. The public/remote - // package mirrors might have updated. Without - // update, we might try to install outdated packages - // below. This most likely fails with a 404 because - // the packages have been purged from the mirrors. - + "apt-get update" - + " && " - // Never be prompted for input - // Download jmx2munin from the INRIA host - // TODO make it part of Toolbox and upload from - // there (it's tiny 48kb anyway) instead. - // This needs some better build-time integration - // between TLA and jmx2munin (probably best to make - // jmx2munin a submodule of the TLA git repo). - // Download an explicit version (commit) to allow - // us to continue development in HEAD. Otherwise, - // an old Toolbox would use the newest jmx2munin - // which might not be compatible with its CDTLCJob. - + "wget https://github.com/lemmy/jmx2munin/raw/515e9b47f5a71fbfe2eeb517a341448b52fdb226/jmx2munin_1.0_all.deb" - + " && " -// + "wget http://tla.msr-inria.inria.fr/jmx2munin/jmx2munin_1.0_all.deb && " - // Install jmx2munin into the system - + "dpkg -i jmx2munin_1.0_all.deb ; " - // Force apt to download and install the - // missing dependencies of jmx2munin without - // user interaction - + "apt-get install --no-install-recommends -fy" - + " && " - // Install all security relevant system packages - + "echo unattended-upgrades unattended-upgrades/enable_auto_updates boolean true | debconf-set-selections" - + " && " - // screen is needed to allow us to re-attach - // to the TLC process if logged in to the - // instance directly (it's probably already - // installed). zip is used to prepare the - // worker tla2tools.jar (strip spec) and - // unattended-upgrades makes sure the instance - // is up-to-date security-wise. - + "apt-get install --no-install-recommends mdadm e2fsprogs screen zip unattended-upgrades oracle-java8-installer oracle-java8-set-default " - + params.getExtraPackages() + " -y" - + " && " - // Delegate file system tuning to cloud specific code. - + params.getOSFilesystemTuning() - // Install Oracle Java8. It supports Java Mission - // Control, an honest profiler. But first, - // automatically accept the Oracle license because - // installation will fail otherwise. -// + " && " -// + "echo debconf shared/accepted-oracle-license-v1-1 select true | debconf-set-selections && " -// + "add-apt-repository ppa:webupd8team/java -y && " -// + "apt-get update && " -// + "apt-get --no-install-recommends install oracle-java8-installer oracle-java8-set-default -y" - // Create /mnt/tlc and change permission to be world writable - // Requires package 'apache2' to be already installed. apache2 - // creates /var/www/html. - // "/mnt/tlc" is on the ephemeral and thus faster storage of the - // instance. - + " && " - + "mkdir -p /mnt/tlc/ && chmod 777 /mnt/tlc/ && " - + "ln -s /mnt/tlc/MC.out /var/www/html/MC.out && " - + "ln -s /mnt/tlc/MC.err /var/www/html/MC.err && " - + "ln -s /mnt/tlc/tlc.jfr /var/www/html/tlc.jfr"), - new TemplateOptions().runAsRoot(true).wrapInInitScript( - false)); - throwExceptionOnErrorResponse(execResponse, "Provisioning TLC environment on all nodes"); - monitor.worked(10); + //TODO Support instance reuse with Cloud distributed TLC. + monitor.subTask("Looking for resusable nodes to quick-start model checking"); + final Set<NodeMetadata> createNodesInGroup = nodes > 1 ? new HashSet<>() + : findReusableNodes(compute, monitor); + monitor.worked(5); if (monitor.isCanceled()) { return Status.CANCEL_STATUS; + } else if (createNodesInGroup.isEmpty()) { + createNodesInGroup.addAll(provisionNodes(compute, monitor)); + if (monitor.isCanceled()) { + return Status.CANCEL_STATUS; + } + } else { + // skipped provisionNodes(...) which takes 35 steps. + monitor.worked(35); } - // Install all security relevant system packages - monitor.subTask("Installing security relevant system package upgrades (in background)"); - execResponse = compute.runScriptOnNodesMatching( - inGroup(groupNameUUID), - exec("screen -dm -S security bash -c \"/usr/bin/unattended-upgrades\""), - new TemplateOptions().runAsRoot(true).wrapInInitScript( - true).blockOnComplete(false).blockUntilRunning(false)); - throwExceptionOnErrorResponse(execResponse, "Installing security relevant system package upgrades"); - monitor.worked(5); - final long provision = System.currentTimeMillis(); - // Choose one of the nodes to be the master and create an // identifying predicate. final NodeMetadata master = Iterables.getLast(createNodesInGroup); @@ -312,13 +208,14 @@ public class CloudDistributedTLCJob extends Job { // world-readable. It is cloud-readable already through the RMI api. monitor.subTask("Copying tla2tools.jar to master node at " + hostname); SshClient sshClient = context.utils().sshForNode().apply(master); - sshClient.put("/tmp/tla2tools.pack.gz", jarPayLoad); + sshClient.put("/tmp/tla2tools.pack.gz", future.get()); monitor.worked(10); if (monitor.isCanceled()) { return Status.CANCEL_STATUS; } - final String tlcMasterCommand = " cd /mnt/tlc/ && " + final String tlcMasterCommand = " shutdown -c && rm -rf /mnt/tlc/* && " // Cancel and remove any pending shutdown and leftovers from previous runs. + + "cd /mnt/tlc/ && " // Decompress tla2tools.pack.gz + "unpack200 /tmp/tla2tools.pack.gz /tmp/tla2tools.jar" + " && " @@ -355,6 +252,7 @@ public class CloudDistributedTLCJob extends Job { + params.getJavaSystemProperties() + " " + "-jar /tmp/tla2tools.jar " + params.getTLCParameters() + " " + + (isCLI ? "|& tee /mnt/tlc/MC.out " : "") + "&& " // Run any cloud specific cleanup tasks. // When CloudDistributedTLCJob runs in synchronous CLI mode (isCLI), it will destroy @@ -369,7 +267,7 @@ public class CloudDistributedTLCJob extends Job { // It uses "sudo" because the script is explicitly // run as a user. No need to run the TLC process as // root. - + "sudo shutdown -h " + (isCLI ? "+10" : "now") + + "sudo shutdown -h +" + SHUTDOWN_AFTER + (isCLI ? "" : "\""); // closing opening '"' of screen/bash -c if (isCLI) { monitor.subTask("Starting TLC model checker process"); @@ -406,30 +304,30 @@ public class CloudDistributedTLCJob extends Job { // Run model checker master on master monitor.subTask("Starting TLC model checker process on the master node (in background)"); - // The predicate will be applied to ALL instances owned by the - // cloud account (ie AWS), even the ones in different regions - // completely unrelated to TLC. - final Predicate<NodeMetadata> isMaster = new Predicate<NodeMetadata>() { - private final String masterHostname = master.getHostname(); - public boolean apply(NodeMetadata nodeMetadata) { - // hostname can be null if instance is terminated. - final String hostname = nodeMetadata.getHostname(); - return masterHostname.equals(hostname); - }; - }; - execResponse = compute.runScriptOnNodesMatching(isMaster, exec(tlcMasterCommand), new TemplateOptions().runAsRoot(false) - .wrapInInitScript(true).blockOnComplete(false).blockUntilRunning(false)); - throwExceptionOnErrorResponse(execResponse, "Starting TLC model checker process on the master node"); + final ExecResponse response = compute.runScriptOnNode(master.getId(), exec(tlcMasterCommand), + new TemplateOptions().overrideLoginCredentials(master.getCredentials()).runAsRoot(false) + .wrapInInitScript(true).blockOnComplete(false).blockUntilRunning(false)); + throwExceptionOnErrorResponse(master, response, "Starting TLC model checker process on the master node"); monitor.worked(5); - final long tlcStartUp = System.currentTimeMillis(); if (nodes > 1) { + // The predicate will be applied to ALL instances owned by the + // cloud account (ie AWS), even the ones in different regions + // completely unrelated to TLC. + final Predicate<NodeMetadata> isMaster = new Predicate<NodeMetadata>() { + private final String masterHostname = master.getHostname(); + public boolean apply(NodeMetadata nodeMetadata) { + // hostname can be null if instance is terminated. + final String hostname = nodeMetadata.getHostname(); + return masterHostname.equals(hostname); + }; + }; // copy the tla2tools.jar to the root of the master's webserver // to make it available to workers. However, strip the spec // (*.tla/*.cfg/...) from the jar file to not share the spec // with the world. monitor.subTask("Make TLC code available to all worker node(s)"); - execResponse = compute.runScriptOnNodesMatching( + Map<? extends NodeMetadata, ExecResponse> execResponse = compute.runScriptOnNodesMatching( isMaster, exec("cp /tmp/tla2tools.jar /var/www/html/tla2tools.jar && " + "zip -d /var/www/html/tla2tools.jar model/*.tla model/*.cfg model/generated.properties"), @@ -496,10 +394,15 @@ public class CloudDistributedTLCJob extends Job { } - // Print runtimes of various work items. -// System.out.printf("%s spinUp\n%s provision\n%s start\n%s finish\n", (spinUp - startUp) / 1000, -// (provision - spinUp) / 1000, (tlcStartUp - provision) / 1000, -// (System.currentTimeMillis() - tlcStartUp) / 1000); + // Get the output from the remote instance and attach the corresponding + // InputStream to the CloudStatus. A UI can then read the InputStream and show + // the output of the TLC process to a user. The SSH connection automatically + // terminates when the TLC process finishes. + // https://askubuntu.com/questions/509881/tail-reading-an-entire-file-and-then-following + ExecChannel execChannel = null; + if (!isCLI) { + execChannel = sshClient.execChannel("tail -q -f -n +1 /mnt/tlc/MC.out --pid $(pgrep -f tla2tools.jar)"); + } // Communicate result to user monitor.done(); @@ -512,8 +415,8 @@ public class CloudDistributedTLCJob extends Job { + "Expect to receive an email at %s with the model checking result eventually.", hostname, props.get("result.mail.address")), null, new URL( - "http://" + hostname + "/munin/")); - } catch (RunNodesException|IOException|RunScriptOnNodesException|NoSuchElementException|AuthorizationException|SshException e) { + "http://" + hostname + "/munin/"), execChannel.getOutput(), sshClient); + } catch (ExecutionException|InterruptedException|RunNodesException|IOException|RunScriptOnNodesException|NoSuchElementException|AuthorizationException|SshException e) { e.printStackTrace(); if (context != null) { destroyNodes(context, groupNameUUID); @@ -540,6 +443,204 @@ public class CloudDistributedTLCJob extends Job { } } + private Set<NodeMetadata> findReusableNodes(final ComputeService compute, final IProgressMonitor monitor) throws IOException { + // Filter out those nodes which haven't been created by the Toolbox. We can't be + // sure if they are reusable or that we are allowed to reuse them. Also, skip + // nodes which are CLI nodes. CLI nodes get destroyed by the Toolbox. Lastly, we + // are only interested in RUNNING instances. + final Set<? extends ComputeMetadata> runningNodes = compute.listNodesDetailsMatching( + node -> node.getName() != null && node.getName().startsWith(providerName.toLowerCase()) + && !node.getTags().contains("CLI") && node.getStatus() == NodeMetadata.Status.RUNNING); + + // TODO what happens if a node terminates before we tried to runScriptOnNode + // below? Does runScriptOnNode throw an exception or does the response indicate + // it? + + for (final ComputeMetadata node : runningNodes) { + final String id = node.getId(); + + // busctl call... atomically cancels a scheduled system shutdown OR returns + // false if none is scheduled. This is similar to the behavior of init5 + // shutdown -c which changed with systemd. Thx to user grawity on IRC + // (systemd@freenode) for coming up with this. + // For more context: + // https://askubuntu.com/questions/835222/detect-pending-sheduled-shutdown-ubuntu-server-16-04-1 + // https://askubuntu.com/questions/838019/shutdownd-service-missing-on-ubuntu-server-16-lts + // https://askubuntu.com/questions/994339/check-if-shutdown-schedule-is-active-and-when-it-is + try { + final ExecResponse response = compute.runScriptOnNode(id, + "busctl call --system org.freedesktop.login1 /org/freedesktop/login1 org.freedesktop.login1.Manager CancelScheduledShutdown", + TemplateOptions.Builder.overrideLoginCredentials(getLoginForCommandExecution()).runAsRoot(true) + .wrapInInitScript(false)); + if (response.getExitStatus() == 0 + && (response.getError() == null || response.getError().isEmpty()) + && response.getOutput().indexOf("true") > 0) { // Part of output of busctl call... + return new HashSet<>(Arrays.asList(new WrapperNodeMetadata(compute.getNodeMetadata(id), getLoginForCommandExecution()))); + } + } catch (RuntimeException e) { + // - NodeMetadata.Status could have changed after we queried the cloud API but + // before we connected to the instance, ie the instance terminated/shutdown. + // - We might not have valid credentials. + //TODO Needs better reporting?! + continue; + } + } + + return new HashSet<>(); + } + + private Set<? extends NodeMetadata> provisionNodes(ComputeService compute, IProgressMonitor monitor) + throws RunNodesException, RunScriptOnNodesException { + + // start a node, but first configure it + final TemplateOptions templateOptions = compute.templateOptions(); + + // Open up node's firewall to allow http traffic in. This allows users to + // look at the munin/ stats generated for the OS as well as TLC specifically. + // (See below where munin gets installed manually) + // This now makes us dependent on EC2 (for now) + templateOptions.inboundPorts(22, 80, 443); + + // note this will create a user with the same name as you on the + // node. ex. you can connect via ssh public IP + templateOptions.runScript(AdminAccess.standard()); + if (isCLI) { + templateOptions.tags(Arrays.asList("CLI")); + } + + final TemplateBuilder templateBuilder = compute.templateBuilder(); + templateBuilder.options(templateOptions); + templateBuilder.imageId(params.getImageId()); + templateBuilder.hardwareId(params.getHardwareId()); + + // Everything configured, now launch node + monitor.subTask(String.format("Starting %s %s instance%s in region %s.", nodes > 1 ? nodes : "a", + params.getHardwareId(), nodes > 1 ? "s" : "", params.getRegion())); + final Set<? extends NodeMetadata> createNodesInGroup = compute.createNodesInGroup(groupNameUUID, + nodes, templateBuilder.build()); + monitor.worked(20); + if (monitor.isCanceled()) { + return createNodesInGroup; + } + + // Install custom tailored jmx2munin to monitor the TLC process. Can + // either monitor standalone tlc2.TLC or TLCServer. + monitor.subTask("Provisioning TLC environment on all node(s)"); + final String email = props.getProperty(TLCJobFactory.MAIL_ADDRESS); + Map<? extends NodeMetadata, ExecResponse> execResponse = compute.runScriptOnNodesMatching( + inGroup(groupNameUUID), + // Creating an entry in /etc/alias that makes sure system email sent + // to root ends up at the address given by the user. Note that this + // has to be done before postfix gets installed later. postfix + // re-generates the aliases file for us. + exec( "echo root: " + email + " >> /etc/aliases" + + " && " + // OS tuning parameters for (distributed) TLC: + // - Disable hugepage defragmentation (especially important on highmem instances) + + "echo never > /sys/kernel/mm/transparent_hugepage/defrag" + + " && " + // - Turn off NUMA balancing + + "echo 0 > /proc/sys/kernel/numa_balancing" + + " && " + // Don't want dpkg to require user interaction. + + "export DEBIAN_FRONTEND=noninteractive" + + " && " + + params.getHostnameSetup() + + " && " + // Oracle Java 8 + + (doJfr ? "add-apt-repository ppa:webupd8team/java -y && " : "/bin/true && ") + // Accept license before apt (dpkg) tries to present it to us (which fails due to 'noninteractive' mode below) + // see http://stackoverflow.com/a/19391042 + + "echo debconf shared/accepted-oracle-license-v1-1 select true | sudo debconf-set-selections && " + + "echo debconf shared/accepted-oracle-license-v1-1 seen true | sudo debconf-set-selections && " + + params.getExtraRepositories() + + " && " + // Update Ubuntu's package index. The public/remote + // package mirrors might have updated. Without + // update, we might try to install outdated packages + // below. This most likely fails with a 404 because + // the packages have been purged from the mirrors. + + "apt-get update" + + " && " + // Never be prompted for input + // Download jmx2munin from the INRIA host + // TODO make it part of Toolbox and upload from + // there (it's tiny 48kb anyway) instead. + // This needs some better build-time integration + // between TLA and jmx2munin (probably best to make + // jmx2munin a submodule of the TLA git repo). + // Download an explicit version (commit) to allow + // us to continue development in HEAD. Otherwise, + // an old Toolbox would use the newest jmx2munin + // which might not be compatible with its CDTLCJob. + + "wget https://github.com/lemmy/jmx2munin/raw/df6ce053a6d178e7a70434ab2f91089acadf0525/jmx2munin_1.0_all.deb" + + " && " +// + "wget http://tla.msr-inria.inria.fr/jmx2munin/jmx2munin_1.0_all.deb && " + // Install jmx2munin into the system + + "dpkg -i jmx2munin_1.0_all.deb ; " + // Force apt to download and install the + // missing dependencies of jmx2munin without + // user interaction + + "apt-get install --no-install-recommends -fy" + + " && " + // Install all security relevant system packages + + "echo unattended-upgrades unattended-upgrades/enable_auto_updates boolean true | debconf-set-selections" + + " && " + // screen is needed to allow us to re-attach + // to the TLC process if logged in to the + // instance directly (it's probably already + // installed). zip is used to prepare the + // worker tla2tools.jar (strip spec) and + // unattended-upgrades makes sure the instance + // is up-to-date security-wise. + + "apt-get install --no-install-recommends mdadm e2fsprogs screen zip unattended-upgrades " + + params.getExtraPackages() + " -y" + + " && " + + (doJfr ? "apt-get install --no-install-recommends oracle-java8-installer oracle-java8-set-default -y " : "/bin/true") + + " && " + // Delegate file system tuning to cloud specific code. + + params.getOSFilesystemTuning() + // Install Oracle Java8. It supports Java Mission + // Control, an honest profiler. But first, + // automatically accept the Oracle license because + // installation will fail otherwise. +// + " && " +// + "echo debconf shared/accepted-oracle-license-v1-1 select true | debconf-set-selections && " +// + "add-apt-repository ppa:webupd8team/java -y && " +// + "apt-get update && " +// + "apt-get --no-install-recommends install oracle-java8-installer oracle-java8-set-default -y" + // Create /mnt/tlc and change permission to be world writable + // Requires package 'apache2' to be already installed. apache2 + // creates /var/www/html. + // "/mnt/tlc" is on the ephemeral and thus faster storage of the + // instance. + + " && " + + "mkdir -p /mnt/tlc/ && chmod 777 /mnt/tlc/ && " + + "ln -s /mnt/tlc/MC.out /var/www/html/MC.out && " + + "ln -s /mnt/tlc/MC.out /var/www/html/MC.txt && " // Microsoft IE and Edge fail to show line breaks correctly unless ".txt" extension. + + "ln -s /mnt/tlc/MC.err /var/www/html/MC.err && " + + "ln -s /mnt/tlc/tlc.jfr /var/www/html/tlc.jfr"), + new TemplateOptions().runAsRoot(true).wrapInInitScript( + false)); + throwExceptionOnErrorResponse(execResponse, "Provisioning TLC environment on all nodes"); + monitor.worked(10); + if (monitor.isCanceled()) { + return createNodesInGroup; + } + + // Install all security relevant system packages + monitor.subTask("Installing security relevant system package upgrades (in background)"); + execResponse = compute.runScriptOnNodesMatching( + inGroup(groupNameUUID), + exec("screen -dm -S security bash -c \"/usr/bin/unattended-upgrades\""), + new TemplateOptions().runAsRoot(true).wrapInInitScript( + true).blockOnComplete(false).blockUntilRunning(false)); + throwExceptionOnErrorResponse(execResponse, "Installing security relevant system package upgrades"); + monitor.worked(5); + + return createNodesInGroup; + } + private void throwExceptionOnErrorResponse(final Map<? extends NodeMetadata, ExecResponse> execResponse, final String step) { execResponse.forEach((node, exec) -> { // If the script above failed on any number of nodes for whatever reason, don't @@ -549,6 +650,14 @@ public class CloudDistributedTLCJob extends Job { } }); } + + private void throwExceptionOnErrorResponse(final NodeMetadata node, final ExecResponse execResponse, final String step) { + // If the script above failed on any number of nodes for whatever reason, don't + // continue but destroy all nodes. + if (execResponse.getExitStatus() > 0) { + throw new ScriptException(node, execResponse, step); + } + } public void setIsCLI(boolean cli) { this.isCLI = cli; @@ -590,16 +699,62 @@ public class CloudDistributedTLCJob extends Job { class CloudStatus extends Status implements ITLCJobStatus { private final URL url; + private final InputStream output; + private final SshClient sshClient; public CloudStatus(int severity, String pluginId, int code, - String message, Throwable exception, URL url) { + String message, Throwable exception, URL url, InputStream output, SshClient sshClient) { super(severity, pluginId, code, message, exception); this.url = url; + this.output = output; + this.sshClient = sshClient; } @Override public URL getURL() { return url; } + + @Override + public InputStream getOutput() { + return this.output; + } + + public void killTLC() { + // For some reason shutdown has to be called before kill (shrugs). + sshClient.execChannel( + String.format("sudo shutdown -h +%s && kill $(pgrep -f tla2tools.jar)", SHUTDOWN_AFTER)); + } + } + + /* + <nacx> jclouds uses a Credential store to persist node credentials + <nacx> if you use the same context after creating a node, the credentials should already be in the credential store + <nacx> the default implementation is in-memory and lives per-ćontext + <nacx> but you can easily create a persistent credential store and use it + <nacx> when creating the context, you can apss your custom credentialstore module + <nacx> https://jclouds.apache.org/reference/javadoc/2.1.x/org/jclouds/rest/config/CredentialStoreModule.html + <nacx> you can instantiate it providing a Map + <nacx> that will hold the credentials. + <nacx> It is up to you to persist that map the way you prefer + */ + + //TODO Does this work on Mac and Windows? + private static LoginCredentials getLoginForCommandExecution() throws IOException { + final String user = System.getProperty("user.name"); + final String privateKey = Files.toString(new File(System.getProperty("user.home") + "/.ssh/id_rsa"), + Charsets.UTF_8); + return LoginCredentials.builder().user(user).privateKey(privateKey).build(); + } + + // TODO Somehow override credentials in wrapped instead of creating wrapper + // instance? + class WrapperNodeMetadata extends NodeMetadataImpl { + public WrapperNodeMetadata(final NodeMetadata m, final LoginCredentials credentials) { + super(m.getProviderId(), m.getName(), m.getId(), m.getLocation(), m.getUri(), m.getUserMetadata(), + m.getTags(), m.getGroup(), m.getHardware(), m.getImageId(), m.getOperatingSystem(), m.getStatus(), + m.getBackendStatus(), m.getLoginPort(), m.getPublicAddresses(), m.getPrivateAddresses(), + credentials, m.getHostname()); + } } } diff --git a/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/EC2CloudTLCInstanceParameters.java b/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/EC2CloudTLCInstanceParameters.java index cc0146fd5823f123f0a999b74ff526f671d58afd..566b30456ca77a4b8a346e803e0659694ad6fab4 100644 --- a/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/EC2CloudTLCInstanceParameters.java +++ b/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/EC2CloudTLCInstanceParameters.java @@ -75,7 +75,9 @@ public class EC2CloudTLCInstanceParameters extends CloudTLCInstanceParameters { return new Status(Status.ERROR, "org.lamport.tla.toolbox.jcloud", "Invalid credentials, please check the environment variables " + "(AWS_ACCESS_KEY_ID & AWS_SECRET_ACCESS_KEY) are correctly " - + "set up and picked up by the Toolbox."); + + "set up and picked up by the Toolbox." + + "\n\nPlease visit the Toolbox help and read section 4 " + + "of \"Cloud based distributed TLC\" on how to setup authentication."); } /* (non-Javadoc) @@ -105,13 +107,13 @@ public class EC2CloudTLCInstanceParameters extends CloudTLCInstanceParameters { */ @Override public String getImageId() { - // Ubuntu 64bit 16.04 Xenial + // Ubuntu 64bit 18.04 Xenial // http://cloud-images.ubuntu.com/locator/ec2/ // See http://aws.amazon.com/amazon-linux-ami/instance-type-matrix/ // for paravirtual vs. hvm (if instance startup fails with funny errors // such as symlinks failing to be created, you accidentally picked paravirtual. - // "us-east-1,xenial,amd64,hvm:instance-store" - final String imageId = System.getProperty("aws-ec2.image", "ami-51025a2b"); + // "us-east-1,bionic,amd64,hvm:instance-store" + final String imageId = System.getProperty("aws-ec2.image", "ami-9fedbbe0"); return getRegion() + "/" + imageId; } diff --git a/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/PayloadHelper.java b/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/PayloadHelper.java index ad9f09ba58260e1b24f9629eabbe0d15e835e16e..b35098915118c6b26b445808a680256751b11bd1 100644 --- a/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/PayloadHelper.java +++ b/org.lamport.tla.toolbox.jclouds/src/org/lamport/tla/toolbox/jcloud/PayloadHelper.java @@ -62,7 +62,6 @@ import org.osgi.framework.FrameworkUtil; public class PayloadHelper { public static Payload appendModel2Jar(final Path modelPath, String mainClass, Properties properties, IProgressMonitor monitor) throws IOException { - monitor.subTask("Tweaking tla2tools.jar to contain the spec & model"); /* * Get the standard tla2tools.jar from the classpath as a blueprint. @@ -98,8 +97,9 @@ public class PayloadHelper { try (FileSystem fs = FileSystems.newFileSystem(uri, env)) { /* * Copy the spec and model into the jar's model/ folder. + * Also copy any module override (.class file) into the jar. */ - try (DirectoryStream<Path> modelDirectoryStream = Files.newDirectoryStream(modelPath, "*.{cfg,tla}")) { + try (DirectoryStream<Path> modelDirectoryStream = Files.newDirectoryStream(modelPath, "*.{cfg,tla,class}")) { for (final Path file: modelDirectoryStream) { final Path to = fs.getPath("/model/" + file.getFileName()); Files.copy(file, to, StandardCopyOption.REPLACE_EXISTING); diff --git a/org.lamport.tla.toolbox.product.product/TLAToolbox.target b/org.lamport.tla.toolbox.product.product/TLAToolbox.target index a1554e902856f6bb685dc157fe26396e87c9afec..2f0af13360adceea3f6ecab3e2990f3a7ec5ca17 100644 --- a/org.lamport.tla.toolbox.product.product/TLAToolbox.target +++ b/org.lamport.tla.toolbox.product.product/TLAToolbox.target @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?> -<?pde version="3.8"?><target name="TLA+ Toolbox" sequenceNumber="79"> +<?pde version="3.8"?><target name="TLA+ Toolbox" sequenceNumber="82"> <locations> <location includeAllPlatforms="false" includeConfigurePhase="false" includeMode="planner" includeSource="true" type="InstallableUnit"> <unit id="org.eclipse.contribution.weaving.feature.group" version="2.2.4.201704242114"/> @@ -30,21 +30,21 @@ <repository location="http://lemmy.github.com/jclouds2p2/"/> </location> <location includeAllPlatforms="false" includeConfigurePhase="false" includeMode="planner" includeSource="true" type="InstallableUnit"> -<unit id="org.eclipse.rcp.id" version="4.7.0.I20170612-0950"/> -<unit id="org.eclipse.help.feature.group" version="2.2.100.v20170612-0950"/> -<unit id="org.eclipse.equinox.core.sdk.feature.group" version="3.13.0.v20170516-1513"/> -<unit id="org.eclipse.rcp.sdk.id" version="4.7.0.I20170612-0950"/> -<unit id="org.eclipse.platform.ide" version="4.7.0.I20170612-0950"/> -<unit id="org.eclipse.rcp.configuration.feature.group" version="1.1.0.v20170612-0950"/> +<unit id="org.eclipse.rcp.id" version="4.7.3.M20180330-0640"/> +<unit id="org.eclipse.help.feature.group" version="2.2.104.v20180330-0640"/> +<unit id="org.eclipse.equinox.core.sdk.feature.group" version="3.13.2.v20180210-1608"/> +<unit id="org.eclipse.rcp.sdk.id" version="4.7.3.M20180330-0640"/> +<unit id="org.eclipse.platform.ide" version="4.7.3.M20180330-0640"/> +<unit id="org.eclipse.rcp.configuration.feature.group" version="1.1.4.v20180330-0640"/> <unit id="org.eclipse.emf.ecore.feature.group" version="2.13.0.v20170609-0707"/> -<unit id="org.eclipse.equinox.executable" version="3.7.0.v20170531-1133"/> +<unit id="org.eclipse.equinox.executable" version="3.7.2.v20171108-1834"/> <unit id="org.eclipse.ecf.core.feature.feature.group" version="1.4.0.v20170516-2248"/> -<unit id="org.eclipse.e4.rcp.feature.group" version="1.6.0.v20170612-1255"/> -<unit id="org.eclipse.platform.sdk" version="4.7.0.I20170612-0950"/> +<unit id="org.eclipse.e4.rcp.feature.group" version="1.6.3.v20180329-0507"/> +<unit id="org.eclipse.platform.sdk" version="4.7.3.M20180330-0640"/> <unit id="org.eclipse.emf.common.feature.group" version="2.13.0.v20170609-0707"/> -<unit id="org.eclipse.equinox.sdk.feature.group" version="3.13.0.v20170531-1133"/> -<unit id="org.eclipse.core.runtime.feature.feature.group" version="1.2.0.v20170518-1049"/> -<unit id="org.eclipse.sdk.ide" version="4.7.0.I20170612-0950"/> +<unit id="org.eclipse.equinox.sdk.feature.group" version="3.13.4.v20180322-2228"/> +<unit id="org.eclipse.core.runtime.feature.feature.group" version="1.2.2.v20180210-1608"/> +<unit id="org.eclipse.sdk.ide" version="4.7.3.M20180330-0640"/> <repository location="http://download.eclipse.org/eclipse/updates/4.7/" id="eclipse"/> </location> <location includeAllPlatforms="false" includeConfigurePhase="false" includeMode="planner" includeSource="true" type="InstallableUnit"> @@ -55,6 +55,19 @@ <unit id="com.abstratt.eclipsegraphviz.feature.feature.group" version="2.1.201501.201606262232"/> <repository location="jar:http://repository-textuml.forge.cloudbees.com/snapshot/com/abstratt/eclipsegraphviz/com.abstratt.eclipsegraphviz.repository/2.1.201501/com.abstratt.eclipsegraphviz.repository-2.1.201501.zip!/"/> </location> +<location includeAllPlatforms="false" includeConfigurePhase="false" includeMode="planner" includeSource="true" type="InstallableUnit"> +<unit id="org.eclipse.recommenders.news.rcp.feature.feature.group" version="2.5.0.v20171201-1623"/> +<repository location="http://download.eclipse.org/releases/oxygen"/> +</location> +<location includeAllPlatforms="false" includeConfigurePhase="false" includeMode="planner" includeSource="true" type="InstallableUnit"> +<unit id="org.apache.commons.collections" version="3.2.2.v201511171945"/> +<repository location="http://download.eclipse.org/tools/orbit/downloads/drops/R20170919201930/repository"/> +</location> +<location includeAllPlatforms="false" includeConfigurePhase="false" includeMode="planner" includeSource="true" type="InstallableUnit"> +<unit id="org.eclipse.mylyn.commons.feature.group" version="3.21.0.v20160707-1856"/> +<unit id="org.eclipse.mylyn.commons.notifications.feature.group" version="1.13.0.v20160721-2347"/> +<repository location="http://download.eclipse.org/mylyn/releases/3.21"/> +</location> </locations> <targetJRE path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/> </target> diff --git a/org.lamport.tla.toolbox.product.product/org.lamport.tla.toolbox.product.product.product b/org.lamport.tla.toolbox.product.product/org.lamport.tla.toolbox.product.product.product index 40c02f80a09e1516c34d004ea4c57081c28a988a..5efc5d875353a521cbb4b495385c04ee657468e6 100644 --- a/org.lamport.tla.toolbox.product.product/org.lamport.tla.toolbox.product.product.product +++ b/org.lamport.tla.toolbox.product.product/org.lamport.tla.toolbox.product.product.product @@ -1,17 +1,17 @@ <?xml version="1.0" encoding="UTF-8"?> <?pde version="3.5"?> -<product name="TLA+ Toolbox" uid="org.lamport.tla.toolbox.product.product" id="org.lamport.tla.toolbox.product.standalone.product" application="org.lamport.tla.toolbox.application" version="1.5.6.qualifier" useFeatures="true" includeLaunchers="true"> +<product name="TLA+ Toolbox" uid="org.lamport.tla.toolbox.product.product" id="org.lamport.tla.toolbox.product.standalone.product" application="org.lamport.tla.toolbox.application" version="1.5.7.qualifier" useFeatures="true" includeLaunchers="true"> <aboutInfo> <image path="/org.lamport.tla.toolbox.product.standalone/images/splash_small.png"/> <text> TLA+ Toolbox provides a user interface for TLA+ Tools. -This is Version 1.5.6 of 29 January 2018 and includes: +This is Version 1.5.7 of 18 July 2018 and includes: - SANY Version 2.1 of 23 July 2017 - - TLC Version 2.12 of 29 January 2018 - - PlusCal Version 1.8 of 07 December 2015 + - TLC Version 2.13 of 18 July 2018 + - PlusCal Version 1.8 of 16 May 2018 - TLATeX Version 1.0 of 20 September 2017 Don't forget to click on help. You can learn about features that you never knew about or have forgotten. @@ -83,7 +83,7 @@ openFile <plugin id="org.eclipse.update.configurator"/> <plugin id="org.lamport.tla.toolbox.jclouds" autoStart="true" startLevel="4" /> <plugin id="sts" autoStart="true" startLevel="4" /> - <property name="eclipse.buildId" value="1.5.6" /> + <property name="eclipse.buildId" value="1.5.7" /> </configurations> <repositories> diff --git a/org.lamport.tla.toolbox.product.product/pom.xml b/org.lamport.tla.toolbox.product.product/pom.xml index 677493d61447a7e2b3db34aa550c23aa9205f6fa..7ee073515578f30521855389520febb1ed136360 100644 --- a/org.lamport.tla.toolbox.product.product/pom.xml +++ b/org.lamport.tla.toolbox.product.product/pom.xml @@ -19,7 +19,7 @@ <!-- Align product.version with the version in org.lamport.tla.toolbox.product.product.product product.version. --> - <product.version>1.5.6</product.version> + <product.version>1.5.7</product.version> <!-- Format build timestamp to adhere to the Debian package guidelines --> <maven.build.timestamp.format>yyyyMMdd-HHmm</maven.build.timestamp.format> <product.build>${maven.build.timestamp}</product.build> diff --git a/org.lamport.tla.toolbox.product.standalone/plugin.xml b/org.lamport.tla.toolbox.product.standalone/plugin.xml index 279444dede17aa3a097718c329cbc6fafdffc5d7..76d7299e36ff4bf97d6c4c58f9d62be810653caf 100644 --- a/org.lamport.tla.toolbox.product.standalone/plugin.xml +++ b/org.lamport.tla.toolbox.product.standalone/plugin.xml @@ -30,7 +30,7 @@ </property> <property name="aboutText" - value="TLA+ Toolbox provides a user interface for TLA+ Tools. 

This is Version 1.5.6 of 29 January 2018 and includes:
 - SANY Version 2.1 of 23 July 2017
 - TLC Version 2.12 of 29 January 2018
 - PlusCal Version 1.8 of 07 December 2015
 - TLATeX Version 1.0 of 20 September 2017

Don't forget to click on help. You can learn about features that you never knew about or have forgotten.

Please send us reports of problems or suggestions; see https://groups.google.com/d/forum/tlaplus ."> + value="TLA+ Toolbox provides a user interface for TLA+ Tools. 

This is Version 1.5.7 of 18 July 2018 and includes:
 - SANY Version 2.1 of 23 July 2017
 - TLC Version 2.13 of 18 July 2018
 - PlusCal Version 1.8 of 16 May 2018
 - TLATeX Version 1.0 of 20 September 2017

Don't forget to click on help. You can learn about features that you never knew about or have forgotten.

Please send us reports of problems or suggestions; see https://groups.google.com/d/forum/tlaplus ."> </property> <property name="aboutImage" diff --git a/org.lamport.tla.toolbox.product.standalone/src/org/lamport/tla/toolbox/Application.java b/org.lamport.tla.toolbox.product.standalone/src/org/lamport/tla/toolbox/Application.java index fffde044e54a2718bf9494ba18513c2758b8e37c..bdae27eae9b4f374598df6414412bda7682a36c6 100644 --- a/org.lamport.tla.toolbox.product.standalone/src/org/lamport/tla/toolbox/Application.java +++ b/org.lamport.tla.toolbox.product.standalone/src/org/lamport/tla/toolbox/Application.java @@ -144,6 +144,14 @@ public class Application implements IApplication { return IApplication.EXIT_RESTART; } return IApplication.EXIT_OK; + } catch (Exception e) { + throw new RuntimeException(e) { + @Override + public String toString() { + return "The Toolbox failed to launch because of an unexpected error. Please try to launch the Toolbox with the \"-clean\" parameter.\n" + + "If \"-clean\" does not fix the problem, please open a bug and attach the .log file.\n\n" + super.toString(); + } + }; } finally { display.dispose(); } diff --git a/org.lamport.tla.toolbox.product.standalone/src/org/lamport/tla/toolbox/ui/intro/ToolboxIntroPart.java b/org.lamport.tla.toolbox.product.standalone/src/org/lamport/tla/toolbox/ui/intro/ToolboxIntroPart.java index a0060c28ca84f47f79122fc2c949f514e68e01e2..e8f4c6e1529f457d6eb328f2b36bab31a631d282 100644 --- a/org.lamport.tla.toolbox.product.standalone/src/org/lamport/tla/toolbox/ui/intro/ToolboxIntroPart.java +++ b/org.lamport.tla.toolbox.product.standalone/src/org/lamport/tla/toolbox/ui/intro/ToolboxIntroPart.java @@ -175,7 +175,7 @@ public class ToolboxIntroPart extends IntroPart implements IIntroPart { final Label lblVersion = new Label(outerContainer, SWT.WRAP); lblVersion.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 2, 1)); - lblVersion.setText("Version 1.5.6 of 29 January 2018"); + lblVersion.setText("Version 1.5.7 of 18 July 2018"); lblVersion.setBackground(backgroundColor); } diff --git a/org.lamport.tla.toolbox.tool.tlc.ui.test/src/org/lamport/tla/toolbox/tool/tlc/output/data/StateSpaceInformationItemTest.java b/org.lamport.tla.toolbox.tool.tlc.ui.test/src/org/lamport/tla/toolbox/tool/tlc/output/data/StateSpaceInformationItemTest.java index 2ea6f70223d6c21f9c2146a0d2972a9deb68fe7c..16d09f54ff85a1f4c412824325b41bfff9314582 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui.test/src/org/lamport/tla/toolbox/tool/tlc/output/data/StateSpaceInformationItemTest.java +++ b/org.lamport.tla.toolbox.tool.tlc.ui.test/src/org/lamport/tla/toolbox/tool/tlc/output/data/StateSpaceInformationItemTest.java @@ -35,5 +35,53 @@ public class StateSpaceInformationItemTest extends TestCase { assertEquals(658832, parsed.getSpm()); assertEquals(9127, parsed.getDistinctSPM()); } + + /** + * Test method for + * {@link org.lamport.tla.toolbox.tool.tlc.output.data.StateSpaceInformationItem#parseInit(java.lang.String)} + * . + */ + public void testParseInit() { + StateSpaceInformationItem parsed = StateSpaceInformationItem + .parseInit("Finished computing initial states: 123456789 distinct states generated."); + assertEquals(0, parsed.getDiameter()); + assertEquals(123456789, parsed.getDistinctStates()); + assertEquals(123456789, parsed.getFoundStates()); + assertEquals(123456789, parsed.getLeftStates()); + assertEquals(0, parsed.getSpm()); + assertEquals(0, parsed.getDistinctSPM()); + } + + public void testParseInit2() { + StateSpaceInformationItem parsed = StateSpaceInformationItem + .parseInit("Finished computing initial states: 1 distinct state generated."); + assertEquals(0, parsed.getDiameter()); + assertEquals(1, parsed.getDistinctStates()); + assertEquals(1, parsed.getFoundStates()); + assertEquals(1, parsed.getLeftStates()); + assertEquals(0, parsed.getSpm()); + assertEquals(0, parsed.getDistinctSPM()); + } + + public void testParseInit3() { + StateSpaceInformationItem parsed = StateSpaceInformationItem + .parseInit("Finished computing initial states: 123456789 states generated, with 123 of them distinct."); + assertEquals(0, parsed.getDiameter()); + assertEquals(123, parsed.getDistinctStates()); + assertEquals(123456789, parsed.getFoundStates()); + assertEquals(123, parsed.getLeftStates()); + assertEquals(0, parsed.getSpm()); + assertEquals(0, parsed.getDistinctSPM()); + } + public void testParseInit4() { + StateSpaceInformationItem parsed = StateSpaceInformationItem + .parseInit("Finished computing initial states: 2 states generated, with 1 of them distinct."); + assertEquals(0, parsed.getDiameter()); + assertEquals(1, parsed.getDistinctStates()); + assertEquals(2, parsed.getFoundStates()); + assertEquals(1, parsed.getLeftStates()); + assertEquals(0, parsed.getSpm()); + assertEquals(0, parsed.getDistinctSPM()); + } } diff --git a/org.lamport.tla.toolbox.tool.tlc.ui.test/src/org/lamport/tla/toolbox/tool/tlc/output/source/Bug267Listener.java b/org.lamport.tla.toolbox.tool.tlc.ui.test/src/org/lamport/tla/toolbox/tool/tlc/output/source/Bug267Listener.java index 8dc17b242aedb7d86bd80d56870714696ef3f4ba..3fc87259b6fd8bc1d01a5eb49d7c1837d3d05994 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui.test/src/org/lamport/tla/toolbox/tool/tlc/output/source/Bug267Listener.java +++ b/org.lamport.tla.toolbox.tool.tlc.ui.test/src/org/lamport/tla/toolbox/tool/tlc/output/source/Bug267Listener.java @@ -35,7 +35,6 @@ public class Bug267Listener extends TLCModelLaunchDataProvider implements lastDetectedError = null; coverageInfo = new Vector<CoverageInformationItem>(); progressInformation = new Vector<StateSpaceInformationItem>(); - startTime = 0; startTimestamp = Long.MIN_VALUE; finishTimestamp = Long.MIN_VALUE; lastCheckpointTimeStamp = Long.MIN_VALUE; diff --git a/org.lamport.tla.toolbox.tool.tlc.ui.uitest/META-INF/MANIFEST.MF b/org.lamport.tla.toolbox.tool.tlc.ui.uitest/META-INF/MANIFEST.MF index be0afd2a67b0456768ca7381468cfdbb3f78fc33..7d12e074a3f589529d9271c8986f85e9a213a6ac 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui.uitest/META-INF/MANIFEST.MF +++ b/org.lamport.tla.toolbox.tool.tlc.ui.uitest/META-INF/MANIFEST.MF @@ -12,7 +12,9 @@ Require-Bundle: org.lamport.tla.toolbox;bundle-version="1.0.0", org.eclipse.core.resources;bundle-version="3.5.0", org.eclipse.debug.core;bundle-version="3.5.0", org.eclipse.ui.editors;bundle-version="3.6.0", - org.eclipse.ui.workbench + org.eclipse.ui.workbench, + org.eclipse.jface.text;bundle-version="3.12.0", + org.apache.commons.io;bundle-version="2.0.1" Import-Package: org.osgi.framework;version="1.3.0" Bundle-RequiredExecutionEnvironment: J2SE-1.5 Bundle-Vendor: Leslie Lamport, Markus Alexander Kuppe diff --git a/org.lamport.tla.toolbox.tool.tlc.ui.uitest/pom.xml b/org.lamport.tla.toolbox.tool.tlc.ui.uitest/pom.xml index 8e015c4f7c789ecd09d06ab52efbf86f4966f0c0..663f6bad89fb71a7cf6ef99650e482417bb5d247 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui.uitest/pom.xml +++ b/org.lamport.tla.toolbox.tool.tlc.ui.uitest/pom.xml @@ -54,6 +54,7 @@ <systemProperties combine.children="append"> <!-- References used by tests to access spec files --> + <org.lamport.tla.toolbox.tool.tlc.ui.test.PathToSpecC>${project.build.directory}/../../org.lamport.tla.toolbox.uitest/farsite/GotoDefinition.tla</org.lamport.tla.toolbox.tool.tlc.ui.test.PathToSpecC> <org.lamport.tla.toolbox.tool.tlc.ui.test.PathToSpecB>${project.build.directory}/../../org.lamport.tla.toolbox.uitest/farsite/DistributedSystemModule.tla</org.lamport.tla.toolbox.tool.tlc.ui.test.PathToSpecB> <org.lamport.tla.toolbox.tool.tlc.ui.test.PathToSpecA>${project.build.directory}/../../org.lamport.tla.toolbox.uitest/DieHard/DieHard.tla</org.lamport.tla.toolbox.tool.tlc.ui.test.PathToSpecA> <!-- JDT weaving debug output --> diff --git a/org.lamport.tla.toolbox.tool.tlc.ui.uitest/src/org/lamport/tla/toolbox/tool/tlc/ui/test/AbstractTest.java b/org.lamport.tla.toolbox.tool.tlc.ui.uitest/src/org/lamport/tla/toolbox/tool/tlc/ui/test/AbstractTest.java index 7fa147f8c268f7369777050b535c73ffa77f130a..41a43564312f006796ef41e774add23a727695d5 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui.uitest/src/org/lamport/tla/toolbox/tool/tlc/ui/test/AbstractTest.java +++ b/org.lamport.tla.toolbox.tool.tlc.ui.uitest/src/org/lamport/tla/toolbox/tool/tlc/ui/test/AbstractTest.java @@ -17,7 +17,11 @@ import org.eclipse.ui.PlatformUI; import org.hamcrest.Matcher; import org.junit.Assert; import org.junit.Before; +import org.lamport.tla.toolbox.Activator; +import org.lamport.tla.toolbox.spec.Spec; import org.lamport.tla.toolbox.test.RCPTestSetupHelper; +import org.lamport.tla.toolbox.tool.tlc.model.Model; +import org.lamport.tla.toolbox.tool.tlc.model.TLCSpec; public abstract class AbstractTest { @@ -51,6 +55,7 @@ public abstract class AbstractTest { /** * Pre flight initialization (run once for each test _case_) */ + @SuppressWarnings("unchecked") // Generics in WidgetMatcherFactory.allOf invocation @Before public void setUp() throws Exception { // Force shell activation to counter, no active Shell when running SWTBot tests in Xvfb/Xvnc @@ -92,4 +97,20 @@ public abstract class AbstractTest { bot.waitUntil(waitForShell); return new SWTBotShell(waitForShell.get(0)); } + + /** + * Verifies that the spec and model show expected state (via API!!!) + * + * @param modelName if null, the model's existence will not be checked + */ + protected void checkSpecAndModelExistenceAPI(final String expectedSpecName, final String modelName) { + final Spec spec = Activator.getSpecManager().getSpecLoaded(); + Assert.assertEquals(expectedSpecName, spec.getName()); + + if (modelName != null) { + final Model model = spec.getAdapter(TLCSpec.class).getModel(modelName); + Assert.assertNotNull("Model could not be found", model); + } + } + } diff --git a/org.lamport.tla.toolbox.tool.tlc.ui.uitest/src/org/lamport/tla/toolbox/tool/tlc/ui/test/DummyJobChangeListener.java b/org.lamport.tla.toolbox.tool.tlc.ui.uitest/src/org/lamport/tla/toolbox/tool/tlc/ui/test/DummyJobChangeListener.java index 61f6a36ee50ced30e00fd1a3efe9eabf148e59e5..4526f1b153d7201055b13460ccd86d5b2a679748 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui.uitest/src/org/lamport/tla/toolbox/tool/tlc/ui/test/DummyJobChangeListener.java +++ b/org.lamport.tla.toolbox.tool.tlc.ui.uitest/src/org/lamport/tla/toolbox/tool/tlc/ui/test/DummyJobChangeListener.java @@ -3,6 +3,7 @@ package org.lamport.tla.toolbox.tool.tlc.ui.test; import org.eclipse.core.runtime.jobs.IJobChangeEvent; import org.eclipse.core.runtime.jobs.IJobChangeListener; import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.swtbot.swt.finder.utils.internal.Assert; import org.eclipse.swtbot.swt.finder.waits.DefaultCondition; import org.eclipse.swtbot.swt.finder.waits.ICondition; import org.lamport.tla.toolbox.tool.tlc.model.Model; @@ -14,6 +15,7 @@ public class DummyJobChangeListener extends DefaultCondition implements IJobChan private Job job; public DummyJobChangeListener(final Model model) { + Assert.isNotNull(model); this.model = model; } diff --git a/org.lamport.tla.toolbox.tool.tlc.ui.uitest/src/org/lamport/tla/toolbox/ui/handler/CloneModelTest.java b/org.lamport.tla.toolbox.tool.tlc.ui.uitest/src/org/lamport/tla/toolbox/ui/handler/CloneModelTest.java index a821dc2d6fd2dc1efa9fbc2ee952ec84efb90d83..4a22fd9753567153982e429c170b6c379307e083 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui.uitest/src/org/lamport/tla/toolbox/ui/handler/CloneModelTest.java +++ b/org.lamport.tla.toolbox.tool.tlc.ui.uitest/src/org/lamport/tla/toolbox/ui/handler/CloneModelTest.java @@ -8,15 +8,11 @@ import org.eclipse.swtbot.swt.finder.junit.SWTBotJunit4ClassRunner; import org.eclipse.swtbot.swt.finder.matchers.WithText; import org.eclipse.swtbot.swt.finder.waits.Conditions; import org.eclipse.swtbot.swt.finder.widgets.SWTBotMenu; -import org.junit.Assert; + import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; -import org.lamport.tla.toolbox.Activator; -import org.lamport.tla.toolbox.spec.Spec; -import org.lamport.tla.toolbox.tool.tlc.model.Model; -import org.lamport.tla.toolbox.tool.tlc.model.TLCSpec; import org.lamport.tla.toolbox.tool.tlc.ui.test.AbstractTest; import org.lamport.tla.toolbox.tool.tlc.ui.test.ModelEditorOpenCondition; @@ -65,7 +61,7 @@ public class CloneModelTest extends AbstractTest { SWTBotEditor activeEditor = bot.activeEditor(); activeEditor.saveAndClose(); - checkSpecAndModelExistenceAPI(TEST_SPEC); + checkSpecAndModelExistenceAPI(TEST_SPEC, TEST_MODEL); } @Test @@ -79,12 +75,4 @@ public class CloneModelTest extends AbstractTest { bot.waitUntil(new ModelEditorOpenCondition(TEST_MODEL_RENAME)); } - // Verify spec and model show expected state (via API!!!) - private void checkSpecAndModelExistenceAPI(final String specExpected) { - final Spec spec = Activator.getSpecManager().getSpecLoaded(); - Assert.assertEquals(specExpected, spec.getName()); - - final Model model = spec.getAdapter(TLCSpec.class).getModel(TEST_MODEL); - Assert.assertNotNull("Model could not be found", model); - } } diff --git a/org.lamport.tla.toolbox.tool.tlc.ui.uitest/src/org/lamport/tla/toolbox/ui/handler/GotoDefinitionTest.java b/org.lamport.tla.toolbox.tool.tlc.ui.uitest/src/org/lamport/tla/toolbox/ui/handler/GotoDefinitionTest.java new file mode 100644 index 0000000000000000000000000000000000000000..22546e0c9a96a2d5b58e62f08c59019dccc23647 --- /dev/null +++ b/org.lamport.tla.toolbox.tool.tlc.ui.uitest/src/org/lamport/tla/toolbox/ui/handler/GotoDefinitionTest.java @@ -0,0 +1,138 @@ +package org.lamport.tla.toolbox.ui.handler; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.util.ArrayList; + +import org.apache.commons.io.IOUtils; + +import org.eclipse.jface.text.Region; +import org.eclipse.swt.widgets.MenuItem; +import org.eclipse.swtbot.eclipse.finder.widgets.SWTBotEditor; +import org.eclipse.swtbot.swt.finder.junit.SWTBotJunit4ClassRunner; +import org.eclipse.swtbot.swt.finder.matchers.WithText; +import org.eclipse.swtbot.swt.finder.utils.FileUtils; +import org.eclipse.swtbot.swt.finder.waits.Conditions; +import org.eclipse.swtbot.swt.finder.widgets.SWTBotMenu; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.lamport.tla.toolbox.editor.basic.tla.TokenSpec; +import org.lamport.tla.toolbox.test.RCPTestSetupHelper; +import org.lamport.tla.toolbox.tool.tlc.ui.test.AbstractTest; +import org.lamport.tla.toolbox.util.UIHelper; + + +/** + * This test started life to provide test cases related to GitHub issue #106. + */ +@RunWith(SWTBotJunit4ClassRunner.class) +public class GotoDefinitionTest extends AbstractTest { + + private static final String TEST_SPEC_NAME = "GotoDefinition"; + private static final String REPOSITORY_SPEC_PATH = System.getProperty("org.lamport.tla.toolbox.tool.tlc.ui.test.PathToSpec", + RCPTestSetupHelper.getAbsolutePath("org.lamport.tla.toolbox.uitest", + "farsite/GotoDefinition.tla")); + + @BeforeClass + public static void beforeClass () { + // mimic super + AbstractTest.beforeClass(); + } + + @Before + public void setUp () throws Exception { + super.setUp(); + + // load our known spec + SWTBotMenu fileMenu = bot.menu("File"); + SWTBotMenu openSpecMenu = fileMenu.menu("Open Spec"); + SWTBotMenu addNewSpecMenu = openSpecMenu.menu("Add New Spec..."); + addNewSpecMenu.click(); + + String path = System.getProperty("java.io.tmpdir") + File.separator + "GDTest" + System.currentTimeMillis(); + FileUtils.mkdirs(path); + + // Put a copy of the spec into our temporary working directory + path += File.separator + TEST_SPEC_NAME + TLA_SUFFIX; + FileInputStream fis = null; + FileOutputStream fos = null; + try { + fis = new FileInputStream(REPOSITORY_SPEC_PATH); + fos = new FileOutputStream(path); + + IOUtils.copy(fis, fos); + } + finally { + IOUtils.closeQuietly(fis); + IOUtils.closeQuietly(fos); + } + + bot.textWithLabel("Root-module file:").setText(path); + bot.button("Finish").click(); + + bot.waitUntil(Conditions.waitForMenu(bot.activeShell(), WithText.<MenuItem> withText(TEST_SPEC_NAME))); + + checkSpecAndModelExistenceAPI(TEST_SPEC_NAME, null); + } + + /** + * See first issue mentioned in https://github.com/tlaplus/tlaplus/issues/106 + * + * We don't need to test the hyperlink jump, we only need to test that the TokenSpec instance returned by + * TokenSpec.findCurrentTokenSpec(IRegion) has a non-null resolvedSymbol attribute. + */ + @Test + public void verifyTokenSpecSymbolResolution () { + // This region is expected to place the cursor just prior to the subscripted identifier, the 's' in "..._s" in: + // Spec == s = "" /\ [][Next(s)]_s + final Region r = new Region(193, 0); + final ArrayList<TokenSpec> crossThreadSmuggler = new ArrayList<>(); + final Runnable uiRunnable = new Runnable () { + public void run () { + TokenSpec ts = TokenSpec.findCurrentTokenSpec(r); + + synchronized (crossThreadSmuggler) { + crossThreadSmuggler.add(ts); + } + } + }; + final TokenSpec ts; + int size = 0; + int waitCycles = 0; + + UIHelper.runUIAsync(uiRunnable); + while ((size == 0) && (waitCycles < 15)) { + try { + Thread.sleep(575); + } + catch (Exception e) { } // NOPMD + + waitCycles++; + synchronized (crossThreadSmuggler) { + size = crossThreadSmuggler.size(); + } + } + + Assert.assertNotEquals("We timed out waiting for the TokenSpec find.", 0, size); + + ts = crossThreadSmuggler.get(0); + + Assert.assertNotNull("TokenSpec was unable to find any token at " + r.toString(), ts); + + Assert.assertEquals("TokenSpec was not for the expected token, perhaps someone has changed GotoDefinition.tla?", "_s", + ts.token); + + Assert.assertNotNull("TokenSpec was unable to resolve the symbol for the token [" + ts.token + "] at " + r.toString(), + ts.resolvedSymbol); + + // No real reason this need be done from a test functionality perspective + SWTBotEditor activeEditor = bot.activeEditor(); + activeEditor.close(); + } + +} diff --git a/org.lamport.tla.toolbox.tool.tlc.ui.uitest/src/org/lamport/tla/toolbox/ui/handler/RenameSpecHandlerTest.java b/org.lamport.tla.toolbox.tool.tlc.ui.uitest/src/org/lamport/tla/toolbox/ui/handler/RenameSpecHandlerTest.java index 0a15c91280241c34dfe0464f8d13718c125461a8..28018399dc93019aeda0ba3fb52650db234fa61d 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui.uitest/src/org/lamport/tla/toolbox/ui/handler/RenameSpecHandlerTest.java +++ b/org.lamport.tla.toolbox.tool.tlc.ui.uitest/src/org/lamport/tla/toolbox/ui/handler/RenameSpecHandlerTest.java @@ -16,13 +16,12 @@ import org.eclipse.swtbot.swt.finder.waits.ICondition; import org.eclipse.swtbot.swt.finder.widgets.SWTBotMenu; import org.eclipse.swtbot.swt.finder.widgets.SWTBotTreeItem; import org.eclipse.ui.IEditorPart; + import org.junit.Assert; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; -import org.lamport.tla.toolbox.Activator; -import org.lamport.tla.toolbox.spec.Spec; import org.lamport.tla.toolbox.tool.ToolboxHandle; import org.lamport.tla.toolbox.tool.tlc.model.Model; import org.lamport.tla.toolbox.tool.tlc.model.TLCSpec; @@ -80,7 +79,7 @@ public class RenameSpecHandlerTest extends AbstractTest { SWTBotEditor activeEditor = bot.activeEditor(); activeEditor.saveAndClose(); - checkSpecAndModelExistenceAPI(TEST_SPEC); + checkSpecAndModelExistenceAPI(TEST_SPEC, TEST_MODEL); } /** @@ -103,7 +102,7 @@ public class RenameSpecHandlerTest extends AbstractTest { bot.waitUntil(new SpecEditorOpenCondition(TEST_SPEC)); // verify (via API) - checkSpecAndModelExistenceAPI(TEST_SPEC + "_Copy"); + checkSpecAndModelExistenceAPI((TEST_SPEC + "_Copy"), TEST_MODEL); // try to find the renamed file (via UI) openSpecExplorer(); @@ -144,16 +143,6 @@ public class RenameSpecHandlerTest extends AbstractTest { }); } } - - // Verify spec and model show expected state (via API!!!) - private void checkSpecAndModelExistenceAPI(final String specExpected) { - final Spec spec = Activator.getSpecManager().getSpecLoaded(); - Assert.assertEquals(specExpected, spec.getName()); - - - final Model model = spec.getAdapter(TLCSpec.class).getModel(TEST_MODEL); - Assert.assertNotNull("Model could not be found", model); - } // check if the models have been renamed correctly too (via UI!!!) private SWTBotTreeItem checkForModelExistenceUI(final SWTBotTreeItem treeItem) { diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/model_running_remotely.gif b/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/model_running_remotely.gif new file mode 100644 index 0000000000000000000000000000000000000000..b16a5f5d2fbdb407abc85cb79b325af8ae58d630 Binary files /dev/null and b/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/model_running_remotely.gif differ diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/thread_view.png b/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/thread_view.png new file mode 100644 index 0000000000000000000000000000000000000000..b554c423825d2511cd2ac7ec13b6cc0984e8958f Binary files /dev/null and b/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/thread_view.png differ diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/thread_view.svg b/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/thread_view.svg new file mode 100644 index 0000000000000000000000000000000000000000..d0b8c9d36d07bbdeba92c5a782a82f7860e7ff30 --- /dev/null +++ b/org.lamport.tla.toolbox.tool.tlc.ui/icons/full/thread_view.svg @@ -0,0 +1,615 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="16" + height="16" + id="svg2" + version="1.1" + inkscape:version="0.91 r13725" + sodipodi:docname="thread_view.svg"> + <defs + id="defs4"> + <linearGradient + inkscape:collect="always" + id="linearGradient4527"> + <stop + style="stop-color:#e5b165;stop-opacity:1" + offset="0" + id="stop4529" /> + <stop + style="stop-color:#ffffb2;stop-opacity:1" + offset="1" + id="stop4531" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient4505"> + <stop + style="stop-color:#766059;stop-opacity:1" + offset="0" + id="stop4507" /> + <stop + id="stop4515" + offset="0.707578" + style="stop-color:#766059;stop-opacity:1;" /> + <stop + style="stop-color:#766059;stop-opacity:1" + offset="1" + id="stop4509" /> + </linearGradient> + <linearGradient + id="linearGradient5281-7"> + <stop + style="stop-color:#df9f3f;stop-opacity:1" + offset="0" + id="stop5283-0" /> + <stop + id="stop5289-6" + offset="0.5" + style="stop-color:#ffbf3f;stop-opacity:1" /> + <stop + style="stop-color:#ffff9f;stop-opacity:1" + offset="1" + id="stop5285-8" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient5291"> + <stop + style="stop-color:#543830;stop-opacity:1" + offset="0" + id="stop5293" /> + <stop + style="stop-color:#543830;stop-opacity:1" + offset="1" + id="stop5295" /> + </linearGradient> + <linearGradient + y2="3.9463863" + x2="31.543701" + y1="11.3844" + x1="31.543701" + gradientTransform="translate(-19.96875,1034.3779)" + gradientUnits="userSpaceOnUse" + id="linearGradient11768" + xlink:href="#linearGradient5281-7" + inkscape:collect="always" /> + <linearGradient + y2="3.5787904" + x2="35.168701" + y1="11.4469" + x1="35.168701" + gradientTransform="translate(-19.96875,1034.3779)" + gradientUnits="userSpaceOnUse" + id="linearGradient11770" + xlink:href="#linearGradient5291" + inkscape:collect="always" /> + <linearGradient + id="linearGradient5281-7-7"> + <stop + style="stop-color:#df9f3f;stop-opacity:1" + offset="0" + id="stop5283-0-40" /> + <stop + id="stop5289-6-9" + offset="0.5" + style="stop-color:#ffbf3f;stop-opacity:1" /> + <stop + style="stop-color:#ffff9f;stop-opacity:1" + offset="1" + id="stop5285-8-4" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient5291-2"> + <stop + style="stop-color:#543830;stop-opacity:1" + offset="0" + id="stop5293-45" /> + <stop + style="stop-color:#543830;stop-opacity:1" + offset="1" + id="stop5295-5" /> + </linearGradient> + <linearGradient + y2="3.9463863" + x2="31.543701" + y1="11.3844" + x1="31.543701" + gradientTransform="translate(-26.947303,1039.2225)" + gradientUnits="userSpaceOnUse" + id="linearGradient10889" + xlink:href="#linearGradient5281-7-7" + inkscape:collect="always" /> + <linearGradient + y2="3.5787904" + x2="35.168701" + y1="11.4469" + x1="35.168701" + gradientTransform="translate(-26.947303,1039.2225)" + gradientUnits="userSpaceOnUse" + id="linearGradient10891" + xlink:href="#linearGradient5291-2" + inkscape:collect="always" /> + <mask + maskUnits="userSpaceOnUse" + id="mask11187"> + <g + style="fill:#ffffff;stroke:#ffffff;display:inline" + id="g11189"> + <path + sodipodi:nodetypes="czc" + inkscape:connector-curvature="0" + id="path11191" + d="m 3.0351066,1040.3678 c 0,0 1.557292,-2.5625 4.4999994,-2.5625 2.942708,0 4.5,2.5625 4.5,2.5625" + style="fill:#ffffff;stroke:#ffffff;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /> + <path + inkscape:connector-curvature="0" + id="path11193" + d="m 2.0351066,1041.3678 3.453125,0 -3.453125,-3.4531 z" + style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;display:inline" /> + <path + sodipodi:nodetypes="czc" + inkscape:connector-curvature="0" + id="path11195" + d="m 13.003856,1048.3678 c 0,0 -1.557292,2.5625 -4.4999994,2.5625 -2.942708,0 -4.5,-2.5625 -4.5,-2.5625" + style="fill:#ffffff;stroke:#ffffff;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline" /> + <path + inkscape:connector-curvature="0" + id="path11197" + d="m 14.003856,1047.3678 -3.453125,0 3.453125,3.4531 z" + style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;display:inline" /> + </g> + </mask> + <linearGradient + y2="1043.8591" + x2="15.523204" + y1="1043.8591" + x1="7.4779682" + gradientUnits="userSpaceOnUse" + id="linearGradient3268" + xlink:href="#linearGradient3851-3" + inkscape:collect="always" /> + <linearGradient + id="linearGradient3851-3"> + <stop + style="stop-color:#ffffff;stop-opacity:1;" + offset="0" + id="stop3853-2" /> + <stop + id="stop3863-0" + offset="0.5" + style="stop-color:#ffffff;stop-opacity:0.82198954;" /> + <stop + style="stop-color:#ffffff;stop-opacity:0;" + offset="1" + id="stop3855-4" /> + </linearGradient> + <linearGradient + y2="1043.8591" + x2="15.523204" + y1="1043.8591" + x1="7.4779682" + gradientUnits="userSpaceOnUse" + id="linearGradient3140-3" + xlink:href="#linearGradient3851-3" + inkscape:collect="always" /> + <linearGradient + id="linearGradient3087"> + <stop + style="stop-color:#ffffff;stop-opacity:1;" + offset="0" + id="stop3089" /> + <stop + id="stop3091" + offset="0.5" + style="stop-color:#ffffff;stop-opacity:0.82198954;" /> + <stop + style="stop-color:#ffffff;stop-opacity:0;" + offset="1" + id="stop3093" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient4011-8" + id="linearGradient4009-9" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(-1,0,0,-1,20.194842,2087.7734)" + x1="8.8282804" + y1="1040.8593" + x2="8.8061829" + y2="1045.5326" /> + <linearGradient + id="linearGradient4011-8"> + <stop + id="stop4013-6" + offset="0" + style="stop-color:#e0b575;stop-opacity:1;" /> + <stop + style="stop-color:#f5ca75;stop-opacity:1" + offset="0.47158596" + id="stop4015-7" /> + <stop + id="stop4017-5" + offset="1" + style="stop-color:#f5f5b5;stop-opacity:1" /> + </linearGradient> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3865-4" + id="radialGradient3349" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1.0861872,-1.0164187,0.71060643,0.75938349,-745.07542,258.35212)" + cx="5.9992619" + cy="1046.9105" + fx="5.9992619" + fy="1046.9105" + r="4.3113923" /> + <linearGradient + id="linearGradient3865-4"> + <stop + id="stop3867-6" + offset="0" + style="stop-color:#ffffff;stop-opacity:1;" /> + <stop + style="stop-color:#ffffff;stop-opacity:0.82198954;" + offset="0.84661269" + id="stop3869-6" /> + <stop + id="stop3871-4" + offset="1" + style="stop-color:#ffffff;stop-opacity:0;" /> + </linearGradient> + <radialGradient + r="4.3113923" + fy="1046.9105" + fx="5.9992619" + cy="1046.9105" + cx="5.9992619" + gradientTransform="matrix(1.0861872,-1.0164187,0.71060643,0.75938349,-745.07542,258.35212)" + gradientUnits="userSpaceOnUse" + id="radialGradient3110" + xlink:href="#linearGradient3865-4" + inkscape:collect="always" /> + <linearGradient + y2="1043.8591" + x2="15.523204" + y1="1043.8591" + x1="7.4779682" + gradientUnits="userSpaceOnUse" + id="linearGradient3140-3-9" + xlink:href="#linearGradient3851-3-1" + inkscape:collect="always" /> + <linearGradient + id="linearGradient3851-3-1"> + <stop + style="stop-color:#ffffff;stop-opacity:1;" + offset="0" + id="stop3853-2-0" /> + <stop + id="stop3863-0-1" + offset="0.5" + style="stop-color:#ffffff;stop-opacity:0.82198954;" /> + <stop + style="stop-color:#ffffff;stop-opacity:0;" + offset="1" + id="stop3855-4-1" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient4011-8-2" + id="linearGradient4009-9-0" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(-1,0,0,-1,20.194842,2087.7734)" + x1="8.8282804" + y1="1040.8593" + x2="8.8061829" + y2="1045.5326" /> + <linearGradient + id="linearGradient4011-8-2"> + <stop + id="stop4013-6-8" + offset="0" + style="stop-color:#e0b575;stop-opacity:1;" /> + <stop + style="stop-color:#f5ca75;stop-opacity:1" + offset="0.47158596" + id="stop4015-7-1" /> + <stop + id="stop4017-5-5" + offset="1" + style="stop-color:#f5f5b5;stop-opacity:1" /> + </linearGradient> + <linearGradient + y2="1043.8591" + x2="15.523204" + y1="1043.8591" + x1="7.4779682" + gradientUnits="userSpaceOnUse" + id="linearGradient3140-3-93" + xlink:href="#linearGradient3851-3-7" + inkscape:collect="always" /> + <linearGradient + id="linearGradient3851-3-7"> + <stop + style="stop-color:#ffffff;stop-opacity:1;" + offset="0" + id="stop3853-2-6" /> + <stop + id="stop3863-0-8" + offset="0.5" + style="stop-color:#ffffff;stop-opacity:0.82198954;" /> + <stop + style="stop-color:#ffffff;stop-opacity:0;" + offset="1" + id="stop3855-4-0" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient4011-8-5" + id="linearGradient4009-9-00" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(-1,0,0,-1,20.194842,2087.7734)" + x1="8.8282804" + y1="1040.8593" + x2="8.8061829" + y2="1045.5326" /> + <linearGradient + id="linearGradient4011-8-5"> + <stop + id="stop4013-6-88" + offset="0" + style="stop-color:#e0b575;stop-opacity:1;" /> + <stop + style="stop-color:#f5ca75;stop-opacity:1" + offset="0.47158596" + id="stop4015-7-7" /> + <stop + id="stop4017-5-9" + offset="1" + style="stop-color:#f5f5b5;stop-opacity:1" /> + </linearGradient> + <linearGradient + id="linearGradient3851-3-1-7"> + <stop + style="stop-color:#ffffff;stop-opacity:1;" + offset="0" + id="stop3853-2-0-3" /> + <stop + id="stop3863-0-1-3" + offset="0.5" + style="stop-color:#ffffff;stop-opacity:0.82198954;" /> + <stop + style="stop-color:#ffffff;stop-opacity:0;" + offset="1" + id="stop3855-4-1-0" /> + </linearGradient> + <linearGradient + id="linearGradient4011-8-2-6"> + <stop + id="stop4013-6-8-3" + offset="0" + style="stop-color:#df9f3f;stop-opacity:1" /> + <stop + style="stop-color:#ffbf3f;stop-opacity:1" + offset="0.38495618" + id="stop4015-7-1-6" /> + <stop + id="stop4017-5-5-9" + offset="1" + style="stop-color:#f5f5b5;stop-opacity:1" /> + </linearGradient> + <linearGradient + y2="1043.8591" + x2="15.523204" + y1="1043.8591" + x1="7.4779682" + gradientUnits="userSpaceOnUse" + id="linearGradient3140-3-9-1-9" + xlink:href="#linearGradient3851-3-1-7-6" + inkscape:collect="always" /> + <linearGradient + id="linearGradient3851-3-1-7-6"> + <stop + style="stop-color:#ffffff;stop-opacity:1;" + offset="0" + id="stop3853-2-0-3-4" /> + <stop + id="stop3863-0-1-3-8" + offset="0.5" + style="stop-color:#ffffff;stop-opacity:0.82198954;" /> + <stop + style="stop-color:#ffffff;stop-opacity:0;" + offset="1" + id="stop3855-4-1-0-4" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient4011-8-2-6-6" + id="linearGradient4009-9-0-4-2" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(-1,0,0,-1,20.194842,2087.7734)" + x1="8.8282804" + y1="1041.7334" + x2="8.8282804" + y2="1046.9712" /> + <linearGradient + id="linearGradient4011-8-2-6-6"> + <stop + id="stop4013-6-8-3-4" + offset="0" + style="stop-color:#df9f3f;stop-opacity:1" /> + <stop + style="stop-color:#ffbf3f;stop-opacity:1" + offset="0.38495618" + id="stop4015-7-1-6-9" /> + <stop + id="stop4017-5-5-9-7" + offset="1" + style="stop-color:#f5f5b5;stop-opacity:1" /> + </linearGradient> + <linearGradient + id="linearGradient3851-3-1-7-6-2"> + <stop + style="stop-color:#ffffff;stop-opacity:1;" + offset="0" + id="stop3853-2-0-3-4-7" /> + <stop + id="stop3863-0-1-3-8-2" + offset="0.5" + style="stop-color:#ffffff;stop-opacity:0.82198954;" /> + <stop + style="stop-color:#ffffff;stop-opacity:0;" + offset="1" + id="stop3855-4-1-0-4-2" /> + </linearGradient> + <linearGradient + id="linearGradient4011-8-2-6-6-9"> + <stop + id="stop4013-6-8-3-4-1" + offset="0" + style="stop-color:#df9f3f;stop-opacity:1" /> + <stop + style="stop-color:#ffbf3f;stop-opacity:1" + offset="0.38495618" + id="stop4015-7-1-6-9-1" /> + <stop + id="stop4017-5-5-9-7-8" + offset="1" + style="stop-color:#f5f5b5;stop-opacity:1" /> + </linearGradient> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient4505" + id="radialGradient4513" + cx="242.60651" + cy="242.606" + fx="242.60651" + fy="242.606" + r="242.6055" + gradientTransform="matrix(1,0,0,1.0000021,0,-5.0000103e-4)" + gradientUnits="userSpaceOnUse" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient4527" + id="linearGradient4533" + x1="221.05089" + y1="397.49014" + x2="221.05089" + y2="88.718819" + gradientUnits="userSpaceOnUse" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient4527" + id="linearGradient4541" + gradientUnits="userSpaceOnUse" + x1="221.05089" + y1="397.49014" + x2="221.05089" + y2="88.718819" /> + </defs> + <sodipodi:namedview + id="base" + pagecolor="#c8c8c8" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:zoom="31.069226" + inkscape:cx="15.107952" + inkscape:cy="8.0000174" + inkscape:document-units="px" + inkscape:current-layer="layer1" + showgrid="true" + inkscape:window-width="2479" + inkscape:window-height="1084" + inkscape:window-x="22" + inkscape:window-y="266" + inkscape:window-maximized="0" + showguides="false" + inkscape:guide-bbox="true" + inkscape:snap-global="true" + inkscape:snap-bbox="true" + inkscape:bbox-nodes="true"> + <inkscape:grid + type="xygrid" + id="grid3971" /> + </sodipodi:namedview> + <metadata + id="metadata7"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1" + style="display:inline" + transform="translate(0,-1036.3622)"> + <g + style="display:inline;fill:url(#linearGradient4533);fill-opacity:1;stroke:none;stroke-opacity:1" + transform="matrix(0.0226705,0,0,0.0226705,3.0000014,1039.3622)" + id="g3-3"> + <path + inkscape:connector-curvature="0" + d="m 485.212,272.93 0,-60.648 -65.535,-10.93 c -4.564,-19.69 -12.321,-38.083 -22.72,-54.756 l 38.647,-54.078 -42.876,-42.883 -54.11,38.62 C 321.943,77.889 303.555,70.1 283.859,65.51 L 272.934,0 212.284,0 201.353,65.509 c -19.662,4.59 -38.083,12.379 -54.756,22.745 L 92.489,49.634 49.607,92.518 88.255,146.596 C 77.859,163.241 70.1,181.662 65.538,201.352 l -65.537,10.93 0,60.648 65.537,10.931 c 4.562,19.695 12.321,38.088 22.717,54.759 l -38.648,54.105 42.881,42.881 54.136,-38.643 c 16.646,10.393 35.066,18.154 54.729,22.714 l 10.931,65.535 60.65,0 10.926,-65.535 c 19.663,-4.56 38.084,-12.321 54.759,-22.714 l 54.11,38.643 42.876,-42.881 -38.647,-54.105 c 10.398,-16.671 18.155,-35.092 22.72,-54.759 z" + id="path5-8" + style="fill:url(#linearGradient4541);fill-opacity:1;stroke:none;stroke-opacity:1" + sodipodi:nodetypes="ccccccccccccccccccccccccccccccccc" /> + </g> + <ellipse + ry="0.99957365" + rx="1.0021901" + cy="1044.8619" + cx="8.5003433" + id="path4475-6-4" + style="fill:#ffffff;fill-opacity:1;stroke:#766059;stroke-width:0.99826074;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + <g + transform="translate(-7.0555633,2.9406003)" + style="fill:url(#linearGradient3268);fill-opacity:1;stroke:none;display:inline" + id="g3878" /> + <image + y="1036.3622" + x="-16" + id="image4375" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAW9JREFU +OI2tk79LAmEcxj9GQ3+Ac7fE/QOBxA1S4hRJg0s6BEoE0dQkF47BcUNEUxChcKC0iJniJAlCh9yf +cLScg4ZG/kAcSngbIukyTLBnfN7v+/A8z/d9PUIIFsHSQrf/Q2B51mFBU4VpOyiyxK6qeeZyUNBU +kYhFhVUtCQA9HQHAqpZEIhYVBU0VMwVM20FPR6gVU5i2M+FqxRR6OjLhvuD5uQWrWhK1YoqTs70p +uxfJW/yhOL6tnUkcl4OCpopW/ZFOd4XxcMB9vsnp8R33+Sbj4YBOd4VW/ZHvMVwCpu0QCHtJquu8 +9frUKxb6zTX1isVbr09SXScQ9rpiuLagyBIPuRdM2yFxtMZG0Efi4JCNoI/33iv61ROKLKHI0t8d +7G+vTnVglBuzOwDIGVmim16McoPzTJvxaMR5po1RbhDd9JIzsq75KQFFlrjMD/GH4iiyROv5k/OH +4lzmhy77v0b4jnle4kyBebDwZ/oABXCsWj/68vsAAAAASUVORK5CYII= +" + style="image-rendering:optimizeSpeed" + preserveAspectRatio="none" + height="16" + width="16" /> + <g + transform="matrix(0.0226705,0,0,0.0226705,3.0000014,1039.3622)" + id="g3" + style="fill:url(#radialGradient4513);fill-opacity:1"> + <path + inkscape:connector-curvature="0" + d="m 485.212,272.93 0,-60.648 -65.535,-10.93 c -4.564,-19.69 -12.321,-38.083 -22.72,-54.756 l 38.647,-54.078 -42.876,-42.883 -54.11,38.62 C 321.943,77.889 303.555,70.1 283.859,65.51 L 272.934,0 212.284,0 201.353,65.509 c -19.662,4.59 -38.083,12.379 -54.756,22.745 L 92.489,49.634 49.607,92.518 88.255,146.596 C 77.859,163.241 70.1,181.662 65.538,201.352 l -65.537,10.93 0,60.648 65.537,10.931 c 4.562,19.695 12.321,38.088 22.717,54.759 l -38.648,54.105 42.881,42.881 54.136,-38.643 c 16.646,10.393 35.066,18.154 54.729,22.714 l 10.931,65.535 60.65,0 10.926,-65.535 c 19.663,-4.56 38.084,-12.321 54.759,-22.714 l 54.11,38.643 42.876,-42.881 -38.647,-54.105 c 10.398,-16.671 18.155,-35.092 22.72,-54.759 l 65.534,-10.931 z m -242.605,90.976 c -66.989,0 -121.302,-54.311 -121.302,-121.3 0,-66.989 54.313,-121.302 121.302,-121.302 66.991,0 121.302,54.313 121.302,121.302 0,66.989 -54.31,121.3 -121.302,121.3 z" + id="path5" + style="fill:url(#radialGradient4513);fill-opacity:1" /> + </g> + </g> +</svg> diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/handlers/DeleteModelHandler.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/handlers/DeleteModelHandler.java index 96a9747462a5959a0c03463d9b13fa9153c2a63f..f83fd961e0d6cfe5aeb228547e1706d72406fc4e 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/handlers/DeleteModelHandler.java +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/handlers/DeleteModelHandler.java @@ -1,5 +1,6 @@ package org.lamport.tla.toolbox.tool.tlc.handlers; +import java.lang.reflect.InvocationTargetException; import java.text.SimpleDateFormat; import java.util.Collection; import java.util.Iterator; @@ -14,18 +15,17 @@ import org.eclipse.core.commands.ExecutionException; import org.eclipse.core.commands.IHandler; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Status; -import org.eclipse.core.runtime.jobs.Job; import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.dialogs.ProgressMonitorDialog; +import org.eclipse.jface.operation.IRunnableContext; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.actions.WorkspaceModifyOperation; import org.eclipse.ui.handlers.HandlerUtil; import org.lamport.tla.toolbox.tool.tlc.model.Model; import org.lamport.tla.toolbox.tool.tlc.output.source.TLCOutputSourceRegistry; import org.lamport.tla.toolbox.tool.tlc.ui.editor.ModelEditor; -import org.lamport.tla.toolbox.util.ToolboxJob; import org.lamport.tla.toolbox.util.UIHelper; public class DeleteModelHandler extends AbstractHandler implements IHandler @@ -105,24 +105,28 @@ public class DeleteModelHandler extends AbstractHandler implements IHandler // 4.) UI is in ready state // Defer deletion to ResourceFramework outside the UI thread (makes // it cancel-able too, keeps track of conflicting resource - // modifications, ...) - final Job job = new ToolboxJob("Deleting models...") { + // modifications, ...). + // Warp model delete operation in a WorkspaceModifyOperation to notify listeners + // after the model delete operation has finished. In other words, for the + // listeners a wrapped delete operation is atomic. If not done atomic, the + // UI might read the model while it's being deleted. This can result in a NPE + // inside the UI thread. + final WorkspaceModifyOperation operation = new WorkspaceModifyOperation() { @Override - protected IStatus run(IProgressMonitor monitor) { - try { - for (Model model : models) { - model.delete(monitor); - } - } catch (CoreException e) { - return new Status(Status.ERROR, - "org.lamport.tla.toolbox.tool.tlc.ui", - e.getMessage(), e); + protected void execute(IProgressMonitor monitor) + throws CoreException, InvocationTargetException, InterruptedException { + for (Model model : models) { + model.delete(monitor); } - return Status.OK_STATUS; } }; - job.schedule(); - } + final IRunnableContext ctxt = new ProgressMonitorDialog(UIHelper.getShell()); + try { + ctxt.run(true, false, operation); + } catch (InvocationTargetException | InterruptedException e) { + throw new ExecutionException(e.getMessage(), e); + } + } return null; } diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/handlers/NewModelHandler.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/handlers/NewModelHandler.java index b61323501b7442fd156f571600ac3047b862ce3d..a592159b1b978d5c136025f74fce50b7786196f5 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/handlers/NewModelHandler.java +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/handlers/NewModelHandler.java @@ -1,5 +1,6 @@ package org.lamport.tla.toolbox.tool.tlc.handlers; +import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; @@ -36,6 +37,7 @@ import org.lamport.tla.toolbox.tool.tlc.model.Assignment; import org.lamport.tla.toolbox.tool.tlc.model.Model; import org.lamport.tla.toolbox.tool.tlc.model.TLCSpec; import org.lamport.tla.toolbox.tool.tlc.ui.TLCUIActivator; +import org.lamport.tla.toolbox.tool.tlc.ui.editor.ISectionConstants; import org.lamport.tla.toolbox.tool.tlc.util.ModelHelper; import org.lamport.tla.toolbox.tool.tlc.util.ModelNameValidator; import org.lamport.tla.toolbox.util.UIHelper; @@ -123,16 +125,16 @@ public class NewModelHandler extends AbstractHandler implements IModelConfigurat ModuleNode moduleNode = specObject.getExternalModuleTable().getRootModule(); // get the list of constants - List constants = ModelHelper.createConstantsList(moduleNode); + final List<Assignment> constants = ModelHelper.createConstantsList(moduleNode); // if defaultInitValue is a constant, initialize it // to be a model value. (Should perhaps be changed to do this // only if the root module or some extended module has an algorithm?) - Iterator iter = constants.iterator(); + Iterator<Assignment> iter = constants.iterator(); boolean done = false; while ((!done) && iter.hasNext()) { - Assignment assign = (Assignment) iter.next(); + Assignment assign = iter.next(); if (assign.getLabel().equals("defaultInitValue") && (assign.getParams().length == 0)) { assign.setRight("defaultInitValue"); @@ -154,7 +156,7 @@ public class NewModelHandler extends AbstractHandler implements IModelConfigurat if (constants.size() == 0) { - launchCopy.setAttribute(MODEL_PARAMETER_CONSTANTS, (List) null); + launchCopy.setAttribute(MODEL_PARAMETER_CONSTANTS, (List<String>) null); } else { launchCopy.setAttribute(MODEL_PARAMETER_CONSTANTS, ModelHelper.serializeAssignmentList(constants)); @@ -296,7 +298,7 @@ public class NewModelHandler extends AbstractHandler implements IModelConfigurat // // Foo == CHOOSE v : v \notin exp or Foo == CHOOSE V : ~(v \in exp) // - Vector overrides = new Vector(); + Vector<String> overrides = new Vector<String>(); for (int i = 0; i < defs.length; i++) { OpDefNode node = defs[i]; @@ -377,9 +379,17 @@ public class NewModelHandler extends AbstractHandler implements IModelConfigurat final Map<String, String> parameters = new HashMap<String, String>(); parameters.put(OpenModelHandler.PARAM_MODEL_NAME, modelName); + final List<String> expand = new ArrayList<>(); + expand.add(ISectionConstants.SEC_COMMENTS); if (foundSpec && foundTermination) { - parameters.put(OpenModelHandler.PARAM_EXPAND_PROPERTIES, "expand"); + expand.add(ISectionConstants.SEC_WHAT_TO_CHECK_PROPERTIES); } + if (!constants.isEmpty()) { + expand.add(ISectionConstants.SEC_WHAT_IS_THE_MODEL); + } + + parameters.put(OpenModelHandler.PARAM_EXPAND_SECTIONS, + String.join(OpenModelHandler.PARAM_EXPAND_SECTIONS_DELIM, expand)); // runs the command and opens the module [should be model?] in the editor // diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/handlers/OpenModelHandler.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/handlers/OpenModelHandler.java index fc52e496e53c2c9856c3c1f427f87c90caf905f0..972a25f28fb0614ad59763f9c124383748724d25 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/handlers/OpenModelHandler.java +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/handlers/OpenModelHandler.java @@ -20,8 +20,9 @@ import org.lamport.tla.toolbox.util.UIHelper; public class OpenModelHandler extends AbstractHandler implements IConfigurationConstants { public static final String COMMAND_ID = "toolbox.tool.tlc.commands.model.open"; public static final String PARAM_MODEL_NAME = "toolbox.tool.tlc.commands.model.open.param"; - public static final String PARAM_EXPAND_PROPERTIES = "toolbox.tool.tlc.commands.model.open.param.expand.properties"; - + public static final String PARAM_EXPAND_SECTIONS = "toolbox.tool.tlc.commands.model.open.param.expand.properties"; + public static final String PARAM_EXPAND_SECTIONS_DELIM = ","; + public static final String EDITOR_ID = "org.lamport.tla.toolbox.tool.tlc.ui.editor.ModelEditor"; /* (non-Javadoc) @@ -41,8 +42,9 @@ public class OpenModelHandler extends AbstractHandler implements IConfigurationC } final ModelEditor modelEditor = (ModelEditor) UIHelper.openEditor(EDITOR_ID, launchFile); - if ("expand".equals(event.getParameter(PARAM_EXPAND_PROPERTIES))) { - modelEditor.expandPropertiesSection(); + final String expand = event.getParameter(PARAM_EXPAND_SECTIONS); + if (expand != null) { + modelEditor.expandSections(expand.split(PARAM_EXPAND_SECTIONS_DELIM)); } return null; diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/handlers/RenameModelHandlerDelegate.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/handlers/RenameModelHandlerDelegate.java index 36089f89aefd00954cebb44e06c9c1e603c749d3..ce7066ac9d9dfc5cde32113d5f1fba7087b49aff 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/handlers/RenameModelHandlerDelegate.java +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/handlers/RenameModelHandlerDelegate.java @@ -1,5 +1,7 @@ package org.lamport.tla.toolbox.tool.tlc.handlers; +import java.lang.reflect.InvocationTargetException; +import java.util.Collection; import java.util.HashMap; import java.util.Map; @@ -7,23 +9,23 @@ import org.eclipse.core.commands.AbstractHandler; import org.eclipse.core.commands.ExecutionEvent; import org.eclipse.core.commands.ExecutionException; import org.eclipse.core.commands.IHandler; +import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Status; -import org.eclipse.core.runtime.jobs.Job; import org.eclipse.jface.dialogs.IInputValidator; import org.eclipse.jface.dialogs.InputDialog; import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.dialogs.ProgressMonitorDialog; +import org.eclipse.jface.operation.IRunnableContext; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.window.Window; import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.actions.WorkspaceModifyOperation; import org.eclipse.ui.handlers.HandlerUtil; import org.lamport.tla.toolbox.tool.tlc.launch.IModelConfigurationConstants; import org.lamport.tla.toolbox.tool.tlc.model.Model; import org.lamport.tla.toolbox.tool.tlc.ui.editor.ModelEditor; import org.lamport.tla.toolbox.tool.tlc.util.ModelNameValidator; -import org.lamport.tla.toolbox.util.ToolboxJob; import org.lamport.tla.toolbox.util.UIHelper; /** @@ -67,26 +69,35 @@ public class RenameModelHandlerDelegate extends AbstractHandler implements IHand "Please input the new name of the model", model.getName(), modelNameInputValidator); dialog.setBlockOnOpen(true); if(dialog.open() == Window.OK) { - // c) close model editor if open - final IEditorPart editor = model.getAdapter(ModelEditor.class); + // c1) close model editor if open + IEditorPart editor = model.getAdapter(ModelEditor.class); if(editor != null) { reopenModelEditorAfterRename = true; UIHelper.getActivePage().closeEditor(editor, true); } + // c2) close snapshot model editors + final Collection<Model> snapshots = model.getSnapshots(); + for (Model snapshot : snapshots) { + editor = snapshot.getAdapter(ModelEditor.class); + if (editor != null) { + UIHelper.getActivePage().closeEditor(editor, true); + } + } - final Job j = new ToolboxJob("Renaming model...") { - /* (non-Javadoc) - * @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor) - */ - protected IStatus run(IProgressMonitor monitor) { + final WorkspaceModifyOperation operation = new WorkspaceModifyOperation() { + @Override + protected void execute(IProgressMonitor monitor) + throws CoreException, InvocationTargetException, InterruptedException { // d) rename final String newModelName = dialog.getValue(); - model.rename(newModelName); + model.rename(newModelName, monitor); // e) reopen (in UI thread) - if (reopenModelEditorAfterRename) { - UIHelper.runUIAsync(new Runnable(){ - /* (non-Javadoc) + if (reopenModelEditorAfterRename) { + UIHelper.runUIAsync(new Runnable() { + /* + * (non-Javadoc) + * * @see java.lang.Runnable#run() */ public void run() { @@ -94,13 +105,17 @@ public class RenameModelHandlerDelegate extends AbstractHandler implements IHand parameters.put(OpenModelHandler.PARAM_MODEL_NAME, newModelName); UIHelper.runCommand(OpenModelHandler.COMMAND_ID, parameters); } - }); - } - return Status.OK_STATUS; + }); + } } }; - j.schedule(); - } + final IRunnableContext ctxt = new ProgressMonitorDialog(UIHelper.getShell()); + try { + ctxt.run(true, false, operation); + } catch (InvocationTargetException | InterruptedException e) { + throw new ExecutionException(e.getMessage(), e); + } + } } return null; } diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/StateSpaceInformationItem.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/StateSpaceInformationItem.java index 6bf6864af57d34d91dca68c23f2b286fc1a499c4..0965c83c9095d7a8f7800eff6bd219393f207fcd 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/StateSpaceInformationItem.java +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/StateSpaceInformationItem.java @@ -4,6 +4,8 @@ import java.text.NumberFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import org.lamport.tla.toolbox.tool.tlc.ui.TLCUIActivator; @@ -52,8 +54,16 @@ public class StateSpaceInformationItem this.spm = spm; this.distinctSPM = distinctSPM; } + + private StateSpaceInformationItem(long foundStates, long distinctStates) { + this(new Date(), 0, foundStates, distinctStates, distinctStates, 0, 0); + } - /** + private StateSpaceInformationItem(long distinctStates) { + this(distinctStates, distinctStates); + } + + /** * @return the isMostRecent */ public boolean isMostRecent() { @@ -184,6 +194,31 @@ public class StateSpaceInformationItem return null; } + public static StateSpaceInformationItem parseInit(final String outputMessage) { + // Handles EC.TLC_INIT_GENERATED1 and EC.TLC_INIT_GENERATED2.- + // From MP#getMessage: + // b.append("Finished computing initial states: %1% distinct state%2% generated."); + // b.append("Finished computing initial states: %1% state%2% generated, with %3% of them distinct."); + + Pattern pattern = Pattern.compile("^Finished computing initial states: ([0-9]+) distinct state[s]* generated.$"); + Matcher matcher = pattern.matcher(outputMessage); + if (matcher.find()) { + final long distinctStates = Long.parseLong(matcher.group(1)); + return new StateSpaceInformationItem(distinctStates); + } + + pattern = Pattern.compile( + "^Finished computing initial states: ([0-9]+) states generated, with ([0-9]+) of them distinct.$"); + matcher = pattern.matcher(outputMessage); + if (matcher.find()) { + final long foundStates = Long.parseLong(matcher.group(1)); + final long distinctStates = Long.parseLong(matcher.group(2)); + return new StateSpaceInformationItem(foundStates, distinctStates); + } + return null; + } + + /** * @param outputMessage * @return diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/TLCModelLaunchDataProvider.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/TLCModelLaunchDataProvider.java index b31380b85bccdb73c934330e5e5c8c65802eb69e..589622770ddc22ec377d0309379ec0e49fba99b7 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/TLCModelLaunchDataProvider.java +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/TLCModelLaunchDataProvider.java @@ -146,24 +146,8 @@ public class TLCModelLaunchDataProvider implements ITLCOutputListener // should be put in the user output widget protected boolean isTLCStarted = false; - /** - * Set to the starting time of the current TLC run. - * Actually, it is set to the time when the TLC Start - * message is processed. Thus, there is no guarantee - * that this time bears any relation to startTimeStamp. - */ - protected long startTime = 0; - protected int numWorkers = 0; - /** - * @return the startTime - */ - public long getStartTime() - { - return startTime; - } - public TLCModelLaunchDataProvider(Model model) { this.model = model; @@ -190,7 +174,6 @@ public class TLCModelLaunchDataProvider implements ITLCOutputListener coverageInfo = new Vector<CoverageInformationItem>(); progressInformation = new Vector<StateSpaceInformationItem>(); - startTime = 0; startTimestamp = Long.MIN_VALUE; finishTimestamp = Long.MIN_VALUE; tlcMode = ""; @@ -385,6 +368,9 @@ public class TLCModelLaunchDataProvider implements ITLCOutputListener break; case EC.TLC_INIT_GENERATED1: case EC.TLC_INIT_GENERATED2: + if (addOrReplaceProgressInformation(StateSpaceInformationItem.parseInit(outputMessage))) { + informPresenter(ITLCModelLaunchDataPresenter.PROGRESS); + } case EC.TLC_INIT_GENERATED3: case EC.TLC_INIT_GENERATED4: this.setCurrentStatus(COMPUTING_REACHABLE); @@ -431,7 +417,6 @@ public class TLCModelLaunchDataProvider implements ITLCOutputListener case EC.TLC_STARTING: isTLCStarted = true; this.startTimestamp = GeneralOutputParsingHelper.parseTLCTimestamp(outputMessage); - this.startTime = System.currentTimeMillis(); informPresenter(ITLCModelLaunchDataPresenter.START_TIME); break; diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/TLCState.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/TLCState.java index d721001590c80880ec526251173afafa22c0f5b9..d3272b3a0792f74de0b57cb8cfb761087aba3631 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/TLCState.java +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/output/data/TLCState.java @@ -159,8 +159,9 @@ public class TLCState implements IModuleLocatable } } - // write the last one - if (stateVarString != null) + // write the last one (for a viewmap (see page 243 of specifying system) + // stateVarString.lenght does not necessarily equal 2) + if (stateVarString != null && stateVarString.length >= 2) { TLCVariable var = new TLCVariable(stateVarString[0], TLCVariableValue.parseValue(stateVarString[1])); vars.add(var); diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/DataBindingManager.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/DataBindingManager.java index 6aa4f4caef90bb5d815a0245b0266f1b16763340..54cb10dd3284ed56db769a825c9bdf46fc7bb37f 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/DataBindingManager.java +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/DataBindingManager.java @@ -71,7 +71,7 @@ public class DataBindingManager implements ISectionConstants * section that is a {@link Composite} but not a {@link Section} * to enabled. */ - public void enableSection(String id, boolean enabled) + private void enableSection(String id, boolean enabled) { SectionPart part = sectionParts.get(id); if (part == null) @@ -98,7 +98,7 @@ public class DataBindingManager implements ISectionConstants * * @param composite */ - public void enableSectionComposite(Composite composite, boolean enable) + private void enableSectionComposite(Composite composite, boolean enable) { Control[] children = composite.getChildren(); for (int i = 0; i < children.length; i++) @@ -154,7 +154,7 @@ public class DataBindingManager implements ISectionConstants * @param pageId page id * @return an array with sections or empty array */ - public String[] getSectionsForPage(String pageId) + private String[] getSectionsForPage(String pageId) { Vector<String> sectionIds = sectionsForPage.get(pageId); if (sectionIds == null) diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/ISectionConstants.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/ISectionConstants.java index 136dd40daacbb459e1b7e1229cdc1b3793636fa0..ae51516878bc148900ad7ea5cc4b99aa9b4bbd23 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/ISectionConstants.java +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/ISectionConstants.java @@ -50,10 +50,11 @@ public interface ISectionConstants public final static String SEC_LAUNCHING_SETUP = "__launching_setup"; // sections of the third page - public final static String SEC_PROGRESS = "__progress"; - public final static String SEC_OUTPUT = "__output"; - public static final String SEC_COVERAGE = "__coverage"; - public static final String SEC_ERRORS = "__errors"; - public static final String SEC_EXPRESSION = "__expression"; + public final static String SEC_GENERAL = "__general"; // General Section + public final static String SEC_OUTPUT = "__output"; // User output + public static final String SEC_STATISTICS = "__coverage"; // Statistics + public static final String SEC_ERRORS = "__errors"; + public static final String SEC_PROGRESS = "__progress"; // Progress output + public static final String SEC_EXPRESSION = "__expression"; // Eval Constant Expressions } \ No newline at end of file diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/ModelEditor.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/ModelEditor.java index 74f9b228047158c1a22e8b36e375302a30f9f03c..43d1ffae76c071130cb4c094e4d9e10a6a4bc7e1 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/ModelEditor.java +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/ModelEditor.java @@ -127,6 +127,21 @@ public class ModelEditor extends FormEditor TLCUIActivator.getDefault().logError("Error initializing editor", e); } } + + // MAK 01/2018: Re-validate the page because running the model removes or sets + // problem markers (Model#setMarkers) which are presented to the user by + // ModelEditor#handleProblemMarkers. If we don't re-validate once a model is + // done running, the user visible presentation resulting from an earlier run of + // handleProblemMarkers gets stale. + // This behavior can be triggered by creating a spec (note commented EXTENDS): + // \* EXTENDS Integers + // VARIABLE s + // Spec == s = 0 /\ [][s'=s]_s + // and a model that defines the invariant (s >= 0). Upon the first launch of + // the model, the ModelEditor correctly marks the invariant due to the operator + // >= being not defined. Uncommenting EXTENDS, saving the spec and rerunning + // the model would incorrectly not remove the marker on the invariant. + UIHelper.runUISync(validateRunable); } } }); @@ -820,7 +835,7 @@ public class ModelEditor extends FormEditor } else { // launching the config model.launch(mode, new SubProgressMonitor(monitor, 1), true); - + /* * Close any tabs in this editor containing read-only * versions of modules. They will be changed by the @@ -872,6 +887,11 @@ public class ModelEditor extends FormEditor // send cancellations to all jobs... runningSpecJobs[i].cancel(); } + } else if (getModel().isRunningRemotely()) { + final Job[] remoteJobs = Job.getJobManager().find(getModel()); + for (Job remoteJob : remoteJobs) { + remoteJob.cancel(); + } } } @@ -1134,16 +1154,12 @@ public class ModelEditor extends FormEditor } /** - * Expands the properties section on the main model editor page. + * Expands the given sections on the model editor pages. */ - public void expandPropertiesSection() { + public void expandSections(final String[] sections) { for (int i = 0; i < pagesToAdd.length; i++) { final BasicFormPage basicFormPage = pagesToAdd[i]; - if (basicFormPage instanceof MainModelPage) { - final MainModelPage mainPage = (MainModelPage) basicFormPage; - mainPage.expandPropertiesSection(); - return; - } + basicFormPage.expandSections(sections); } } diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/BasicFormPage.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/BasicFormPage.java index 2a170482dac5be31ecfd9e771476fba5c5ca093b..d40dcfc0bc8ce9827cb0016cd9c520068fae3836 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/BasicFormPage.java +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/BasicFormPage.java @@ -458,7 +458,7 @@ public abstract class BasicFormPage extends FormPage implements IModelConfigurat /** * Handle the problem markers */ - public void handleProblemMarkers(boolean switchToErrorPage) + private void handleProblemMarkers(boolean switchToErrorPage) { // delegate to the editor ((ModelEditor) getEditor()).handleProblemMarkers(switchToErrorPage); @@ -509,6 +509,15 @@ public abstract class BasicFormPage extends FormPage implements IModelConfigurat getDataBindingManager().expandSection(sectionId); } + /** + * Expands the given sections. + */ + public void expandSections(final String[] sections) { + for (String section : sections) { + expandSection(section); + } + } + /** * Enables or disables the page * @param enabled, if true the page controls are enabled, otherwise disabled @@ -882,7 +891,7 @@ public abstract class BasicFormPage extends FormPage implements IModelConfigurat */ public boolean isEnabled() { - return getModel().isRunning(); + return getModel().isRunning() || getModel().isRunningRemotely(); } } diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/MainModelPage.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/MainModelPage.java index a2f18dc31378b6f98b57e6666f81a6b74d343164..3e97ed82522546a4c597ea4e4169154073dae67e 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/MainModelPage.java +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/MainModelPage.java @@ -12,7 +12,9 @@ import java.util.Collections; import java.util.Comparator; import java.util.Enumeration; import java.util.List; +import java.util.Set; import java.util.Vector; +import java.util.function.Consumer; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IWorkspaceRunnable; @@ -296,6 +298,9 @@ public class MainModelPage extends BasicFormPage implements IConfigurationConsta // constants from the model List<String> savedConstants = getModel().getAttribute(MODEL_PARAMETER_CONSTANTS, new Vector<String>()); FormHelper.setSerializedInput(constantTable, savedConstants); + if (!savedConstants.isEmpty()) { + expandSection(SEC_WHAT_IS_THE_MODEL); + } // recover from the checkpoint boolean recover = getModel().getAttribute(LAUNCH_RECOVER, LAUNCH_RECOVER_DEFAULT); @@ -342,7 +347,10 @@ public class MainModelPage extends BasicFormPage implements IConfigurationConsta // comments/description/notes String commentsStr = getModel().getAttribute(MODEL_COMMENTS, EMPTY_STRING); - commentsSource.setDocument(new Document(commentsStr)); + commentsSource.setDocument(new Document(commentsStr)); + if (!EMPTY_STRING.equals(commentsStr)) { + expandSection(SEC_COMMENTS); + } } public void validatePage(boolean switchToErrorPage) @@ -640,9 +648,14 @@ public class MainModelPage extends BasicFormPage implements IConfigurationConsta // to allow the No Spec option to be selected when there are variables. if (rootModuleNode != null) { - if (rootModuleNode.getVariableDecls().length == 0) + final Control errorMsgControl = UIHelper.getWidget(getDataBindingManager().getAttributeControl(MODEL_BEHAVIOR_NO_SPEC)); + final String errorMsgKey = MODEL_BEHAVIOR_NO_SPEC + "ErrorMsgKey"; + if (rootModuleNode.getVariableDecls().length == 0) { setHasVariables(false); + modelEditor.addErrorMessage(errorMsgKey, + "\"What is the behavior spec?\" automatically set to \"No Behavior Spec\" because spec has no declared variables.", this.getId(), + IMessageProvider.INFORMATION, errorMsgControl); // set selection to the NO SPEC field if (!noSpecRadio.getSelection()) @@ -655,6 +668,7 @@ public class MainModelPage extends BasicFormPage implements IConfigurationConsta } else { setHasVariables(true); + modelEditor.removeErrorMessage(errorMsgKey, errorMsgControl); // if there are variables, the user // may still want to choose no spec @@ -675,18 +689,40 @@ public class MainModelPage extends BasicFormPage implements IConfigurationConsta // or not. // This must occur after the preceeding code in case // that code changes the selection. - Section whatToCheckSection = dm.getSection(SEC_WHAT_TO_CHECK).getSection(); - - if (noSpecRadio.getSelection()) - { - whatToCheckSection.setExpanded(false); - whatToCheckSection.setEnabled(false); - - } else - { - whatToCheckSection.setExpanded(true); - whatToCheckSection.setEnabled(true); - } + final Section whatToCheckSection = dm.getSection(SEC_WHAT_TO_CHECK).getSection(); + final Set<Section> resultPageSections = ((ResultPage) modelEditor.findPage(ResultPage.ID)).getSections(SEC_GENERAL, SEC_STATISTICS); + + final String hint = " (\"What is the behavior spec?\" above has no behavior spec)"; + final String hintResults = " (\"What is the behavior spec?\" on \"Model Overview\" page has no behavior spec)"; + if (noSpecRadio.getSelection()) { + whatToCheckSection + .setText(!whatToCheckSection.getText().endsWith(hint) ? whatToCheckSection.getText() + hint + : whatToCheckSection.getText()); + whatToCheckSection.setExpanded(false); + whatToCheckSection.setEnabled(false); + + resultPageSections.forEach(new Consumer<Section>() { + @Override + public void accept(Section sec) { + sec.setText(!sec.getText().endsWith(hintResults) ? sec.getText() + hintResults : sec.getText()); + sec.setEnabled(false); + sec.setExpanded(false); + } + }); + } else { + whatToCheckSection.setText(whatToCheckSection.getText().replace(hint, "")); + whatToCheckSection.setExpanded(true); + whatToCheckSection.setEnabled(true); + + resultPageSections.forEach(new Consumer<Section>() { + @Override + public void accept(Section sec) { + sec.setText(sec.getText().replace(hintResults, "")); + sec.setEnabled(true); + sec.setExpanded(true); + } + }); + } // The following code is not needed now because we automatically change // the selection to No Spec if there are no variables. @@ -736,6 +772,29 @@ public class MainModelPage extends BasicFormPage implements IConfigurationConsta } } + // Verify that the user provided email address is valid and can be used to send + // the model checking result to. + if (this.distributedCombo.getSelectionIndex() > 1) { + final String text = resultMailAddressText.getText(); + try { + javax.mail.internet.InternetAddress.parse(text, true); + } catch (javax.mail.internet.AddressException exp) { + modelEditor.addErrorMessage("email address invalid", + "For Cloud TLC to work please enter a valid email address.", this.getId(), + IMessageProvider.ERROR, + UIHelper.getWidget(dm.getAttributeControl(LAUNCH_DISTRIBUTED_RESULT_MAIL_ADDRESS))); + setComplete(false); + expandSection(SEC_HOW_TO_RUN); + } + if ("".equals(text.trim())) { + modelEditor.addErrorMessage("email address missing", + "For Cloud TLC to work please enter an email address.", this.getId(), IMessageProvider.ERROR, + UIHelper.getWidget(dm.getAttributeControl(LAUNCH_DISTRIBUTED_RESULT_MAIL_ADDRESS))); + setComplete(false); + expandSection(SEC_HOW_TO_RUN); + } + } + mm.setAutoUpdate(true); super.validatePage(switchToErrorPage); @@ -965,8 +1024,7 @@ public class MainModelPage extends BasicFormPage implements IConfigurationConsta twd.colspan = 2; top.setLayoutData(twd); - section = FormHelper.createSectionComposite(top, "Model description", "", toolkit, sectionFlags - | Section.EXPANDED, getExpansionListener()); + section = FormHelper.createSectionComposite(top, "Model description", "", toolkit, sectionFlags, getExpansionListener()); final ValidateableSectionPart commentsPart = new ValidateableSectionPart(section, this, SEC_COMMENTS); managedForm.addPart(commentsPart); @@ -1133,8 +1191,8 @@ public class MainModelPage extends BasicFormPage implements IConfigurationConsta // Constants ValidateableConstantSectionPart constantsPart = new ValidateableConstantSectionPart(right, - "What is the model?", "Specify the values of declared constants.", toolkit, sectionFlags - | Section.EXPANDED, this, SEC_WHAT_IS_THE_MODEL); + "What is the model?", "Specify the values of declared constants.", toolkit, sectionFlags, this, + SEC_WHAT_IS_THE_MODEL); managedForm.addPart(constantsPart); constantTable = constantsPart.getTableViewer(); dm.bindAttribute(MODEL_PARAMETER_CONSTANTS, constantTable, constantsPart); @@ -1620,7 +1678,7 @@ public class MainModelPage extends BasicFormPage implements IConfigurationConsta gd = new GridData(); gd.grabExcessHorizontalSpace = true; gd.horizontalIndent = 10; - gd.widthHint = 200; + gd.widthHint = 400; resultMailAddressText.setLayoutData(gd); resultMailAddressText.addModifyListener(howToRunListener); dm.bindAttribute(LAUNCH_DISTRIBUTED_RESULT_MAIL_ADDRESS, resultMailAddressText, howToRunPart); @@ -1697,14 +1755,6 @@ public class MainModelPage extends BasicFormPage implements IConfigurationConsta distributedOptions.layout(); } - /** - * Expands the properties table. - */ - public void expandPropertiesSection() { - final SectionPart section = getDataBindingManager().getSection(SEC_WHAT_TO_CHECK_PROPERTIES); - section.getSection().setExpanded(true); - } - /** * On a refresh, the checkpoint information is re-read */ diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/ResultPage.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/ResultPage.java index c167881362d87e2904b8840b58f8c5a45083c815..3212972822f58d601c1a42b261c4333510e9a879 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/ResultPage.java +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/editor/page/ResultPage.java @@ -4,13 +4,20 @@ import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.text.SimpleDateFormat; +import java.util.Arrays; import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; import java.util.Hashtable; import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.TimeZone; import java.util.Vector; +import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; +import java.util.stream.Collectors; import org.eclipse.core.resources.IMarker; import org.eclipse.core.resources.IWorkspace; @@ -24,6 +31,8 @@ import org.eclipse.core.runtime.jobs.Job; import org.eclipse.jface.action.Action; import org.eclipse.jface.resource.JFaceResources; import org.eclipse.jface.text.Document; +import org.eclipse.jface.text.IDocumentPartitioner; +import org.eclipse.jface.text.ITextOperationTarget; import org.eclipse.jface.text.source.SourceViewer; import org.eclipse.jface.viewers.IStructuredContentProvider; import org.eclipse.jface.viewers.ITableColorProvider; @@ -33,6 +42,8 @@ import org.eclipse.jface.viewers.LabelProvider; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.jface.viewers.Viewer; import org.eclipse.swt.SWT; +import org.eclipse.swt.events.KeyEvent; +import org.eclipse.swt.events.KeyListener; import org.eclipse.swt.events.PaintEvent; import org.eclipse.swt.events.PaintListener; import org.eclipse.swt.events.SelectionEvent; @@ -63,6 +74,10 @@ import org.eclipse.ui.forms.widgets.Section; import org.eclipse.ui.forms.widgets.TableWrapData; import org.eclipse.ui.forms.widgets.TableWrapLayout; import org.eclipse.ui.progress.UIJob; +import org.lamport.tla.toolbox.editor.basic.TLAEditorActivator; +import org.lamport.tla.toolbox.editor.basic.TLAFastPartitioner; +import org.lamport.tla.toolbox.editor.basic.TLAPartitionScanner; +import org.lamport.tla.toolbox.editor.basic.TLASourceViewerConfiguration; import org.lamport.tla.toolbox.tool.tlc.model.Model; import org.lamport.tla.toolbox.tool.tlc.output.data.CoverageInformationItem; import org.lamport.tla.toolbox.tool.tlc.output.data.ITLCModelLaunchDataPresenter; @@ -104,10 +119,10 @@ public class ResultPage extends BasicFormPage implements ITLCModelLaunchDataPres private SourceViewer progressOutput; private SourceViewer expressionEvalResult; private SourceViewer expressionEvalInput; + private long startTimestamp; private Text startTimestampText; // startTime is provided by the TLCModelLaunchDataProvider's getStartTime() // method. - private long startTime = 0; private Text finishTimestampText; private Text tlcModeText; private Text lastCheckpointTimeText; @@ -116,7 +131,7 @@ public class ResultPage extends BasicFormPage implements ITLCModelLaunchDataPres private Text fingerprintCollisionProbabilityText; private TableViewer coverage; private TableViewer stateSpace; - + private final Map<String, Section> sections = new HashMap<String, Section>(); private final Lock disposeLock = new ReentrantLock(true); // listener on changes to the tlc output font preference @@ -180,8 +195,8 @@ public class ResultPage extends BasicFormPage implements ITLCModelLaunchDataPres ResultPage.this.expressionEvalResult.getTextWidget().setText(dataProvider.getCalcOutput()); break; case START_TIME: - final long startTimestamp = dataProvider.getStartTimestamp(); - if (startTimestamp < 0) { + ResultPage.this.startTimestamp = dataProvider.getStartTimestamp(); + if (ResultPage.this.startTimestamp < 0) { // Leave the starttime text empty on a negative // timestamp. A negative one indicates that the // model has never been checked. See Long.MIN_VALUE in @@ -189,8 +204,7 @@ public class ResultPage extends BasicFormPage implements ITLCModelLaunchDataPres ResultPage.this.startTimestampText.setText(""); break; } - ResultPage.this.startTimestampText.setText(new Date(startTimestamp).toString()); - ResultPage.this.startTime = dataProvider.getStartTime(); + ResultPage.this.startTimestampText.setText(new Date(ResultPage.this.startTimestamp).toString()); break; case END_TIME: long finishTimestamp = dataProvider.getFinishTimestamp(); @@ -361,7 +375,12 @@ public class ResultPage extends BasicFormPage implements ITLCModelLaunchDataPres } // constant expression - expressionEvalInput.setDocument(new Document(getModel().getEvalExpression())); + final Document document = new Document(getModel().getEvalExpression()); + final IDocumentPartitioner partitioner = new TLAFastPartitioner( + TLAEditorActivator.getDefault().getTLAPartitionScanner(), TLAPartitionScanner.TLA_PARTITION_TYPES); + document.setDocumentPartitioner(TLAPartitionScanner.TLA_PARTITIONING, partitioner); + partitioner.connect(document); + expressionEvalInput.setDocument(document); } /** @@ -378,7 +397,7 @@ public class ResultPage extends BasicFormPage implements ITLCModelLaunchDataPres return; } this.startTimestampText.setText(""); - this.startTime = 0; + this.startTimestamp = 0; this.finishTimestampText.setText(""); this.tlcModeText.setText(""); this.lastCheckpointTimeText.setText(""); @@ -472,6 +491,7 @@ public class ResultPage extends BasicFormPage implements ITLCModelLaunchDataPres section = FormHelper.createSectionComposite(body, "General", "" /* "The current progress of model-checking"*/, toolkit, sectionFlags & ~Section.DESCRIPTION, getExpansionListener()); + sections.put(SEC_GENERAL, section); twd = new TableWrapData(TableWrapData.FILL); twd.colspan = 1; @@ -519,6 +539,7 @@ public class ResultPage extends BasicFormPage implements ITLCModelLaunchDataPres section = FormHelper.createSectionComposite(body, "Statistics", "", /*"The current progress of model-checking",*/ toolkit, (sectionFlags | Section.COMPACT) & ~Section.DESCRIPTION, getExpansionListener()); + sections.put(SEC_STATISTICS, section); twd = new TableWrapData(TableWrapData.FILL); twd.colspan = 1; section.setLayoutData(twd); @@ -540,6 +561,7 @@ public class ResultPage extends BasicFormPage implements ITLCModelLaunchDataPres // extra empty line would appear below the title. section = FormHelper.createSectionComposite(body, "Evaluate Constant Expression", "", toolkit, sectionFlags & ~Section.DESCRIPTION, getExpansionListener()); + sections.put(SEC_EXPRESSION, section); Composite resultArea = (Composite) section.getClient(); GridLayout gLayout = new GridLayout(2, false); @@ -554,8 +576,31 @@ public class ResultPage extends BasicFormPage implements ITLCModelLaunchDataPres expressionComposite.setLayout(gLayout); toolkit.createLabel(expressionComposite, "Expression: "); - expressionEvalInput = FormHelper.createFormsSourceViewer(toolkit, expressionComposite, expressionFieldFlags); + expressionEvalInput = FormHelper.createFormsSourceViewer(toolkit, expressionComposite, expressionFieldFlags, + new TLASourceViewerConfiguration()); + expressionEvalInput.getTextWidget().addKeyListener(new KeyListener() { + @Override + public void keyPressed(KeyEvent e) { + if (isUndoKeyPress(e)) { + expressionEvalInput.doOperation(ITextOperationTarget.UNDO); + } else if (isRedoKeyPress(e)) { + expressionEvalInput.doOperation(ITextOperationTarget.REDO); + } + } + + private boolean isRedoKeyPress(KeyEvent e) { + return ((e.stateMask & SWT.CONTROL) > 0) && ((e.keyCode == 'y') || (e.keyCode == 'Y')); + } + private boolean isUndoKeyPress(KeyEvent e) { + return ((e.stateMask & SWT.CONTROL) > 0) && ((e.keyCode == 'z') || (e.keyCode =='Z')); + } + + @Override + public void keyReleased(KeyEvent e) { + } + }); + // We want the value section to get larger as the window // gets larger but not the expression section. Composite valueComposite = toolkit.createComposite(resultArea); @@ -569,7 +614,7 @@ public class ResultPage extends BasicFormPage implements ITLCModelLaunchDataPres // this causes the text box to be extremely // tall instead of having a scroll bar. gd = new GridData(SWT.FILL, SWT.FILL, true, false); - gd.minimumWidth = 500; + gd.widthHint = 500; gd.heightHint = 80; expressionEvalResult.getTextWidget().setLayoutData(gd); // The expression section should not grab excess horizontal @@ -612,10 +657,11 @@ public class ResultPage extends BasicFormPage implements ITLCModelLaunchDataPres section = FormHelper.createSectionComposite(body, "User Output", "TLC output generated by evaluating Print and PrintT expressions.", toolkit, sectionFlags, getExpansionListener()); + sections.put(SEC_OUTPUT, section); Composite outputArea = (Composite) section.getClient(); outputArea.setLayout(new GridLayout()); // output viewer - userOutput = FormHelper.createFormsOutputViewer(toolkit, outputArea, textFieldFlags); + userOutput = FormHelper.createFormsOutputViewer(toolkit, outputArea, textFieldFlags | SWT.WRAP); // We dont want this item to fill excess // vertical space because then in some cases @@ -623,7 +669,7 @@ public class ResultPage extends BasicFormPage implements ITLCModelLaunchDataPres // tall instead of having a scroll bar. gd = new GridData(SWT.FILL, SWT.LEFT, true, false); gd.heightHint = 300; - gd.minimumWidth = 300; + gd.widthHint = 300; userOutput.getControl().setLayoutData(gd); userOutput.getControl().setFont(JFaceResources.getFont(ITLCPreferenceConstants.I_TLC_OUTPUT_FONT)); @@ -634,8 +680,9 @@ public class ResultPage extends BasicFormPage implements ITLCModelLaunchDataPres // are passed in. If the bit were not changed to 0, an // extra empty line would appear below the title. section = FormHelper.createSectionComposite(body, "Progress Output", "", - /* "The current progress of model-checking",*/ + /* "The current progress of model-checking",*/ toolkit, sectionFlags & ~Section.DESCRIPTION, getExpansionListener()); + sections.put(SEC_PROGRESS, section); section.setExpanded(false); Composite progressArea = (Composite) section.getClient(); progressArea = (Composite) section.getClient(); @@ -787,7 +834,7 @@ public class ResultPage extends BasicFormPage implements ITLCModelLaunchDataPres } }); - this.stateSpace.setLabelProvider(new StateSpaceLabelProvider()); + this.stateSpace.setLabelProvider(new StateSpaceLabelProvider(this)); getSite().setSelectionProvider(this.stateSpace); return statespaceComposite; } @@ -893,10 +940,14 @@ public class ResultPage extends BasicFormPage implements ITLCModelLaunchDataPres public final static int COL_DISTINCT = 3; public final static int COL_LEFT = 4; - private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); // $NON-NLS-1$ private boolean doHighlight = false; + private final ResultPage resultPage; - /* (non-Javadoc) + public StateSpaceLabelProvider(ResultPage resultPage) { + this.resultPage = resultPage; + } + + /* (non-Javadoc) * @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnImage(java.lang.Object, int) */ public Image getColumnImage(Object element, int columnIndex) @@ -934,7 +985,7 @@ public class ResultPage extends BasicFormPage implements ITLCModelLaunchDataPres StateSpaceInformationItem item = (StateSpaceInformationItem) element; switch (columnIndex) { case COL_TIME: - return sdf.format(item.getTime()); + return formatInterval(resultPage.startTimestamp, item.getTime().getTime()); case COL_DIAMETER: if (item.getDiameter() >= 0) { @@ -994,6 +1045,15 @@ public class ResultPage extends BasicFormPage implements ITLCModelLaunchDataPres public void unsetHighlightUnexplored() { doHighlight = false; } + + private static String formatInterval(final long firstTS, final long secondTS) { + final long interval = secondTS - firstTS; + final long hr = TimeUnit.MILLISECONDS.toHours(interval); + final long min = TimeUnit.MILLISECONDS.toMinutes(interval - TimeUnit.HOURS.toMillis(hr)); + final long sec = TimeUnit.MILLISECONDS + .toSeconds(interval - TimeUnit.HOURS.toMillis(hr) - TimeUnit.MINUTES.toMillis(min)); + return String.format("%02d:%02d:%02d", hr, min, sec); + } } /** @@ -1207,7 +1267,7 @@ public class ResultPage extends BasicFormPage implements ITLCModelLaunchDataPres data[0] = 0; times[0] = 0; - long startTime = resultPage.startTime; + long startTime = resultPage.startTimestamp; TLCUIActivator.getDefault().logDebug("first reported time - starttime = " + (ssInfo[0].getTime().getTime() - startTime)); if (startTime > ssInfo[0].getTime().getTime() - 1000) @@ -1337,4 +1397,9 @@ public class ResultPage extends BasicFormPage implements ITLCModelLaunchDataPres return title + " " + getGraphTitleSuffix(resultPage); } + public Set<Section> getSections(String ...sectionIDs) { + final Set<String> set = new HashSet<String>(Arrays.asList(sectionIDs)); + return this.sections.entrySet().stream().filter(e -> set.contains(e.getKey())).map(Map.Entry::getValue) + .collect(Collectors.toSet()); + } } diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/modelexplorer/ModelContentProvider.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/modelexplorer/ModelContentProvider.java index c09e6532346e096c1eab5790268d3cc01e95adf6..220185b5b96e6226c82d4d69f91325f4adcbdfc5 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/modelexplorer/ModelContentProvider.java +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/modelexplorer/ModelContentProvider.java @@ -70,6 +70,13 @@ public class ModelContentProvider implements ITreeContentProvider { getViewer().remove(parent, new Object[] {model}); } }); + } else if (event.getState() == State.REMOTE_NOT_RUNNING) { + UIHelper.runUISync(new Runnable() { + @Override + public void run() { + getViewer().refresh(event.getModel(), true); + } + }); } return true; } diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/modelexplorer/ModelLabelProvider.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/modelexplorer/ModelLabelProvider.java index 8d185b2cbe1a24bbb19b51940f3683a2335e6500..7c1a78c9e5b6f16f7882c2a19fdc8b5d8cbe3dba 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/modelexplorer/ModelLabelProvider.java +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/modelexplorer/ModelLabelProvider.java @@ -25,6 +25,7 @@ ******************************************************************************/ package org.lamport.tla.toolbox.tool.tlc.ui.modelexplorer; +import java.io.File; import java.text.SimpleDateFormat; import org.eclipse.jface.viewers.LabelProvider; @@ -43,6 +44,7 @@ public class ModelLabelProvider extends LabelProvider implements IDescriptionPro private Image modelImage = TLCUIActivator.getImageDescriptor("/icons/full/choice_sc_obj.gif").createImage(); private Image modelNoError = TLCUIActivator.getImageDescriptor("/icons/full/model_no_error.gif").createImage(); private Image modelWithError = TLCUIActivator.getImageDescriptor("/icons/full/model_with_error.gif").createImage(); + private Image modelCloudTLCRunning = TLCUIActivator.getImageDescriptor("/icons/full/thread_view.png").createImage(); /** * Retrieves model's image @@ -53,6 +55,9 @@ public class ModelLabelProvider extends LabelProvider implements IDescriptionPro } else if (element instanceof Model) { final Model model = (Model) element; if (model.isSnapshot()) { + if (model.isRunningRemotely()) { + return modelCloudTLCRunning; + } if (model.hasError()) { return modelWithError; } @@ -95,7 +100,7 @@ public class ModelLabelProvider extends LabelProvider implements IDescriptionPro final Model model = (Model) element; final String comments = model.getComments(); if (comments.equals("")) { - return getText(element); + return getText(element) + " [ " + model.getFolder().getLocation().toFile() + File.separator + " ]"; } return comments; } diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/preference/TLCPreferenceInitializer.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/preference/TLCPreferenceInitializer.java index a7c8e57d6b85cb9f46a57b3ae2039437ca946d5f..69d260e308408580c1b60725fd385cd1c5eaba1b 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/preference/TLCPreferenceInitializer.java +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/preference/TLCPreferenceInitializer.java @@ -7,6 +7,7 @@ import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.ui.internal.IPreferenceConstants; import org.eclipse.ui.internal.WorkbenchPlugin; import org.lamport.tla.toolbox.tool.tlc.TLCActivator; +import org.lamport.tla.toolbox.tool.tlc.job.TLCProcessJob; import org.lamport.tla.toolbox.tool.tlc.ui.TLCUIActivator; import org.osgi.service.prefs.BackingStoreException; @@ -20,7 +21,7 @@ import tlc2.tool.fp.FPSetFactory; public class TLCPreferenceInitializer extends AbstractPreferenceInitializer { - public static final int MAX_HEAP_SIZE_DEFAULT = 25; + public static final int MAX_HEAP_SIZE_DEFAULT = TLCProcessJob.HEAP_SIZE_DEFAULT; /** * @see org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer#initializeDefaultPreferences() diff --git a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/util/FormHelper.java b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/util/FormHelper.java index 865847dba64ec71ef4bf7f3429a8eded6d5b1d0a..69d600ce1402750d8ea7c31bf8c31ed5a8baff78 100644 --- a/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/util/FormHelper.java +++ b/org.lamport.tla.toolbox.tool.tlc.ui/src/org/lamport/tla/toolbox/tool/tlc/ui/util/FormHelper.java @@ -150,9 +150,13 @@ public class FormHelper * @param flags * @return */ - public static SourceViewer createFormsSourceViewer(FormToolkit toolkit, Composite parent, int flags) + public static SourceViewer createFormsSourceViewer(FormToolkit toolkit, Composite parent, int flags) { + return createFormsSourceViewer(toolkit, parent, flags, new SourceViewerConfiguration()); + } + + public static SourceViewer createFormsSourceViewer(FormToolkit toolkit, Composite parent, int flags, SourceViewerConfiguration config) { - SourceViewer sourceViewer = createSourceViewer(parent, flags); + SourceViewer sourceViewer = createSourceViewer(parent, flags, config); sourceViewer.setData(FormToolkit.KEY_DRAW_BORDER, FormToolkit.TREE_BORDER); sourceViewer.getTextWidget().setData(FormToolkit.KEY_DRAW_BORDER, FormToolkit.TREE_BORDER); @@ -204,11 +208,14 @@ public class FormHelper * @param flags * @return */ - public static SourceViewer createSourceViewer(Composite parent, int flags) + public static SourceViewer createSourceViewer(Composite parent, int flags) { + return createSourceViewer(parent, flags, new SourceViewerConfiguration()); + } + + public static SourceViewer createSourceViewer(Composite parent, int flags, SourceViewerConfiguration config) { SourceViewer sourceViewer = new SourceViewer(parent, null, null, false, flags); - SourceViewerConfiguration configuration = new SourceViewerConfiguration(); - sourceViewer.configure(configuration); + sourceViewer.configure(config); sourceViewer.setTabsToSpacesConverter(getTabToSpacesConverter()); StyledText control = sourceViewer.getTextWidget(); diff --git a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/job/ITLCJobStatus.java b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/job/ITLCJobStatus.java index 28e175b6d22d59cd1aa1520dbec5e5d358b8cbfa..c57c0d90767e871e9f9568d7cf430c38326354bb 100644 --- a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/job/ITLCJobStatus.java +++ b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/job/ITLCJobStatus.java @@ -1,5 +1,6 @@ package org.lamport.tla.toolbox.tool.tlc.job; +import java.io.InputStream; import java.net.URL; import org.eclipse.core.runtime.IStatus; @@ -8,4 +9,7 @@ public interface ITLCJobStatus extends IStatus { URL getURL(); + InputStream getOutput(); + + void killTLC(); } diff --git a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/job/TLCJob.java b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/job/TLCJob.java index 232602e963e4fd26b8c7cd3099cef70dbcdf1471..5507b1a9be244065dc81ab9e607676f03d0de000 100644 --- a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/job/TLCJob.java +++ b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/job/TLCJob.java @@ -120,29 +120,24 @@ public abstract class TLCJob extends AbstractJob implements IModelConfigurationC ILaunchConfiguration config = launch.getLaunchConfiguration(); // deadlock - boolean checkDeadlock = config.getAttribute(IModelConfigurationConstants.MODEL_CORRECTNESS_CHECK_DEADLOCK, - IModelConfigurationDefaults.MODEL_CORRECTNESS_CHECK_DEADLOCK_DEFAULT); - if (!checkDeadlock) /* "!" added by LL on 22 Aug 2009 */ + if (!checkDeadlock()) /* "!" added by LL on 22 Aug 2009 */ { arguments.add("-deadlock"); } // adjust checkpointing - arguments.add("-checkpoint"); - arguments.add(String.valueOf(CHECKPOINT_INTERVAL)); - - boolean hasSpec = config.getAttribute(MODEL_BEHAVIOR_SPEC_TYPE, MODEL_BEHAVIOR_TYPE_DEFAULT) != IModelConfigurationDefaults.MODEL_BEHAVIOR_TYPE_NO_SPEC; + if (checkPoint()) { + arguments.add("-checkpoint"); + arguments.add(String.valueOf(CHECKPOINT_INTERVAL)); + } + final boolean hasSpec = hasSpec(config); if (hasSpec) { - boolean runAsModelCheck = config.getAttribute(IModelConfigurationConstants.LAUNCH_MC_MODE, - IModelConfigurationDefaults.LAUNCH_MC_MODE_DEFAULT); - if (runAsModelCheck) + if (runAsModelCheck()) { // look for advanced model checking parameters - boolean isDepthFirst = config.getAttribute(IModelConfigurationConstants.LAUNCH_DFID_MODE, - IModelConfigurationDefaults.LAUNCH_DFID_MODE_DEFAULT); - if (isDepthFirst) + if (isDepthFirst()) { // for depth-first run, look for the depth int dfidDepth = config.getAttribute(IModelConfigurationConstants.LAUNCH_DFID_DEPTH, @@ -183,9 +178,7 @@ public abstract class TLCJob extends AbstractJob implements IModelConfigurationC // recover from checkpoint if (hasSpec) { - boolean recover = config.getAttribute(IModelConfigurationConstants.LAUNCH_RECOVER, - IModelConfigurationDefaults.LAUNCH_RECOVER_DEFAULT); - if (recover) + if (recover()) { IResource[] checkpoints = config.getAdapter(Model.class).getCheckpoints(false); if (checkpoints.length > 0) @@ -225,14 +218,14 @@ public abstract class TLCJob extends AbstractJob implements IModelConfigurationC } // Visualize state graph - final boolean visualizeStateGraph = launch.getLaunchConfiguration().getAttribute(LAUNCH_VISUALIZE_STATEGRAPH, false); - if (visualizeStateGraph && hasSpec) { + if (visualizeStateGraph() && hasSpec) { // Visualize state graph when requested and a behavior spec is given. A behavior - // spec is required for TLC to create states. - arguments.add("-dump"); - arguments.add("dot"); - arguments.add(modelName); - } + // spec is required for TLC to create states. Default to always colorize edges and + // not to add action edge labels. + arguments.add("-dump"); + arguments.add("dot,colorize"); + arguments.add(modelName); + } arguments.add("-config"); arguments.add(cfgFile.getName()); // configuration file @@ -273,6 +266,41 @@ public abstract class TLCJob extends AbstractJob implements IModelConfigurationC return (String[]) arguments.toArray(new String[arguments.size()]); } + + // Allow subclasses to veto command line parameters if needed. + + protected boolean recover() throws CoreException { + return launch.getLaunchConfiguration().getAttribute(IModelConfigurationConstants.LAUNCH_RECOVER, + IModelConfigurationDefaults.LAUNCH_RECOVER_DEFAULT); + } + + protected boolean isDepthFirst() throws CoreException { + return launch.getLaunchConfiguration().getAttribute(IModelConfigurationConstants.LAUNCH_DFID_MODE, + IModelConfigurationDefaults.LAUNCH_DFID_MODE_DEFAULT); + } + + protected boolean runAsModelCheck() throws CoreException { + return launch.getLaunchConfiguration().getAttribute(IModelConfigurationConstants.LAUNCH_MC_MODE, + IModelConfigurationDefaults.LAUNCH_MC_MODE_DEFAULT); + } + + protected boolean checkPoint() { + return true; + } + + protected boolean checkDeadlock() throws CoreException { + return launch.getLaunchConfiguration().getAttribute( + IModelConfigurationConstants.MODEL_CORRECTNESS_CHECK_DEADLOCK, + IModelConfigurationDefaults.MODEL_CORRECTNESS_CHECK_DEADLOCK_DEFAULT); + } + + protected boolean visualizeStateGraph() throws CoreException { + return launch.getLaunchConfiguration().getAttribute(LAUNCH_VISUALIZE_STATEGRAPH, false); + } + + protected boolean hasSpec(final ILaunchConfiguration config) throws CoreException { + return config.getAttribute(MODEL_BEHAVIOR_SPEC_TYPE, MODEL_BEHAVIOR_TYPE_DEFAULT) != IModelConfigurationDefaults.MODEL_BEHAVIOR_TYPE_NO_SPEC; + } /** * Returns the action that tells all registered result diff --git a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/job/TLCProcessJob.java b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/job/TLCProcessJob.java index 93a04490e534d84b530dcdc67bb02a3841904ec8..7874d120cde4610fbb8a8b15d40863026d13141c 100644 --- a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/job/TLCProcessJob.java +++ b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/job/TLCProcessJob.java @@ -31,6 +31,7 @@ import org.lamport.tla.toolbox.util.ResourceHelper; import tlc2.TLC; import tlc2.tool.fp.FPSetFactory; +import tlc2.tool.fp.NoopFPSet; import tlc2.tool.fp.OffHeapDiskFPSet; import util.TLCRuntime; @@ -41,7 +42,8 @@ import util.TLCRuntime; */ public class TLCProcessJob extends TLCJob { - protected IProcess process = null; + public static final int HEAP_SIZE_DEFAULT = 25; + protected IProcess process = null; private BroadcastStreamListener listener = null; /** @@ -100,7 +102,7 @@ public class TLCProcessJob extends TLCJob final List<String> vmArgs = new ArrayList<String>(); // get max heap size as fraction from model editor - final double maxHeapSize = launch.getLaunchConfiguration().getAttribute(LAUNCH_MAX_HEAP_SIZE, 50) / 100d; + final double maxHeapSize = launch.getLaunchConfiguration().getAttribute(LAUNCH_MAX_HEAP_SIZE, HEAP_SIZE_DEFAULT) / 100d; final TLCRuntime instance = TLCRuntime.getInstance(); long absolutePhysicalSystemMemory = instance.getAbsolutePhysicalSystemMemory(maxHeapSize); @@ -109,7 +111,13 @@ public class TLCProcessJob extends TLCJob // TLC's default set. // If the user happened to select OffHeapDiskFPSet, the -XX:MaxDirectMemorySize // is set by getVMArguments. - final String clazz = launch.getLaunchConfiguration().getAttribute(LAUNCH_FPSET_IMPL, (String) null); + String clazz = launch.getLaunchConfiguration().getAttribute(LAUNCH_FPSET_IMPL, (String) null); + if (!hasSpec(launch.getLaunchConfiguration())) { + // If a spec has no behaviors, TLC won't need a fingerprint set. Thus, use the + // NoopFPSet whose initialization cost is next to nothing. Real fpsets on the + // other hand - such as OffHeapDiskFPSet - do heavy weight initialization at startup. + clazz = NoopFPSet.class.getName(); + } if (clazz == null || clazz.equals(OffHeapDiskFPSet.class.getName())) { if (OffHeapDiskFPSet.isSupported()) { // ...good, can use lock-free/scalabe fpset, but need to divide assigned memory @@ -246,7 +254,7 @@ public class TLCProcessJob extends TLCJob } catch (InterruptedException e) { e.printStackTrace(); return new Status(IStatus.ERROR, TLCActivator.PLUGIN_ID, - "Error waiting for process termianation.", e); + "Error waiting for process termination.", e); } } if (!process.isTerminated()) { diff --git a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/job/TraceExplorerJob.java b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/job/TraceExplorerJob.java index ecc57c7884c35821bef6a5fa18f9144d09a55451..928034425dde06d258d2613b4298fe90abd64e43 100644 --- a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/job/TraceExplorerJob.java +++ b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/job/TraceExplorerJob.java @@ -1,7 +1,5 @@ package org.lamport.tla.toolbox.tool.tlc.job; -import java.util.Vector; - import org.eclipse.core.runtime.CoreException; import org.eclipse.debug.core.ILaunch; import org.eclipse.swt.widgets.Display; @@ -46,28 +44,67 @@ public class TraceExplorerJob extends TLCProcessJob }); } - /** - * We override this method in order to always - * make sure that deadlock is always checked. - * This method simply removes "-deadlock" from the - * array of arguments, if it is present in the super class - * implementation of this method. - * - * @throws CoreException - */ - public String[] constructProgramArguments() throws CoreException - { - Vector args = new Vector(); - String[] argsFromSuper = super.constructProgramArguments(); - for (int i = 0; i < argsFromSuper.length; i++) - { - if (!argsFromSuper[i].equals("-deadlock")) - { - args.add(argsFromSuper[i]); - } - } + // Veto several TLC command line arguments only relevant for regular model + // checking but not for trace exploration. This demonstrates why + // TraceExplorerJob shouldn't be a subclass of TLCJob. + + /* (non-Javadoc) + * @see org.lamport.tla.toolbox.tool.tlc.job.TLCJob#recover() + */ + @Override + protected boolean recover() throws CoreException { + // There is nothing that trace exploration could recover from. + return false; + } - return (String[]) args.toArray(new String[args.size()]); - } + /* (non-Javadoc) + * @see org.lamport.tla.toolbox.tool.tlc.job.TLCJob#isDepthFirst() + */ + @Override + protected boolean isDepthFirst() throws CoreException { + // Always want BFS in trace exploration. + return false; + } + + /* (non-Javadoc) + * @see org.lamport.tla.toolbox.tool.tlc.job.TLCJob#runAsModelCheck() + */ + @Override + protected boolean runAsModelCheck() throws CoreException { + // We don't want trace exploration to run in simulation mode. + return true; + } + + /* (non-Javadoc) + * @see org.lamport.tla.toolbox.tool.tlc.job.TLCJob#checkPoint() + */ + @Override + protected boolean checkPoint() { + // Why would the trace explorer create a checkpoint!?! + return false; + } + + /* (non-Javadoc) + * @see org.lamport.tla.toolbox.tool.tlc.job.TLCJob#checkDeadlock() + */ + @Override + protected boolean checkDeadlock() throws CoreException { + // We override this method in order to always make sure that deadlock is always + // checked. This method simply removes "-deadlock" from the array of arguments, + // if it is present in the super class implementation of this method. The trace + // requests deadlock checking - which is turned on when "-deadlock" is NOT set - + // is to always print a counterexample. This counterexample contains the + // evaluated expressions defined in Error-Trace exploration. + return true; + } + /* (non-Javadoc) + * @see org.lamport.tla.toolbox.tool.tlc.job.TLCJob#visualizeStateGraph() + */ + @Override + protected boolean visualizeStateGraph() throws CoreException { + // Never use an IStateWriter to write out the states created by trace + // exploration. A trace is just a txt file with a sequence of states. + return false; + } } diff --git a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/launch/TLCModelLaunchDelegate.java b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/launch/TLCModelLaunchDelegate.java index d2dcdf1046590c7df43e04ccfd8fe662615b7912..8165a2afa9449550053844608faa7c26ce286084 100644 --- a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/launch/TLCModelLaunchDelegate.java +++ b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/launch/TLCModelLaunchDelegate.java @@ -1,8 +1,13 @@ package org.lamport.tla.toolbox.tool.tlc.launch; +import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; import java.net.URL; +import java.util.ArrayList; import java.util.Hashtable; import java.util.List; import java.util.Properties; @@ -22,6 +27,7 @@ import org.eclipse.core.runtime.IExtensionRegistry; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.SubProgressMonitor; import org.eclipse.core.runtime.jobs.IJobChangeEvent; @@ -29,8 +35,10 @@ import org.eclipse.core.runtime.jobs.ISchedulingRule; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.core.runtime.jobs.JobChangeAdapter; import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.DebugPlugin; import org.eclipse.debug.core.ILaunch; import org.eclipse.debug.core.ILaunchConfiguration; +import org.eclipse.debug.core.Launch; import org.eclipse.debug.core.model.IProcess; import org.eclipse.debug.core.model.IStreamsProxy; import org.eclipse.debug.core.model.LaunchConfigurationDelegate; @@ -49,10 +57,11 @@ import org.lamport.tla.toolbox.tool.tlc.job.DistributedTLCJob; import org.lamport.tla.toolbox.tool.tlc.job.ITLCJobStatus; import org.lamport.tla.toolbox.tool.tlc.job.TLCJobFactory; import org.lamport.tla.toolbox.tool.tlc.job.TLCProcessJob; -import org.lamport.tla.toolbox.tool.tlc.model.Assignment; +import org.lamport.tla.toolbox.tool.tlc.model.Assignment; import org.lamport.tla.toolbox.tool.tlc.model.Model; import org.lamport.tla.toolbox.tool.tlc.model.ModelWriter; import org.lamport.tla.toolbox.tool.tlc.model.TypedSet; +import org.lamport.tla.toolbox.tool.tlc.output.IProcessOutputSink; import org.lamport.tla.toolbox.tool.tlc.util.ModelHelper; import org.lamport.tla.toolbox.util.AdapterFactory; import org.lamport.tla.toolbox.util.ResourceHelper; @@ -100,13 +109,24 @@ public class TLCModelLaunchDelegate extends LaunchConfigurationDelegate implemen */ public static final String MODE_GENERATE = "generate"; + private Launch launch; + /** * 1. method called during the launch */ public ILaunch getLaunch(ILaunchConfiguration configuration, String mode) throws CoreException { - // delegate to the super implementation - return super.getLaunch(configuration, mode); + // MAK 02/22/2018 changed super.getLaunch(...) - which returned null - to + // explicitly create the Launch instance here to get hold of the instance. + // Return null here causes + // org.eclipse.debug.internal.core.LaunchConfiguration.launch(String, + // IProgressMonitor, boolean, boolean) to create the instance but it doesn't + // correctly clean up the instance if our finalLaunchCheck below throws an + // error. This in turn causes calls to + // org.lamport.tla.toolbox.tool.tlc.model.Model.isRunning() to return true even + // though finalLaunchCheck threw an exception. + this.launch = new Launch(configuration, mode, null); + return launch; } /** @@ -523,7 +543,7 @@ public class TLCModelLaunchDelegate extends LaunchConfigurationDelegate implemen // parse the MC file IParseResult parseResult = ToolboxHandle.parseModule(rootModule, new SubProgressMonitor(monitor, 1), false, false); - Vector<TLAMarkerInformationHolder> detectedErrors = parseResult.getDetectedErrors(); + final Vector<TLAMarkerInformationHolder> detectedErrors = parseResult.getDetectedErrors(); boolean status = !AdapterFactory.isProblemStatus(parseResult.getStatus()); monitor.worked(1); @@ -574,6 +594,9 @@ public class TLCModelLaunchDelegate extends LaunchConfigurationDelegate implemen } else { + // see getLaunch(...) above + DebugPlugin.getDefault().getLaunchManager().removeLaunch(this.launch); + // the reported error is not pointing to the MC file. throw new CoreException(new Status(IStatus.ERROR, TLCActivator.PLUGIN_ID, "Fatal error during validation of the model. " @@ -583,6 +606,9 @@ public class TLCModelLaunchDelegate extends LaunchConfigurationDelegate implemen } } else { + // see getLaunch(...) above + DebugPlugin.getDefault().getLaunchManager().removeLaunch(this.launch); + throw new CoreException(new Status(IStatus.ERROR, TLCActivator.PLUGIN_ID, "Fatal error during validation of the model. " + "SANY discovered an error somewhere else than the MC file. " @@ -728,6 +754,13 @@ public class TLCModelLaunchDelegate extends LaunchConfigurationDelegate implemen tlcParams.append(" "); } + // add -lncheck final if requested. + if (model.getAttribute(LAUNCH_DEFER_LIVENESS, false)) { + tlcParams.append("-lncheck "); + tlcParams.append("final"); + tlcParams.append(" "); + } + boolean checkDeadlock = config.getAttribute(IModelConfigurationConstants.MODEL_CORRECTNESS_CHECK_DEADLOCK, IModelConfigurationDefaults.MODEL_CORRECTNESS_CHECK_DEADLOCK_DEFAULT); if (!checkDeadlock) { @@ -893,7 +926,7 @@ public class TLCModelLaunchDelegate extends LaunchConfigurationDelegate implemen this.model = model; } - public void done(IJobChangeEvent event) + public void done(final IJobChangeEvent event) { super.done(event); @@ -964,10 +997,101 @@ public class TLCModelLaunchDelegate extends LaunchConfigurationDelegate implemen refreshJob = new WorkspaceJob("Taking snapshot of " + model.getName() + "...") { public IStatus runInWorkspace(final IProgressMonitor monitor) throws CoreException { monitor.beginTask("Taking snapshot of " + model.getName() + "...", 1); - model.snapshot(); + final Model snapshot = model.snapshot(); + + // If the result is an ITLCJobStatus, it means that TLC is running with Cloud + // TLC. In other words, it is running remotely. Thus, we get the output from + // the remote cloud instance and feed it to the regular Toolbox sinks. + final IStatus status = event.getJob().getResult(); + if (status instanceof ITLCJobStatus) { + + snapshot.setRunningRemotely(true); + + final List<IProcessOutputSink> sinks = getProcessOutputSinks(snapshot); + // Wrap in a job so that the parent job of which this joblistener is being + // called can terminate. Otherwise, the model remains in model checking state. + final Job j = new Job( + String.format("Consuming output of Cloud TLC for model %s", model.getName())) { + @Override + protected IStatus run(IProgressMonitor monitor) { + final ITLCJobStatus tlcJobStatus = (ITLCJobStatus) status; + // Read the output provided by the status and send it to all sinks. The sinks + // take care of updating the UI. + final InputStream output = tlcJobStatus.getOutput(); + try { + final BufferedReader in = new BufferedReader( + new InputStreamReader(output)); + String line; + while ((line = in.readLine()) != null) { + // sinks expect a newline to correctly handle the line. + for (IProcessOutputSink iProcessOutputSink : sinks) { + iProcessOutputSink.appendText(line + "\n"); + } + + // Kill remote process when monitor gets c + if (monitor.isCanceled() && !PlatformUI.getWorkbench().isClosing()) { + tlcJobStatus.killTLC(); + return Status.OK_STATUS; + } + } + } catch (IOException e) { + if (e.getClass().getName() + .equals("net.schmizz.sshj.transport.TransportException")) { + // Indicates TLC process has terminated. + return Status.OK_STATUS; + } + return new Status(IStatus.ERROR, TLCActivator.PLUGIN_ID, e.getMessage(), e); + } finally { + snapshot.setRunningRemotely(false); + } + return Status.OK_STATUS; + } + + /* (non-Javadoc) + * @see org.eclipse.core.runtime.jobs.Job#belongsTo(java.lang.Object) + */ + @Override + public boolean belongsTo(final Object family) { + return snapshot == family; + } + + @Override + protected void canceling() { + if (PlatformUI.getWorkbench().isClosing()) { + // Do not terminate the remote instance when the Toolbox gets closed. + super.canceling(); + return; + } + if (status instanceof ITLCJobStatus && snapshot.isRunningRemotely()) { + final ITLCJobStatus tlcJobStatus = (ITLCJobStatus) status; + tlcJobStatus.killTLC(); + snapshot.setRunningRemotely(false); + } + super.canceling(); + } + }; + j.schedule(); + } monitor.done(); return Status.OK_STATUS; } + + private List<IProcessOutputSink> getProcessOutputSinks(final Model snapshot) { + final IConfigurationElement[] decls = Platform.getExtensionRegistry() + .getConfigurationElementsFor(IProcessOutputSink.EXTENSION_ID); + final List<IProcessOutputSink> sinks = new ArrayList<>(decls.length); + for (int i = 0; i < decls.length; i++) { + try { + final IProcessOutputSink sink = (IProcessOutputSink) decls[i] + .createExecutableExtension("class"); + sink.initializeSink(snapshot, IProcessOutputSink.TYPE_OUT); + sinks.add(sink); + } catch (CoreException e) { + TLCActivator.logError("Error instatiating the IProcessSink extension", e); + } + } + return sinks; + } }; refreshJob.setRule(model.getSpec().getProject()); refreshJob.schedule(); diff --git a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/launch/TraceExplorerDelegate.java b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/launch/TraceExplorerDelegate.java index 4382b591c025eac4bf61c5b2487e4c7b68b42414..bd64336d1d33575a656c34a8d4a29d0290c39408 100644 --- a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/launch/TraceExplorerDelegate.java +++ b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/launch/TraceExplorerDelegate.java @@ -61,6 +61,7 @@ import org.lamport.tla.toolbox.tool.tlc.model.Assignment; import org.lamport.tla.toolbox.tool.tlc.model.Model; import org.lamport.tla.toolbox.tool.tlc.model.ModelWriter; import org.lamport.tla.toolbox.tool.tlc.model.TLCSpec; +import org.lamport.tla.toolbox.tool.tlc.model.TraceExpressionModelWriter; import org.lamport.tla.toolbox.tool.tlc.model.TypedSet; import org.lamport.tla.toolbox.tool.tlc.traceexplorer.SimpleTLCState; import org.lamport.tla.toolbox.tool.tlc.util.ModelHelper; @@ -410,7 +411,7 @@ public class TraceExplorerDelegate extends TLCModelLaunchDelegate implements ILa // trace = TLCErrorTraceRegistry.getErrorTraceRegistry().getTrace(config); trace = model.getErrorTrace(); - ModelWriter writer = new ModelWriter(); + final TraceExpressionModelWriter writer = new TraceExpressionModelWriter(); // add extend primer writer.addPrimer(ModelHelper.TE_MODEL_NAME, ResourceHelper.getModuleName(model.getSpec().getRootFilename())); @@ -434,14 +435,14 @@ public class TraceExplorerDelegate extends TLCModelLaunchDelegate implements ILa * of each expression. This is done in finalLaunchCheck() using the ParseResult * object returned by SANY. */ - traceExpressionData = writer.createAndAddTEVariablesAndDefinitions(ModelHelper.deserializeFormulaList(config + traceExpressionData = writer.createAndAddVariablesAndDefinitions(ModelHelper.deserializeFormulaList(config .getAttribute(IModelConfigurationConstants.TRACE_EXPLORE_EXPRESSIONS, new Vector<String>())), TRACE_EXPLORE_EXPRESSIONS); // add the initial state predicate and next state action without // the trace exploration expressions in order to determine if they parse // initNext[0] is the identifier for init, initNext[1] is the identifier for next - String[] initNext = writer.addInitNextForTE(trace, null); + String[] initNext = writer.addInitNext(trace, null); if (initNext != null) { initId = initNext[0]; @@ -604,11 +605,11 @@ public class TraceExplorerDelegate extends TLCModelLaunchDelegate implements ILa monitor.subTask("Creating contents"); - ModelWriter writer = new ModelWriter(); + final TraceExpressionModelWriter writer = new TraceExpressionModelWriter(); // add comments giving information about the level of each expression and // which variable corresponds to which expression - writer.addTraceExplorerExpressionInfoComments(traceExpressionData); + writer.addInfoComments(traceExpressionData); // add extend primer writer.addPrimer(ModelHelper.TE_MODEL_NAME, ResourceHelper.getModuleName(model.getSpec().getRootFilename())); @@ -617,10 +618,10 @@ public class TraceExplorerDelegate extends TLCModelLaunchDelegate implements ILa writeModelInfo(configuration, writer); // variables declarations for trace explorer expressions - writer.addTEVariablesAndDefinitions(traceExpressionData, TRACE_EXPLORE_EXPRESSIONS, false); + writer.addVariablesAndDefinitions(traceExpressionData, TRACE_EXPLORE_EXPRESSIONS, false); // add init and next - writer.addInitNextForTE(trace, traceExpressionData, initId, nextId); + writer.addInitNext(trace, traceExpressionData, initId, nextId); SimpleTLCState finalState = (SimpleTLCState) trace.get(trace.size() - 1); boolean isBackToState = finalState.isBackToState(); @@ -630,10 +631,10 @@ public class TraceExplorerDelegate extends TLCModelLaunchDelegate implements ILa // read the method comments to see the form of the invariant or property if (isStuttering) { - writer.addStutteringPropertyForTraceExplorer((SimpleTLCState) trace.get(trace.size() - 2)); + writer.addStutteringProperty((SimpleTLCState) trace.get(trace.size() - 2)); } else if (isBackToState) { - writer.addBackToStatePropertyForTraceExplorer((SimpleTLCState) trace.get(trace.size() - 2), + writer.addBackToStateProperty((SimpleTLCState) trace.get(trace.size() - 2), (SimpleTLCState) trace.get(finalState.getStateNumber() - 1)); } else { diff --git a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/model/Model.java b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/model/Model.java index e62fee95bc847918c7af6feeb8cdde337223ed00..b90c75a3f47b33c3acfddadec964fca7f9fc6fa9 100644 --- a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/model/Model.java +++ b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/model/Model.java @@ -146,7 +146,7 @@ public class Model implements IModelConfigurationConstants, IAdaptable { public static class ChangeEvent { public enum State { - RUNNING, NOT_RUNNING, DELETED; + RUNNING, NOT_RUNNING, DELETED, REMOTE_RUNNING, REMOTE_NOT_RUNNING; public boolean in(State ... states) { for (State state : states) { @@ -261,13 +261,21 @@ public class Model implements IModelConfigurationConstants, IAdaptable { } } - public void rename(String newModelName) { + public void rename(String newModelName, IProgressMonitor monitor) throws CoreException { final Collection<Model> snapshots = getSnapshots(); + // Rename the model directory to the new name. + final IFolder modelDir = getTargetDirectory(); + if (modelDir != null && modelDir.exists()) { + final IPath src = modelDir.getFullPath(); + final IPath dst = src.removeLastSegments(1).append(newModelName); + modelDir.move(dst, true, monitor); + } + renameLaunch(getSpec(), sanitizeName(newModelName)); for (Model snapshot : snapshots) { - snapshot.rename(newModelName + snapshot.getSnapshotSuffix()); + snapshot.rename(newModelName + snapshot.getSnapshotSuffix(), monitor); } } @@ -378,6 +386,17 @@ public class Model implements IModelConfigurationConstants, IAdaptable { } } + private boolean isRunningRemotely = false; + + public boolean isRunningRemotely() { + return this.isRunningRemotely; + } + + public void setRunningRemotely(boolean isRunning) { + this.isRunningRemotely = isRunning; + notifyListener(new StateChangeListener.ChangeEvent(this, isRunning ? State.REMOTE_RUNNING : State.REMOTE_NOT_RUNNING)); + } + /* * Snapshot related methods. */ @@ -399,7 +418,7 @@ public class Model implements IModelConfigurationConstants, IAdaptable { } public Collection<Model> getSnapshots() { - return getSpec().getModels(getName() + SNAPSHOT_REGEXP, true).values(); + return getSpec().getModels(Pattern.quote(getName()) + SNAPSHOT_REGEXP, true).values(); } public boolean isSnapshot() { @@ -407,7 +426,7 @@ public class Model implements IModelConfigurationConstants, IAdaptable { } public boolean hasSnapshots() { - return !getSpec().getModels(getName() + SNAPSHOT_REGEXP, true).isEmpty(); + return !getSpec().getModels(Pattern.quote(getName()) + SNAPSHOT_REGEXP, true).isEmpty(); } public Model getSnapshotFor() { @@ -499,7 +518,9 @@ public class Model implements IModelConfigurationConstants, IAdaptable { public boolean hasStateGraphDump() { final String name = getName().concat(DOT_FILE_EXT); - final IFile file = getFolder().getFile(name); + // Convert to java.io.File rather than Eclipse's IFile. For the latter + // file.exists might return null if Eclipse's internal FS cache is stale. + final File file = getFolder().getFile(name).getLocation().toFile(); return file.exists(); } @@ -721,11 +742,14 @@ public class Model implements IModelConfigurationConstants, IAdaptable { } /** - * Retrieves the working directory for the model - * <br>Note, this is a handle operation only, the resource returned may not exist - * @param config - * @return the Folder. - */ + * Retrieves the working directory for the model. Returns null if the model has + * not run yet. In other words, gets created by running TLC.<br> + * Note, this is a handle operation only, the resource returned may not exist + * + * @param config + * @return the Folder. + * @see Model#getFolder() + */ public IFolder getTargetDirectory() { return (IFolder) getSpec().getProject().findMember(getName()); } @@ -1052,13 +1076,9 @@ public class Model implements IModelConfigurationConstants, IAdaptable { return launch; } - public void launch(String mode, IProgressMonitor subProgressMonitor, boolean build) { - try { - Assert.isTrue(this.workingCopy == null, "Cannot launch dirty model, save first."); - this.launch = this.launchConfig.launch(mode, subProgressMonitor, build); - } catch (CoreException shouldNotHappen) { - TLCActivator.logError(shouldNotHappen.getMessage(), shouldNotHappen); - } + public void launch(String mode, IProgressMonitor subProgressMonitor, boolean build) throws CoreException { + Assert.isTrue(this.workingCopy == null, "Cannot launch dirty model, save first."); + this.launch = this.launchConfig.launch(mode, subProgressMonitor, build); } public Model save(final IProgressMonitor monitor) { diff --git a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/model/ModelWriter.java b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/model/ModelWriter.java index 4713750461e97b23cef648775a790d889c459622..eacbe82bd1f7c91e4071815ba4273029c2194ea3 100644 --- a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/model/ModelWriter.java +++ b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/model/ModelWriter.java @@ -26,7 +26,6 @@ package org.lamport.tla.toolbox.tool.tlc.model; import java.util.Hashtable; -import java.util.Iterator; import java.util.List; import java.util.Vector; import java.util.concurrent.atomic.AtomicLong; @@ -40,10 +39,6 @@ import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.Region; import org.lamport.tla.toolbox.tool.ToolboxHandle; -import org.lamport.tla.toolbox.tool.tlc.launch.IModelConfigurationConstants; -import org.lamport.tla.toolbox.tool.tlc.launch.TraceExpressionInformationHolder; -import org.lamport.tla.toolbox.tool.tlc.traceexplorer.SimpleTLCState; -import org.lamport.tla.toolbox.tool.tlc.traceexplorer.SimpleTLCVariable; import org.lamport.tla.toolbox.tool.tlc.util.ModelHelper; import org.lamport.tla.toolbox.util.ResourceHelper; @@ -101,8 +96,8 @@ public class ModelWriter public static final String L_PAREN = "("; public static final String R_PAREN = ")"; - private StringBuffer tlaBuffer; - private StringBuffer cfgBuffer; + protected final StringBuffer tlaBuffer; + protected final StringBuffer cfgBuffer; /** * Constructs new model writer @@ -362,714 +357,6 @@ public class ModelWriter } } - /** - * This only changes the tla file. This method generates and adds a variable declaration - * for each expression in the list. It also creates an identifier for each - * expression and defines the identifier to be that expression. - * It returns an array of {@link TraceExpressionInformationHolder} where each element - * contains the expression, the identifier, and the variable name. - * - * If the expressions are x' + y and x > 3, The tla file will contain something like - * - *\* comment line - * VARIABLES __trace_var_21034978347834, __trace_var_90234782309 - * - * \* comment line - * trace_def_3214234234234 == - * x' + y - * ---- - * - * \* comment line - * trace_def_2342342342342 == - * x > 3 - * ---- - * - * @param expressions a list of formulas, each one an expression the user wants to have evaluated - * at each state of the trace - * @return array of {@link TraceExpressionInformationHolder} where each element - * contains the expression, the identifier, and the variable name - */ - public TraceExpressionInformationHolder[] createAndAddTEVariablesAndDefinitions(List<Formula> expressions, - String attributeName) - { - - TraceExpressionInformationHolder[] expressionData = new TraceExpressionInformationHolder[expressions.size()]; - Iterator<Formula> it = expressions.iterator(); - int position = 0; - while (it.hasNext()) - { - String expression = it.next().getFormula(); - - if (expression != null && expression.length() > 0) - { - expressionData[position] = new TraceExpressionInformationHolder(expression, - getValidIdentifier(TRACE_EXPR_DEF_SCHEME), getValidIdentifier(TRACE_EXPR_VAR_SCHEME)); - } - - position++; - } - - addTEVariablesAndDefinitions(expressionData, attributeName, true); - - return expressionData; - } - - /** - * This only changes the tla file. This method adds a variable declaration - * for each element of traceExpressionData and, if the flag addDefinitions is true, - * defines the identifier of each element to be the expression for that element. - * - * If the expressions are x' + y and x > 3, The tla file will contain something like - * - *\* comment line - * VARIABLES __trace_var_21034978347834, __trace_var_90234782309 - * - * \* comment line - * trace_def_3214234234234 == - * x' + y - * ---- - * - * \* comment line - * trace_def_2342342342342 == - * x > 3 - * ---- - * - * @param traceExpressionData information about the trace expressions - * @param attributeName - * @param addDefinitions whether or not to define each identifier as the expression - */ - public void addTEVariablesAndDefinitions(TraceExpressionInformationHolder[] traceExpressionData, - String attributeName, boolean addDefinitions) - { - if (traceExpressionData.length == 0) - { - return; - } - - StringBuffer variableDecls = new StringBuffer(); - StringBuffer definitions = new StringBuffer(); - - for (int i = 0; i < traceExpressionData.length; i++) - { - TraceExpressionInformationHolder expressionInfo = traceExpressionData[i]; - - variableDecls.append(expressionInfo.getVariableName()); - // we add a comma after every variable except for the last - if (i != traceExpressionData.length - 1) - { - variableDecls.append(COMMA); - } - - if (addDefinitions) - { - // define the identifier corresponding to this expression - looks like: - // \* comment line - // trace_def_213123123123 == - // expression - // ---- - definitions.append(COMMENT).append("TRACE EXPLORER identifier definition ").append(ATTRIBUTE).append( - attributeName).append(CR); - definitions.append(expressionInfo.getIdentifier()).append(DEFINES_CR).append( - expressionInfo.getExpression()).append(CR); - definitions.append(SEP).append(CR).append(CR); - } - } - - // variable declaration - tlaBuffer.append(COMMENT).append("TRACE EXPLORER variable declaration ").append(ATTRIBUTE) - .append(attributeName).append(CR); - tlaBuffer.append("VARIABLES ").append(variableDecls.toString()).append(CR); - - tlaBuffer.append(SEP).append(CR).append(CR); - - if (addDefinitions) - { - // append the expression definitions - tlaBuffer.append(definitions.toString()); - } - } - - /** - * This will generate two identifiers equal to the initial and next state - * predicate for the trace. If expressionData is not null, it should contain information - * about trace explorer expressions. This information is used to appropriately put - * the variables representing trace explorer expressions in the trace. In the following example, trace - * explorer expressions are used, but if expressionData is null, those variables will not appear in the - * init and next definitions, but everything else will be the same. - * - * Note: In the following example, the expressions expr1,...,expr6, texpr1, texpr2 can take up multiple - * lines. - * - * Consider the following trace: - * - * <Initial predicate> <State num 1> - * var1=expr1 - * var2=expr2 - * - * <Action...> <State num 2> - * var1=expr3 - * var2=expr4 - * - * <Action...> <State num 3> - * var1=expr5 - * var2=expr6 - * - * The user has defined two expressions in the trace explorer: - * - * texpr1 (level 2 represented by var3) - * texpr2 (level 1 represented by var4) - * - * This method defines the following identifiers: - * - * init_4123123123 == - * var1=( - * expr1 - * )/\ - * var2=( - * expr2 - * )/\ - * var3=( - * "--" - * )/\ - * var4=( - * texpr2 - * ) - * - * next_12312312312 == - * (var1=( - * expr1 - * )/\ - * var2=( - * expr2 - * )/\ - * var1'=( - * expr3 - * )/\ - * var2'=( - * expr4 - * )/\ - * var3'=( - * texpr1 - * )/\ - * var4'=( - * texpr2 - * )') - * \/ - * (var1=( - * expr3 - * )/\ - * var2=( - * expr4 - * )/\ - * var1'=( - * expr5 - * )/\ - * var2'=( - * expr6 - * )/\ - * var3'=( - * texpr1 - * )/\ - * var4'=( - * texpr2 - * )') - * - * If the last state is back to state i, then this method treats - * the trace as if it has the state labeled "Back to state i" removed and - * replaced with a copy of state i. - * - * If the last state is stuttering, then this method treats the trace as if it - * has the state labeled "Stuttering" removed and replaced with a copy - * of the state before the state labeled "Stuttering". - * - * @param trace - * @param expressionData data on trace explorer expressions, can be null - * @return String[], first element is the identifier for the initial state predicate, - * second element is the identifier for the next-state action - */ - public String[] addInitNextForTE(List<SimpleTLCState> trace, TraceExpressionInformationHolder[] expressionData) - { - String initId = getValidIdentifier(INIT_SCHEME); - String nextId = getValidIdentifier(NEXT_SCHEME); - - addInitNextForTE(trace, expressionData, initId, nextId); - - return new String[] { initId, nextId }; - } - - /** - * This will set initId equal to the initial state predicate and nextId equal to the next state - * action for the trace. If expressionData is not null, it should contain information - * about trace explorer expressions. This information is used to appropriately put - * the variables representing trace explorer expressions in the trace. In the following example, trace - * explorer expressions are used, but if expressionData is null, those variables will not appear in the - * init and next definitions, but everything else will be the same. - * - * Note: In the following example, the expressions expr1,...,expr6, texpr1, texpr2 can take up multiple - * lines. - * - * Consider the following trace: - * - * <Initial predicate> <State num 1> - * var1=expr1 - * var2=expr2 - * - * <Action...> <State num 2> - * var1=expr3 - * var2=expr4 - * - * <Action...> <State num 3> - * var1=expr5 - * var2=expr6 - * - * The user has defined two expressions in the trace explorer: - * - * texpr1 (level 2 represented by var3) - * texpr2 (level 1 represented by var4) - * - * This method defines the following identifiers: - * - * init_4123123123 == - * var1=( - * expr1 - * )/\ - * var2=( - * expr2 - * )/\ - * var3=( - * "--" - * )/\ - * var4=( - * texpr2 - * ) - * - * next_12312312312 == - * (var1=( - * expr1 - * )/\ - * var2=( - * expr2 - * )/\ - * var1'=( - * expr3 - * )/\ - * var2'=( - * expr4 - * )/\ - * var3'=( - * texpr1 - * )/\ - * var4'=( - * texpr2 - * )') - * \/ - * (var1=( - * expr3 - * )/\ - * var2=( - * expr4 - * )/\ - * var1'=( - * expr5 - * )/\ - * var2'=( - * expr6 - * )/\ - * var3'=( - * texpr1 - * )/\ - * var4'=( - * texpr2 - * )') - * - * If the last state is back to state i, then this method treats - * the trace as if it has the state labeled "Back to state i" removed and - * replaced with a copy of state i. - * - * If the last state is stuttering, then this method treats the trace as if it - * has the state labeled "Stuttering" removed and replaced with a copy - * of the state before the state labeled "Stuttering". - * - * @param trace - * @param expressionData data on trace explorer expressions, can be null - * @param initId the identifier to be used for the initial state predicate, cannot be null - * @param nextId the identifier to be used for the next-state action, cannot be null - */ - public void addInitNextForTE(List<SimpleTLCState> trace, TraceExpressionInformationHolder[] expressionData, String initId, - String nextId) - { - - if (trace.size() > 0) - { - Iterator<SimpleTLCState> it = trace.iterator(); - SimpleTLCState currentState = it.next(); - - /******************************************************* - * Add the init definition. * - *******************************************************/ - cfgBuffer.append(COMMENT).append("INIT definition").append(CR); - cfgBuffer.append("INIT").append(CR); - cfgBuffer.append(initId).append(CR); - - tlaBuffer.append(COMMENT).append("TRACE INIT definition").append( - IModelConfigurationConstants.TRACE_EXPLORE_INIT).append(CR); - tlaBuffer.append(initId).append(DEFINES_CR); - SimpleTLCVariable[] vars = currentState.getVars(); - - // variables from spec - for (int i = 0; i < vars.length; i++) - { - SimpleTLCVariable var = vars[i]; - /* - * var=( - * expr - * ) - */ - tlaBuffer.append(var.getVarName()).append(EQ).append(L_PAREN).append(CR).append(var.getValueAsString()) - .append(CR).append(R_PAREN); - /* - * Add /\ after right parenthesis except for the last variable - * - * var=( - * expr - * )/\ - */ - if (i != vars.length - 1) - { - tlaBuffer.append(TLA_AND).append(CR); - } - } - - // variables representing trace explorer expressions - if (expressionData != null) - { - for (int i = 0; i < expressionData.length; i++) - { - TraceExpressionInformationHolder expressionInfo = expressionData[i]; - tlaBuffer.append(TLA_AND).append(CR).append(expressionInfo.getVariableName()).append(EQ).append( - L_PAREN).append(CR); - - if (expressionInfo.getLevel() == 2) - { - // add "--" if the expression is temporal level - tlaBuffer.append(TRACE_NA); - } else - { - // add the actual expression if it is not temporal level - tlaBuffer.append(expressionInfo.getExpression()); - } - - tlaBuffer.append(CR).append(R_PAREN); - } - } - - tlaBuffer.append(CR).append(SEP).append(CR).append(CR); - - /********************************************************** - * Now add the next state actions definition * - **********************************************************/ - cfgBuffer.append(COMMENT).append("NEXT definition").append(CR); - cfgBuffer.append("NEXT").append(CR); - cfgBuffer.append(nextId).append(CR); - - tlaBuffer.append(COMMENT).append("TRACE NEXT definition").append( - IModelConfigurationConstants.TRACE_EXPLORE_NEXT).append(CR); - tlaBuffer.append(nextId).append(DEFINES_CR); - - SimpleTLCState nextState = null; - boolean isSingleState; - if (it.hasNext()) - { - nextState = (SimpleTLCState) it.next(); - isSingleState = false; - } else - { - nextState = currentState; - isSingleState = true; - } - - while (nextState != null) - { - /* - * Handle Back to state and stuttering. - * - * nextState is assigned to the state which the "Back to state" - * or "Stuttering" state represents. If nextState is "Back to state i", - * then it is assigned to state i. If nextState is "Stuttering", then - * it is assigned to the current state. - */ - if (nextState.isBackToState()) - { - nextState = (SimpleTLCState) trace.get(nextState.getStateNumber() - 1); - } else if (nextState.isStuttering()) - { - nextState = currentState; - } - - /* - * Write the action: - * - * (var1=( - * expr1 - * )/\ - * var2=( - * expr2 - * )/\ - * var1'=( - * expr3 - * )/\ - * var2'=( - * expr4 - * )) - */ - tlaBuffer.append(L_PAREN); - - SimpleTLCVariable[] currentStateVars = currentState.getVars(); - SimpleTLCVariable[] nextStateVars = nextState.getVars(); - - /* - * Iterate through current state variables. This adds: - * - * var1=( - * expr1 - * )/\ - * var2=( - * expr2 - * )/\ - * - */ - for (int i = 0; i < currentStateVars.length; i++) - { - SimpleTLCVariable currentStateVar = currentStateVars[i]; - tlaBuffer.append(currentStateVar.getVarName()).append(EQ).append(L_PAREN).append(CR).append( - currentStateVar.getValueAsString()).append(CR).append(R_PAREN).append(TLA_AND).append(CR); - } - - /* - * If the trace is a single state, make the next state - * action never enabled. The model will deadlock in the initial state. - * This adds: - * - * FALSE - * /\ - */ - if (isSingleState) - { - tlaBuffer.append("FALSE").append(CR).append(TLA_AND).append(CR); - } - - /* - * Iterate through next state variables. This adds: - * - * var1'=( - * expr3 - * )/\ - * var2'=( - * expr4 - * ) - */ - for (int i = 0; i < currentStateVars.length; i++) - { - SimpleTLCVariable nextStateVar = nextStateVars[i]; - tlaBuffer.append(nextStateVar.getVarName()).append(PRIME).append(EQ).append(L_PAREN).append(CR) - .append(nextStateVar.getValueAsString()).append(CR).append(R_PAREN); - // add /\ for each variable except the last one - if (i != currentStateVars.length - 1) - { - tlaBuffer.append(TLA_AND).append(CR); - } - } - - /* - * Iterate through the trace explorer expressions if there are any. This adds: - * - * /\ - * var3'=( - * texpr1 - * )/\ - * var4'=( - * texpr2 - * )' - * - */ - if (expressionData != null) - { - for (int i = 0; i < expressionData.length; i++) - { - TraceExpressionInformationHolder expressionInfo = expressionData[i]; - tlaBuffer.append(TLA_AND).append(CR).append(expressionInfo.getVariableName()).append(PRIME) - .append(EQ).append(L_PAREN).append(CR).append(expressionInfo.getExpression()) - .append(CR).append(R_PAREN); - - if (expressionInfo.getLevel() < 2) - { - tlaBuffer.append(PRIME); - } - } - } - - tlaBuffer.append(R_PAREN); - - if (it.hasNext()) - { - tlaBuffer.append(CR).append(TLA_OR).append(CR); - } - - currentState = nextState; - - if (it.hasNext()) - { - nextState = (SimpleTLCState) it.next(); - } else - { - nextState = null; - } - } - - tlaBuffer.append(CR).append(SEP).append(CR).append(CR); - - } - - } - - /** - * Adds the invariant ~(P) where P is the formula describing finalState. The format - * in the tla file is as follows: - * - * inv_12312321321 == - * ~( - * P - * ) - * ---- - * - * @param finalState - */ - public void addInvariantForTraceExplorer(SimpleTLCState finalState) - { - String id = getValidIdentifier(INVARIANT_SCHEME); - cfgBuffer.append(COMMENT).append("INVARIANT definition").append(CR); - cfgBuffer.append("INVARIANT").append(CR); - cfgBuffer.append(id).append(CR); - - tlaBuffer.append(COMMENT).append("INVARIANT definition").append(CR); - tlaBuffer.append(id).append(DEFINES_CR); - tlaBuffer.append(TLA_NOT).append(L_PAREN).append(CR).append(getStateConjunction(finalState)).append(CR).append( - R_PAREN).append(CR); - - tlaBuffer.append(SEP).append(CR).append(CR); - } - - /** - * Adds the temporal property ~<>[](P) where P is the formula describing finalState. - * The format in the tla file is as follows: - * - * prop_23112321 == - * ~<>[]( - * P - * ) - * ---- - * - * @param finalState - */ - public void addStutteringPropertyForTraceExplorer(SimpleTLCState finalState) - { - String id = getValidIdentifier(PROP_SCHEME); - cfgBuffer.append(COMMENT).append("PROPERTY definition").append(CR); - cfgBuffer.append("PROPERTY").append(CR); - cfgBuffer.append(id).append(CR); - - tlaBuffer.append(COMMENT).append("PROPERTY definition").append(CR); - tlaBuffer.append(id).append(DEFINES_CR); - tlaBuffer.append(TLA_NOT).append(TLA_EVENTUALLY_ALWAYS).append(L_PAREN).append(CR).append( - getStateConjunction(finalState)).append(CR).append(R_PAREN).append(CR); - - tlaBuffer.append(SEP).append(CR).append(CR); - } - - /** - * Adds the temporal property ~([]<>P /\ []<>Q), where P is the formula describing finalState and - * Q the formula describing backToState. The formating in the tla file is as follows: - * - * prop_21321312 == - * ~(([]<>( - * P - * ))/\([]<>( - * Q - * ))) - * ---- - * - * @param finalState - * @param backToState - */ - public void addBackToStatePropertyForTraceExplorer(SimpleTLCState finalState, SimpleTLCState backToState) - { - String id = getValidIdentifier(PROP_SCHEME); - cfgBuffer.append(COMMENT).append("PROPERTY definition").append(CR); - cfgBuffer.append("PROPERTY").append(CR); - cfgBuffer.append(id).append(CR); - - tlaBuffer.append(COMMENT).append("PROPERTY definition").append(CR); - tlaBuffer.append(id).append(DEFINES_CR); - tlaBuffer.append(TLA_NOT).append(L_PAREN).append(L_PAREN).append(TLA_INF_OFTEN).append(L_PAREN).append(CR) - .append(getStateConjunction(finalState)).append(CR).append(R_PAREN).append(R_PAREN).append(TLA_AND) - .append(L_PAREN).append(TLA_INF_OFTEN).append(L_PAREN).append(CR).append( - getStateConjunction(backToState)).append(CR).append(R_PAREN).append(R_PAREN).append(R_PAREN) - .append(CR); - - tlaBuffer.append(SEP).append(CR).append(CR); - } - - /** - * Returns a string representing the formula describing the state. - * If the state has var1=expr1, var2 = expr2, and var3=expr3, then this returns: - * - * var1=( - * expr1 - * )/\ - * var2=( - * expr2 - * )/\ - * var3=( - * expr3 - * ) - * - * - * The expressions expr1, expr2, and expr3 can take up multiple lines. - * - * This will return null if the state is stuttering or back to state. - * - * @param state - * @return - */ - private static String getStateConjunction(SimpleTLCState state) - { - if (state.isBackToState()) - { - return null; - } else if (state.isStuttering()) - { - return null; - } else - { - StringBuffer formula = new StringBuffer(); - SimpleTLCVariable[] vars = state.getVars(); - for (int i = 0; i < vars.length; i++) - { - SimpleTLCVariable var = vars[i]; - formula.append(var.getVarName()).append(EQ).append(L_PAREN).append(CR).append(var.getValueAsString()) - .append(CR).append(R_PAREN); - - // append /\ except for the last variable - if (i != vars.length - 1) - { - formula.append(TLA_AND).append(CR); - } - } - - return formula.toString(); - } - } - /** * Adds the ASSUME PrintT statement and identifier for the constant expression * evaluation. The MC.tla file will contain: @@ -1223,27 +510,6 @@ public class ModelWriter tlaBuffer.append(definitions).append(CR).append(SEP).append(CR); } - /** - * Writes comments that will be used for associating variable names with expressions - * and will give the level of each expression. In particular, for each expression "expr" - * with level x and variable name ___trace_var_3242348934343 this - * will append the following comment to the tla file: - * - * \* :x:___trace_var_3242348934343:expr"$!@$!@$!@$!@$!" - * - * @param traceExpressionData - */ - public void addTraceExplorerExpressionInfoComments(TraceExpressionInformationHolder[] traceExpressionData) - { - for (int i = 0; i < traceExpressionData.length; i++) - { - TraceExpressionInformationHolder expressionData = traceExpressionData[i]; - tlaBuffer.append(COMMENT).append(INDEX).append(expressionData.getLevel()).append(INDEX).append( - expressionData.getVariableName()).append(INDEX).append(expressionData.getExpression()).append( - CONSTANT_EXPRESSION_EVAL_IDENTIFIER).append(CR); - } - } - /** * Create the content for a single source element * @return a list with at most one String[] element @@ -1459,147 +725,6 @@ public class ModelWriter return resultContent; } - /** - * This adds the trace explorer variables to initWithoutTraceVars. - * The method returns a list with one element, a - * String[]. The first element of the array is put in TE.cfg, and the - * second element is put in TE.tla. The intention is to use - * the return value as the first argument of {@link ModelWriter#addFormulaList(List, String, String)}. - * - * This can be best explained with an example. - * - * The trace is the following: - - STATE 1: <Initial predicate> - /\ x = 0 - /\ y = 0 - - STATE 2: <Action line 8, col 3 to line 9, col 15 of module Test> - /\ x = 1 - /\ y = 0 - - STATE 3: <Action line 8, col 3 to line 9, col 15 of module Test> - /\ x = 2 - /\ y = 1 - - STATE 4: <Action line 8, col 3 to line 9, col 15 of module Test> - /\ x = 3 - /\ y = 3 - - The user wants to evaluate two expressions: - - x + y - x' > y - - The file TE.tla will define two new variables: - - VARIABLES sum, big - - The variables are named "sum" and "big" for the simplicity of this example. In - reality they will be something like "trace_2348902347238", unless the user is - responsible to assigning labels to the expressions. The file will also define - two new identifiers: - - sum_def == x + y - big_def == x' >y - - We define the initial predicate and next-state relation as follows: - - TInit == - /\ x = 0 - /\ y = 0 - /\ sum = sum_def - /\ big = "--" - - TNext == - \/ /\ x = 0 - /\ y = 0 - /\ x' = 1 - /\ y' = 0 - /\ sum' = sum_def' - /\ big' = big_def - - \/ /\ x = 1 - /\ y = 0 - /\ x' = 2 - /\ y' = 1 - /\ sum' = sum_def' - /\ big' = big_def - - \/ /\ x = 2 - /\ y = 1 - /\ x' = 3 - /\ y' = 3 - /\ sum' = sum_def' - /\ big' = big_def - - The expression defined by big_def has primed variables so the variable big - takes the value "--" in the initial state predicate. The expression defined by - sum_def does not contain primed variables. This will produce an error trace by - defining the invariant: - - ~(x=3/\y=3) - - * - * @param traceInit - * @param nextWithoutTraceVars - * @param traceExpressionData - * @return - */ - public static List<String[]> createTraceInitContent(String traceInit, TraceExpressionInformationHolder[] traceExpressionData) - { - String id = getValidIdentifier(INIT_SCHEME); - StringBuffer initPredicate = new StringBuffer(); - initPredicate.append(id).append(DEFINES_CR); - initPredicate.append(traceInit); - for (int i = 0; i < traceExpressionData.length; i++) - { - TraceExpressionInformationHolder expressionInfo = traceExpressionData[i]; - initPredicate.append(TLA_AND).append(expressionInfo.getVariableName()).append(EQ); - if (expressionInfo.getLevel() < 2) - { - initPredicate.append(L_PAREN).append(expressionInfo.getExpression()).append(R_PAREN); - } else - { - initPredicate.append(TRACE_NA); - } - } - Vector<String[]> toReturn = new Vector<String[]>(); - toReturn.add(new String[] { id, initPredicate.toString() }); - return toReturn; - } - - public static List<String[]> createTraceNextContent(List<String> traceNextActions, - TraceExpressionInformationHolder[] traceExpressionData) - { - String id = getValidIdentifier(NEXT_SCHEME); - StringBuffer nextActionDisj = new StringBuffer(); - nextActionDisj.append(id).append(DEFINES_CR); - Iterator<String> it = traceNextActions.iterator(); - while (it.hasNext()) - { - String actionConj = it.next(); - nextActionDisj.append(TLA_OR).append(L_PAREN).append(actionConj); - for (int i = 0; i < traceExpressionData.length; i++) - { - TraceExpressionInformationHolder expressionInfo = traceExpressionData[i]; - nextActionDisj.append(TLA_AND).append(expressionInfo.getVariableName()).append(PRIME).append(EQ); - if (expressionInfo.getLevel() < 2) - { - nextActionDisj.append(L_PAREN).append(expressionInfo.getExpression()).append(R_PAREN).append(PRIME); - } else - { - nextActionDisj.append(L_PAREN).append(expressionInfo.getExpression()).append(R_PAREN); - } - } - nextActionDisj.append(R_PAREN).append(CR); - } - - Vector<String[]> toReturn = new Vector<String[]>(); - toReturn.add(new String[] { id, nextActionDisj.toString() }); - return toReturn; - } - /** * A pattern to match IDs generated by the {@link ModelWriter#getValidIdentifier(String)} method */ diff --git a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/model/TLCSpec.java b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/model/TLCSpec.java index d7366460cb435941f56dccd646d80de4a332d4eb..ba16e0f9a60651daefdf591cf73d183cdd9c46c0 100644 --- a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/model/TLCSpec.java +++ b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/model/TLCSpec.java @@ -29,6 +29,7 @@ package org.lamport.tla.toolbox.tool.tlc.model; import java.util.Collection; import java.util.HashMap; import java.util.Map; +import java.util.regex.Pattern; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; @@ -102,7 +103,7 @@ public class TLCSpec extends Spec { public Model getModel(final String modelName) { final String sanitizedName = Model.sanitizeName(modelName); - final Map<String, Model> models = getModels(sanitizedName, true); + final Map<String, Model> models = getModels(Pattern.quote(sanitizedName), true); return models.get(sanitizedName); } diff --git a/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/model/TraceExpressionModelWriter.java b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/model/TraceExpressionModelWriter.java new file mode 100644 index 0000000000000000000000000000000000000000..c1db2a1af2d9a651aa9f7da9ab35c5f15235dc37 --- /dev/null +++ b/org.lamport.tla.toolbox.tool.tlc/src/org/lamport/tla/toolbox/tool/tlc/model/TraceExpressionModelWriter.java @@ -0,0 +1,898 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package org.lamport.tla.toolbox.tool.tlc.model; + +import java.util.Iterator; +import java.util.List; +import java.util.Vector; + +import org.lamport.tla.toolbox.tool.tlc.launch.IModelConfigurationConstants; +import org.lamport.tla.toolbox.tool.tlc.launch.TraceExpressionInformationHolder; +import org.lamport.tla.toolbox.tool.tlc.traceexplorer.SimpleTLCState; +import org.lamport.tla.toolbox.tool.tlc.traceexplorer.SimpleTLCVariable; + +public class TraceExpressionModelWriter extends ModelWriter { + + /** + * This only changes the tla file. This method generates and adds a variable declaration + * for each expression in the list. It also creates an identifier for each + * expression and defines the identifier to be that expression. + * It returns an array of {@link TraceExpressionInformationHolder} where each element + * contains the expression, the identifier, and the variable name. + * + * If the expressions are x' + y and x > 3, The tla file will contain something like + * + *\* comment line + * VARIABLES __trace_var_21034978347834, __trace_var_90234782309 + * + * \* comment line + * trace_def_3214234234234 == + * x' + y + * ---- + * + * \* comment line + * trace_def_2342342342342 == + * x > 3 + * ---- + * + * @param expressions a list of formulas, each one an expression the user wants to have evaluated + * at each state of the trace + * @return array of {@link TraceExpressionInformationHolder} where each element + * contains the expression, the identifier, and the variable name + */ + public TraceExpressionInformationHolder[] createAndAddVariablesAndDefinitions(List<Formula> expressions, String attributeName) { + + TraceExpressionInformationHolder[] expressionData = new TraceExpressionInformationHolder[expressions.size()]; + Iterator<Formula> it = expressions.iterator(); + int position = 0; + while (it.hasNext()) + { + String expression = it.next().getFormula(); + + if (expression != null && expression.length() > 0) + { + expressionData[position] = new TraceExpressionInformationHolder(expression, + getValidIdentifier(TRACE_EXPR_DEF_SCHEME), getValidIdentifier(TRACE_EXPR_VAR_SCHEME)); + } + + position++; + } + + addVariablesAndDefinitions(expressionData, attributeName, true); + + return expressionData; + } + + /** + * This only changes the tla file. This method adds a variable declaration + * for each element of traceExpressionData and, if the flag addDefinitions is true, + * defines the identifier of each element to be the expression for that element. + * + * If the expressions are x' + y and x > 3, The tla file will contain something like + * + *\* comment line + * VARIABLES __trace_var_21034978347834, __trace_var_90234782309 + * + * \* comment line + * trace_def_3214234234234 == + * x' + y + * ---- + * + * \* comment line + * trace_def_2342342342342 == + * x > 3 + * ---- + * + * @param traceExpressionData information about the trace expressions + * @param attributeName + * @param addDefinitions whether or not to define each identifier as the expression + */ + public void addVariablesAndDefinitions(TraceExpressionInformationHolder[] traceExpressionData, String attributeName, boolean addDefinitions) { + if (traceExpressionData.length == 0) + { + return; + } + + StringBuffer variableDecls = new StringBuffer(); + StringBuffer definitions = new StringBuffer(); + + for (int i = 0; i < traceExpressionData.length; i++) + { + TraceExpressionInformationHolder expressionInfo = traceExpressionData[i]; + + variableDecls.append(expressionInfo.getVariableName()); + // we add a comma after every variable except for the last + if (i != traceExpressionData.length - 1) + { + variableDecls.append(COMMA); + } + + if (addDefinitions) + { + // define the identifier corresponding to this expression - looks like: + // \* comment line + // trace_def_213123123123 == + // expression + // ---- + definitions.append(COMMENT).append("TRACE EXPLORER identifier definition ").append(ATTRIBUTE).append( + attributeName).append(CR); + definitions.append(expressionInfo.getIdentifier()).append(DEFINES_CR).append( + expressionInfo.getExpression()).append(CR); + definitions.append(SEP).append(CR).append(CR); + } + } + + // variable declaration + tlaBuffer.append(COMMENT).append("TRACE EXPLORER variable declaration ").append(ATTRIBUTE) + .append(attributeName).append(CR); + tlaBuffer.append("VARIABLES ").append(variableDecls.toString()).append(CR); + + tlaBuffer.append(SEP).append(CR).append(CR); + + if (addDefinitions) + { + // append the expression definitions + tlaBuffer.append(definitions.toString()); + } + } + + /** + * This will generate two identifiers equal to the initial and next state + * predicate for the trace. If expressionData is not null, it should contain information + * about trace explorer expressions. This information is used to appropriately put + * the variables representing trace explorer expressions in the trace. In the following example, trace + * explorer expressions are used, but if expressionData is null, those variables will not appear in the + * init and next definitions, but everything else will be the same. + * + * Note: In the following example, the expressions expr1,...,expr6, texpr1, texpr2 can take up multiple + * lines. + * + * Consider the following trace: + * + * <Initial predicate> <State num 1> + * var1=expr1 + * var2=expr2 + * + * <Action...> <State num 2> + * var1=expr3 + * var2=expr4 + * + * <Action...> <State num 3> + * var1=expr5 + * var2=expr6 + * + * The user has defined two expressions in the trace explorer: + * + * texpr1 (level 2 represented by var3) + * texpr2 (level 1 represented by var4) + * + * This method defines the following identifiers: + * + * init_4123123123 == + * var1=( + * expr1 + * )/\ + * var2=( + * expr2 + * )/\ + * var3=( + * "--" + * )/\ + * var4=( + * texpr2 + * ) + * + * next_12312312312 == + * (var1=( + * expr1 + * )/\ + * var2=( + * expr2 + * )/\ + * var1'=( + * expr3 + * )/\ + * var2'=( + * expr4 + * )/\ + * var3'=( + * texpr1 + * )/\ + * var4'=( + * texpr2 + * )') + * \/ + * (var1=( + * expr3 + * )/\ + * var2=( + * expr4 + * )/\ + * var1'=( + * expr5 + * )/\ + * var2'=( + * expr6 + * )/\ + * var3'=( + * texpr1 + * )/\ + * var4'=( + * texpr2 + * )') + * + * If the last state is back to state i, then this method treats + * the trace as if it has the state labeled "Back to state i" removed and + * replaced with a copy of state i. + * + * If the last state is stuttering, then this method treats the trace as if it + * has the state labeled "Stuttering" removed and replaced with a copy + * of the state before the state labeled "Stuttering". + * + * @param trace + * @param expressionData data on trace explorer expressions, can be null + * @return String[], first element is the identifier for the initial state predicate, + * second element is the identifier for the next-state action + */ + public String[] addInitNext(List<SimpleTLCState> trace, TraceExpressionInformationHolder[] expressionData) { + String initId = getValidIdentifier(INIT_SCHEME); + String nextId = getValidIdentifier(NEXT_SCHEME); + + addInitNext(trace, expressionData, initId, nextId); + + return new String[] { initId, nextId }; + } + + /** + * This will set initId equal to the initial state predicate and nextId equal to the next state + * action for the trace. If expressionData is not null, it should contain information + * about trace explorer expressions. This information is used to appropriately put + * the variables representing trace explorer expressions in the trace. In the following example, trace + * explorer expressions are used, but if expressionData is null, those variables will not appear in the + * init and next definitions, but everything else will be the same. + * + * Note: In the following example, the expressions expr1,...,expr6, texpr1, texpr2 can take up multiple + * lines. + * + * Consider the following trace: + * + * <Initial predicate> <State num 1> + * var1=expr1 + * var2=expr2 + * + * <Action...> <State num 2> + * var1=expr3 + * var2=expr4 + * + * <Action...> <State num 3> + * var1=expr5 + * var2=expr6 + * + * The user has defined two expressions in the trace explorer: + * + * texpr1 (level 2 represented by var3) + * texpr2 (level 1 represented by var4) + * + * This method defines the following identifiers: + * + * init_4123123123 == + * var1=( + * expr1 + * )/\ + * var2=( + * expr2 + * )/\ + * var3=( + * "--" + * )/\ + * var4=( + * texpr2 + * ) + * + * next_12312312312 == + * (var1=( + * expr1 + * )/\ + * var2=( + * expr2 + * )/\ + * var1'=( + * expr3 + * )/\ + * var2'=( + * expr4 + * )/\ + * var3'=( + * texpr1 + * )/\ + * var4'=( + * texpr2 + * )') + * \/ + * (var1=( + * expr3 + * )/\ + * var2=( + * expr4 + * )/\ + * var1'=( + * expr5 + * )/\ + * var2'=( + * expr6 + * )/\ + * var3'=( + * texpr1 + * )/\ + * var4'=( + * texpr2 + * )') + * + * If the last state is back to state i, then this method treats + * the trace as if it has the state labeled "Back to state i" removed and + * replaced with a copy of state i. + * + * If the last state is stuttering, then this method treats the trace as if it + * has the state labeled "Stuttering" removed and replaced with a copy + * of the state before the state labeled "Stuttering". + * + * @param trace + * @param expressionData data on trace explorer expressions, can be null + * @param initId the identifier to be used for the initial state predicate, cannot be null + * @param nextId the identifier to be used for the next-state action, cannot be null + */ + public void addInitNext(List<SimpleTLCState> trace, TraceExpressionInformationHolder[] expressionData, String initId, String nextId) { + + if (trace.size() > 0) + { + Iterator<SimpleTLCState> it = trace.iterator(); + SimpleTLCState currentState = it.next(); + + /******************************************************* + * Add the init definition. * + *******************************************************/ + cfgBuffer.append(COMMENT).append("INIT definition").append(CR); + cfgBuffer.append("INIT").append(CR); + cfgBuffer.append(initId).append(CR); + + tlaBuffer.append(COMMENT).append("TRACE INIT definition").append( + IModelConfigurationConstants.TRACE_EXPLORE_INIT).append(CR); + tlaBuffer.append(initId).append(DEFINES_CR); + SimpleTLCVariable[] vars = currentState.getVars(); + + // variables from spec + for (int i = 0; i < vars.length; i++) + { + SimpleTLCVariable var = vars[i]; + /* + * var=( + * expr + * ) + */ + tlaBuffer.append(var.getVarName()).append(EQ).append(L_PAREN).append(CR).append(var.getValueAsString()) + .append(CR).append(R_PAREN); + /* + * Add /\ after right parenthesis except for the last variable + * + * var=( + * expr + * )/\ + */ + if (i != vars.length - 1) + { + tlaBuffer.append(TLA_AND).append(CR); + } + } + + // variables representing trace explorer expressions + if (expressionData != null) + { + for (int i = 0; i < expressionData.length; i++) + { + TraceExpressionInformationHolder expressionInfo = expressionData[i]; + tlaBuffer.append(TLA_AND).append(CR).append(expressionInfo.getVariableName()).append(EQ).append( + L_PAREN).append(CR); + + if (expressionInfo.getLevel() == 2) + { + // add "--" if the expression is temporal level + tlaBuffer.append(TRACE_NA); + } else + { + // add the actual expression if it is not temporal level + tlaBuffer.append(expressionInfo.getExpression()); + } + + tlaBuffer.append(CR).append(R_PAREN); + } + } + + tlaBuffer.append(CR).append(SEP).append(CR).append(CR); + + /********************************************************** + * Now add the next state actions definition * + **********************************************************/ + cfgBuffer.append(COMMENT).append("NEXT definition").append(CR); + cfgBuffer.append("NEXT").append(CR); + cfgBuffer.append(nextId).append(CR); + + tlaBuffer.append(COMMENT).append("TRACE NEXT definition").append( + IModelConfigurationConstants.TRACE_EXPLORE_NEXT).append(CR); + tlaBuffer.append(nextId).append(DEFINES_CR); + + SimpleTLCState nextState = null; + boolean isSingleState; + if (it.hasNext()) + { + nextState = (SimpleTLCState) it.next(); + isSingleState = false; + } else + { + nextState = currentState; + isSingleState = true; + } + + while (nextState != null) + { + /* + * Handle Back to state and stuttering. + * + * nextState is assigned to the state which the "Back to state" + * or "Stuttering" state represents. If nextState is "Back to state i", + * then it is assigned to state i. If nextState is "Stuttering", then + * it is assigned to the current state. + */ + if (nextState.isBackToState()) + { + nextState = (SimpleTLCState) trace.get(nextState.getStateNumber() - 1); + } else if (nextState.isStuttering()) + { + nextState = currentState; + } + + /* + * Write the action: + * + * (var1=( + * expr1 + * )/\ + * var2=( + * expr2 + * )/\ + * var1'=( + * expr3 + * )/\ + * var2'=( + * expr4 + * )) + */ + tlaBuffer.append(L_PAREN); + + SimpleTLCVariable[] currentStateVars = currentState.getVars(); + SimpleTLCVariable[] nextStateVars = nextState.getVars(); + + /* + * Iterate through current state variables. This adds: + * + * var1=( + * expr1 + * )/\ + * var2=( + * expr2 + * )/\ + * + */ + for (int i = 0; i < currentStateVars.length; i++) + { + SimpleTLCVariable currentStateVar = currentStateVars[i]; + tlaBuffer.append(currentStateVar.getVarName()).append(EQ).append(L_PAREN).append(CR).append( + currentStateVar.getValueAsString()).append(CR).append(R_PAREN).append(TLA_AND).append(CR); + } + + /* + * If the trace is a single state, make the next state + * action never enabled. The model will deadlock in the initial state. + * This adds: + * + * FALSE + * /\ + */ + if (isSingleState) + { + tlaBuffer.append("FALSE").append(CR).append(TLA_AND).append(CR); + } + + /* + * Iterate through next state variables. This adds: + * + * var1'=( + * expr3 + * )/\ + * var2'=( + * expr4 + * ) + */ + for (int i = 0; i < currentStateVars.length; i++) + { + SimpleTLCVariable nextStateVar = nextStateVars[i]; + tlaBuffer.append(nextStateVar.getVarName()).append(PRIME).append(EQ).append(L_PAREN).append(CR) + .append(nextStateVar.getValueAsString()).append(CR).append(R_PAREN); + // add /\ for each variable except the last one + if (i != currentStateVars.length - 1) + { + tlaBuffer.append(TLA_AND).append(CR); + } + } + + /* + * Iterate through the trace explorer expressions if there are any. This adds: + * + * /\ + * var3'=( + * texpr1 + * )/\ + * var4'=( + * texpr2 + * )' + * + */ + if (expressionData != null) + { + for (int i = 0; i < expressionData.length; i++) + { + TraceExpressionInformationHolder expressionInfo = expressionData[i]; + tlaBuffer.append(TLA_AND).append(CR).append(expressionInfo.getVariableName()).append(PRIME) + .append(EQ).append(L_PAREN).append(CR).append(expressionInfo.getExpression()) + .append(CR).append(R_PAREN); + + if (expressionInfo.getLevel() < 2) + { + tlaBuffer.append(PRIME); + } + } + } + + tlaBuffer.append(R_PAREN); + + if (it.hasNext()) + { + tlaBuffer.append(CR).append(TLA_OR).append(CR); + } + + currentState = nextState; + + if (it.hasNext()) + { + nextState = (SimpleTLCState) it.next(); + } else + { + nextState = null; + } + } + + tlaBuffer.append(CR).append(SEP).append(CR).append(CR); + + } + + } + + /** + * Adds the invariant ~(P) where P is the formula describing finalState. The format + * in the tla file is as follows: + * + * inv_12312321321 == + * ~( + * P + * ) + * ---- + * + * @param finalState + */ + public void addInvariant(SimpleTLCState finalState) { + String id = getValidIdentifier(INVARIANT_SCHEME); + cfgBuffer.append(COMMENT).append("INVARIANT definition").append(CR); + cfgBuffer.append("INVARIANT").append(CR); + cfgBuffer.append(id).append(CR); + + tlaBuffer.append(COMMENT).append("INVARIANT definition").append(CR); + tlaBuffer.append(id).append(DEFINES_CR); + tlaBuffer.append(TLA_NOT).append(L_PAREN).append(CR).append(getStateConjunction(finalState)).append(CR).append( + R_PAREN).append(CR); + + tlaBuffer.append(SEP).append(CR).append(CR); + } + + /** + * Adds the temporal property ~<>[](P) where P is the formula describing finalState. + * The format in the tla file is as follows: + * + * prop_23112321 == + * ~<>[]( + * P + * ) + * ---- + * + * @param finalState + */ + public void addStutteringProperty(SimpleTLCState finalState) { + String id = getValidIdentifier(PROP_SCHEME); + cfgBuffer.append(COMMENT).append("PROPERTY definition").append(CR); + cfgBuffer.append("PROPERTY").append(CR); + cfgBuffer.append(id).append(CR); + + tlaBuffer.append(COMMENT).append("PROPERTY definition").append(CR); + tlaBuffer.append(id).append(DEFINES_CR); + tlaBuffer.append(TLA_NOT).append(TLA_EVENTUALLY_ALWAYS).append(L_PAREN).append(CR).append( + getStateConjunction(finalState)).append(CR).append(R_PAREN).append(CR); + + tlaBuffer.append(SEP).append(CR).append(CR); + } + + /** + * Adds the temporal property ~([]<>P /\ []<>Q), where P is the formula describing finalState and + * Q the formula describing backToState. The formating in the tla file is as follows: + * + * prop_21321312 == + * ~(([]<>( + * P + * ))/\([]<>( + * Q + * ))) + * ---- + * + * @param finalState + * @param backToState + */ + public void addBackToStateProperty(SimpleTLCState finalState, SimpleTLCState backToState) { + String id = getValidIdentifier(PROP_SCHEME); + cfgBuffer.append(COMMENT).append("PROPERTY definition").append(CR); + cfgBuffer.append("PROPERTY").append(CR); + cfgBuffer.append(id).append(CR); + + tlaBuffer.append(COMMENT).append("PROPERTY definition").append(CR); + tlaBuffer.append(id).append(DEFINES_CR); + tlaBuffer.append(TLA_NOT).append(L_PAREN).append(L_PAREN).append(TLA_INF_OFTEN).append(L_PAREN).append(CR) + .append(getStateConjunction(finalState)).append(CR).append(R_PAREN).append(R_PAREN).append(TLA_AND) + .append(L_PAREN).append(TLA_INF_OFTEN).append(L_PAREN).append(CR).append( + getStateConjunction(backToState)).append(CR).append(R_PAREN).append(R_PAREN).append(R_PAREN) + .append(CR); + + tlaBuffer.append(SEP).append(CR).append(CR); + } + + /** + * Writes comments that will be used for associating variable names with expressions + * and will give the level of each expression. In particular, for each expression "expr" + * with level x and variable name ___trace_var_3242348934343 this + * will append the following comment to the tla file: + * + * \* :x:___trace_var_3242348934343:expr"$!@$!@$!@$!@$!" + * + * @param traceExpressionData + */ + public void addInfoComments(TraceExpressionInformationHolder[] traceExpressionData) { + for (int i = 0; i < traceExpressionData.length; i++) + { + TraceExpressionInformationHolder expressionData = traceExpressionData[i]; + tlaBuffer.append(COMMENT).append(INDEX).append(expressionData.getLevel()).append(INDEX).append( + expressionData.getVariableName()).append(INDEX).append(expressionData.getExpression()).append( + CONSTANT_EXPRESSION_EVAL_IDENTIFIER).append(CR); + } + } + + /** + * Returns a string representing the formula describing the state. + * If the state has var1=expr1, var2 = expr2, and var3=expr3, then this returns: + * + * var1=( + * expr1 + * )/\ + * var2=( + * expr2 + * )/\ + * var3=( + * expr3 + * ) + * + * + * The expressions expr1, expr2, and expr3 can take up multiple lines. + * + * This will return null if the state is stuttering or back to state. + * + * @param state + * @return + */ + private static String getStateConjunction(SimpleTLCState state) + { + if (state.isBackToState()) + { + return null; + } else if (state.isStuttering()) + { + return null; + } else + { + StringBuffer formula = new StringBuffer(); + SimpleTLCVariable[] vars = state.getVars(); + for (int i = 0; i < vars.length; i++) + { + SimpleTLCVariable var = vars[i]; + formula.append(var.getVarName()).append(EQ).append(L_PAREN).append(CR).append(var.getValueAsString()) + .append(CR).append(R_PAREN); + + // append /\ except for the last variable + if (i != vars.length - 1) + { + formula.append(TLA_AND).append(CR); + } + } + + return formula.toString(); + } + } + + /** + * This adds the trace explorer variables to initWithoutTraceVars. + * The method returns a list with one element, a + * String[]. The first element of the array is put in TE.cfg, and the + * second element is put in TE.tla. The intention is to use + * the return value as the first argument of {@link ModelWriter#addFormulaList(List, String, String)}. + * + * This can be best explained with an example. + * + * The trace is the following: + + STATE 1: <Initial predicate> + /\ x = 0 + /\ y = 0 + + STATE 2: <Action line 8, col 3 to line 9, col 15 of module Test> + /\ x = 1 + /\ y = 0 + + STATE 3: <Action line 8, col 3 to line 9, col 15 of module Test> + /\ x = 2 + /\ y = 1 + + STATE 4: <Action line 8, col 3 to line 9, col 15 of module Test> + /\ x = 3 + /\ y = 3 + + The user wants to evaluate two expressions: + + x + y + x' > y + + The file TE.tla will define two new variables: + + VARIABLES sum, big + + The variables are named "sum" and "big" for the simplicity of this example. In + reality they will be something like "trace_2348902347238", unless the user is + responsible to assigning labels to the expressions. The file will also define + two new identifiers: + + sum_def == x + y + big_def == x' >y + + We define the initial predicate and next-state relation as follows: + + TInit == + /\ x = 0 + /\ y = 0 + /\ sum = sum_def + /\ big = "--" + + TNext == + \/ /\ x = 0 + /\ y = 0 + /\ x' = 1 + /\ y' = 0 + /\ sum' = sum_def' + /\ big' = big_def + + \/ /\ x = 1 + /\ y = 0 + /\ x' = 2 + /\ y' = 1 + /\ sum' = sum_def' + /\ big' = big_def + + \/ /\ x = 2 + /\ y = 1 + /\ x' = 3 + /\ y' = 3 + /\ sum' = sum_def' + /\ big' = big_def + + The expression defined by big_def has primed variables so the variable big + takes the value "--" in the initial state predicate. The expression defined by + sum_def does not contain primed variables. This will produce an error trace by + defining the invariant: + + ~(x=3/\y=3) + + * + * @param traceInit + * @param nextWithoutTraceVars + * @param traceExpressionData + * @return + */ + public static List<String[]> createInitContent(String traceInit, TraceExpressionInformationHolder[] traceExpressionData) + { + String id = getValidIdentifier(INIT_SCHEME); + StringBuffer initPredicate = new StringBuffer(); + initPredicate.append(id).append(DEFINES_CR); + initPredicate.append(traceInit); + for (int i = 0; i < traceExpressionData.length; i++) + { + TraceExpressionInformationHolder expressionInfo = traceExpressionData[i]; + initPredicate.append(TLA_AND).append(expressionInfo.getVariableName()).append(EQ); + if (expressionInfo.getLevel() < 2) + { + initPredicate.append(L_PAREN).append(expressionInfo.getExpression()).append(R_PAREN); + } else + { + initPredicate.append(TRACE_NA); + } + } + Vector<String[]> toReturn = new Vector<String[]>(); + toReturn.add(new String[] { id, initPredicate.toString() }); + return toReturn; + } + + public static List<String[]> createNextContent(List<String> traceNextActions, + TraceExpressionInformationHolder[] traceExpressionData) + { + String id = getValidIdentifier(NEXT_SCHEME); + StringBuffer nextActionDisj = new StringBuffer(); + nextActionDisj.append(id).append(DEFINES_CR); + Iterator<String> it = traceNextActions.iterator(); + while (it.hasNext()) + { + String actionConj = it.next(); + nextActionDisj.append(TLA_OR).append(L_PAREN).append(actionConj); + for (int i = 0; i < traceExpressionData.length; i++) + { + TraceExpressionInformationHolder expressionInfo = traceExpressionData[i]; + nextActionDisj.append(TLA_AND).append(expressionInfo.getVariableName()).append(PRIME).append(EQ); + if (expressionInfo.getLevel() < 2) + { + nextActionDisj.append(L_PAREN).append(expressionInfo.getExpression()).append(R_PAREN).append(PRIME); + } else + { + nextActionDisj.append(L_PAREN).append(expressionInfo.getExpression()).append(R_PAREN); + } + } + nextActionDisj.append(R_PAREN).append(CR); + } + + Vector<String[]> toReturn = new Vector<String[]>(); + toReturn.add(new String[] { id, nextActionDisj.toString() }); + return toReturn; + } + +} diff --git a/org.lamport.tla.toolbox.uitest/.classpath b/org.lamport.tla.toolbox.uitest/.classpath index eca7bdba8f03f22510b7980a94dbfe10c16c0901..1ecf151b94e4a7dfd1f424840af91c2761db83d2 100644 --- a/org.lamport.tla.toolbox.uitest/.classpath +++ b/org.lamport.tla.toolbox.uitest/.classpath @@ -3,5 +3,6 @@ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/> <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/> <classpathentry kind="src" path="src"/> + <classpathentry excluding="org/lamport/tla/toolbox/test/threading/MonitorAspect.aj" kind="src" path="src-aj"/> <classpathentry kind="output" path="bin"/> </classpath> diff --git a/org.lamport.tla.toolbox.uitest/.project b/org.lamport.tla.toolbox.uitest/.project index 15268b624524fefe512d6fc6fba946aac14a225e..ba4ccd6e5e6f3012d738cee520799b9b5bd30a7d 100644 --- a/org.lamport.tla.toolbox.uitest/.project +++ b/org.lamport.tla.toolbox.uitest/.project @@ -6,7 +6,7 @@ </projects> <buildSpec> <buildCommand> - <name>org.eclipse.ajdt.core.ajbuilder</name> + <name>org.eclipse.jdt.core.javabuilder</name> <arguments> </arguments> </buildCommand> @@ -22,7 +22,6 @@ </buildCommand> </buildSpec> <natures> - <nature>org.eclipse.ajdt.ui.ajnature</nature> <nature>org.eclipse.pde.PluginNature</nature> <nature>org.eclipse.jdt.core.javanature</nature> </natures> diff --git a/org.lamport.tla.toolbox.uitest/META-INF/MANIFEST.MF b/org.lamport.tla.toolbox.uitest/META-INF/MANIFEST.MF index f29ed17cc4a83105f50378ce332312798c05198e..1c3577f614d1afac577e708888e00f03a93aab42 100644 --- a/org.lamport.tla.toolbox.uitest/META-INF/MANIFEST.MF +++ b/org.lamport.tla.toolbox.uitest/META-INF/MANIFEST.MF @@ -9,7 +9,7 @@ Import-Package: org.eclipse.core.resources, org.osgi.framework;version="1.3.0" Require-Bundle: org.eclipse.swt;bundle-version="3.5.0";visibility:=reexport, org.eclipse.swtbot.go;bundle-version="2.0.0";visibility:=reexport, - org.aspectj.runtime;bundle-version="1.6.0";visibility:=reexport, + org.aspectj.runtime;bundle-version="1.8.10";visibility:=reexport, org.lamport.tla.toolbox;bundle-version="1.0.0";visibility:=reexport, org.lamport.tla.toolbox.editor.basic;bundle-version="1.0.0", org.apache.log4j;visibility:=reexport, diff --git a/org.lamport.tla.toolbox.uitest/build.ajproperties b/org.lamport.tla.toolbox.uitest/build.ajproperties index 420ac7ad799e262535cacba681b893cc56dbdd37..58a50155b093c66556513ffe847fb24b441dfe1e 100644 --- a/org.lamport.tla.toolbox.uitest/build.ajproperties +++ b/org.lamport.tla.toolbox.uitest/build.ajproperties @@ -1 +1 @@ -src.includes = src/org/lamport/tla/toolbox/test/threading/MonitorAspect.aj +src.includes = src-aj/org/lamport/tla/toolbox/test/threading/MonitorAspect.aj diff --git a/org.lamport.tla.toolbox.uitest/build.properties b/org.lamport.tla.toolbox.uitest/build.properties index c86a1eb2d9f308e8744d51124a7272afbbbdf55d..ca2cfafb2dd07c66d8f16d6ccc9a59c7773e5ccd 100644 --- a/org.lamport.tla.toolbox.uitest/build.properties +++ b/org.lamport.tla.toolbox.uitest/build.properties @@ -1,4 +1,5 @@ -source.. = src/ +source.. = src/,\ + src-aj/ output.. = bin/ bin.includes = META-INF/,\ .,\ diff --git a/org.lamport.tla.toolbox.uitest/farsite/GotoDefinition.tla b/org.lamport.tla.toolbox.uitest/farsite/GotoDefinition.tla new file mode 100644 index 0000000000000000000000000000000000000000..06d77a9d8ca10344966de49c6207352890d1ce8b --- /dev/null +++ b/org.lamport.tla.toolbox.uitest/farsite/GotoDefinition.tla @@ -0,0 +1,9 @@ +--------------------------- MODULE GotoDefinition --------------------------- +EXTENDS Integers +VARIABLE s + +Next(var) == \E val \in 0..1: (var' = val /\ var' > 0) + +Spec == s = "" /\ [][Next(s)]_s + +============================================================================= diff --git a/org.lamport.tla.toolbox.uitest/pom.xml b/org.lamport.tla.toolbox.uitest/pom.xml index 501526535b348f389f00c388eee5b278ce929092..a5ec737119fef4609bf45b21f67211b15f912368 100644 --- a/org.lamport.tla.toolbox.uitest/pom.xml +++ b/org.lamport.tla.toolbox.uitest/pom.xml @@ -22,7 +22,7 @@ <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> - <version>1.8.5</version> + <version>1.9.1</version> </dependency> <!-- Down below we manually install the standalone feature. Maven/Tycho isn't smart enough to figure this out by itself. Thus, we have to tell Tycho @@ -68,7 +68,7 @@ <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>aspectj-maven-plugin</artifactId> - <version>1.7</version> + <version>1.11</version> <configuration> <ajdtBuildDefFile>build.ajproperties</ajdtBuildDefFile> </configuration> diff --git a/org.lamport.tla.toolbox.uitest/src/org/lamport/tla/toolbox/test/threading/MonitorAdaptor.java b/org.lamport.tla.toolbox.uitest/src-aj/org/lamport/tla/toolbox/test/threading/MonitorAdaptor.java similarity index 100% rename from org.lamport.tla.toolbox.uitest/src/org/lamport/tla/toolbox/test/threading/MonitorAdaptor.java rename to org.lamport.tla.toolbox.uitest/src-aj/org/lamport/tla/toolbox/test/threading/MonitorAdaptor.java diff --git a/org.lamport.tla.toolbox.uitest/src/org/lamport/tla/toolbox/test/threading/MonitorAspect.aj b/org.lamport.tla.toolbox.uitest/src-aj/org/lamport/tla/toolbox/test/threading/MonitorAspect.aj similarity index 100% rename from org.lamport.tla.toolbox.uitest/src/org/lamport/tla/toolbox/test/threading/MonitorAspect.aj rename to org.lamport.tla.toolbox.uitest/src-aj/org/lamport/tla/toolbox/test/threading/MonitorAspect.aj diff --git a/org.lamport.tla.toolbox/.classpath b/org.lamport.tla.toolbox/.classpath index c9ce4d71e89ef7ca9996b668daded4af5fe9478e..eca7bdba8f03f22510b7980a94dbfe10c16c0901 100644 --- a/org.lamport.tla.toolbox/.classpath +++ b/org.lamport.tla.toolbox/.classpath @@ -1,8 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <classpath> - <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/> + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/> <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/> <classpathentry kind="src" path="src"/> - <classpathentry exported="true" kind="lib" path="StandardModules" sourcepath="StandardModules"/> <classpathentry kind="output" path="bin"/> </classpath> diff --git a/org.lamport.tla.toolbox/.settings/org.eclipse.jdt.core.prefs b/org.lamport.tla.toolbox/.settings/org.eclipse.jdt.core.prefs index 608e1c19eff2eb11e5ca581534f0a6576e2e41a4..0c68a61dca867ceb49e79d2402935261ec3e3809 100644 --- a/org.lamport.tla.toolbox/.settings/org.eclipse.jdt.core.prefs +++ b/org.lamport.tla.toolbox/.settings/org.eclipse.jdt.core.prefs @@ -1,8 +1,7 @@ -#Mon May 09 12:19:05 CEST 2011 eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 -org.eclipse.jdt.core.compiler.compliance=1.5 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.compliance=1.8 org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -org.eclipse.jdt.core.compiler.source=1.5 +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/org.lamport.tla.toolbox/META-INF/MANIFEST.MF b/org.lamport.tla.toolbox/META-INF/MANIFEST.MF index 61031a1930fdd347833a007b8a93d0a245446251..604b0d9588d70bd37653c41645f5c575d0b9d48c 100644 --- a/org.lamport.tla.toolbox/META-INF/MANIFEST.MF +++ b/org.lamport.tla.toolbox/META-INF/MANIFEST.MF @@ -19,10 +19,11 @@ Require-Bundle: org.eclipse.ui, org.eclipse.team.ui, org.eclipse.core.filesystem;bundle-version="1.5.0", org.lamport.tla.toolbox.product.standalone -Bundle-RequiredExecutionEnvironment: J2SE-1.5 +Bundle-RequiredExecutionEnvironment: JavaSE-1.8 Bundle-ActivationPolicy: lazy Bundle-ClassPath: ., StandardModules/ +DynamicImport-Package: * Export-Package: org.lamport.tla.toolbox, org.lamport.tla.toolbox.spec; uses:="org.eclipse.core.runtime, @@ -62,9 +63,12 @@ Export-Package: org.lamport.tla.toolbox, org.eclipse.jface.viewers, org.eclipse.swt.widgets, util", + org.lamport.tla.toolbox.util.e4, org.lamport.tla.toolbox.util.pref Eclipse-BundleShape: dir Import-Package: org.eclipse.e4.core.contexts, + org.eclipse.e4.core.di, + org.eclipse.e4.core.di.annotations, org.eclipse.e4.core.services.events, org.eclipse.e4.ui.model.application, org.eclipse.e4.ui.model.application.ui, diff --git a/org.lamport.tla.toolbox/StandardModules/Bags.tla b/org.lamport.tla.toolbox/StandardModules/Bags.tla deleted file mode 100644 index 7be7a4420403141009471a0c2c3804cf12a28615..0000000000000000000000000000000000000000 --- a/org.lamport.tla.toolbox/StandardModules/Bags.tla +++ /dev/null @@ -1,147 +0,0 @@ ------------------------------ MODULE Bags -------------------------------- -(**************************************************************************) -(* A bag, also called a multiset, is a set that can contain multiple *) -(* copies of the same element. A bag can have infinitely many elements, *) -(* but only finitely many copies of any single element. *) -(* *) -(* We represent a bag in the usual way as a function whose range is a *) -(* subset of the positive integers. An element e belongs to bag B iff e *) -(* is in the domain of B, in which case bag B contains B[e] copies of e. *) -(**************************************************************************) -EXTENDS TLC -LOCAL INSTANCE Naturals - -IsABag(B) == - (************************************************************************) - (* True iff B is a bag. *) - (************************************************************************) - B \in [DOMAIN B -> {n \in Nat : n > 0}] - -BagToSet(B) == DOMAIN B - (************************************************************************) - (* The set of elements at least one copy of which is in B. *) - (************************************************************************) - -SetToBag(S) == [e \in S |-> 1] - (************************************************************************) - (* The bag that contains one copy of every element of the set S. *) - (************************************************************************) - -BagIn(e,B) == e \in BagToSet(B) - (************************************************************************) - (* The \in operator for bags. *) - (************************************************************************) - -EmptyBag == SetToBag({}) - -B1 (+) B2 == - (************************************************************************) - (* The union of bags B1 and B2. *) - (************************************************************************) - [e \in (DOMAIN B1) \cup (DOMAIN B2) |-> - (IF e \in DOMAIN B1 THEN B1[e] ELSE 0) - + (IF e \in DOMAIN B2 THEN B2[e] ELSE 0) ] - -B1 (-) B2 == - (************************************************************************) - (* The bag B1 with the elements of B2 removed--that is, with one copy *) - (* of an element removed from B1 for each copy of the same element in *) - (* B2. If B2 has at least as many copies of e as B1, then B1 (-) B2 *) - (* has no copies of e. *) - (************************************************************************) - LET B == [e \in DOMAIN B1 |-> IF e \in DOMAIN B2 THEN B1[e] - B2[e] - ELSE B1[e]] - IN [e \in {d \in DOMAIN B : B[d] > 0} |-> B[e]] - -LOCAL Sum(f) == - (******************************************************************) - (* The sum of f[x] for all x in DOMAIN f. The definition assumes *) - (* that f is a Nat-valued function and that f[x] equals 0 for all *) - (* but a finite number of elements x in DOMAIN f. *) - (******************************************************************) - LET DSum[S \in SUBSET DOMAIN f] == - LET elt == CHOOSE e \in S : TRUE - IN IF S = {} THEN 0 - ELSE f[elt] + DSum[S \ {elt}] - IN DSum[DOMAIN f] - -BagUnion(S) == - (************************************************************************) - (* The bag union of all elements of the set S of bags. *) - (************************************************************************) - [e \in UNION {BagToSet(B) : B \in S} |-> - Sum( [B \in S |-> IF BagIn(e, B) THEN B[e] ELSE 0] ) ] - -B1 \sqsubseteq B2 == - (************************************************************************) - (* The subset operator for bags. B1 \sqsubseteq B2 iff, for all e, bag *) - (* B2 has at least as many copies of e as bag B1 does. *) - (************************************************************************) - /\ (DOMAIN B1) \subseteq (DOMAIN B2) - /\ \A e \in DOMAIN B1 : B1[e] \leq B2[e] - -SubBag(B) == - (************************************************************************) - (* The set of all subbags of bag B. *) - (* *) - (* The following definition is not the one described in the TLA+ book, *) - (* but rather one that TLC can evaluate. *) - (************************************************************************) - - LET RemoveFromDom(x, f) == [y \in (DOMAIN f) \ {x} |-> f[y]] - Combine(x, BagSet) == - BagSet \cup - {[y \in (DOMAIN f) \cup {x} |-> IF y = x THEN i ELSE f[y]] : - f \in BagSet, i \in 1..B[x]} - Biggest == LET Range == {B[x] : x \in DOMAIN B} - IN IF Range = {} THEN 0 - ELSE CHOOSE r \in Range : - \A s \in Range : r \geq s - RSB[BB \in UNION {[S -> 1..Biggest] : S \in SUBSET DOMAIN B}] == - IF BB = << >> THEN {<< >>} - ELSE LET x == CHOOSE x \in DOMAIN BB : TRUE - IN Combine(x, RSB[RemoveFromDom(x, BB)]) - IN RSB[B] - - (******************* Here is the definition from the TLA+ book. ******** - LET AllBagsOfSubset == - (******************************************************************) - (* The set of all bags SB such that BagToSet(SB) \subseteq *) - (* BagToSet(B). *) - (******************************************************************) - UNION {[SB -> {n \in Nat : n > 0}] : SB \in SUBSET BagToSet(B)} - IN {SB \in AllBagsOfSubset : \A e \in DOMAIN SB : SB[e] \leq B[e]} - ***************************************************************************) - -BagOfAll(F(_), B) == - (************************************************************************) - (* The bag analog of the set {F(x) : x \in B} for a set B. It's the bag *) - (* that contains, for each element e of B, one copy of F(e) for every *) - (* copy of e in B. This defines a bag iff, for any value v, the set of *) - (* e in B such that F(e) = v is finite. *) - (************************************************************************) - [e \in {F(d) : d \in BagToSet(B)} |-> - Sum( [d \in BagToSet(B) |-> IF F(d) = e THEN B[d] ELSE 0] ) ] - -BagCardinality(B) == - (************************************************************************) - (* If B is a finite bag (one such that BagToSet(B) is a finite set), *) - (* then this is its cardinality (the total number of copies of elements *) - (* in B). Its value is unspecified if B is infinite. *) - (************************************************************************) - Sum(B) - -CopiesIn(e, B) == - (************************************************************************) - (* If B is a bag, then CopiesIn(e, B) is the number of copies of e in *) - (* B. If ~BagIn(e, B), then CopiesIn(e, B) = 0. *) - (************************************************************************) - IF BagIn(e, B) THEN B[e] ELSE 0 -============================================================================= - -(* Last modified on Fri 26 Jan 2007 at 8:45:03 PST by lamport *) - - 6 Apr 99 : Modified version for standard module set - 7 Dec 98 : Corrected error found by Stephan Merz. - 6 Dec 98 : Modified comments based on suggestions by Lyle Ramshaw. - 5 Dec 98 : Initial version. diff --git a/org.lamport.tla.toolbox/StandardModules/FiniteSets.tla b/org.lamport.tla.toolbox/StandardModules/FiniteSets.tla deleted file mode 100644 index 57ac40235075b64119e4ab2ddf92abeab9120a5a..0000000000000000000000000000000000000000 --- a/org.lamport.tla.toolbox/StandardModules/FiniteSets.tla +++ /dev/null @@ -1,23 +0,0 @@ ----------------------------- MODULE FiniteSets ----------------------------- -LOCAL INSTANCE Naturals -LOCAL INSTANCE Sequences - (*************************************************************************) - (* Imports the definitions from Naturals and Sequences, but doesn't *) - (* export them. *) - (*************************************************************************) - -IsFiniteSet(S) == - (*************************************************************************) - (* A set S is finite iff there is a finite sequence containing all its *) - (* elements. *) - (*************************************************************************) - \E seq \in Seq(S) : \A s \in S : \E n \in 1..Len(seq) : seq[n] = s - -Cardinality(S) == - (*************************************************************************) - (* Cardinality is defined only for finite sets. *) - (*************************************************************************) - LET CS[T \in SUBSET S] == IF T = {} THEN 0 - ELSE 1 + CS[T \ {CHOOSE x : x \in T}] - IN CS[S] -============================================================================= diff --git a/org.lamport.tla.toolbox/StandardModules/Integers.tla b/org.lamport.tla.toolbox/StandardModules/Integers.tla deleted file mode 100644 index 2df47a87a219821e9bbd243defdc826992636431..0000000000000000000000000000000000000000 --- a/org.lamport.tla.toolbox/StandardModules/Integers.tla +++ /dev/null @@ -1,10 +0,0 @@ --------------------------------- MODULE Integers ---------------------------- -(***************************************************************************) -(* A dummy module that declares the operators that are defined in the *) -(* real Integers module. *) -(***************************************************************************) -EXTENDS Naturals - -Int == { } --. a == 0 - a -============================================================================= diff --git a/org.lamport.tla.toolbox/StandardModules/Naturals.tla b/org.lamport.tla.toolbox/StandardModules/Naturals.tla deleted file mode 100644 index 6dc13fea6ae556e21f74d4f0322d0f7751c6a448..0000000000000000000000000000000000000000 --- a/org.lamport.tla.toolbox/StandardModules/Naturals.tla +++ /dev/null @@ -1,19 +0,0 @@ --------------------------------- MODULE Naturals ---------------------------- -(***************************************************************************) -(* A dummy module that defines the operators that are defined by the *) -(* real Naturals module. *) -(***************************************************************************) - -Nat == { } -a+b == {a, b} -a-b == {a, b} -a*b == {a, b} -a^b == {a, b} -a<b == a = b -a>b == a = b -a \leq b == a = b -a \geq b == a = b -a % b == {a, b} -a \div b == {a, b} -a .. b == {a, b} -============================================================================= diff --git a/org.lamport.tla.toolbox/StandardModules/RealTime.tla b/org.lamport.tla.toolbox/StandardModules/RealTime.tla deleted file mode 100644 index 1026c66a4b853a896a3b6f3374b02292f0562753..0000000000000000000000000000000000000000 --- a/org.lamport.tla.toolbox/StandardModules/RealTime.tla +++ /dev/null @@ -1,22 +0,0 @@ ------------------------------ MODULE RealTime ------------------------------- -EXTENDS Reals -VARIABLE now - -RTBound(A, v, D, E) == - LET TNext(t) == t' = IF <<A>>_v \/ ~(ENABLED <<A>>_v)' - THEN 0 - ELSE t + (now'-now) - - Timer(t) == (t=0) /\ [][TNext(t)]_<<t, v, now>> - - MaxTime(t) == [](t \leq E) - - MinTime(t) == [][A => t \geq D]_v - IN \EE t : Timer(t) /\ MaxTime(t) /\ MinTime(t) ------------------------------------------------------------------------------ -RTnow(v) == LET NowNext == /\ now' \in {r \in Real : r > now} - /\ UNCHANGED v - IN /\ now \in Real - /\ [][NowNext]_now - /\ \A r \in Real : WF_now(NowNext /\ (now'>r)) -============================================================================= diff --git a/org.lamport.tla.toolbox/StandardModules/Reals.tla b/org.lamport.tla.toolbox/StandardModules/Reals.tla deleted file mode 100644 index 55f51b511088170ff47fdb60e078f9e8255fa39c..0000000000000000000000000000000000000000 --- a/org.lamport.tla.toolbox/StandardModules/Reals.tla +++ /dev/null @@ -1,12 +0,0 @@ --------------------------------- MODULE Reals ------------------------------- -(***************************************************************************) -(* A dummy module that declares the operators that are defined in the *) -(* real Reals module. It should produce an error if TLC tries to *) -(* evaluate these operators when it shouldn't. *) -(***************************************************************************) -EXTENDS Integers - -Real == "Reals" -a / b == CHOOSE m \in Real : m * b = a -Infinity == CHOOSE i : (i \notin Real) /\ (\A r \in Real : i > r) -============================================================================= diff --git a/org.lamport.tla.toolbox/StandardModules/Sequences.tla b/org.lamport.tla.toolbox/StandardModules/Sequences.tla deleted file mode 100644 index df77a97facdf6d62ce44aa6d4dd304894742fc1d..0000000000000000000000000000000000000000 --- a/org.lamport.tla.toolbox/StandardModules/Sequences.tla +++ /dev/null @@ -1,60 +0,0 @@ ------------------------------- MODULE Sequences ----------------------------- -(***************************************************************************) -(* Defines operators on finite sequences, where a sequence of length n is *) -(* represented as a function whose domain is the set 1..n (the set *) -(* {1, 2, ... , n}). This is also how TLA+ defines an n-tuple, so *) -(* tuples are sequences. *) -(***************************************************************************) - -LOCAL INSTANCE Naturals - (*************************************************************************) - (* Imports the definitions from Naturals, but don't export them. *) - (*************************************************************************) - -Seq(S) == UNION {[1..n -> S] : n \in Nat} - (*************************************************************************) - (* The set of all sequences of elements in S. *) - (*************************************************************************) - -Len(s) == CHOOSE n \in Nat : DOMAIN s = 1..n - (*************************************************************************) - (* The length of sequence s. *) - (*************************************************************************) - -s \o t == [i \in 1..(Len(s) + Len(t)) |-> IF i \leq Len(s) THEN s[i] - ELSE t[i-Len(s)]] - (*************************************************************************) - (* The sequence obtained by concatenating sequences s and t. *) - (*************************************************************************) - -Append(s, e) == s \o <<e>> - (**************************************************************************) - (* The sequence obtained by appending element e to the end of sequence s. *) - (**************************************************************************) - -Head(s) == s[1] -Tail(s) == CASE s # << >> -> [i \in 1..(Len(s)-1) |-> s[i+1]] - (*************************************************************************) - (* The usual head (first) and tail (rest) operators. (Definition of Tail *) - (* changed on 4 Jun 2013 because original defined Tail(<< >>) = << >> . *) - (*************************************************************************) - -SubSeq(s, m, n) == [i \in 1..(1+n-m) |-> s[i+m-1]] - (*************************************************************************) - (* The sequence <<s[m], s[m+1], ... , s[n]>>. *) - (*************************************************************************) - -SelectSeq(s, Test(_)) == - (*************************************************************************) - (* The subsequence of s consisting of all elements s[i] such that *) - (* Test(s[i]) is true. *) - (*************************************************************************) - LET F[i \in 0..Len(s)] == - (*******************************************************************) - (* F[i] equals SelectSeq(SubSeq(s, 1, i), Test] *) - (*******************************************************************) - IF i = 0 THEN << >> - ELSE IF Test(s[i]) THEN Append(F[i-1], s[i]) - ELSE F[i-1] - IN F[Len(s)] -============================================================================= diff --git a/org.lamport.tla.toolbox/StandardModules/TLC.tla b/org.lamport.tla.toolbox/StandardModules/TLC.tla deleted file mode 100644 index a9567ac5272fc5fcd620e58e13a9f1652510b3bd..0000000000000000000000000000000000000000 --- a/org.lamport.tla.toolbox/StandardModules/TLC.tla +++ /dev/null @@ -1,36 +0,0 @@ -------------------------------- MODULE TLC ---------------------------------- -LOCAL INSTANCE Naturals -LOCAL INSTANCE Sequences ------------------------------------------------------------------------------ -Print(out, val) == val -PrintT(out) == TRUE -Assert(val, out) == IF val = TRUE THEN TRUE - ELSE CHOOSE v : TRUE -JavaTime == CHOOSE n : n \in Nat -TLCGet(i) == CHOOSE n : TRUE -TLCSet(i, v) == TRUE ------------------------------------------------------------------------------ -d :> e == [x \in {d} |-> e] -f @@ g == [x \in (DOMAIN f) \cup (DOMAIN g) |-> - IF x \in DOMAIN f THEN f[x] ELSE g[x]] -Permutations(S) == - {f \in [S -> S] : \A w \in S : \E v \in S : f[v]=w} ------------------------------------------------------------------------------ -(***************************************************************************) -(* In the following definition, we use Op as the formal parameter rather *) -(* than \prec because TLC Version 1 can't handle infix formal parameters. *) -(***************************************************************************) -SortSeq(s, Op(_, _)) == - LET Perm == CHOOSE p \in Permutations(1 .. Len(s)) : - \A i, j \in 1..Len(s) : - (i < j) => Op(s[p[i]], s[p[j]]) \/ (s[p[i]] = s[p[j]]) - IN [i \in 1..Len(s) |-> s[Perm[i]]] - -RandomElement(s) == CHOOSE x \in s : TRUE - -Any == CHOOSE x : TRUE - -ToString(v) == (CHOOSE x \in [a : v, b : STRING] : TRUE).b - -TLCEval(v) == v -============================================================================= diff --git a/org.lamport.tla.toolbox/build.properties b/org.lamport.tla.toolbox/build.properties index 9aa2097dcfe2d9c074a5212bd6390648f24ef4f4..96e3bb4fa8c7ee5c807dc08a8a92e87ac5b36be5 100644 --- a/org.lamport.tla.toolbox/build.properties +++ b/org.lamport.tla.toolbox/build.properties @@ -4,8 +4,6 @@ bin.includes = plugin.xml,\ META-INF/,\ .,\ icons/,\ - StandardModules/,\ helpContexts.xml,\ images/ -jars.compile.order = .,\ - StandardModules/ +jars.compile.order = . diff --git a/org.lamport.tla.toolbox/plugin.xml b/org.lamport.tla.toolbox/plugin.xml index ca9051143a645461a643ff46ec8680e6e7881f3b..bb4747949db5de90d3543b80c276b8509978baed 100644 --- a/org.lamport.tla.toolbox/plugin.xml +++ b/org.lamport.tla.toolbox/plugin.xml @@ -311,12 +311,6 @@ id="toolbox.command.module.parse.active" name="Parse Module"> </command> - <command - categoryId="toolbox.command.category.module" - description="Translates PCal in the active editor" - id="toolbox.command.module.translate.active" - name="Translate module"> - </command> <!-- Module preferences are disabled --> <!-- command categoryId="toolbox.command.category.module" @@ -894,10 +888,6 @@ class="org.lamport.tla.toolbox.ui.handler.OpenSpecHandler" commandId="toolbox.command.spec.open"> </handler> - <handler - class="org.lamport.tla.toolbox.ui.handler.PCalTranslateModuleHandler" - commandId="toolbox.command.module.translate.active"> - </handler> <handler class="org.lamport.tla.toolbox.ui.handler.ParseModuleHandler" commandId="toolbox.command.module.parse.active"> @@ -1098,13 +1088,6 @@ </extension> <extension point="org.eclipse.core.expressions.propertyTesters"> - <propertyTester - class="org.lamport.tla.toolbox.ui.expression.PCalPropertyTester" - id="toolbox.propertyTester.PCALTester" - namespace="toolbox.property" - properties="hasPCALAlgorithm" - type="org.eclipse.jface.viewers.ISelection"> - </propertyTester> <propertyTester class="org.lamport.tla.toolbox.ui.expression.CurrentSpecTester" id="toolbox.propertyTester.isCurrentSpec" @@ -1245,17 +1228,6 @@ </run> </builder> </extension> - <extension - id="toolbox.builder.PCalAlgorithmSearchingBuilder" - name="PCal Algorthim Definition Detecting Builder" - point="org.eclipse.core.resources.builders"> - <builder - hasNature="true"> - <run - class="org.lamport.tla.toolbox.spec.nature.PCalDetectingBuilder"> - </run> - </builder> - </extension> <!-- ================================================================================= --> <!-- Natures --> @@ -1272,9 +1244,6 @@ <builder id="toolbox.builder.TLAParserBuilder"> </builder> - <builder - id="toolbox.builder.PCalAlgorithmSearchingBuilder"> - </builder> </extension> <!-- @@ -1392,6 +1361,20 @@ </participant> </extension> + +<!-- ================================================================================= --> +<!-- News RSS Feeds - polling interval is in minutes --> +<!-- ================================================================================= --> + <extension + point="org.eclipse.recommenders.news.rcp.feed"> + <feed + id="org.lamport.tla.tooblox.rss.feed" + name="TLA+ News" + uri="https://groups.google.com/forum/feed/tlaplus-announce/msgs/rss_v2_0.xml" + pollingInterval="60"> + </feed> + </extension> + <!-- --> <!-- Specification content --> <!-- --> diff --git a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/job/TranslatorJob.java b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/job/TranslatorJob.java deleted file mode 100644 index 10d0bf799645f3125fe316f8adb5c0778410ac85..0000000000000000000000000000000000000000 --- a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/job/TranslatorJob.java +++ /dev/null @@ -1,223 +0,0 @@ -package org.lamport.tla.toolbox.job; - -import java.lang.reflect.InvocationTargetException; -import java.util.List; -import java.util.Vector; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.eclipse.core.resources.IMarker; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.resources.WorkspaceJob; -import org.eclipse.core.runtime.Assert; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Status; -import org.eclipse.jface.operation.IRunnableWithProgress; -import org.eclipse.jface.preference.IPreferenceStore; -import org.lamport.tla.toolbox.Activator; -import org.lamport.tla.toolbox.spec.Spec; -import org.lamport.tla.toolbox.util.ResourceHelper; -import org.lamport.tla.toolbox.util.TLAMarkerHelper; -import org.lamport.tla.toolbox.util.pref.IPreferenceConstants; -import org.lamport.tla.toolbox.util.pref.PreferenceStoreHelper; - -import pcal.TLAtoPCalMapping; -import pcal.Translator; - -/** - * Runs the PCal translator - * @author Simon Zambrovski - * @version $Id$ - */ -public class TranslatorJob extends WorkspaceJob -{ - private Translator translator; - private Vector callParams; - private IResource fileToBuild; - - /** - * @param name - */ - public TranslatorJob(IResource fileToBuild) - { - super("PCal Translation"); - this.translator = new Translator(); - this.fileToBuild = fileToBuild; - this.callParams = new Vector(); - - Activator.getDefault().logDebug("Translating " + fileToBuild.getLocation().toOSString()); - - boolean hasPcalAlg = false; - String[] params; - Object prop; - - try - { - prop = fileToBuild - .getSessionProperty(ResourceHelper.getQName(IPreferenceConstants.CONTAINS_PCAL_ALGORITHM)); - if (prop != null) - { - hasPcalAlg = ((Boolean) prop).booleanValue(); - } - - IPreferenceStore projectPreferenceStore = PreferenceStoreHelper.getProjectPreferenceStore(fileToBuild - .getProject()); - - String paramString = projectPreferenceStore.getString(IPreferenceConstants.PCAL_CAL_PARAMS); - - if (paramString != null) - { - params = paramString.split(" "); - } else - { - params = new String[0]; - } - - } catch (CoreException e1) - { - Activator.getDefault().logError("Error reading parameters", e1); - params = new String[0]; - } - - if (!hasPcalAlg) - { - // no algorithm detected - Activator.getDefault().logDebug("No algorithm found"); - } else - { - Activator.getDefault().logDebug("Algorithm found"); - } - - // add params from the resource setting - for (int i = 0; i < params.length; i++) - { - if (params[i] != null && !params[i].equals("")) - { - callParams.add(params[i]); - } - } - callParams.add(fileToBuild.getLocation().toOSString()); - - } - - /** - * @see org.eclipse.core.resources.WorkspaceJob#runInWorkspace(org.eclipse.core.runtime.IProgressMonitor) - */ - public IStatus runInWorkspace(IProgressMonitor monitor) throws CoreException - { - monitor.beginTask("PCal Translation", IProgressMonitor.UNKNOWN); - - // remove markers - monitor.setTaskName("Removing problem markers"); - TLAMarkerHelper - .removeProblemMarkers(fileToBuild, monitor, TLAMarkerHelper.TOOLBOX_MARKERS_TRANSLATOR_MARKER_ID); - - StringBuffer buffer = new StringBuffer(); - for (int i = 0; i < callParams.size(); i++) - { - buffer.append(" " + callParams.elementAt(i)); - } - Activator.getDefault().logDebug("Translator invoked with params: '" + buffer.toString() + "'"); - - TLAtoPCalMapping mapping = translator.runTranslation((String[]) callParams.toArray(new String[callParams.size()])); - // If no mapping has been created (e.g. due to a parsing error), the - // mapping object will be null. In this case we don't invalidate the old - // mapping. - if (mapping != null) { - /* - * At this point, fileToBuild.getName() returns the simple name of - * the file--e.g., "Test.tla". - */ - Spec currentSpec = Activator.getSpecManager().getSpecLoaded(); - currentSpec.setTpMapping(mapping, fileToBuild.getName(), monitor); - } - - monitor.worked(1); - monitor.setTaskName("Analyzing results"); - - List errors = translator.getErrorMessages(); - - if (errors.size() > 0) - { - monitor.setTaskName("Installing problem markers"); - for (int i = 0; i < errors.size(); i++) - { - String errorMessage = (String) errors.get(i); - - TLAMarkerHelper.installProblemMarker(fileToBuild, fileToBuild.getName(), IMarker.SEVERITY_ERROR, - detectLocation(errorMessage), errorMessage, monitor, - TLAMarkerHelper.TOOLBOX_MARKERS_TRANSLATOR_MARKER_ID); - } - } - - monitor.worked(1); - monitor.done(); - return Status.OK_STATUS; - } - - /** - * Return as runnable instead of the job - * @param fileToBuild - * @return - */ - public static IRunnableWithProgress getAsRunnableWithProgress(final IResource fileToBuild) - { - final TranslatorJob job = new TranslatorJob(fileToBuild); - return new IRunnableWithProgress() { - public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException - { - try - { - job.setRule(ResourceHelper.getModifyRule(fileToBuild)); - job.runInWorkspace(monitor); - } catch (CoreException e) - { - throw new InvocationTargetException(e); - } - } - }; - } - - private int[] detectLocation(String message) - { - String LINE = "line "; - String COLUMN = ", column "; - - int lineStarts = message.indexOf(LINE); - int lineEnds = message.indexOf(COLUMN); - if (lineStarts != -1 && lineEnds != -1) - { - String line = message.substring(lineStarts + LINE.length(), lineEnds); - /* - * afterColumnString is the substring of message that comes after the - * first occurance of ", column" in message. - */ - String afterColumnString = message.substring(lineEnds + COLUMN.length()); - // match any number of white spaces followed by the first string of digits. - Matcher matcher = Pattern.compile("\\s*\\d+").matcher(afterColumnString); - Assert.isTrue(matcher.find(), "No column number found in PlusCal message " + message); - // the column string that should be a parsable int - String column = matcher.group().trim(); - - int lineNumber = -1; - int columnNumber = -1; - try - { - lineNumber = Integer.parseInt(line); - } catch (NumberFormatException e) - { - } - try - { - columnNumber = Integer.parseInt(column); - } catch (NumberFormatException e) - { - } - return new int[] { lineNumber, columnNumber, lineNumber, columnNumber + 1 }; - } - return new int[] { -1, -1, -1, -1 }; - } - -} diff --git a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/spec/Module.java b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/spec/Module.java index e2ac47c45b3122b1a4b39acfc0800301143821d4..cbcaad9ef3ce0c428e86cd84d8e98d25fe98baf0 100644 --- a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/spec/Module.java +++ b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/spec/Module.java @@ -29,9 +29,9 @@ package org.lamport.tla.toolbox.spec; import java.io.File; import org.eclipse.core.resources.IResource; -import org.lamport.tla.toolbox.util.RCPNameToFileIStream; import tla2sany.semantic.ModuleNode; +import tlc2.module.BuiltInModuleHelper; /** * Representation of a module @@ -128,11 +128,11 @@ public class Module * Determines if current module is a standard module <br> * TODO Fishy method. improve/unify it * - * @return true iff the absolute path of the module contains RCPNameToFileIStream.STANDARD_MODULES value + * @return true iff the absolute path of the module contains BuiltInModuleHelper.STANDARD_MODULES value */ public boolean isStandardModule() { - return (getAbsolutePath().indexOf(RCPNameToFileIStream.STANDARD_MODULES) != -1); + return (getAbsolutePath().indexOf(BuiltInModuleHelper.STANDARD_MODULES) != -1); } diff --git a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/spec/nature/PCalDetectingBuilder.java b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/spec/nature/PCalDetectingBuilder.java deleted file mode 100644 index 9fd16016df77fec2588754abcdc3fca767f84f54..0000000000000000000000000000000000000000 --- a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/spec/nature/PCalDetectingBuilder.java +++ /dev/null @@ -1,185 +0,0 @@ -package org.lamport.tla.toolbox.spec.nature; - -import java.io.File; -import java.util.Map; - -import org.eclipse.core.filebuffers.ITextFileBuffer; -import org.eclipse.core.filebuffers.ITextFileBufferManager; -import org.eclipse.core.filebuffers.LocationKind; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.resources.IResourceVisitor; -import org.eclipse.core.resources.IncrementalProjectBuilder; -import org.eclipse.core.resources.ResourcesPlugin; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.NullProgressMonitor; -import org.eclipse.core.runtime.QualifiedName; -import org.eclipse.core.runtime.Status; -import org.eclipse.jface.text.BadLocationException; -import org.eclipse.jface.text.FindReplaceDocumentAdapter; -import org.eclipse.jface.text.IDocument; -import org.eclipse.jface.text.IRegion; -import org.lamport.tla.toolbox.Activator; -import org.lamport.tla.toolbox.spec.Spec; -import org.lamport.tla.toolbox.util.ResourceHelper; -import org.lamport.tla.toolbox.util.pref.IPreferenceConstants; - -public class PCalDetectingBuilder extends IncrementalProjectBuilder -{ - - public static final String BUILDER_ID = "toolbox.builder.PCalAlgorithmSearchingBuilder"; - private static final String PCAL_ALGORITHM_DEFINITION = "--algorithm"; - private static final String PCAL_FAIR_ALGORITHM_DEFINITION = "--fair"; - - private PCalDetectingVisitor visitor = new PCalDetectingVisitor(); - - /* (non-Javadoc) - * @see org.eclipse.core.resources.IncrementalProjectBuilder#build(int, java.util.Map, org.eclipse.core.runtime.IProgressMonitor) - */ - protected IProject[] build(int kind, @SuppressWarnings("rawtypes") Map args, IProgressMonitor monitor) throws CoreException - { - if (!Activator.isSpecManagerInstantiated()) { - // Reschedule the build assuming the spec manager will be - // instantiated later. The spec manager gets created by a workspace - // job in Activator#start, thus belonging to the same job family - // which is why it can run with us concurrently. - // Also see TLAParsingBuilder. - ResourcesPlugin.getWorkspace().build(kind, null); - return null; - } - - final Spec spec = Activator.getSpecManager().getSpecLoaded(); - if (spec == null) - { - return null; - } - - final IProject project = getProject(); - - if (project != spec.getProject()) - { - // skip the build calls on wrong projects (which are in WS, but not a current spec) - return null; - } - - project.accept(visitor); - - // must return null - return null; - } - - class PCalDetectingVisitor implements IResourceVisitor - { - /* (non-Javadoc) - * @see org.eclipse.core.resources.IResourceVisitor#visit(org.eclipse.core.resources.IResource) - */ - /* (non-Javadoc) - * @see org.eclipse.core.resources.IResourceVisitor#visit(org.eclipse.core.resources.IResource) - */ - public boolean visit(IResource resource) throws CoreException { - // check for resource existence (WS in-sync or out-of-sync) - if (!resource.exists() || !new File(resource.getLocation().toOSString()).exists()) { - return false; - } - if (IResource.PROJECT == resource.getType()) { - return true; - } else if (IResource.FILE == resource.getType() && ResourceHelper.isModule(resource)) { - final IPath fullPath = resource.getFullPath(); - final IDocument document = getDocument(fullPath, LocationKind.NORMALIZE); - final FindReplaceDocumentAdapter searchAdapter = new FindReplaceDocumentAdapter(document); - try { - // matchRegion is set non-null iff there is a "--algorithm" - // or "--fair" - // string in the file. The "--fair" option added by LL on 6 - // July 2011. - - // LL added the following test for nonzero document length on 28 Nov 2012 to - // fix the following problem. For some unfathomable reason, `document' was - // randomly getting set to a zero-length document. This triggered what seems - // to me to be a bug in the Eclipse code, causing FindReplaceDocumentAdapter.find - // to generate a BadLocationException in its call of - // FindReplaceDocumentAdapter.findReplace by giving it a startOffset - // value of -1. (Of course, there's no such thing as a bug if there's no - // specification of what the code is supposed to do.) This may be a bad idea - // because I don't know what bad things might happen if this error occurs when there - // actually is an algorithm. But I don't see why. In fact, I don't know what - // because the absence of spec doesn't disable the translate button and doesn't - // prevent the translator from being called (and raising an error because it - // finds no algorithm). All this code seems to be doing is setting the - // CONTAINS_PCAL_ALGORITHM property, and as near as I can tell, all that property - // does is determine whether Activator.getDefault().logDebug is called with - // a message indicating that an algorithm was or was not found--before - // calling the translator in either case. Of course, this property may - // have some well-hidden influence that I didn't find. - // - // By the way, when the error occurs, it is reported 14 times. I presume that, - // that this piece of code is called 14 times whenever the module is parsed. - // One hopes it is idempotent. - IRegion matchRegion = null ; - if (document.getLength() != 0) { - matchRegion = searchAdapter.find(0, PCAL_ALGORITHM_DEFINITION, true, true, false, false); - if (matchRegion == null) { - matchRegion = searchAdapter.find(0, PCAL_FAIR_ALGORITHM_DEFINITION, true, true, false, false); - } - - } else { - Activator.getDefault().logError( - "Error occurred when checking if there is a PlusCal algorithm") ; - } - - - // store the session property - final QualifiedName key = new QualifiedName(Activator.PLUGIN_ID, - IPreferenceConstants.CONTAINS_PCAL_ALGORITHM); - - // found a algorithm definition - if (matchRegion != null) { - resource.setSessionProperty(key, Boolean.TRUE); - } else { - resource.setSessionProperty(key, null); - } - } catch (BadLocationException e) { - // do not swallow exceptions locally - throw new CoreException(new Status(Status.ERROR, Activator.PLUGIN_ID, - "Error trying to detect the algorithm", e)); - } finally { - // Release document handle so the ITextFileBufferManager can - // correctly dispose of the document. Disposing means all - // consumers of the document disconnect. This is done by - // reference counting per document. - // If we don't correctly dispose, subsequent document - // consumers might get an out dated version from the - // manager's cache if the document names happen to be - // identical. This is e.g. the case, when a spec with name - // "frob" is deleted and recreated with name "frob" in a - // different file system location. - final ITextFileBufferManager bufferManager = ITextFileBufferManager.DEFAULT; - bufferManager.disconnect(fullPath, LocationKind.NORMALIZE, new NullProgressMonitor()); - } - } - return false; - } - - /** - * @param resource A {@link IResource} for which the corresponding {@link IDocument} should be received - */ - /** - * @param resourcePath The {@link IPath} to the {@link IResource} for which an {@link IDocument} should be received - * @param locKind The {@link LocationKind} of the {@link IPath} - * @return The corresponding {@link IDocument} or null - * @throws CoreException If the resource could not successfully be received - */ - private IDocument getDocument(final IPath resourcePath, final LocationKind locKind) throws CoreException { - // connect the buffer manager to the given resource - // the buffermanager takes care of cleanup/disconnecting - final ITextFileBufferManager bufferManager = ITextFileBufferManager.DEFAULT; - bufferManager.connect(resourcePath, locKind, new NullProgressMonitor()); - - // get the text file buf from the manager and receive the document - final ITextFileBuffer itfb = bufferManager.getTextFileBuffer(resourcePath, locKind); - return itfb.getDocument(); - } - } -} diff --git a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/spec/nature/TLANature.java b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/spec/nature/TLANature.java index 541e22a5a5367a93d5d70685b6cb9610c399c1e8..f91c99ac10a7e42ddfb6b60c53461e196cac7da7 100644 --- a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/spec/nature/TLANature.java +++ b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/spec/nature/TLANature.java @@ -29,7 +29,7 @@ public class TLANature implements IProjectNature boolean tlaBuilderFound = false; boolean pcalBuilderFound = false; - int numberOfBuildersToInstall = 2; + int numberOfBuildersToInstall = 1; for (int i = 0; i < commands.length; ++i) { @@ -38,10 +38,6 @@ public class TLANature implements IProjectNature { tlaBuilderFound = true; numberOfBuildersToInstall--; - } else if (builderName.equals(PCalDetectingBuilder.BUILDER_ID)) - { - pcalBuilderFound = true; - numberOfBuildersToInstall--; } if (tlaBuilderFound && pcalBuilderFound) @@ -62,12 +58,6 @@ public class TLANature implements IProjectNature newCommands[position] = command; position++; } - if (!pcalBuilderFound) - { - ICommand command = desc.newCommand(); - command.setBuilderName(PCalDetectingBuilder.BUILDER_ID); - newCommands[position] = command; - } desc.setBuildSpec(newCommands); project.setDescription(desc, null); @@ -84,7 +74,7 @@ public class TLANature implements IProjectNature ICommand[] commands = description.getBuildSpec(); for (int i = 0; i < commands.length; ++i) { String builderName = commands[i].getBuilderName(); - if (builderName.equals(TLAParsingBuilder.BUILDER_ID) || builderName.equals(PCalDetectingBuilder.BUILDER_ID)) { + if (builderName.equals(TLAParsingBuilder.BUILDER_ID)) { ICommand[] newCommands = new ICommand[commands.length - 1]; System.arraycopy(commands, 0, newCommands, 0, i); System.arraycopy(commands, i + 1, newCommands, i, diff --git a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/contribution/ModuleListContributionItem.java b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/contribution/ModuleListContributionItem.java index 99ccf42fe3d8a69b436d257da829479c2ddc8bde..87f51fc1df0f171863b25ed664bae93cda806e63 100644 --- a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/contribution/ModuleListContributionItem.java +++ b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/contribution/ModuleListContributionItem.java @@ -36,7 +36,6 @@ import org.eclipse.ui.actions.CompoundContributionItem; import org.eclipse.ui.menus.CommandContributionItem; import org.eclipse.ui.menus.CommandContributionItemParameter; import org.lamport.tla.toolbox.Activator; -import org.lamport.tla.toolbox.job.DeleteOutOfSyncJob; import org.lamport.tla.toolbox.spec.Spec; import org.lamport.tla.toolbox.ui.handler.AddModuleHandler; import org.lamport.tla.toolbox.ui.handler.OpenModuleHandler; @@ -62,8 +61,6 @@ public class ModuleListContributionItem extends CompoundContributionItem final Vector<IContributionItem> moduleContributions = new Vector<IContributionItem>(); HashMap<String, String> parameters = new HashMap<String, String>(); - final Vector<IResource> outOfSyncResourcesToDelete = new Vector<IResource>(); - // create the contribution item for add module CommandContributionItemParameter param = new CommandContributionItemParameter(UIHelper.getActiveWindow(), "toolbox.command.module.add", AddModuleHandler.COMMAND_ID, parameters, iconAddModule, null, null, @@ -86,11 +83,6 @@ public class ModuleListContributionItem extends CompoundContributionItem { continue; } - if (!modules[i].isSynchronized(IResource.DEPTH_ZERO)) - { - outOfSyncResourcesToDelete.add(modules[i]); - continue; - } isRoot = rootModule.equals(modules[i]); @@ -110,13 +102,6 @@ public class ModuleListContributionItem extends CompoundContributionItem moduleContributions.add(new CommandContributionItem(param)); } } - - if (outOfSyncResourcesToDelete.size() > 0) { - final DeleteOutOfSyncJob job = new DeleteOutOfSyncJob( - (IResource[]) outOfSyncResourcesToDelete.toArray(new IResource[outOfSyncResourcesToDelete.size()])); - job.schedule(); - } - return (IContributionItem[]) moduleContributions.toArray(new IContributionItem[moduleContributions.size()]); } } diff --git a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/expression/PCalPropertyTester.java b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/expression/PCalPropertyTester.java deleted file mode 100644 index 9f3444cc1d24119cf7185147629b1a7130665194..0000000000000000000000000000000000000000 --- a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/expression/PCalPropertyTester.java +++ /dev/null @@ -1,63 +0,0 @@ -package org.lamport.tla.toolbox.ui.expression; - -import org.eclipse.core.expressions.PropertyTester; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.QualifiedName; -import org.eclipse.jface.viewers.ISelectionProvider; -import org.eclipse.jface.viewers.IStructuredSelection; -import org.lamport.tla.toolbox.Activator; -import org.lamport.tla.toolbox.util.UIHelper; -import org.lamport.tla.toolbox.util.pref.IPreferenceConstants; - -/** - * Tests if a module in the editor includes a PCal algorithm - * @author Simon Zambrovski - * @version $Id$ - */ -public class PCalPropertyTester extends PropertyTester -{ - private static QualifiedName key = new QualifiedName(Activator.PLUGIN_ID, - IPreferenceConstants.CONTAINS_PCAL_ALGORITHM); - private ISelectionProvider provider = UIHelper.getActiveEditorFileSelectionProvider(); - - /** - * Executes the property test determined by the parameter <code>property</code>. - * - * @param receiver the receiver of the property test - * @param property the property to test - * @param args additional arguments to evaluate the property. If no arguments - * are specified in the <code>test</code> expression an array of length 0 - * is passed - * @param expectedValue the expected value of the property. The value is either - * of type <code>java.lang.String</code> or a boxed base type. If no value was - * specified in the <code>test</code> expressions then <code>null</code> is passed - * - * @return returns <code>true<code> if the property is equal to the expected value; - * otherwise <code>false</code> is returned - */ - public boolean test(Object receiver, String property, Object[] args, Object expectedValue) - { - // IEditorInput input = ((IEditorPart) receiver).getEditorInput(); - if ("hasPCALAlgorithm".equals(property)) - { - if (provider.getSelection() != null && !provider.getSelection().isEmpty()) - { - IResource resource = (IResource) ((IStructuredSelection) provider.getSelection()).getFirstElement(); - try - { - boolean result = false; - Boolean sessionProperty = (Boolean) resource.getSessionProperty(key); - result = (sessionProperty != null && sessionProperty.booleanValue()); - return result; - } catch (CoreException e) - { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - } - return false; - } - -} diff --git a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/handler/PCalTranslateModuleHandler.java b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/handler/PCalTranslateModuleHandler.java deleted file mode 100644 index 58f9bc8db1be184fdebf3622b505905bdd5121fb..0000000000000000000000000000000000000000 --- a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/handler/PCalTranslateModuleHandler.java +++ /dev/null @@ -1,121 +0,0 @@ -package org.lamport.tla.toolbox.ui.handler; - -import java.lang.reflect.InvocationTargetException; - -import org.eclipse.core.commands.ExecutionEvent; -import org.eclipse.core.commands.ExecutionException; -import org.eclipse.core.commands.IHandler; -import org.eclipse.core.commands.IHandler2; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.jface.dialogs.ProgressMonitorDialog; -import org.eclipse.jface.operation.IRunnableWithProgress; -import org.eclipse.swt.widgets.Shell; -import org.eclipse.ui.IEditorInput; -import org.eclipse.ui.IFileEditorInput; -import org.eclipse.ui.IWorkbenchWindow; -import org.lamport.tla.toolbox.Activator; -import org.lamport.tla.toolbox.job.TranslatorJob; -import org.lamport.tla.toolbox.util.UIHelper; - -/** - * Triggers the PCal translation of the module - * @author Simon Zambrovski - * @version $Id$ - */ -public class PCalTranslateModuleHandler extends SaveDirtyEditorAbstractHandler implements IHandler, IHandler2 -{ - public final static String COMMAND_ID = "toolbox.command.module.translate.active"; - - /* (non-Javadoc) - * @see org.eclipse.core.commands.AbstractHandler#execute(org.eclipse.core.commands.ExecutionEvent) - */ - public Object execute(ExecutionEvent event) throws ExecutionException - { - if (!saveDirtyEditor(event)) { - return null; - } - - IEditorInput editorInput = activeEditor.getEditorInput(); - if (editorInput instanceof IFileEditorInput) - { - final IResource fileToBuild = ((IFileEditorInput) editorInput).getFile(); - - IRunnableWithProgress translatorOperation = TranslatorJob.getAsRunnableWithProgress(fileToBuild); - try - { - // Getting progress monitor - final IWorkbenchWindow window = UIHelper.getActiveWindow(); - final Shell shell = (window != null) ? window.getShell() : null; - final ProgressMonitorDialog progressDialog = new ProgressMonitorDialog(shell); - final IProgressMonitor monitor = progressDialog.getProgressMonitor(); - // Changing the first argument of the following call to false - // will make the translator run in the UI thread, making the UI - // unresponsive while the translator is running. However, it - // might fix the Heisenbug that causes the translator to produce - // a bogus "missing `begin'" error when run after fixing - // a real error. Or again, it might not. - // - Note added by LL on 2 Apr 2013 - // Note added by LL on 17 Aug 2015: - // Changing the first argument apparently does not fix that bug. - // However, running the translator on the following algorithm - // reliably produces the bug: - // - // (* --algorithm alok_test { - // { - // print "hello" - // print "world" - // } - // } *) - // - // Running the translator repeatedly on it switches between the - // "missing ;" and the "missing `begin'" error. After correcting - // the "missing ;" error, it reliably produces the "missing begin" - // error. The translator behaves correctly when run from the - // command line, so this is only a problem when the translator is - // run from the Toolbox. - // - // This bug was fixed on 17 Aug 2015 by a change to ParseAlgorithm.java. - // - progressDialog.run(true, false, translatorOperation); - fileToBuild.refreshLocal(IResource.DEPTH_ONE, monitor); - - } catch (InvocationTargetException e) - { - Activator.getDefault().logError("Error during PlusCal Trnaslation", e); - } catch (InterruptedException e) - { - Activator.getDefault().logError("Error during PlusCal Trnaslation", e); - } catch (CoreException e) - { - Activator.getDefault().logError("Error during PlusCal Trnaslation", e); - } - - /* - TranslatorJob job = new TranslatorJob(fileToBuild); - job.setUser(true); - // TODO config file is also changed - job.setRule(getModifyRule(new IResource[]{fileToBuild})); - job.addJobChangeListener(new JobChangeAdapter(){ - public void done(IJobChangeEvent event) - { - if (Status.OK_STATUS.equals(event.getResult())) - { - try - { - fileToBuild.refreshLocal(IResource.DEPTH_ONE, null); - } catch (CoreException e) - { - e.printStackTrace(); - } - } - } - }); - job.schedule(); - */ - - } - return null; - } -} diff --git a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/handler/SaveDirtyEditorAbstractHandler.java b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/handler/SaveDirtyEditorAbstractHandler.java index 4b38acd01e6f5c40c106b6b02437a45683e39c25..9e27d4d2a0c645cda67f68be8f1e696bfb24c540 100644 --- a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/handler/SaveDirtyEditorAbstractHandler.java +++ b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/handler/SaveDirtyEditorAbstractHandler.java @@ -30,6 +30,14 @@ public abstract class SaveDirtyEditorAbstractHandler extends AbstractHandler { getPrefs().setDefault(this.getClass() + ".dontBother", false); if (getPrefs().getBoolean(this.getClass() + ".dontBother")) { // TODO decouple from ui thread + // Use NullProgressMonitor instead of newly created monitor. The + // parent ProgressMonitorDialog would need to be properly + // initialized first. + // @see Bug #256 in general/bugzilla/index.html + // + // Generally though, saving a resource involves I/O which should be + // decoupled from the UI thread in the first place. Properly doing + // this, would be from inside a Job which provides a ProgressMonitor activeEditor.doSave(new NullProgressMonitor()); } else { final Shell shell = HandlerUtil.getActiveShell(event); @@ -43,21 +51,19 @@ public abstract class SaveDirtyEditorAbstractHandler extends AbstractHandler { } if (res == MessageDialog.OK || res == MessageDialog.CONFIRM) { // TODO decouple from ui thread + // Use NullProgressMonitor instead of newly created monitor. The + // parent ProgressMonitorDialog would need to be properly + // initialized first. + // @see Bug #256 in general/bugzilla/index.html + // + // Generally though, saving a resource involves I/O which should be + // decoupled from the UI thread in the first place. Properly doing + // this, would be from inside a Job which provides a ProgressMonitor activeEditor.doSave(new NullProgressMonitor()); } else { return false; } } - - // Use NullProgressMonitor instead of newly created monitor. The - // parent ProgressMonitorDialog would need to be properly - // initialized first. - // @see Bug #256 in general/bugzilla/index.html - // - // Generally though, saving a resource involves I/O which should be - // decoupled from the UI thread in the first place. Properly doing - // this, would be from inside a Job which provides a ProgressMonitor - activeEditor.doSave(new NullProgressMonitor()); } return true; } diff --git a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/provider/SpecContentProvider.java b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/provider/SpecContentProvider.java index abdacbba28df70c23931898f41e46db02e1e888a..ee4fead21cf291f2d6d6a8c76483617cd938efb2 100644 --- a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/provider/SpecContentProvider.java +++ b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/provider/SpecContentProvider.java @@ -32,7 +32,6 @@ import org.eclipse.core.resources.IResource; import org.eclipse.jface.viewers.ITreeContentProvider; import org.eclipse.jface.viewers.Viewer; import org.lamport.tla.toolbox.Activator; -import org.lamport.tla.toolbox.job.DeleteOutOfSyncJob; import org.lamport.tla.toolbox.spec.Module; import org.lamport.tla.toolbox.spec.Spec; import org.lamport.tla.toolbox.spec.manager.WorkspaceSpecManager; @@ -114,7 +113,6 @@ public class SpecContentProvider implements ITreeContentProvider { } protected Module[] constructModules(Spec spec) { - final Vector<IResource> outOfSyncResourcesToDelete = new Vector<IResource>(); final Vector<Module> modules = new Vector<Module>(); final IResource[] moduleResources = spec.getModuleResources(); for (int i = 0; i < moduleResources.length; i++) { @@ -122,21 +120,9 @@ public class SpecContentProvider implements ITreeContentProvider { if (!ResourceHelper.isModule(moduleResources[i])) { continue; } - // skip non-existing files - if (!moduleResources[i].isSynchronized(IResource.DEPTH_ZERO)) { - outOfSyncResourcesToDelete.add(moduleResources[i]); - continue; - } final Module module = new Module(moduleResources[i]); modules.add(module); } - - if (outOfSyncResourcesToDelete.size() > 0) { - final DeleteOutOfSyncJob job = new DeleteOutOfSyncJob( - (IResource[]) outOfSyncResourcesToDelete.toArray(new IResource[outOfSyncResourcesToDelete.size()])); - job.schedule(500); - } - return (Module[]) modules.toArray(new Module[modules.size()]); } diff --git a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/provider/ToolboxLabelProvider.java b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/provider/ToolboxLabelProvider.java index 4625647417aec6e1d768b95f47406b0b5078acbf..a03c11e40d5e00297ac7cb28d7b913313ccb0902 100644 --- a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/provider/ToolboxLabelProvider.java +++ b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/ui/provider/ToolboxLabelProvider.java @@ -61,7 +61,19 @@ public class ToolboxLabelProvider extends LabelProvider implements ILabelProvide return null; } + // This is at least shown in the Toolbox's status line at the bottom. public String getDescription(final Object element) { + if (element instanceof Spec) { + final Spec spec = (Spec) element; + final IFile root = spec.getRootFile(); + if (root == null) { + return super.getText(element); + } + return spec.getName() + " [ " + root.getLocation().toFile() + " ]"; + } else if (element instanceof Module) { + final Module module = (Module) element; + return module.getModuleName() + " [ " + module.getResource().getLocation().toFile() + " ]"; + } return super.getText(element); } diff --git a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/RCPNameToFileIStream.java b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/RCPNameToFileIStream.java index 67eabc268b6ea2247413fa8e159ac1afeb3fa088..301ccf20d72fb612438102470a63ecb1b1f5a2fd 100644 --- a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/RCPNameToFileIStream.java +++ b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/RCPNameToFileIStream.java @@ -7,9 +7,11 @@ import java.util.Enumeration; import java.util.Vector; import org.eclipse.core.runtime.FileLocator; -import org.lamport.tla.toolbox.Activator; +import org.eclipse.core.runtime.Platform; +import org.osgi.framework.Bundle; import tla2sany.semantic.ModuleNode; +import tlc2.module.BuiltInModuleHelper; import util.FilenameToStream; import util.ToolIO; @@ -21,9 +23,7 @@ import util.ToolIO; public class RCPNameToFileIStream implements FilenameToStream { - // TODO move to generic constant interface - public static final String STANDARD_MODULES = "StandardModules"; - private Vector libraryPathEntries = new Vector(); + private final Vector<String> libraryPathEntries = new Vector<String>(); /** * Initialization of the name resolver <br> @@ -56,22 +56,31 @@ public class RCPNameToFileIStream implements FilenameToStream { try { - Enumeration installedInternalModules = Activator.getDefault().getBundle().findEntries(File.separator, - STANDARD_MODULES, true); - Vector paths = new Vector(); + final Bundle bundle = Platform.getBundle(BuiltInModuleHelper.BUNDLE_ID); + + Enumeration<URL> installedInternalModules = bundle + .findEntries(BuiltInModuleHelper.STANDARD_MODULES_PATH, BuiltInModuleHelper.STANDARD_MODULES, true); + + if (installedInternalModules == null) { + // Toolbox is running from inside Eclipse (dev mode) and the StandardModules are + // found in a slightly different location. + installedInternalModules = bundle.findEntries( + File.separator + "src" + File.separator + BuiltInModuleHelper.STANDARD_MODULES_PATH, + BuiltInModuleHelper.STANDARD_MODULES, true); + } + while (installedInternalModules.hasMoreElements()) { - URL library = (URL) installedInternalModules.nextElement(); + final URL library = installedInternalModules.nextElement(); if (library != null) { // add external (resolved) URL - paths.addElement(FileLocator.resolve(library).getPath()); + final String path = FileLocator.resolve(library).getPath(); + libraryPathEntries.add(path); } } - libraryPathEntries.addAll(paths); } catch (IOException e) { - // TODO Auto-generated catch block e.printStackTrace(); } diff --git a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/ResourceHelper.java b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/ResourceHelper.java index 466f6b4692f962816d89e189976b12ccb4b26f2b..21c3b34904b978d2241f0221da6dc016d7d2c8ca 100644 --- a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/ResourceHelper.java +++ b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/ResourceHelper.java @@ -53,7 +53,6 @@ import org.eclipse.ui.progress.UIJob; import org.lamport.tla.toolbox.Activator; import org.lamport.tla.toolbox.job.NewTLAModuleCreationOperation; import org.lamport.tla.toolbox.spec.Spec; -import org.lamport.tla.toolbox.spec.nature.PCalDetectingBuilder; import org.lamport.tla.toolbox.spec.nature.TLANature; import org.lamport.tla.toolbox.spec.nature.TLAParsingBuilder; import org.lamport.tla.toolbox.spec.parser.IParseConstants; @@ -271,8 +270,7 @@ public class ResourceHelper // check builders and install if missing ICommand[] commands = description.getBuildSpec(); boolean tlaBuilderFound = false; - boolean pcalBuilderFound = false; - int numberOfBuildersToInstall = 2; + int numberOfBuildersToInstall = 1; for (int i = 0; i < commands.length; ++i) { @@ -281,13 +279,9 @@ public class ResourceHelper { tlaBuilderFound = true; numberOfBuildersToInstall--; - } else if (builderName.equals(PCalDetectingBuilder.BUILDER_ID)) - { - pcalBuilderFound = true; - numberOfBuildersToInstall--; } - if (tlaBuilderFound && pcalBuilderFound) + if (tlaBuilderFound) { break; } @@ -307,12 +301,6 @@ public class ResourceHelper newCommands[position] = command; position++; } - if (!pcalBuilderFound) - { - ICommand command = description.newCommand(); - command.setBuilderName(PCalDetectingBuilder.BUILDER_ID); - newCommands[position] = command; - } } } else { @@ -326,12 +314,9 @@ public class ResourceHelper // set TLA+ Parsing Builder ICommand command = description.newCommand(); command.setBuilderName(TLAParsingBuilder.BUILDER_ID); - // set PCal detecting builder - ICommand command2 = description.newCommand(); - command2.setBuilderName(PCalDetectingBuilder.BUILDER_ID); // setup the builders - description.setBuildSpec(new ICommand[] { command, command2 }); + description.setBuildSpec(new ICommand[] { command }); } // create the project diff --git a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/e4/E4HandlerWrapper.java b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/e4/E4HandlerWrapper.java new file mode 100644 index 0000000000000000000000000000000000000000..8f8b34c4ec862a2fefe67daa2a3a346cb7f73db3 --- /dev/null +++ b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/e4/E4HandlerWrapper.java @@ -0,0 +1,116 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package org.lamport.tla.toolbox.util.e4; + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.core.runtime.IExecutableExtension; +import org.eclipse.core.runtime.IExecutableExtensionFactory; +import org.eclipse.core.runtime.Status; +import org.eclipse.e4.core.contexts.ContextInjectionFactory; +import org.eclipse.e4.core.contexts.IEclipseContext; +import org.eclipse.ui.PlatformUI; +import org.lamport.tla.toolbox.Activator; +import org.eclipse.e4.core.contexts.ContextInjectionFactory; +import org.eclipse.e4.core.contexts.IEclipseContext; +import org.eclipse.e4.core.di.annotations.Execute; + +@SuppressWarnings("unused") +public class E4HandlerWrapper implements IExecutableExtensionFactory, IExecutableExtension { + + private String clazz; + + /* (non-Javadoc) + * @see org.eclipse.core.runtime.IExecutableExtensionFactory#create() + */ + @Override + public Object create() throws CoreException { + try { + return new E4Handler<>(Class.forName(clazz)); + } catch (ClassNotFoundException e) { + throw new CoreException(new Status(1, Activator.PLUGIN_ID, e.getMessage(), e)); + } + } + + /* (non-Javadoc) + * @see org.eclipse.core.runtime.IExecutableExtension#setInitializationData(org.eclipse.core.runtime.IConfigurationElement, java.lang.String, java.lang.Object) + */ + @Override + public void setInitializationData(IConfigurationElement config, String propertyName, Object data) + throws CoreException { + final String defaultHandler = config.getAttribute("defaultHandler"); + if (defaultHandler.contains(":")) { + clazz = defaultHandler.split(":")[1]; + } + } + + /******************************************************************************* + * Copyright (c) 2012, 2015 EclipseSource München GmbH and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Jonas Helming <jhelming@eclipsesource.com> - initial API and implementation + * Lars Vogel <Lars.Vogel@gmail.com> - Bug 421453 + ******************************************************************************/ + public static class E4Handler<C> extends AbstractHandler { + private final C component; + + public E4Handler(Class<C> clazz) { + final IEclipseContext context = getActiveContext(); + component = ContextInjectionFactory.make(clazz, context); + } + + private static IEclipseContext getActiveContext() { + final IEclipseContext parentContext = getParentContext(); + return parentContext.getActiveLeaf(); + } + + private static IEclipseContext getParentContext() { + return PlatformUI.getWorkbench().getService(IEclipseContext.class); + } + + /* (non-Javadoc) + * @see org.eclipse.core.commands.IHandler#execute(org.eclipse.core.commands.ExecutionEvent) + */ + @Override + public Object execute(ExecutionEvent event) throws ExecutionException { + // MAK: Add ExecutionEvent to context in order for the component to have it + // invoked. E.g. stateful handlers will need it. + getActiveContext().set(ExecutionEvent.class, event); + try { + return ContextInjectionFactory.invoke(component, Execute.class, getActiveContext()); + } finally { + getActiveContext().remove(ExecutionEvent.class); + } + } + } +} diff --git a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/pref/IPreferenceConstants.java b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/pref/IPreferenceConstants.java index 46a4169ad060fef8d00ed9f4ba66f38868b69aac..24a8227a3ae92d3e08848cfe37197a325775e63e 100644 --- a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/pref/IPreferenceConstants.java +++ b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/pref/IPreferenceConstants.java @@ -53,6 +53,4 @@ public interface IPreferenceConstants /** Resource persistent property for sticking the pcal call params */ public static final String PCAL_CAL_PARAMS = "pCalCallParams"; - /** Session property indicating if the resource has Pcal algorithm */ - public static final String CONTAINS_PCAL_ALGORITHM = "hasPcalAlgorithm"; } diff --git a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/pref/PreferenceStoreHelper.java b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/pref/PreferenceStoreHelper.java index 1ecabd0565aaa8271591974a7b87a45afe4040d4..9acd6de61f22a788b112a1c335ac3cbc4a31ca47 100644 --- a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/pref/PreferenceStoreHelper.java +++ b/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/util/pref/PreferenceStoreHelper.java @@ -10,6 +10,7 @@ import org.eclipse.core.runtime.preferences.IEclipsePreferences; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.ui.preferences.ScopedPreferenceStore; import org.lamport.tla.toolbox.Activator; +import org.lamport.tla.toolbox.spec.Spec; import org.lamport.tla.toolbox.util.ResourceHelper; import org.osgi.service.prefs.BackingStoreException; import org.osgi.service.prefs.Preferences; @@ -130,6 +131,10 @@ public class PreferenceStoreHelper ScopedPreferenceStore store = new ScopedPreferenceStore(scope, Activator.PLUGIN_ID /*Activator.getDefault().getBundle().getSymbolicName()*/); return store; } + + public static IPreferenceStore getProjectPreferenceStore(Spec spec) { + return getProjectPreferenceStore(spec.getProject()); + } /** * Retrieves preference store with the workspace scope @@ -140,4 +145,13 @@ public class PreferenceStoreHelper IPreferenceStore store = Activator.getDefault().getPreferenceStore(); return store; } + + public static String[] getStringArray(Spec spec, String key, String[] def) { + final IPreferenceStore projectPreferences = getProjectPreferenceStore(spec); + final String string = projectPreferences.getString(key); + if (string == null) { + return def; + } + return string.split(" "); + } } diff --git a/pom.xml b/pom.xml index 473967c499e40f8ec44595b1cef7d61754b7d822..0a64a5ac510af2d6670f23a3023f2d47f3975bad 100644 --- a/pom.xml +++ b/pom.xml @@ -88,7 +88,7 @@ <!-- http://maven.apache.org/general.html#encoding-warning --> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> - <tycho-version>1.0.0</tycho-version> + <tycho-version>1.1.0</tycho-version> <!-- no default here --> <tycho.test.vm.argline>-Xmx500m -Xdebug -Xrunjdwp:transport=dt_socket,address=1044,server=y,suspend=n</tycho.test.vm.argline> @@ -241,11 +241,6 @@ <environments> <!-- Linux --> - <environment> - <os>linux</os> - <ws>gtk</ws> - <arch>x86</arch> - </environment> <environment> <os>linux</os> <ws>gtk</ws> @@ -253,11 +248,6 @@ </environment> <!-- Windows --> - <environment> - <os>win32</os> - <ws>win32</ws> - <arch>x86</arch> - </environment> <environment> <os>win32</os> <ws>win32</ws> diff --git a/tlatools/.classpath b/tlatools/.classpath index 1fe074bee9d05529b82884cadf03067bd5110a4e..973889d035931e7371769667c608904a77b482d9 100644 --- a/tlatools/.classpath +++ b/tlatools/.classpath @@ -8,7 +8,9 @@ <classpathentry kind="src" path="test-long"/> <classpathentry kind="src" path="test-concurrent"/> <classpathentry kind="src" path="test-verify"/> + <classpathentry kind="src" path="test-benchmark"/> <classpathentry kind="lib" path="lib/javax.mail.jar"/> <classpathentry kind="lib" path="lib/jpf.jar"/> + <classpathentry kind="lib" path="lib/jmh/jmh-core-1.21.jar"/> <classpathentry kind="output" path="class"/> </classpath> diff --git a/tlatools/customBuild.xml b/tlatools/customBuild.xml index 5da1c0ff2a7263c8f87cb22efcb85c4c0b86a43e..7ec621c557a24b76bac98d6cf520f6dd3c3cb017 100644 --- a/tlatools/customBuild.xml +++ b/tlatools/customBuild.xml @@ -294,8 +294,10 @@ <batchtest fork="yes" todir="${test.reports}"> <fileset dir="${test.dir}"> <include name="**/*Test*.java" /> + <exclude name="**/PCalTest.java" /> <exclude name="**/CommonTestCase.java" /> <exclude name="**/ModelCheckerTestCase.java" /> + <exclude name="**/PCalModelCheckerTestCase.java" /> <exclude name="**/SuiteTestCase.java" /> <exclude name="**/SuiteETestCase.java" /> <exclude name="**/DistributedTLCTestCase.java" /> @@ -308,6 +310,16 @@ <exclude name="**/TestDriver.java" /> <exclude name="**/TestDriver2.java" /> <exclude name="**/AllTests.java" /> + <!-- Known test failures --> + <exclude name="**/pcal/StackTestTest.java" /> + <exclude name="**/pcal/TestPCandStackTest.java" /> + <!-- These take too long --> + <exclude name="**/MacroQuicksortTest.java" /> + <exclude name="**/MacroRealQuicksortTest.java" /> + <exclude name="**/PcalPaxosTest.java" /> + <exclude name="**/DetlefsTest.java" /> + <exclude name="**/StarkMutexTest.java" /> + <exclude name="**/SimpleMultiProcTest.java" /> </fileset> </batchtest> </junit> @@ -342,8 +354,10 @@ <batchtest fork="yes" todir="${test.reports}/onJar"> <fileset dir="${test.dir}"> <include name="**/*Test*.java" /> + <exclude name="**/PCalTest.java" /> <exclude name="**/CommonTestCase.java" /> <exclude name="**/ModelCheckerTestCase.java" /> + <exclude name="**/PCalModelCheckerTestCase.java" /> <exclude name="**/SuiteTestCase.java" /> <exclude name="**/SuiteETestCase.java" /> <exclude name="**/DistributedTLCTestCase.java" /> @@ -356,6 +370,16 @@ <exclude name="**/TestDriver.java" /> <exclude name="**/TestDriver2.java" /> <exclude name="**/AllTests.java" /> + <!-- Known test failures --> + <exclude name="**/pcal/StackTestTest.java" /> + <exclude name="**/pcal/TestPCandStackTest.java" /> + <!-- These take too long --> + <exclude name="**/MacroQuicksortTest.java" /> + <exclude name="**/MacroRealQuicksortTest.java" /> + <exclude name="**/PcalPaxosTest.java" /> + <exclude name="**/DetlefsTest.java" /> + <exclude name="**/StarkMutexTest.java" /> + <exclude name="**/SimpleMultiProcTest.java" /> </fileset> </batchtest> </junit> @@ -460,6 +484,34 @@ </junit> </target> + <!-- http://hg.openjdk.java.net/code-tools/jmh/file/3769055ad883/jmh-ant-sample/build.xml --> + <target name="benchmark" description="Generate the self-contained JMH benchmark JAR (run with java -jar target/benchmarks.jar)"> + <!-- Compile benchmark class files in test-benchmark against jmh. --> + <delete dir="target/benchmark/" /> + <mkdir dir="target/benchmark/" /> + <javac includeantruntime="false" srcdir="test-benchmark/" destdir="target/benchmark/"> + <classpath refid="project.classpath" /> + <classpath> + <pathelement path="${class.dir}" /> + <pathelement location="lib/jmh/jmh-core-1.21.jar" /> + <pathelement location="lib/jmh/jmh-generator-annprocess-1.21.jar" /> + </classpath> + </javac> + + <!-- Build benchmark jar which includes third-party deps, TLC proper (without tests) and the benchmark files compiled in the previous step. --> + <delete file="target/benchmarks.jar" /> + <jar jarfile="target/benchmarks.jar" basedir="target/benchmark/"> + <manifest> + <attribute name="Main-Class" value="org.openjdk.jmh.Main" /> + </manifest> +<!-- <zipfileset dir="${src.dir}" includes="**/*.java" />--> + <fileset dir="${class.dir}" includes="**/*" /> + <zipfileset src="lib/jmh/jmh-core-1.21.jar" excludes="**/META-INF/services/**" /> + <zipfileset src="lib/jmh/jopt-simple-4.6.jar" /> + <zipfileset src="lib/jmh/commons-math3-3.2.jar" /> + </jar> + </target> + <!-- Build a distribution --> <target name="dist-mixed-jar" depends="default"> <!-- create a JAR file for the users --> diff --git a/tlatools/lib/jmh/commons-math3-3.2.jar b/tlatools/lib/jmh/commons-math3-3.2.jar new file mode 100644 index 0000000000000000000000000000000000000000..f8b7db295b1a2e76c0adeff371043187a75a4580 Binary files /dev/null and b/tlatools/lib/jmh/commons-math3-3.2.jar differ diff --git a/tlatools/lib/jmh/jmh-core-1.21.jar b/tlatools/lib/jmh/jmh-core-1.21.jar new file mode 100644 index 0000000000000000000000000000000000000000..c83a3fd5da73588954ecf3b2e583a71bbb211648 Binary files /dev/null and b/tlatools/lib/jmh/jmh-core-1.21.jar differ diff --git a/tlatools/lib/jmh/jmh-generator-annprocess-1.21.jar b/tlatools/lib/jmh/jmh-generator-annprocess-1.21.jar new file mode 100644 index 0000000000000000000000000000000000000000..4082540fedd436e5c4f7019126459cff873c300e Binary files /dev/null and b/tlatools/lib/jmh/jmh-generator-annprocess-1.21.jar differ diff --git a/tlatools/lib/jmh/jopt-simple-4.6.jar b/tlatools/lib/jmh/jopt-simple-4.6.jar new file mode 100644 index 0000000000000000000000000000000000000000..a963d1fa4dcc1645d2d1172db6ddb97372a1bec3 Binary files /dev/null and b/tlatools/lib/jmh/jopt-simple-4.6.jar differ diff --git a/tlatools/pom.xml b/tlatools/pom.xml index ab33768f575571a6277983967840f06d806b300a..867aa9fcac6e8591ca34c7d2712bb94ad1a5e16a 100644 --- a/tlatools/pom.xml +++ b/tlatools/pom.xml @@ -110,7 +110,7 @@ <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>aspectj-maven-plugin</artifactId> - <version>1.7</version> + <version>1.11</version> <configuration> <ajdtBuildDefFile>build.ajproperties</ajdtBuildDefFile> </configuration> @@ -135,7 +135,7 @@ <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> - <version>1.8.2</version> + <version>1.9.1</version> </dependency> </dependencies> diff --git a/tlatools/src/pcal/AST.java b/tlatools/src/pcal/AST.java index c9d203d445fc1f2ab05d16a1ccbd03a6536a25d6..5107add92b89272ed1baf35682471a01f441a08e 100644 --- a/tlatools/src/pcal/AST.java +++ b/tlatools/src/pcal/AST.java @@ -17,7 +17,7 @@ * However, there are the following classes that do not represent explicit * * non-terminals of the +CAL grammar. * * * -* Uniprocess MultiProcess SingleAssign CallReturn * +* Uniprocess MultiProcess SingleAssign CallReturn CallGoto * * * * Every AST has col and line fields that contain the position of the * * first character of the corresponding portion of the algorithm text (as * @@ -100,6 +100,7 @@ public class AST public static AST.Call CallObj ; public static AST.Return ReturnObj ; public static AST.CallReturn CallReturnObj ; + public static AST.CallGoto CallGotoObj ; public static AST.Goto GotoObj ; public static AST.Macro MacroObj ; public static AST.MacroCall MacroCallObj ; @@ -214,6 +215,7 @@ public class AST CallObj = new AST.Call() ; ReturnObj = new AST.Return() ; CallReturnObj = new AST.CallReturn() ; + CallGotoObj = new AST.CallGoto() ; GotoObj = new AST.Goto() ; MacroObj = new AST.Macro() ; MacroCallObj = new AST.MacroCall() ; @@ -845,6 +847,24 @@ public class AST } } + public static class CallGoto extends AST + { public String after = "" ; + public String to = "" ; + public Vector args = null ; // of TLAExpr + public CallGoto() { }; + public String toString() + { return + Indent(lineCol()) + + "[type |-> \"callGoto\"," + NewLine() + + " after |-> \"" + after + "\"," + NewLine() + + " to |-> \"" + to + "\"," + NewLine() + + Indent("args |-> ") + VectorToSeqString(args) + + "]" + NewLine() + + EndIndent() + + EndIndent() ; + } + } + public static class Goto extends AST { public String to = "" ; public Goto() {}; diff --git a/tlatools/src/pcal/PCalTLAGenerator.java b/tlatools/src/pcal/PCalTLAGenerator.java index 6887de50c617c3649772b2dc713da5d5878b1810..75054b0aaacbd36e6f00ce6075277bc32a41ae40 100644 --- a/tlatools/src/pcal/PCalTLAGenerator.java +++ b/tlatools/src/pcal/PCalTLAGenerator.java @@ -64,13 +64,13 @@ public class PCalTLAGenerator * Note that this requires RemoveNameConflicts to be called first * * because of the grotty use of the class variable st. * ********************************************************************/ - public Vector translate() throws RemoveNameConflictsException + public Vector<String> translate() throws RemoveNameConflictsException { - Vector result = new Vector(); + Vector<String> result = new Vector<String>(); AST xast = null; // Set to the exploded AST for (int i = 0; i < st.disambiguateReport.size(); i++) - result.addElement(st.disambiguateReport.elementAt(i)); + result.addElement((String) st.disambiguateReport.elementAt(i)); // System.out.println("Before: " + ast.toString()); // System.out.println("After renaming: " + ast.toString()); try diff --git a/tlatools/src/pcal/ParseAlgorithm.java b/tlatools/src/pcal/ParseAlgorithm.java index faa9f19c9caf00333bd27ee752ba8632bda51d7b..3f8d7bd28890ff0aa99086e4ed4d65bf89b47d29 100644 --- a/tlatools/src/pcal/ParseAlgorithm.java +++ b/tlatools/src/pcal/ParseAlgorithm.java @@ -49,9 +49,10 @@ * holds the label (the absence of a label represented by * * a lbl field equal to the empty string ""). The only difference * * from the simple grammar is that a <Call> followed by an unlabeled * -* <Return> is converted into a single AST.CallReturn object. This * -* pass does not produce any AST.If or AST.Either objects, and any * -* AST.While object it produces has an empty labDo field. * +* <Return> or <Goto> is converted into a single AST.CallReturn or * +* AST.CallGoto object, respectively. This pass does not produce any * +* AST.If or AST.Either objects, and any AST.While object it produces * +* has an empty labDo field. * * * * - It calls the procedure AddLabelsToStmtSeq to check for missing * * labels and either add them or report an error if it finds one, * @@ -1077,7 +1078,7 @@ public class ParseAlgorithm if (nextTok.equals("print")) { return GetPrintS() ; } ; if (nextTok.equals("assert")) { return GetAssert() ; } ; if (nextTok.equals("skip")) { return GetSkip() ; } ; - if (nextTok.equals("call")) { return GetCallOrCallReturn() ; } ; + if (nextTok.equals("call")) { return GetCallOrCallReturnOrCallGoto() ; } ; if (nextTok.equals("return")) { return GetReturn() ; } ; if (nextTok.equals("goto")) { return GetGoto() ; } ; if (nextTok.equals("while")) { return GetWhile() ; } ; @@ -1585,7 +1586,7 @@ public class ParseAlgorithm return result ; } - public static AST GetCallOrCallReturn() throws ParseAlgorithmException + public static AST GetCallOrCallReturnOrCallGoto() throws ParseAlgorithmException /********************************************************************** * Note: should not complain if it finds a return that is not inside * * a procedure because it could be in a macro that is called only * @@ -1605,6 +1606,23 @@ public class ParseAlgorithm result.setOrigin(new Region(theCall.getOrigin().getBegin(), end)) ; return result ; } + else if (PeekAtAlgToken(1).equals("goto")) + { MustGobbleThis("goto") ; + AST.CallGoto result = new AST.CallGoto(); + result.col = theCall.col ; + result.line = theCall.line ; + result.to = theCall.to ; + result.after = GetAlgToken() ; + result.args = theCall.args ; + PCalLocation end = new PCalLocation(lastTokLine-1, lastTokCol-1+result.to.length()); + result.setOrigin(new Region(theCall.getOrigin().getBegin(), end)) ; + gotoUsed = true ; + if (result.to.equals("Done") || result.to.equals("\"Done\"")) { + gotoDoneUsed = true; + } + GobbleThis(";") ; + return result ; + } else { return theCall; } } @@ -2020,15 +2038,16 @@ public class ParseAlgorithm * set assignedVbls to the set of variables being assigned * * by this statement. Should set nextStepNeedsLabel to * * true and set assignedVbls to a non-empty set iff this is * - * a call, return, or callReturn. * + * a call, return, callReturn, or callGoto. * ************************************************************/ nextStepNeedsLabel = false ; Vector assignedVbls = new Vector() ; /************************************************************ - * Set isCallOrReturn true iff this is a call, return, or * - * callReturn. Will set setsPrcdVbls true iff this is a * - * return or callReturn or a call of currentProcedure. * + * Set isCallOrReturn true iff this is a call, return, * + * callReturn, or callGoto. Will set setsPrcdVbls true iff * + * this is a return or callReturn or a call of * + * currentProcedure. * ************************************************************/ boolean isCallOrReturn = false ; boolean setsPrcdVbls = false ; @@ -2041,6 +2060,12 @@ public class ParseAlgorithm if (obj.to.equals(currentProcedure)) { setsPrcdVbls = true ; } ; } + else if (stmt.getClass().equals(AST.CallGotoObj.getClass())) + { AST.CallGoto obj = (AST.CallGoto) stmt ; + isCallOrReturn = true ; + if (obj.to.equals(currentProcedure)) + { setsPrcdVbls = true ; } ; + } else if ( stmt.getClass().equals(AST.ReturnObj.getClass()) || stmt.getClass().equals(AST.CallReturnObj.getClass()) ) @@ -2493,8 +2518,10 @@ public class ParseAlgorithm } ; result = 1 ; } - else if (node.getClass().equals( - AST.GotoObj.getClass()) + else if ( node.getClass().equals( + AST.GotoObj.getClass()) + || node.getClass().equals( + AST.CallGotoObj.getClass()) ) { result = 1 ; } @@ -3161,6 +3188,25 @@ public class ParseAlgorithm return result; } ; + if (stmt.getClass().equals( AST.CallGotoObj.getClass())) + { AST.CallGoto tstmt = (AST.CallGoto) stmt ; + AST.CallGoto result = new AST.CallGoto() ; + result.col = tstmt.col ; + result.line = tstmt.line ; + result.macroCol = tstmt.macroCol ; + result.macroLine = tstmt.macroLine ; + result.setOrigin(tstmt.getOrigin()) ; + if (macroLine > 0) + { result.macroLine = macroLine ; + result.macroCol = macroCol ; + } ; + result.to = tstmt.to ; + result.after = tstmt.after ; + result.args = + TLAExpr.SeqSubstituteForAll(tstmt.args, args, params) ; + return result; + } ; + if (stmt.getClass().equals( AST.GotoObj.getClass())) { AST.Goto tstmt = (AST.Goto) stmt ; AST.Goto result = new AST.Goto() ; diff --git a/tlatools/src/pcal/PcalFixIDs.java b/tlatools/src/pcal/PcalFixIDs.java index ac08502054e8dec858a3f092487d8ad58e480af7..38a43533e1ec81819e09e56d2d76c2e5e395e6ed 100644 --- a/tlatools/src/pcal/PcalFixIDs.java +++ b/tlatools/src/pcal/PcalFixIDs.java @@ -73,6 +73,8 @@ public class PcalFixIDs { FixReturn((AST.Return) ast, context); else if (ast.getClass().equals(AST.CallReturnObj.getClass())) FixCallReturn((AST.CallReturn) ast, context); + else if (ast.getClass().equals(AST.CallGotoObj.getClass())) + FixCallGoto((AST.CallGoto) ast, context); else if (ast.getClass().equals(AST.GotoObj.getClass())) FixGoto((AST.Goto) ast, context); @@ -395,6 +397,13 @@ public class PcalFixIDs { FixExpr((TLAExpr) ast.args.elementAt(i), context); } + private static void FixCallGoto(AST.CallGoto ast, String context) throws PcalFixIDException { + ast.after = st.UseThis(PcalSymTab.PROCEDURE, ast.after, context); + ast.to = st.UseThis(PcalSymTab.PROCEDURE, ast.to, context); + for (int i = 0; i < ast.args.size(); i++) + FixExpr((TLAExpr) ast.args.elementAt(i), context); + } + private static void FixGoto(AST.Goto ast, String context) throws PcalFixIDException { /* * Report an error if the goto destination is not a label. This check diff --git a/tlatools/src/pcal/PcalParams.java b/tlatools/src/pcal/PcalParams.java index 35c68b56889aa6aeadaba0201aa499d459291027..7244b30ee741aaf0860f00e9ae5a42af1df8a5a3 100644 --- a/tlatools/src/pcal/PcalParams.java +++ b/tlatools/src/pcal/PcalParams.java @@ -18,7 +18,7 @@ public final class PcalParams /** * Parameters to be updated on each new release. */ - public static final String modDate = "18 Aug 2015"; + public static final String modDate = "16 May 2016"; public static final String version = "1.8"; /** * SZ Mar 9, 2009: @@ -91,6 +91,11 @@ public final class PcalParams * The file name if the -spec option is chosen. * ***********************************************************************/ + public static boolean tlcTranslation() { + return PcalParams.SpecOption || PcalParams.MyspecOption || PcalParams.Spec2Option + || PcalParams.Myspec2Option; + } + public static boolean WriteASTFlag = false ; /*********************************************************************** * True if the -writeAST option is chosen. * @@ -151,11 +156,11 @@ public final class PcalParams * Default initial value changed to "defaultInitValue" * * by LL on 22 Aug 2007 * *********************************************************************/ - { Vector line = new Vector() ; + { Vector<TLAToken> line = new Vector<TLAToken>() ; // line.addElement(new TLAToken("{", 0, 0)) ; // line.addElement(new TLAToken("}", 0, 0)) ; line.addElement(new TLAToken("defaultInitValue", 0, 0)); - Vector vec = new Vector() ; + Vector<Vector<TLAToken>> vec = new Vector<Vector<TLAToken>>() ; vec.addElement(line) ; TLAExpr exp = new TLAExpr(vec) ; exp.normalize() ; diff --git a/tlatools/src/pcal/PcalResourceFileReader.java b/tlatools/src/pcal/PcalResourceFileReader.java index db66736b0597694a3d92a9fc38bb2ee1ff6dd82e..ebfb9f307dfb34bbbd9a9b12421be1c537824fe1 100644 --- a/tlatools/src/pcal/PcalResourceFileReader.java +++ b/tlatools/src/pcal/PcalResourceFileReader.java @@ -47,12 +47,12 @@ public class PcalResourceFileReader inputReader = new BufferedReader(new InputStreamReader(input)) ; }; - public static Vector ResourceFileToStringVector(String fileName) throws PcalResourceFileReaderException + public static Vector<String> ResourceFileToStringVector(String fileName) throws PcalResourceFileReaderException /*********************************************************************** * Reads file fileName into a StringVector, a vector in which each * * element is a line of the file. * ***********************************************************************/ - { Vector inputVec = new Vector(100) ; + { Vector<String> inputVec = new Vector<String>(100) ; PcalResourceFileReader wordFileReader = new PcalResourceFileReader(fileName); diff --git a/tlatools/src/pcal/PcalSymTab.java b/tlatools/src/pcal/PcalSymTab.java index f3ce69d66be24b78589a9e17d842060c6c9dc65e..e31fffa8d5b55978eb776c14c66e3a2b49ce99d9 100644 --- a/tlatools/src/pcal/PcalSymTab.java +++ b/tlatools/src/pcal/PcalSymTab.java @@ -484,6 +484,8 @@ public class PcalSymTab { ExtractReturn((AST.Return) ast, context, cType); else if (ast.getClass().equals(AST.CallReturnObj.getClass())) ExtractCallReturn((AST.CallReturn) ast, context, cType); + else if (ast.getClass().equals(AST.CallGotoObj.getClass())) + ExtractCallGoto((AST.CallGoto) ast, context, cType); else if (ast.getClass().equals(AST.GotoObj.getClass())) ExtractGoto((AST.Goto) ast, context, cType); @@ -669,6 +671,11 @@ public class PcalSymTab { String cType) { } + private void ExtractCallGoto(AST.CallGoto ast, + String context, + String cType) { + } + private void ExtractGoto(AST.Goto ast, String context, String cType) { } diff --git a/tlatools/src/pcal/PcalTLAGen.java b/tlatools/src/pcal/PcalTLAGen.java index 5d040ea3caf6c40945d040497ef12ff4f1dea73d..02e72dd47d2c90d53b2464cf5384c33c4d585b76 100644 --- a/tlatools/src/pcal/PcalTLAGen.java +++ b/tlatools/src/pcal/PcalTLAGen.java @@ -1,4327 +1,4338 @@ -package pcal; - -import java.util.Vector; - -import pcal.AST.VarDecl; -import pcal.exception.PcalTLAGenException; -import pcal.exception.TLAExprException; -import tla2tex.Debug; - -/**************************************************************************** - * Given an exploded and disambiguated AST, generate the equivalent TLA+. - * <br> - * {@link PcalTLAGen#generate(AST, PcalSymTab)} returns a vector of Strings, one entry per line of generated TLA+. - * - * @version $Id$ - * @author Leslie Lamport (modified on Thu 6 March 2008 at 10:16:22 PST) - * (minor change on 9 December 2009) - * @author keith (modified on Mon 3 Oct 2005 at 21:43:09 UT) - * - ****************************************************************************/ -public class PcalTLAGen -{ - // Constants that control formatting - public final static boolean boxUnderCASE = true; /* else [] at end of line */ - - // The following two variables made non-final on 9 Dec 2009 so they can - // be set by options. They are initialized in PcalParams.resetParams(). - public static int wrapColumn ; - /* If the line width will be greater than this, then try to wrap */ - public static int ssWrapColumn ; - // I think that this is used as follows: - // when translating an assignment statement (or multiassignment?) - // to var' = [var EXCEPT ...], it begins the ... on a new line - // iff the ... would begin in a column > ssWrapColumn. - // For the time being, it is set to wrapColumn - 33. We may want - // to do something cleverer or else make it a user option. - - // Private class variables - /** The tlacode field accumulates the translation as it is constructed. It - * should be a vector of separate lines. Keiths original implementation put - * multiple lines in a single element of tlacode in: - * - * GenVarsAndDefs - * GenVarDecl - */ - private Vector tlacode = new Vector(); /* of lines */ - - /** - * The tlacodeNextLine field accumulates characters for the next - * line of tlacode. It is always a string. It is assumed that - * when it equals "", then a new line can be started without - * adding the current string in tlacodeNextLine as a new line. - */ - private String tlacodeNextLine = "" ; - - /** - * mappingVector is a local pointer to {@link TLAtoPCalMapping#mappingVector}, - * which is used to accumulate the TLA+ to PlusCal mapping. It approximately - * reflects the TLA+ that has been inserted in the {@link PcalTLAGen#tlacode} - * vector. It is set in the {@link TLAtoPCalMapping#generate} method. - */ - private Vector mappingVector; - - /** - * mappingVectorNextLine contains the sequence of MappingObject objects - * that correspond to the strings added to tlacodeNextLine. - */ - private Vector mappingVectorNextLine = new Vector() ; - - /** - * The self field is set to "self" by GenProcess when called for a single process - * (rather than a process set) and by GenProcedure for a multiprocess algorithm. - * It is set to the process id by GenProcess when called for a single process. - * selfIsSelf is set to true when self is set to "self", and to false when self is - * set to a process id. The self field never seems to be reset to null. - */ - private TLAExpr self = null; // changed by LL on 22 jan 2011 from: private String self = null; /* for current process */ - private boolean selfIsSelf = false; - - private Vector vars = new Vector(); /* list of all disambiguated vars */ - private Vector pcV = new Vector(); /* sublist of vars of variables representing - procedure parameters and procedure variables */ - private Vector psV = new Vector(); /* sublist of vars local to a process set */ - private PcalSymTab st = null; /* symbol table */ - private boolean mp = false; /* true if multiprocess, else unip */ - private Vector nextStep = new Vector(); /* unparam actions */ // For multiprocess alg, these are the individual (=) processes - private Vector nextStepSelf = new Vector(); /* param actions */ // These are process sets (\in processes) and procedures - // Following added to keep track of the length of the "lbl... == /\ " - // that precedes all the statements in the definition of a label's action - // because Keith screwed up and handled the assignment to the pc different - // from that of all other variables, forgetting that the subscript exp - // in pc[exp] := ... can be multi-line. - private int kludgeToFixPCHandlingBug ; - /** - * The public method: generate TLA+ as a vector of strings. - * @param ast the AST of the PCal - * @param symtab the symbol table - * @return the vector of strings with TLA+ code - * @throws PcalTLAGenException on any unrecoverable methods - */ - - /* - * The string currentProcName is the name of the current process (for a multiprocess algorithm) - * or "Next" for a uniprocess algorithm. When ParseAlgorithm.omitPC is true, this is used - * instead of the label when generating the process's or the entire algorithm's next-state - * action. Thus, with a single label lbl, this generates - * Next == Xlation - * instead of - * lbl == Xlation - * Next == lbl - */ - private String currentProcName ; - - /** - * Generates the translation. - * - * @param ast The AST produced by parsing and exploding. - * @param symtab The symbol table. - * @param report A vector of strings, containing the reports of renaming. - * @return A vector of strings. - * @throws PcalTLAGenException - */ - public Vector generate(AST ast, PcalSymTab symtab, Vector report) throws PcalTLAGenException - { - TLAtoPCalMapping map = PcalParams.tlaPcalMapping; - mappingVector = new Vector(50); - /* - * Add the reports of renaming to the output. - */ - for (int i = 0; i < report.size(); i++) { - addOneLineOfTLA((String) report.elementAt(i)); - } - - st = symtab; - GenSym(ast, ""); - - /* - * We put at the beginning and end of mappingVector a LeftParen - * and RightParen with location (0, 0), so that location will - * be found by the TLA+ to PCal translation algorithm if the - * user selects the entire algorithm, in which case it will - * return the null region to GotoPCalSourceHandler.execute. - */ - PCalLocation ZeroLocation = new PCalLocation(0, 0); - ((Vector) mappingVector.elementAt(0)). - add(0, new MappingObject.LeftParen(ZeroLocation)); - Vector lastLine = (Vector) mappingVector.elementAt(mappingVector.size()-1); - lastLine.add(lastLine.size(), new MappingObject.RightParen(ZeroLocation)); - - /* - * For testing, throw a null pointer exception if the parentheses are not - * properly matching in mappingVector. - */ - //int[] depths = new int[10000]; - - int parenDepth = 0; - for (int i = 0; i < mappingVector.size(); i++) { - Vector line = (Vector) mappingVector.elementAt(i); - for (int j = 0; j < line.size(); j++) { - MappingObject obj = (MappingObject) line.elementAt(j); - if (obj.getType() == MappingObject.LEFT_PAREN) { - parenDepth++; - } - else if (obj.getType() == MappingObject.RIGHT_PAREN) { - parenDepth--; - if (parenDepth < 0) { - throw new NullPointerException("paren depth < 0"); - } - } - } - // depths[i] = parenDepth; - } - if (parenDepth != 0) { - throw new NullPointerException("Unmatched Left Paren"); - } - /* ------------------ end testing --------------------------*/ - Vector nonredundantMappingVector = - TLAtoPCalMapping.RemoveRedundantParens(mappingVector); - map.makeMapping(nonredundantMappingVector); - -//System.out.println("Original mappingvector:"); -//MappingObject.printMappingVector(mappingVector); -//System.out.println("RemoveRedundantParens(mappingVector)"); -//MappingObject.printMappingVector(TLAtoPCalMapping.RemoveRedundantParens(mappingVector)); -//System.out.println("Should be original mappingvector:"); -//MappingObject.printMappingVector(mappingVector); -// Debugging -//for (int i = 0; i < tlacode.size(); i++) { -//System.out.println("\nline " + i); -//System.out.println((String) tlacode.elementAt(i)) ; -//} -//MappingObject.printMappingVector(mappingVector); - - return tlacode; - } - - /****************************************************************/ - /* Returns whether the string is present in a vector of string. */ - /****************************************************************/ - private static boolean InVector(String var, Vector v) - { - for (int i = 0; i < v.size(); i++) - if (var.equals((String) v.elementAt(i))) - return true; - return false; - } - - /******************************************************/ - /* True if var is in the list of procedure variables. */ - /******************************************************/ - private boolean IsProcedureVar(String var) - { - return InVector(var, pcV); - } - - /****************************************************/ - /* True if var is in the list of process variables. */ - /****************************************************/ - private boolean IsProcessSetVar(String var) - { - return InVector(var, psV); - } - - /**********************************************/ - /* Returns a string of length n of all spaces */ - /**********************************************/ - private static String NSpaces(int n) - { - StringBuffer sb = new StringBuffer(); - AddSpaces(sb, n); - return sb.toString(); - } - - /*********************************************/ - /* Appends n spaces to the string buffer sb. */ - /*********************************************/ - private static void AddSpaces(StringBuffer sb, int num) - { - for (int i = 0; i < num; i++) - sb.append(" "); - } - - /****************************************/ - /* True if expr is an empty expression. */ - /****************************************/ - private static boolean EmptyExpr(TLAExpr expr) - { - if (expr == null) - return true; - if (expr.tokens == null || expr.tokens.size() == 0) - return true; - return false; - } - - /*****************************************************************/ - /* Top level routines. Context is "", "procedure", or "process". */ - /** - ****************************************************************/ - private void GenSym(AST ast, String context) throws PcalTLAGenException - { - if (ast.getClass().equals(AST.UniprocessObj.getClass())) - GenUniprocess((AST.Uniprocess) ast, context); - else if (ast.getClass().equals(AST.MultiprocessObj.getClass())) - GenMultiprocess((AST.Multiprocess) ast, context); - else if (ast.getClass().equals(AST.ProcedureObj.getClass())) - GenProcedure((AST.Procedure) ast, context); - else if (ast.getClass().equals(AST.ProcessObj.getClass())) - GenProcess((AST.Process) ast, context); - else if (ast.getClass().equals(AST.LabeledStmtObj.getClass())) - GenLabeledStmt((AST.LabeledStmt) ast, context); - } - - private void GenUniprocess(AST.Uniprocess ast, String context) throws PcalTLAGenException - { - mp = false; - currentProcName = "Next"; - GenVarsAndDefs(ast.decls, ast.prcds, null, ast.defs); - GenInit(ast.decls, ast.prcds, null); - for (int i = 0; i < ast.prcds.size(); i++) - GenProcedure((AST.Procedure) ast.prcds.elementAt(i), ""); - for (int i = 0; i < ast.body.size(); i++) - { - AST.LabeledStmt ls = (AST.LabeledStmt) ast.body.elementAt(i); - /* Add this step to the disjunct of steps */ - nextStep.addElement(ls.label); - GenLabeledStmt(ls, ""); - } - GenNext(); - GenSpec(); - GenTermination(); - } - - private void GenMultiprocess(AST.Multiprocess ast, String context) throws PcalTLAGenException - { - mp = true; - GenVarsAndDefs(ast.decls, ast.prcds, ast.procs, ast.defs); - GenProcSet(); - GenInit(ast.decls, ast.prcds, ast.procs); - for (int i = 0; i < ast.prcds.size(); i++) - GenProcedure((AST.Procedure) ast.prcds.elementAt(i), ""); - for (int i = 0; i < ast.procs.size(); i++) - GenProcess((AST.Process) ast.procs.elementAt(i), ""); - GenNext(); - GenSpec(); - GenTermination(); - } - - private void GenProcedure(AST.Procedure ast, String context) throws PcalTLAGenException { - /* - * First, generate the body's actions. Must set self and selfIsSelf (?) for - * use by GenLabeledStmt. - */ - if (mp) { - - self = selfAsExpr(); // subscript for variables is "self" - selfIsSelf = true; -// /* Add this step to the disjunct of steps with (self) */ - nextStepSelf.addElement(ast.name + "(self)"); - } else - { - /* Add this step to the disjunct of steps */ - nextStep.addElement(ast.name); - } - for (int i = 0; i < ast.body.size(); i++) { - AST.LabeledStmt stmt = (AST.LabeledStmt) ast.body.elementAt(i); - GenLabeledStmt(stmt, "procedure"); - } - - /* - * Next add the definition of the procedure--e.g., - * - * procedureName(self) == label_1(self) \/ ... \/ label_k(self) - * - * We put Left/RightParens for the entire procedure around the entire - * definition, and Left/RightParens around each disjunction for - * the labeled statement. - */ - addLeftParen(ast.getOrigin()); - String argument = (mp) ? "(self)" : ""; - StringBuffer buf = new StringBuffer(ast.name + argument + " == "); - addOneTokenToTLA(buf.toString()); - String indentSpaces = NSpaces(buf.length() + 2); - for (int i = 0; i < ast.body.size(); i++) { - AST.LabeledStmt stmt = (AST.LabeledStmt) ast.body.elementAt(i); - String disjunct = stmt.label + argument; - if ( i != 0 - && tlacodeNextLine.length() + 7 /* the 7 was obtained empirically */ - + disjunct.length() > wrapColumn) { - endCurrentLineOfTLA(); - } - if (i != 0) { - addOneTokenToTLA(((tlacodeNextLine.length() == 0)? indentSpaces : "") + " \\/ "); - } - addLeftParen(stmt.getOrigin()); - addOneTokenToTLA(disjunct); - addRightParen(stmt.getOrigin()); - } - addRightParen(ast.getOrigin()); - addOneLineOfTLA(""); - -// The previous version was very convoluted just to avoid having to go through the -// list of labeled statements twice. It seemed easier to just reimplement from -// scratch. -// /* ns and nsV accumulate the disjunct of the steps of the procedure, where -// * ns contains the contents of the current line and nsV is the vector of -// * already accumulated lines. -// * -// */ -// StringBuffer ns = new StringBuffer(); -// Vector nsV = new Vector(); -// -// int nsC = ast.name.length() + ((mp) ? "(self)".length() : 0) + " == ".length(); -// if (mp) -// { -// self = selfAsExpr(); // subscript for variables is "self" -// selfIsSelf = true; -// /* Add this step to the disjunct of steps with (self) */ -// nextStepSelf.addElement(ast.name + "(self)"); -// } else -// { -// /* Add this step to the disjunct of steps */ -// nextStep.addElement(ast.name); -// } -// for (int i = 0; i < ast.body.size(); i++) -// { -// AST.LabeledStmt stmt = (AST.LabeledStmt) ast.body.elementAt(i); -// if ((ns.length() + stmt.label.length() + " \\/ ".length() + ((mp) ? "(self)".length() : 0)) > wrapColumn -// - nsC - " \\/ ".length()) -// { -// nsV.addElement(ns.toString()); -// ns = new StringBuffer(); -// } -// if (ns.length() > 0) -// ns.append(" \\/ "); -// ns.append(stmt.label); -// if (mp) -// ns.append("(self)"); -// GenLabeledStmt(stmt, "procedure"); -// } -// nsV.addElement(ns.toString()); -// // Generate definition of procedure steps -// ns = new StringBuffer(); -// ns.append(ast.name); -// if (mp) -// ns.append("(self)"); -// ns.append(" == "); -// ns.append((String) nsV.elementAt(0)); -// tlacode.addElement(ns.toString()); -// for (int i = 1; i < nsV.size(); i++) -// { -// ns = new StringBuffer(NSpaces(nsC + 2)); -// ns.append(" \\/ "); -// ns.append((String) nsV.elementAt(i)); -// tlacode.addElement(ns.toString()); -// } -// tlacode.addElement(""); - } - - private void GenProcess(AST.Process ast, String context) throws PcalTLAGenException - { - currentProcName = ast.name; - - /* - * Generate the body's actions. Must set self and selfIsSelf (?) for - * use by GenLabeledStmt. - */ - boolean isSet = true; - /************************************************************/ - /* Decide if it is a process set or not. If so, set self to */ - /* the string "self"; otherwise set self to the process id. */ - /************************************************************/ - if (ast.isEq) - { - self = ast.id ; - selfIsSelf = false; - isSet = false; - } else { - self = selfAsExpr(); - selfIsSelf = true; - } - - if (isSet) - { - nextStepSelf.addElement(ast.name + "(self)"); - } else - nextStep.addElement(ast.name); - - for (int i = 0; i < ast.body.size(); i++) { - AST.LabeledStmt stmt = (AST.LabeledStmt) ast.body.elementAt(i); - GenLabeledStmt(stmt, "process"); - } - - /* - * Next add the definition of the process--e.g., - * - * processName(self) == label_1(self) \/ ... \/ label_k(self) - * - * We put Left/RightParens for the entire procedure around the entire - * definition, and Left/RightParens around each disjunction for - * the labeled statement. - * - * However, we don't add this definition if we are omitting the pc, - * because we have already defined the process name to equal the - * only label action. - */ - - if (! ParseAlgorithm.omitPC) { - addLeftParen(ast.getOrigin()); - String argument = (isSet) ? "(self)" : ""; - StringBuffer buf = new StringBuffer(ast.name + argument + " == "); - addOneTokenToTLA(buf.toString()); - String indentSpaces = NSpaces(buf.length() + 2); - for (int i = 0; i < ast.body.size(); i++) { - AST.LabeledStmt stmt = (AST.LabeledStmt) ast.body.elementAt(i); - String disjunct = stmt.label + argument; - if ( i != 0 - && tlacodeNextLine.length() + 7 /* the 7 was obtained empirically */ - + disjunct.length() > wrapColumn) { - endCurrentLineOfTLA(); - } - if (i != 0) { - addOneTokenToTLA(((tlacodeNextLine.length() == 0)? indentSpaces : "") + " \\/ "); - } - addLeftParen(stmt.getOrigin()); - addOneTokenToTLA(disjunct); - addRightParen(stmt.getOrigin()); - } - addRightParen(ast.getOrigin()); - addOneLineOfTLA(""); - } - - -// As with GenProcedure, the original implementation was quite convoluted, so -// it was rewritten. The code above was copied with modifications from -// the rewritten GenProcedure code. -// /* ns accumulates the disjunt of the steps of the process */ -// StringBuffer ns = new StringBuffer(); -// Vector nsV = new Vector(); -// boolean isSet = true; -// /************************************************************/ -// /* Decide if it is a process set or not. If so, set self to */ -// /* the string "self"; otherwise set self to the process id. */ -// /************************************************************/ -// if (ast.isEq) -// { -// self = ast.id ; -// selfIsSelf = false; -// isSet = false; -// } else { -// self = selfAsExpr(); -// selfIsSelf = true; -// } -// -// int nsC = ast.name.length() + ((isSet) ? "(self)".length() : 0) + " == ".length(); -// if (isSet) -// { -// nextStepSelf.addElement(ast.name + "(self)"); -// } else -// nextStep.addElement(ast.name); -// for (int i = 0; i < ast.body.size(); i++) -// { -// AST.LabeledStmt stmt = (AST.LabeledStmt) ast.body.elementAt(i); -// if ((ns.length() + stmt.label.length() + " \\/ ".length() + ((isSet) ? "(self)".length() : 0)) > wrapColumn -// - nsC - " \\/ ".length()) -// { -// nsV.addElement(ns.toString()); -// ns = new StringBuffer(); -// } -// if (ns.length() > 0) -// ns.append(" \\/ "); -// ns.append(stmt.label); -// if (isSet) -// ns.append("(self)"); -// GenLabeledStmt(stmt, "process"); -// } -// nsV.addElement(ns.toString()); -// // Generate definition of process steps -// // This apparently defines the process name -// // to equal the disjunction of all the individual -// // label-named actions. If we are omitting -// // the pc, we have already defined the process name -// // to equal the only label action, so we skip -// // this. -// if (! ParseAlgorithm.omitPC) { -// ns = new StringBuffer(); -// ns.append(ast.name); -// if (isSet) -// ns.append("(self)"); -// ns.append(" == "); -// ns.append((String) nsV.elementAt(0)); -// tlacode.addElement(ns.toString()); -// for (int i = 1; i < nsV.size(); i++) -// { -// ns = new StringBuffer(NSpaces(nsC + 2)); -// ns.append(" \\/ "); -// ns.append((String) nsV.elementAt(i)); -// tlacode.addElement(ns.toString()); -// } -// } -// tlacode.addElement(""); - } - - /*****************************************************/ - /* Generates an action with name equal to the label. */ - /** - ****************************************************/ - private void GenLabeledStmt(AST.LabeledStmt ast, String context) throws PcalTLAGenException - { - // Set actionName to the name of the action being defined. - // This is the label, except when we are omitting the PC, - // in which case it is "Next" for a uniprocess algorithm - // and the process name for a multiprocess algorithm. - String actionName = ast.label; - if (ParseAlgorithm.omitPC) { - actionName = currentProcName; - } - StringBuffer sb = new StringBuffer(actionName); - /* c is used to determine which vars are in UNCHANGED. */ - Changed c = new Changed(vars); - if (mp && (context.equals("procedure") || selfIsSelf)) { // self.equals("self"))) - sb.append("(self)"); - } - sb.append(" == "); - int col = sb.length(); - kludgeToFixPCHandlingBug = col; - // There's a problem here. If ast.stmts.size() = 1, then we don't preface - // the statement's translation with "/\". However, that means that if we - // then add an UNCHANGED conjunct, we wind up with - // A - // /\ UNCHANGED ... - // where A is the statement's translation. This looks bad and could wind up - // putting the UNCHANGED inside prefix operator--e.g., - // x' = CHOOSE t : ... - // /\ UNCHANGED ... - // This is seems to be a problem only when omitPC = true, since otherwise the - // testing and setting of pc ensures that there is more than one element in ast.stmts. - // What we do is always add the "/\ ", but remove it afterwards if there's only - // a single statement in ast.stmts and there is no UNCHANGED clause. - // The code for doing this is based on the observation that the contents of - // StringBuffer sb begin the next line added to tlacode. - // - /* if (ast.stmts.size() > 1) { */ - sb.append("/\\ "); - kludgeToFixPCHandlingBug = kludgeToFixPCHandlingBug + 3; - /* } */ - - // We set defStartLine to the index of the next line added to tlacode and - // colAfterAnd to the column position in that line immediately following - // the added "/\ ". This gives us the information needed to remove the - // "/\ " later from tlacode. - int defStartLine = tlacode.size(); - int colAfterAnd = sb.length(); - - /* - * Note: it would make sense for this method to insert sb into the tlacode - * output, but it seems safer to maintain the current structure in which - * each GenX for each statement type X does that. - */ - - /* - * We set macroBeginLeft to the macroOriginBegin field of the first statement - * in ast.stmts with a non-null origin, and macroEndRight to the macroOriginEnd - * field of the last statement in ast.stmts with a non-null origin. - */ - PCalLocation macroBeginLeft = null; - PCalLocation macroEndRight = null; - boolean nonNullNotFound = true; - for (int i = 0 ; i < ast.stmts.size(); i++) { - AST stmt = (AST) ast.stmts.elementAt(i); - if (stmt.getOrigin() != null) { - if (nonNullNotFound) { - nonNullNotFound = false; - macroBeginLeft = stmt.macroOriginBegin; - } - macroEndRight = stmt.macroOriginEnd; - } - } - - /* - * addLeftParenV used instead of addLeftParen because if the first statement - * that came from PlusCal code arose from a macro call, then we want the - * location of the macro call rather than that of the macro's code. - */ - addLeftParenV(ast, macroBeginLeft); - for (int i = 0; i < ast.stmts.size(); i++) - { - GenStmt((AST) ast.stmts.elementAt(i), c, context, sb.toString(), sb.length()); - sb = new StringBuffer(NSpaces(col)); - sb.append("/\\ "); - } - - /* - * Since the UNCHANGED conjunct just consists of TLATokens, with no - * SourceTokens, we can just use the old code, simply replacing each - * tlacode.addElement call with a call of addOneLineOfTLA--except that - * the last one is replaced with a call of addOneTokenToTLA so we can - * put the RightParen object in mappingVector. - */ - Vector unc = c.Unchanged(wrapColumn - col - "/\\ UNCHANGED << ".length()); - if (c.NumUnchanged() > 1) - { - sb = new StringBuffer(NSpaces(col)); - sb.append("/\\ UNCHANGED << "); - int here = sb.length(); - sb.append((String) unc.elementAt(0)); - for (int i = 1; i < unc.size(); i++) - { -// tlacode.addElement(sb.toString()); - addOneLineOfTLA(sb.toString()); - sb = new StringBuffer(NSpaces(here)); - sb.append((String) unc.elementAt(i)); - } - sb.append(" >>"); -// tlacode.addElement(sb.toString()); - addOneTokenToTLA(sb.toString()); - } else if (c.NumUnchanged() == 1) { - // Change made by LL on 16 Mar 2011 so that, if there is a single - // unchanged variable v, it produces v' = v if v is a short variable, - // otherwise it produces UNCHANGED v - if (c.Unchanged().length() > 5) { -// tlacode.addElement(NSpaces(col) + "/\\ UNCHANGED " + c.Unchanged()); - addOneTokenToTLA(NSpaces(col) + "/\\ UNCHANGED " + c.Unchanged()); - } else { -// tlacode.addElement(NSpaces(col) + "/\\ " + c.Unchanged() + "' = " -// + c.Unchanged()); - addOneTokenToTLA(NSpaces(col) + "/\\ " + c.Unchanged() + "' = " - + c.Unchanged()); - } - } else { - // No unchanged. If there was only one conjunction, remove it. - // To do that, we must remove the "/\ " and then remove three spaces - // from all other lines that were added. We must also modify the - // TLAToken objects appropriately in the corresponding lines of - // mappingVector - if (ast.stmts.size() == 1) { - for (int i = defStartLine; i < tlacode.size(); i++) { - String line = (String) tlacode.elementAt(i); - if (i == defStartLine) { - // remove the "/\ " added - tlacode.setElementAt(line.substring(0, colAfterAnd-3) + - line.substring(colAfterAnd, line.length()) , i); - shiftMappingVectorTokensLeft(i, colAfterAnd, 3); - - } else { - // Remove three blanks from any following lines. We test the length - // of the line just in case one or more short (hopefully blank) lines - // have been added. - if (line.length() > 3) { - tlacode.setElementAt(line.substring(3, line.length()) , i); - shiftMappingVectorTokensLeft(i, colAfterAnd, 3); - } - } - } - } - } - /* - * We call addRightParenV rather than addRightParen because it the last statement - * that came from the PCal code arose from the expansion of a macro call, then we - * want the RightParen's location to be the end of the call, not the end of the - * macro's code. - */ - addRightParenV(ast, macroEndRight); - addOneLineOfTLA(""); -// tlacode.addElement(""); - } - - /** - * Adjusts the objects in line lineNum of mappingVector so all column - * numbers starting with startCol are decreased by `shift'. If any Begin/EndTLAToken - * pairs are changed to have a non-positive width, a bug is reported. - * - * Note: It is assumed that there is no aliasing of MappingTokens in mappingVector. - * That is, other than in transient local variables, the only pointer to a - * MappingToken in mappingVector is the single one in its line of mappingVector. - * I can't see how any aliasing of MappingTokens could arise. - * - * This method is called only by GenLabeledStmts. - * - * @param lineNum - * @param startCol - * @param shift - */ - private void shiftMappingVectorTokensLeft(int lineNum, int startCol, int shift) { - boolean lastWasBeginTLAToken = false; - int lastBeginTLATokCol = -777; // to keep the compiler happy. - Vector line = (Vector) mappingVector.elementAt(lineNum); - for (int i = 0; i < line.size(); i++) { - MappingObject obj = (MappingObject) line.elementAt(i); - if (obj.getType() == MappingObject.BEGIN_TLATOKEN) { - MappingObject.BeginTLAToken tobj = (MappingObject.BeginTLAToken) obj; - int col = tobj.getColumn(); - if (col >= startCol) { - tobj.setColumn(col - shift); - } - lastWasBeginTLAToken = true; - lastBeginTLATokCol = tobj.getColumn(); - } - else { - if (obj.getType() == MappingObject.END_TLATOKEN) { - MappingObject.EndTLAToken tobj = (MappingObject.EndTLAToken) obj; - int col = tobj.getColumn(); - if (col >= startCol) { - tobj.setColumn(col - shift); - } - if (lastWasBeginTLAToken && tobj.getColumn() <= lastBeginTLATokCol) { - PcalDebug.ReportBug( - "PcalTLAGen.shiftMappingVectorTokensLeft created a null TLA Token"); - } - } - else if (obj.getType() == MappingObject.SOURCE_TOKEN) { - MappingObject.SourceToken tobj = (MappingObject.SourceToken) obj; - int col = tobj.getBeginColumn(); - if (col >= startCol) { - tobj.setBeginColumn(col - shift); - } - col = tobj.getEndColumn(); - if (col >= startCol) { - tobj.setEndColumn(col - shift); - } - - lastWasBeginTLAToken = false; - } - } - } - - - } - - /*************************************************************************** - * LL Comment added 27 Jan 2006: * - * * - * There is a basic flaw in the way GenStmt works. It now generates the * - * output on the fly. This means that * - * * - * - There is no way to avoid the prefix /\ on a one-element conjunct * - * because GenStmt has no way of knowing if there's another conjunct * - * coming. * - * * - * - The handling of the UNCHANGEDs of the THEN and ELSE clauses of * - * an IF is a kludge, because the UNCHANGED of the THEN clause is * - * output before it can be known. * - * * - * The correct way of doing things is to define GenStmt so it returns a * - * sequence (vector) of string vectors, each string vector being a * - * conjunction expression (without a leading /\ or any leading spaces) and * - * the new Changed object (which it can do as it now does by modifying its * - * Changed object argument). It would also be useful to define a * - * GenStmtSeq that simply calls GenStmt iteratively on a sequence of * - * simple statements. The method that calls GenStmtSeq would then add the * - * Unchanged conjunct and call a method that returns a sequence of * - * conjuncts and a prefix into a string vector containing the prefix and * - * the necessary /\s. * - ***************************************************************************/ - - /*****************************************************************/ - /* General entry for generating the TLA+ for a simple statement. */ - /* Prefix is the prefix of the first line. Col is where to start */ - /* subsequent lines (I think we could replace it with the length */ - /* of prefix). */ - /* */ - /* And what on earth are `c' and `context'? LL */ - /** - ****************************************************************/ - private void GenStmt(AST ast, Changed c, String context, String prefix, int col) throws PcalTLAGenException - { - if (ast.getClass().equals(AST.AssignObj.getClass())) - GenAssign((AST.Assign) ast, c, context, prefix, col); - else if (ast.getClass().equals(AST.IfObj.getClass())) - GenIf((AST.If) ast, c, context, prefix, col); - // Either case added by LL on 27 Jan 2006 - else if (ast.getClass().equals(AST.EitherObj.getClass())) - GenEither((AST.Either) ast, c, context, prefix, col); - else if (ast.getClass().equals(AST.WithObj.getClass())) - GenWith((AST.With) ast, c, context, prefix, col); - else if (ast.getClass().equals(AST.WhenObj.getClass())) - GenWhen((AST.When) ast, c, context, prefix, col); - else if (ast.getClass().equals(AST.PrintSObj.getClass())) - GenPrintS((AST.PrintS) ast, c, context, prefix, col); - else if (ast.getClass().equals(AST.AssertObj.getClass())) - GenAssert((AST.Assert) ast, c, context, prefix, col); - else if (ast.getClass().equals(AST.SkipObj.getClass())) - GenSkip((AST.Skip) ast, c, context, prefix, col); - else - PcalDebug.ReportBug("Unexpected AST type " + ast.toString()); - } - - /*****************************************************************/ - /* Generates a sequence of single assigns. Since all of them are */ - /* executed "at the same time", we accumulate the changes in a */ - /* separate Changed cThis, and use c to determine which vars in */ - /* the right hand side are primed. */ - /** - * ***************************************************************/ - - /** - * @param ast - * @param c - * @param context - * @param prefix - * @param col - * @throws PcalTLAGenException - */ - private void GenAssign(AST.Assign ast, Changed c, String context, String prefix, int col) - throws PcalTLAGenException - { - Changed cThis = new Changed(c); - StringBuffer sb = new StringBuffer(); -// Vector vlines = new Vector(); - /* - * Sort the vector ast.ass so that assignments to the same variable - * follow one another. - */ - ast.ass = SortSass(ast.ass); - - addOneTokenToTLA(prefix); - addLeftParen(ast.getOrigin()); - - int i = 0; - int numAssigns = 0; - /* - * hasMultipleVars set true iff the assignment assigns values to - * more than one variable, and hence the statement's translation - * has multiple conjuncts. - */ - boolean hasMultipleVars = false; - while (i < ast.ass.size()) - { - int iFirst = i; - AST.SingleAssign sF = (AST.SingleAssign) ast.ass.elementAt(i); - int iLast = i; - boolean hasAssignmentWithNoSubscript = false; - boolean lastAssignmentHasNoSubscript = EmptyExpr(sF.lhs.sub); - AST.SingleAssign sL = (AST.SingleAssign) ast.ass.elementAt(i); - while (iLast < ast.ass.size() && sF.lhs.var.equals(sL.lhs.var)) - { - if (lastAssignmentHasNoSubscript) { - hasAssignmentWithNoSubscript = true; - } - iLast = iLast + 1; - if (iLast < ast.ass.size()) { - sL = (AST.SingleAssign) ast.ass.elementAt(iLast); - if (EmptyExpr(sL.lhs.sub)) { - lastAssignmentHasNoSubscript = true; - } - } - } - - /* - * If there are assignments to multiple variables, then this sets - * hasMultiplevars true on the first execution of the outer while loop. - */ - if (iLast != ast.ass.size()) { - hasMultipleVars = true; - } - - iLast = iLast - 1; - // All statements from iFirst to iLast are to the same variable - - /* - * Throws an error if there are multiple assignments to the variable - * in different statements, or if there are multiple assignments to - * the variable in this statement and at least one of them has no - * subscript. - */ - if (cThis.Set(sF.lhs.var) > 1 || - (iLast - iFirst > 0 && hasAssignmentWithNoSubscript)) { - /*********************************************************** - * The following was changed by LL on 3 Mar 06 to use * - * AST.location to properly report the location of an * - * error in a line created by expanding a macro. * - * However, it doesn't work very well otherwise. This * - * should be fixed. * - ***********************************************************/ - throw new PcalTLAGenException("Multiple assignment to " + sF.lhs.var, ast /* sF */); - } - numAssigns = numAssigns + 1; - Vector lines = new Vector(); // For collecting generated lines - - if (hasMultipleVars) { - sb.append("/\\ "); - } - if (iFirst == iLast) - { - /* - * This is a single assignment to the variable. - */ - AST.SingleAssign sass = sF; - - addLeftParen(sass.getOrigin()); - TLAExpr sub = AddSubscriptsToExpr(sass.lhs.sub, SubExpr(Self(context)), c); - TLAExpr rhs = AddSubscriptsToExpr(sass.rhs, SubExpr(Self(context)), c); - if (mp - && (sass.lhs.var.equals("pc") || IsProcedureVar(sass.lhs.var) || IsProcessSetVar(sass.lhs.var) || sass.lhs.var - .equals("stack"))) - { - /* Generate single assignment to variable with self subscript */ - sb.append(sass.lhs.var); - sb.append("' = ["); - int wrapCol = sb.length() + 2; - sb.append(sass.lhs.var); - sb.append(" EXCEPT "); - - Vector selfAsSV = self.toStringVector(); - - // The test for selfAsSV size added by LL on 22 Jan 2011 - // because wrapping screws up the kludgeToFixPCHandlingBug - // hack. - if ( (sb.length() + prefix.length() > ssWrapColumn) - && (selfAsSV.size() == 0)) - { -// lines.addElement(sb.toString()); - addOneLineOfTLA(sb.toString()); - sb = new StringBuffer(NSpaces(wrapCol)); - } - sb.append("!["); - addOneTokenToTLA(sb.toString()); - addLeftParen(self.getOrigin()); - addExprToTLA(self); - addRightParen(self.getOrigin()); - -// -// // following code was modified by LL on 22 Jan 2011 as part of -// // fixing bug 11_01_13, which required modifications to handle -// // the case where self is a multi-line formula, which can happen -// // for a "process (P = exp)" when exp is multi-line. -// int here = sb.length(); -// for (int idx = 0; idx < selfAsSV.size(); idx++) { -// if (idx > 0) { -// sb.append("\n"); -// sb.append(NSpaces(here + kludgeToFixPCHandlingBug)); -// } -// sb.append((String) selfAsSV.elementAt(idx)) ; -// } -//// sb.append(self); -// sb.append("]"); -// here = here + ((String) selfAsSV.elementAt(selfAsSV.size()-1)).length() + 1; - addOneTokenToTLA("]"); - Vector sv = sub.toStringVector(); - /***************************************************** - * Was * - * * - * Vector sv = sass.lhs.sub.toStringVector(); * - * * - * Changed by Chi Ho on 3 Aug 2006 to add * - * subscript. See bug_06_08_03. * - *****************************************************/ - if (sv.size() > 0) - { - addLeftParen(sub.getOrigin()); - addExprToTLA(sub); - addRightParen(sub.getOrigin()); - -// sb.append((String) sv.elementAt(0)); -// for (int v = 1; v < sv.size(); v++) -// { -// lines.addElement(sb.toString()); -// sb = new StringBuffer(NSpaces(here)); -// sb.append((String) sv.elementAt(v)); -// } - } - addOneTokenToTLA(" = ");; - addLeftParen(rhs.getOrigin()); - addExprToTLA(rhs); - addRightParen(rhs.getOrigin()); - addOneTokenToTLA("]"); -// sb.append(" = "); -// here = sb.length(); -// sv = rhs.toStringVector(); -// sb.append((String) sv.elementAt(0)); -// for (int v = 1; v < sv.size(); v++) -// { -// lines.addElement(sb.toString()); -// sb = new StringBuffer(NSpaces(here)); -// sb.append((String) sv.elementAt(v)); -// } -// sb.append("]"); -// lines.addElement(sb.toString()); - sb = new StringBuffer(); - } else if (!EmptyExpr(sass.lhs.sub)) - { - /* - * Generate single assignment to variable with no [self] subscript - * but with an explicit subscript. - */ - sb.append(sass.lhs.var); - sb.append("' = ["); - sb.append(sass.lhs.var); - sb.append(" EXCEPT !"); - addOneTokenToTLA(sb.toString()); - addLeftParen(sub.getOrigin()); - addExprToTLA(sub); - addRightParen(sub.getOrigin()); - addOneTokenToTLA(" = "); - addLeftParen(rhs.getOrigin()); - addExprToTLA(rhs); - addRightParen(rhs.getOrigin()); - addOneTokenToTLA("]"); -// -// int here = sb.length(); -// Vector sv = sub.toStringVector(); -// sb.append((String) sv.elementAt(0)); -// for (int v = 1; v < sv.size(); v++) -// { -// lines.addElement(sb.toString()); -// sb = new StringBuffer(NSpaces(here)); -// sb.append((String) sv.elementAt(v)); -// } -// sb.append(" = "); -// here = sb.length(); -// sv = rhs.toStringVector(); -// sb.append((String) sv.elementAt(0)); -// for (int v = 1; v < sv.size(); v++) -// { -// lines.addElement(sb.toString()); -// sb = new StringBuffer(NSpaces(here)); -// sb.append((String) sv.elementAt(v)); -// } -// sb.append("]"); -// lines.addElement(sb.toString()); - sb = new StringBuffer(); - } else - { - /* - * Generate assignment to a variable with no subscript at all. - */ - sb.append(sass.lhs.var); - sb.append("' = "); -// int here = sb.length(); - boolean needsParens = NeedsParentheses(rhs.toStringVector()); - if (needsParens) { - sb.append("("); - } - addOneTokenToTLA(sb.toString()); - addLeftParen(rhs.getOrigin()); - addExprToTLA(rhs); - addRightParen(rhs.getOrigin()); - if (needsParens) { - addOneTokenToTLA(")"); - } - -// Vector sv = Parenthesize(rhs.toStringVector()); -// /******************************************************* -// * Call of Parenthesize added by LL on 27 Feb 2008. * -// * See bug_08-02-18. * -// *******************************************************/ -// for (int v = 0; v < sv.size(); v++) -// { -// sb.append((String) sv.elementAt(v)); -// lines.addElement(sb.toString()); -// sb = new StringBuffer(NSpaces(here)); -// } -// Debugging -//Vector exprVec = rhs.toMappingVector(); -//MappingObject.shiftMappingVector(exprVec, here); -//MappingObject.printMappingVector(exprVec); -//System.out.println("origin: " + rhs.getOrigin().toString() ); - - sb = new StringBuffer(); - } - addRightParen(sass.getOrigin()); - } else - { - /* - * Multiple assignments to the same variable, which must therefore - * each have a user-specified subscript. - */ - AST.SingleAssign sass = sF; - sb.append(sass.lhs.var); - sb.append("' = ["); - sb.append(sass.lhs.var); - sb.append(" EXCEPT "); - int cc = sb.length(); - /* - * If this the first variable, so i = 0, then sb does not contain - * any spaces to compensate for the missing prefix; otherwise it - * does. - */ - if (i == 0) { - cc = cc + prefix.length(); - } - boolean subscript = (mp && (IsProcedureVar(sass.lhs.var) || IsProcessSetVar(sass.lhs.var))); - while (iFirst <= iLast) - { - sass = (AST.SingleAssign) ast.ass.elementAt(iFirst); - TLAExpr sub = AddSubscriptsToExpr(sass.lhs.sub, SubExpr(Self(context)), c); - TLAExpr rhs = AddSubscriptsToExpr(sass.rhs, SubExpr(Self(context)), c); - addLeftParen(sass.getOrigin()); - sb.append("!"); - - // On 21 Jan 2011, LL moved the following statement to below the if - // to correct part 3 of bug_11_01_13. - // -// int here = sb.length(); - if (subscript) { - /* - * This variable has a "self" subscript in addition to its user-specified - * subscript. - */ - sb.append("["); - addOneTokenToTLA(sb.toString()); - TLAExpr self = Self(context); - addLeftParen(self.getOrigin()); - addExprToTLA(self); - addOneTokenToTLA("]"); - -// Vector selfAsSV = Self(context).toStringVector(); -// for (int idx = 0; idx < selfAsSV.size(); idx++) { -// String start = " "; -// if (idx == 0) { -// sb.append("["); -// } else { -// sb.append("\n"); -// sb.append(NSpaces(here + 1)); -// } -// sb.append((String) selfAsSV.elementAt(idx)); -// } -// sb.append("]"); -// here = here + ((String) selfAsSV.elementAt(selfAsSV.size()-1)).length() + 2; - } - else { - addOneTokenToTLA(sb.toString()); - } - - addLeftParen(sub.getOrigin()); - addExprToTLA(sub); - addRightParen(sub.getOrigin()); - addOneTokenToTLA(" = "); - addLeftParen(rhs.getOrigin()); - addExprToTLA(rhs); - addRightParen(rhs.getOrigin()); - addRightParen(sass.getOrigin()); - addOneTokenToTLA((iFirst == iLast) ? "]" : ","); -// Vector sv = sub.toStringVector(); -// if (sv.size() > 0) -// { -// sb.append((String) sv.elementAt(0)); -// for (int v = 1; v < sv.size(); v++) -// { -// lines.addElement(sb.toString()); -// sb = new StringBuffer(NSpaces(here)); -// sb.append((String) sv.elementAt(v)); -// } -// } -// sb.append(" = "); -// here = sb.length(); -// sv = rhs.toStringVector(); -// sb.append((String) sv.elementAt(0)); -// for (int v = 1; v < sv.size(); v++) -// { -// lines.addElement(sb.toString()); -// sb = new StringBuffer(NSpaces(here)); -// sb.append((String) sv.elementAt(v)); -// } -// sb.append(((iFirst == iLast) ? "]" : ",")); -// lines.addElement(sb.toString()); - sb = new StringBuffer(); - if (iFirst < iLast) { - endCurrentLineOfTLA(); - AddSpaces(sb, cc); - } - iFirst = iFirst + 1; - } - } - -// vlines.addElement(lines); - i = iLast + 1; - if (i < ast.ass.size()) { - endCurrentLineOfTLA(); - AddSpaces(sb, prefix.length()); - } - } - addRightParen(ast.getOrigin()); - endCurrentLineOfTLA(); - - c.Merge(cThis); - // Append generated code to tlacode -// sb = new StringBuffer(prefix); -// col = sb.length(); -// if (numAssigns > 1) -// sb.append("/\\ "); -// if (vlines.size() > 0) -// { -// for (int v1 = 0; v1 < vlines.size(); v1++) -// { -// Vector vl = (Vector) vlines.elementAt(v1); -// for (int v2 = 0; v2 < vl.size(); v2++) -// { -// sb.append((String) vl.elementAt(v2)); -// tlacode.addElement(sb.toString()); -// sb = new StringBuffer(NSpaces(col)); -// if ((v1 > 0 || numAssigns > 1) && (v2 != vl.size() - 1)) -// sb.append(" "); -// } -// sb.append("/\\ "); -// } -// } - } - - /** - * Generate TLA+ for if statement. Each branch has its own - * UNCHANGED that lists variables that were changed in the - * other branch. This is a little difficult since we don't - * know the UNCHANGED for the Then branch until the code - * for the Else branch is generated. So, we fix the - * line in the Then branch after the Else branch is done. - * The corresponding mappingVector line also has to be changed, - * but that's not a problem because the UNCHANGED is a TLA+ - * token with no corresponding source. - */ - private void GenIf(AST.If ast, Changed c, String context, String prefix, int col) throws PcalTLAGenException - { - Changed cThen = new Changed(c); - Changed cElse = new Changed(c); - int lineUncThen; - StringBuffer sb = new StringBuffer(prefix); - TLAExpr test = null; - test = AddSubscriptsToExpr(ast.test, SubExpr(Self(context)), c); -// Vector sv = test.toStringVector(); - sb.append("IF "); - int here = sb.length(); - /************************************************************* - * LL removed a bogus "- 1" here on 31 Jan 2006. * - *************************************************************/ - addLeftParen(ast.getOrigin()); - addOneTokenToTLA(sb.toString()); - addExprToTLA(test); - endCurrentLineOfTLA(); - -// sb.append((String) sv.elementAt(0)); -// for (int v = 1; v < sv.size(); v++) -// { -// tlacode.addElement(sb.toString()); -// sb = new StringBuffer(NSpaces(here)); -// sb.append((String) sv.elementAt(v)); -// } -// tlacode.addElement(sb.toString()); - - sb = new StringBuffer(NSpaces(here)); - sb.append("THEN "); - here = sb.length(); - - sb.append("/\\ "); - for (int i = 0; i < ast.Then.size(); i++) - { - GenStmt((AST) ast.Then.elementAt(i), cThen, context, sb.toString(), - /******************************************************************* - * LL added the +3 on 18 Feb 2006 to take account of the * - * indentation of the "IF ". * - *******************************************************************/ - here + 3); - sb = new StringBuffer(NSpaces(here) + "/\\ "); - } - lineUncThen = tlacode.size(); -// tlacode.addElement(sb.toString()); - addOneLineOfTLA(sb.toString()); - sb = new StringBuffer(NSpaces(here - "THEN ".length()) + "ELSE "); - here = sb.length(); - if (ast.Else.size() == 0) - { - sb.append("/\\ TRUE"); -// tlacode.addElement(sb.toString()); - addOneLineOfTLA(sb.toString()); - - sb = new StringBuffer(NSpaces(here) + "/\\ "); - } else - { - sb.append("/\\ "); - for (int i = 0; i < ast.Else.size(); i++) - { - GenStmt((AST) ast.Else.elementAt(i), cElse, context, sb.toString(), - /******************************************************************* - * LL added the +3 on 18 Feb 2006 to take account of the * - * indentation of the "IF ". * - *******************************************************************/ - here + 3); - sb = new StringBuffer(NSpaces(here) + "/\\ "); - } - } - // Generate UNCHANGED for the ELSE branch - if (cElse.NumUnchanged(cThen) > 1) - { - Vector uncElse = cElse.Unchanged(cThen, wrapColumn - sb.length() - "UNCHANGED << ".length()); - sb.append("UNCHANGED << "); - int cc = sb.length(); - sb.append((String) uncElse.elementAt(0)); - for (int i = 1; i < uncElse.size(); i++) - { -// tlacode.addElement(sb.toString()); - addOneLineOfTLA(sb.toString()); - sb = new StringBuffer(NSpaces(cc)); - sb.append((String) uncElse.elementAt(i)); - } - sb.append(" >>"); -// tlacode.addElement(sb.toString()); - addOneTokenToTLA(sb.toString()); - addRightParen(ast.getOrigin()); - endCurrentLineOfTLA(); - } else if (cElse.NumUnchanged(cThen) == 1) - { // Change made by LL on 16 Mar 2011 so that, if there is a single - // unchanged variable v, it produces v' = v if v is a short variable, - // otherwise it produces UNCHANGED v - // - // sb.append("UNCHANGED " + cElse.Unchanged(cThen)); - String uc = cElse.Unchanged(cThen); - if (uc.length() > 5) { - sb.append("UNCHANGED " + uc); - } else { - sb.append(uc + "' = " + uc); - } -// tlacode.addElement(sb.toString()); - addOneTokenToTLA(sb.toString()); - addRightParen(ast.getOrigin()); - endCurrentLineOfTLA(); - } else - { - /* - * There is no UNCHANGED after the ELSE, so we have to put - * the RightParen for the whole if statement at the end of - * the last line already generated - */ - ((Vector) mappingVector.elementAt(mappingVector.size()-1)) - .add(new MappingObject.RightParen(ast.getOrigin().getEnd())); - } - - // Patch up the UNCHANGED for the THEN branch - sb = new StringBuffer((String) tlacode.elementAt(lineUncThen)); - tlacode.removeElementAt(lineUncThen); - mappingVector.removeElementAt(lineUncThen); - if (cThen.NumUnchanged(cElse) > 1) - { - Vector uncThen = cThen.Unchanged(cElse, wrapColumn - sb.length() - "UNCHANGED << ".length()); - sb.append("UNCHANGED << "); - int cc = sb.length(); - sb.append((String) uncThen.elementAt(0)); - for (int i = 1; i < uncThen.size(); i++) - { - tlacode.insertElementAt(sb.toString(), lineUncThen); - - //set the mappingVector entry - mappingVector.insertElementAt(stringToTLATokens(sb.toString()), lineUncThen); - - lineUncThen = lineUncThen + 1; - sb = new StringBuffer(NSpaces(cc)); - sb.append((String) uncThen.elementAt(i)); - } - sb.append(" >>"); - tlacode.insertElementAt(sb.toString(), lineUncThen); - Vector vec = stringToTLATokens(sb.toString()); - - // The following is bogus because the RightParen for the - // entire procedure is inserted after (or instead of) the - // ELSE's UNCHANGED - // vec.add(new MappingObject.RightParen(ast.getOrigin().getEnd())); - - mappingVector.insertElementAt(vec, lineUncThen); - - } else if (cThen.NumUnchanged(cElse) == 1) - { // Change made by LL on 16 Mar 2011 so that, if there is a single - // unchanged variable v, it produces v' = v if v is a short variable, - // otherwise it produces UNCHANGED v - // - // sb.append("UNCHANGED "); - // sb.append(cThen.Unchanged(cElse)); - String uc = cThen.Unchanged(cElse); - if (uc.length() > 5) { - sb.append("UNCHANGED " + uc); - } else { - sb.append(uc + "' = " + uc); - } - tlacode.insertElementAt(sb.toString(), lineUncThen); - Vector vec = stringToTLATokens(sb.toString()); - // The following is bogus because the RightParen for the - // entire procedure is inserted after (or instead of) the - // ELSE's UNCHANGED - // vec.add(new MappingObject.RightParen(ast.getOrigin().getEnd())); - mappingVector.insertElementAt(vec, lineUncThen); - } - - // Merge the change lists together - c.Merge(cThen); - c.Merge(cElse); - } - - /** - * Returns the vector of MappingObjects containing the BeginTLAToken and - * EndTLAToken that are put in the mappingVector by a call of addOneLineOfTLA. - * The code was essentially copied from addOneTokenToTLA. - * - * @param token - * @return - */ - private Vector stringToTLATokens(String token) { - Vector result = new Vector(3); - - String trimmedToken = token.trim() ; - - int numberOfLeftTrimmedTokens = - (trimmedToken.length() == 0) ? -1 : - token.indexOf(trimmedToken.charAt(0)); - - /** - * Handle a token of only space characters. - */ - if (numberOfLeftTrimmedTokens == -1) { - numberOfLeftTrimmedTokens = 0 ; - trimmedToken = token ; - } - - int objBegin = numberOfLeftTrimmedTokens; - result.addElement(new MappingObject.BeginTLAToken(objBegin)); - result.addElement(new MappingObject.EndTLAToken(objBegin + trimmedToken.length())); - return result; - } - - /*********************************************************************** - * Added by LL on 30 Jan 2006. * - * * - * Generate TLA+ for the `either' statement. This performs the same * - * sort of hackery as for the `if' statement, necessitated by the * - * design flaw commented on above. - ** - ***********************************************************************/ - private void GenEither(AST.Either ast, Changed c, String context, String prefix, int col) - throws PcalTLAGenException - { - Changed allC = new Changed(c); - /******************************************************************* - * Accumulates the variable changes of all the clauses. * - *******************************************************************/ - Changed[] cOrs = new Changed[ast.ors.size()]; - /******************************************************************* - * cOrs[i] is the Changed vector for the i-th `or' clause. * - *******************************************************************/ - int[] ucLocs = new int[ast.ors.size()]; // location of unchangeds. - /****************************************************************** - * tlaout.elementAt(ucLocs[i]) is the UNCHANGED clause for the * - * i-th `or' clause. * - ******************************************************************/ - StringBuffer sb = new StringBuffer(prefix); - int prefixIndent = sb.length(); - sb.append("\\/ "); - int here = sb.length(); - /******************************************************************* - * The number of columns to the left of the code generated for * - * each `or' clause. * - *******************************************************************/ - - /* - * Add the left paren for the statement. - */ - addLeftParen(ast.getOrigin()); - /********************************************************************* - * Produce the output for the clauses, but with a dummy line in * - * place of the UNCHANGED clause, and compute allC, cOrs, and * - * ucLocs. * - *********************************************************************/ - for (int i = 0; i < ast.ors.size(); i++) - { - if (i != 0) - { - sb = new StringBuffer(NSpaces(prefixIndent) + "\\/ "); - } - ; - sb.append("/\\ "); - Vector orClause = (Vector) ast.ors.elementAt(i); - Changed cC = new Changed(c); - for (int j = 0; j < orClause.size(); j++) - { - /*********************************************************** - * On 6 Jun 2010, LL added the "+3" in the following call * - * of GenStmt. This seems to fix a bug which caused * - * * - * either when \/ A * - * \/ B * - * or ... * - * * - * to produce * - * \/ /\ \/ A * - * \/ B * - * \/ ... * - ***********************************************************/ - GenStmt((AST) orClause.elementAt(j), cC, context, sb.toString(), here + 3); - sb = new StringBuffer(NSpaces(here) + "/\\ "); - } - ; - cOrs[i] = cC; - allC.Merge(cC); - ucLocs[i] = tlacode.size(); -// tlacode.addElement("Replace by UNCHANGED"); // - addOneLineOfTLA("Replace by UNCHANGED"); - } - ; // End of for i - - /********************************************************************** - * Insert real UNCHANGED clauses. Note that we have to go through * - * loop backwards since we will remove a line of output for each `or' * - * clause that doesn't get an UNCHANGED. * - **********************************************************************/ - int i = ast.ors.size(); - while (i > 0) - { - i = i - 1; - tlacode.removeElementAt(ucLocs[i]); - mappingVector.removeElementAt(ucLocs[i]); - int numUnchanged = cOrs[i].NumUnchanged(allC); - String NotChanged = cOrs[i].Unchanged(allC); - if (numUnchanged > 1) - { - /* - * The line should be wrapped if it's too long. - */ - String line = NSpaces(here) + "/\\ UNCHANGED <<" + NotChanged + ">>"; - tlacode.insertElementAt(line, ucLocs[i]); - mappingVector.insertElementAt(stringToTLATokens(line), ucLocs[i]); - } else if (numUnchanged == 1) - { // Change made by LL on 16 Mar 2011 so that, if there is a single - // unchanged variable v, it produces v' = v if v is a short variable, - // otherwise it produces UNCHANGED v - // - // tlacode.insertElementAt(NSpaces(here) + "/\\ UNCHANGED " + NotChanged, ucLocs[i]); - if (NotChanged.length() > 5) { - String line = NSpaces(here) + "/\\ UNCHANGED " + NotChanged; - tlacode.insertElementAt(line, ucLocs[i]); - mappingVector.insertElementAt(stringToTLATokens(line), ucLocs[i]); -// tlacode.insertElementAt(NSpaces(here) + "/\\ UNCHANGED " + NotChanged, ucLocs[i]); - } else { - String line = NSpaces(here) + "/\\ " + NotChanged + "' = " + NotChanged; - tlacode.insertElementAt(line, ucLocs[i]); - mappingVector.insertElementAt(stringToTLATokens(line), ucLocs[i]); -// tlacode.insertElementAt(NSpaces(here) + "/\\ " + NotChanged + "' = " -// + NotChanged, ucLocs[i]); - } - } - } - ; - /* - * Add the right paren for the entire statement. - */ - ((Vector) mappingVector.elementAt(mappingVector.size()-1)) - .add(new MappingObject.RightParen(ast.getOrigin().getEnd())); - /********************************************************************** - * Add the statement's unchangeds to c. * - **********************************************************************/ - c.Merge(allC); - } - - private void GenWith(AST.With ast, Changed c, String context, String prefix, int col) throws PcalTLAGenException - { - addLeftParen(ast.getOrigin()); - StringBuffer sb = new StringBuffer(prefix); - TLAExpr exp = AddSubscriptsToExpr(ast.exp, SubExpr(Self(context)), c); -// Vector sv = exp.toStringVector(); - if (ast.isEq) - { - /* generate LET statement */ - sb.append("LET "); - sb.append(ast.var); - sb.append(" == "); - addOneTokenToTLA(sb.toString()); - addLeftParen(exp.getOrigin()); - addExprToTLA(exp); - addRightParen(exp.getOrigin()); -// int here = sb.length(); -// sb.append((String) sv.elementAt(0)); -// for (int v = 1; v < sv.size(); v++) -// { -// tlacode.addElement(sb.toString()); -// sb = new StringBuffer(NSpaces(here)); -// sb.append((String) sv.elementAt(v)); -// } - addOneTokenToTLA(" IN"); - endCurrentLineOfTLA(); -// sb.append(" IN"); -// tlacode.addElement(sb.toString()); - sb = new StringBuffer(NSpaces(col + 2)); - /************************************************************* - * LL changed "col + 4" to "col + 2" here to correct an * - * alignment problem on 31 Jan 2006. * - *************************************************************/ - if (ast.Do.size() > 1) - sb.append("/\\ "); - } else - { - /* generate \E statement */ - sb.append("\\E "); - sb.append(ast.var); - sb.append(" \\in "); - addOneTokenToTLA(sb.toString()); - addLeftParen(exp.getOrigin()); - addExprToTLA(exp); - addRightParen(exp.getOrigin()); -// int here = sb.le - addOneTokenToTLA(":"); - endCurrentLineOfTLA(); -// sb.append(":"); -// tlacode.addElement(sb.toString()); - sb = new StringBuffer(NSpaces(col + 2)); - if (ast.Do.size() > 1) - sb.append("/\\ "); - } - for (int i = 0; i < ast.Do.size(); i++) - { - GenStmt((AST) ast.Do.elementAt(i), c, context, sb.toString(), sb.length()); - sb = new StringBuffer(NSpaces(col + 2) + "/\\ "); - } - // tlacode.addElement(NSpaces(col) + ")"); - - /* - * Add the right paren for the entire statement. - */ - ((Vector) mappingVector.elementAt(mappingVector.size()-1)) - .add(new MappingObject.RightParen(ast.getOrigin().getEnd())); - } - - private void GenWhen(AST.When ast, Changed c, String context, String prefix, int col) throws PcalTLAGenException - { - addOneTokenToTLA(prefix); - -// StringBuffer sb = new StringBuffer(prefix); - TLAExpr exp = AddSubscriptsToExpr(ast.exp, SubExpr(Self(context)), c); - addLeftParen(exp.getOrigin()); - addExprToTLA(exp); - addRightParen(exp.getOrigin()); - endCurrentLineOfTLA(); -// Vector sv = exp.toStringVector(); -// -//// Debugging -////Vector vec = exp.toMappingVector(); -////System.out.println("Original vec:"); -////MappingObject.printMappingVector(vec); -////System.out.println("RemoveRedundantParens(vec)"); -////MappingObject.printMappingVector(TLAtoPCalMapping.RemoveRedundantParens(vec)); -////System.out.println("Should be original mappingvector:"); -////MappingObject.printMappingVector(vec); -// -// sb.append((String) sv.elementAt(0)); -// for (int v = 1; v < sv.size(); v++) -// { -// tlacode.addElement(sb.toString()); -// sb = new StringBuffer(NSpaces(col)); -// sb.append((String) sv.elementAt(v)); -// } -// tlacode.addElement(sb.toString()); - } - - private void GenPrintS(AST.PrintS ast, Changed c, String context, String prefix, int col) - throws PcalTLAGenException - { - StringBuffer sb = new StringBuffer(prefix); - TLAExpr exp = AddSubscriptsToExpr(ast.exp, SubExpr(Self(context)), c); - addLeftParen(ast.getOrigin()); - addOneTokenToTLA(prefix + "PrintT("); - addExprToTLA(exp); - addOneTokenToTLA(")"); - addRightParen(ast.getOrigin()); - endCurrentLineOfTLA(); - -// Vector sv = exp.toStringVector(); -// // The following modified 19 Nov 05 by LL to use PrintT instead of Print -// sb.append("PrintT("); -// sb.append((String) sv.elementAt(0)); -// for (int v = 1; v < sv.size(); v++) -// { -// tlacode.addElement(sb.toString()); -// sb = new StringBuffer(NSpaces(col + "PrintT(".length())); -// sb.append((String) sv.elementAt(v)); -// } -// sb.append(")"); -// tlacode.addElement(sb.toString()); - } - - /********************************************************/ - /* Assert(ast.expr, "Failure of assertion at... ") */ - /** - *******************************************************/ - private void GenAssert(AST.Assert ast, Changed c, String context, String prefix, int col) - throws PcalTLAGenException - { - addLeftParen(ast.getOrigin()); - StringBuffer sb = new StringBuffer(prefix); - StringBuffer sc = new StringBuffer(); - TLAExpr exp = AddSubscriptsToExpr(ast.exp, SubExpr(Self(context)), c); -// Vector sv = exp.toStringVector(); - sb.append("Assert("); - addOneTokenToTLA(sb.toString()); - addLeftParen(exp.getOrigin()); - addExprToTLA(exp); - addRightParen(exp.getOrigin()); - int here = sb.length(); -// sb.append((String) sv.elementAt(0)); -// for (int v = 1; v < sv.size(); v++) -// { -// tlacode.addElement(sb.toString()); -// sb = new StringBuffer(NSpaces(col + "Assert(".length())); -// sb.append((String) sv.elementAt(v)); -// } -// sb.append(", "); - sb = new StringBuffer(", "); - sc.append("\"Failure of assertion at "); - sc.append(ast.location()); - // modified on 23 Mar 2006 by LL to use location() instead of - // ast.line and ast.col - sc.append(".\")"); - if (tlacodeNextLine.length() + sb.length() + sc.length() < wrapColumn) { - addOneTokenToTLA(sb.toString() + sc.toString()); - } -// if (sb.length() + sc.length() < wrapColumn) -// tlacode.addElement(sb.toString() + sc.toString()); - else - { - addOneTokenToTLA(sb.toString()); - endCurrentLineOfTLA(); - addOneTokenToTLA(NSpaces(here) + sc.toString()); -// tlacode.addElement(sb.toString()); -// tlacode.addElement(NSpaces(here) + sc.toString()); - } - addRightParen(ast.getOrigin()); - endCurrentLineOfTLA(); - } - - /********************************************************/ - /* I generate a TRUE conjunct, which is useless, but so */ - /* is a skip statement. */ - /********************************************************/ - private void GenSkip(AST.Skip ast, Changed c, String context, String prefix, int col) - { -// tlacode.addElement(prefix + "TRUE"); - addOneTokenToTLA(prefix); - addLeftParen(ast.getOrigin()); - addOneTokenToTLA("TRUE"); - addRightParen(ast.getOrigin()); - endCurrentLineOfTLA(); - } - - /*********************************************************************** - * Generate the VARIABLES declaration(s), output the TLA+ "code" from * - * a `define' statement, if any, and generate the definition of * - * `vars'. * - * * - * Method renamed from GenVars and given the defs argument by LL on * - * 25 Jan 2006 to handle the `define' statement. * - ***********************************************************************/ - private void GenVarsAndDefs(Vector globals, Vector procs, Vector processes, TLAExpr defs) - throws PcalTLAGenException - { - /******************************************************************* - * lVars and gVars are vectors of strings, each element being a * - * variable name. They hold the local and global variables, * - * respectively. * - *******************************************************************/ - Vector lVars = new Vector(); - Vector gVars = new Vector(); - - /** - * lVarsSource and gVarsSource are vectors of AST.VarDecl objects that - * generated the elements of lVars and gVars, where PVarDecl objects - * are converted to VarDecl objects. - */ - Vector lVarsSource = new Vector(); - Vector gVarsSource = new Vector(); - - /******************************************************************* - * Set gVars to the global variables, including pc and `stack' if * - * there are procedures, and add these variables to vars. * - *******************************************************************/ - if (globals != null) - for (int i = 0; i < globals.size(); i++) - { - AST.VarDecl decl = (AST.VarDecl) globals.elementAt(i); - gVars.addElement(decl.var); - gVarsSource.addElement(decl); - vars.addElement(decl.var); - } - if (! ParseAlgorithm.omitPC) { - gVars.addElement("pc"); - /** - * For added variables, create a VarDecl with null origin. - */ - AST.VarDecl pcVarDecl = new AST.VarDecl(); - pcVarDecl.var = "pc"; - gVarsSource.addElement(pcVarDecl); - vars.addElement("pc"); - } - if (procs != null && procs.size() > 0) - { - gVars.addElement("stack"); - /** - * For added variables, create a VarDecl with null origin. - */ - AST.VarDecl pcVarDecl = new AST.VarDecl(); - pcVarDecl.var = "stack"; - gVarsSource.addElement(pcVarDecl); - vars.addElement("stack"); - } - /******************************************************************* - * Add local procedure variables to lVars, vars, and pcV. * - *******************************************************************/ - if (procs != null) - for (int i = 0; i < procs.size(); i++) - { - AST.Procedure proc = (AST.Procedure) procs.elementAt(i); - if (proc.params != null) - for (int p = 0; p < proc.params.size(); p++) - { - AST.PVarDecl decl = (AST.PVarDecl) proc.params.elementAt(p); - lVars.addElement(decl.var); - lVarsSource.addElement(decl.toVarDecl()) ; - vars.addElement(decl.var); - pcV.addElement(decl.var); - } - if (proc.decls != null) - for (int p = 0; p < proc.decls.size(); p++) - { - AST.PVarDecl decl = (AST.PVarDecl) proc.decls.elementAt(p); - lVars.addElement(decl.var); - lVarsSource.addElement(decl.toVarDecl()) ; - vars.addElement(decl.var); - pcV.addElement(decl.var); - } - } - - /******************************************************************* - * Add local process variables to lVars, vars, and psV for * - * variables local to process sets. * - *******************************************************************/ - if (processes != null) - for (int i = 0; i < processes.size(); i++) - { - AST.Process proc = (AST.Process) processes.elementAt(i); - if (proc.decls != null) - for (int p = 0; p < proc.decls.size(); p++) - { - AST.VarDecl decl = (AST.VarDecl) proc.decls.elementAt(p); - lVars.addElement(decl.var); - lVarsSource.addElement(decl); - vars.addElement(decl.var); - if (!proc.isEq) - psV.addElement(decl.var); - } - } - - /******************************************************************** - * Add a declaration of the constant defaultInitValue if it is * - * used. (Added by LL on 22 Aug 2007.) * - ********************************************************************/ - if (ParseAlgorithm.hasDefaultInitialization) - { - addOneLineOfTLA("CONSTANT defaultInitValue"); - } - ; - - if (EmptyExpr(defs)) - { - /****************************************************************** - * There is no `define' statement. In this case, generate a * - * single VARIABLES statement and set gVars to vector of all * - * variables. * - ******************************************************************/ - gVars.addAll(lVars); - gVarsSource.addAll(lVarsSource) ; - GenVarDecl(gVars, gVarsSource); - } else - { - /****************************************************************** - * There is a `define' statement. In this case, must declare * - * global and local variables separately. Also, set gVars to * - * vector of all variables. * - ******************************************************************/ - GenVarDecl(gVars, gVarsSource); - addOneLineOfTLA(""); - addOneLineOfTLA("(* define statement *)"); - addExprToTLA(defs); -// Vector sv = defs.toStringVector(); -// for (int i = 0; i < sv.size(); i++) -// { -// tlacode.addElement((String) sv.elementAt(i)); -// } - ; - addOneLineOfTLA(""); - GenVarDecl(lVars, lVarsSource); // to be fixed - gVars.addAll(lVars); - gVarsSource.addAll(lVarsSource); - } - ; - addOneLineOfTLA(""); - - /* - * We check for the unlikely case in which there are no variables. - * Without this check, the Init is not generated but appears in - * the definition of Spec. - */ - if (gVars.size() == 0) { - throw new PcalTLAGenException("The algorithm has no variables."); - } - /******************************************************************* - * Generate definition of var. * - *******************************************************************/ -// StringBuffer var = new StringBuffer("vars == << "); -// StringBuffer curLine = new StringBuffer("vars == << "); - addOneTokenToTLA("vars == << ") ; - int indent = tlacodeNextLine.length(); - for (int i = 0; i < gVars.size(); i++) - { - if (i > 0) - { -// var.append(", "); -// curLine.append(", "); -// tlacodeNextLine = tlacodeNextLine + ", "; - addOneTokenToTLA(", "); - } - ; - String vbl = (String) gVars.elementAt(i); - AST.VarDecl vblDecl = (AST.VarDecl) gVarsSource.elementAt(i); - Region vblOrigin = vblDecl.getOrigin(); -// if (curLine.length() + vbl.length() + 1 > wrapColumn) - if (tlacodeNextLine.length() + vbl.length() + 1 > wrapColumn) - { -// curLine = new StringBuffer("vars == << "); -// var.append("\n" + NSpaces("vars == << ".length())); - endCurrentLineOfTLA(); - tlacodeNextLine = NSpaces(indent); - } -// var.append(vbl); -// curLine.append(vbl); - addOneSourceTokenToTLA(vbl, vblOrigin); - } -// if (curLine.length() + " >>".length() + 1 > wrapColumn) - if (tlacodeNextLine.length() + " >>".length() + 1 > wrapColumn) - { -// var.append("\n" + NSpaces("vars ==".length())); - endCurrentLineOfTLA() ; - tlacodeNextLine = NSpaces("vars ==".length()); - } - ; -// var.append(" >>"); -// tlacodeNextLine = tlacodeNextLine + " >>"; - addOneTokenToTLA(" >>"); -// tlacode.addElement(var.toString()); - addOneLineOfTLA(""); - } - - /** - * Generate a VARIABLE(S) declarations. The varVec argument is a vector of - * strings that are the variables to be declared. It does nothing if - * the vector has length 0. The varVecSource argument is a vector - * of the same size as varVec that contains the AST.VarDecl objects. - * <p> - * Method added by LL on 25 Jan 2006. - * - * Modified 16 Dec 2011 to add varVecSource argument and generate TLA to - * PCal mapping. - * - * @param varVec A vector of strings. - * - * @param varVecSource A vector of AST.VarDecl objects. - */ - public void GenVarDecl(Vector varVec, Vector varVecSource) - { -// StringBuffer res = new StringBuffer(); -// StringBuffer curLine = new StringBuffer("VARIABLES "); - // for measuring length - if (varVec.size() == 0) - { - return; - } - ; - if (varVec.size() > 1) - { -// res.append("VARIABLES "); - addOneTokenToTLA("VARIABLES "); - } else - { -// res.append("VARIABLE "); - addOneTokenToTLA("VARIABLE "); - } - ; - for (int i = 0; i < varVec.size(); i++) - { - if (i > 0) - { -// res.append(", "); -// curLine.append(", "); - addOneTokenToTLA(", "); - } - ; - String vbl = (String) varVec.elementAt(i); - AST vblsource = (AST) varVecSource.elementAt(i); -// if (curLine.length() + vbl.length() + 1 > wrapColumn) - if (tlacodeNextLine.length() + vbl.length() + 1 > wrapColumn) - { -// curLine = new String - endCurrentLineOfTLA(); - if (varVec.size() > 1) - { -// res.append(NSpaces("VARIABLES ".length())); - tlacodeNextLine = tlacodeNextLine + NSpaces("VARIABLES ".length()); - } else - { -// res.append(NSpaces("VARIABLE ".length())); - tlacodeNextLine = tlacodeNextLine + NSpaces("VARIABLE ".length()); - } - ; - } - ; -// res.append(vbl); -// curLine.append(vbl); - addOneSourceTokenToTLA(vbl, vblsource.getOrigin()); - } - ; -// tlacode.addElement(res.toString()); - endCurrentLineOfTLA(); - } - - /** - * Generates the "ProcSet == ..." output. It is just a union of all the - * process sets, all on one line (except if a process set is a multi-line - * expression). It wouldn't be too hard to break long lines, but that - * should be done later, if desired, after the TLA to PCal translation - * is finished. - */ - public void GenProcSet() - { - StringBuffer ps = new StringBuffer(); - if (st.processes == null || st.processes.size() == 0) - return; -// ps.append("ProcSet == "); - addOneTokenToTLA("ProcSet == "); - for (int i = 0; i < st.processes.size(); i++) - { - PcalSymTab.ProcessEntry proc = (PcalSymTab.ProcessEntry) st.processes.elementAt(i); -// Vector sv = proc.id.toStringVector(); - if (i > 0) { -// ps.append(" \\cup "); - addOneTokenToTLA(" \\cup "); - } - addLeftParen(proc.id.getOrigin()); - if (proc.isEq) { -// ps.append("{"); - addOneTokenToTLA("{"); - } - else { -// ps.append("("); - addOneTokenToTLA("("); - } - int col = ps.length(); -// ps.append((String) sv.elementAt(0)); -// for (int v = 1; v < sv.size(); v++) -// { -// tlacode.addElement(ps.toString()); -// ps = new StringBuffer(NSpaces(col)); -// ps.append((String) sv.elementAt(v)); -// } - addExprToTLA(proc.id); - if (proc.isEq) { -// ps.append("}"); - addOneTokenToTLA("}"); - } - else { -// ps.append(")"); - addOneTokenToTLA(")"); - } - addRightParen(proc.id.getOrigin()); - } -// tlacode.addElement(ps.toString()); -// tlacode.addElement(""); - endCurrentLineOfTLA(); - addOneLineOfTLA(""); - } - - /***********************************/ - /* Generate the Init == statement. */ - /** - **********************************/ - private void GenInit(Vector globals, Vector procs, Vector processes) throws PcalTLAGenException - { - int col = "Init == ".length(); - StringBuffer is = new StringBuffer(); - is.append("Init == "); - - /* Global variables */ - if (globals != null && globals.size() > 0) - { - is.append("(* Global variables *)"); -// tlacode.addElement(is.toString()); - addOneLineOfTLA(is.toString()) ; - is = new StringBuffer(NSpaces(col)); - for (int i = 0; i < globals.size(); i++) - { - AST.VarDecl decl = (AST.VarDecl) globals.elementAt(i); - addVarDeclToTLA(decl, is); - is = new StringBuffer(NSpaces(col)); - } - } - if (procs != null && procs.size() > 0) - { - /* Procedure variables and parameters */ - for (int i = 0; i < procs.size(); i++) - { - AST.Procedure proc = (AST.Procedure) procs.elementAt(i); - if (proc.params.size() == 0 && proc.decls.size() == 0) - // No parameters or procedure variables in this procedure - continue; - is.append("(* Procedure "); - is.append(proc.name); - is.append(" *)"); -// tlacode.addElement(is.toString()); - addOneLineOfTLA(is.toString()); - is = new StringBuffer(NSpaces(col)); - for (int p = 0; p < proc.params.size(); p++) - { - AST.PVarDecl decl = (AST.PVarDecl) proc.params.elementAt(p); - if (!mp) { - addVarDeclToTLA(decl.toVarDecl(), is); - } - else { - is.append("/\\ "); - addOneTokenToTLA(is.toString()); - addLeftParen(decl.getOrigin()); -// is.append(decl.var); - is = new StringBuffer(decl.var); - /******************************************************* - * Modified on 31 Jan 2006 by LL to add subscripts to * - * initialization expression if needed. Also replaced * - * test for "\\in" with assertion that it can't occur, * - * since it's forbidden by the grammar. * - *******************************************************/ - PcalDebug.Assert(decl.isEq); - is.append(" = "); - -// Vector sv; -// if (mp) -// { -// sv = AddSubscriptsToExpr(decl.val, -// SubExpr(Self("procedure")), new Changed(new Vector())) -// .toStringVector(); -// } else -// { -// sv = Parenthesize(decl.val.toStringVector()); -// /************************************************* -// * Call to Parenthesize added by LL on 27 Feb 2008. * -// * See bug_08-02-18. * -// *************************************************/ -// } -// ; -// if (mp) -// { - is.append("[ self \\in ProcSet |-> "); -// } - addOneTokenToTLA(is.toString()); - addLeftParen(decl.val.getOrigin()); - addExprToTLA( - AddSubscriptsToExpr(decl.val, - SubExpr(Self("procedure")), - new Changed(new Vector()))); - addRightParen(decl.val.getOrigin()); - addOneTokenToTLA("]"); - addRightParen(decl.getOrigin()); - endCurrentLineOfTLA(); - -// int col2 = is.length(); -// is.append((String) sv.elementAt(0)); -// for (int v = 1; v < sv.size(); v++) -// { -// tlacode.addElement(is.toString()); -// is = new StringBuffer(NSpaces(col2)); -// is.append((String) sv.elementAt(v)); -// } -// if (mp) -// is.append("]"); -// tlacode.addElement(is.toString()); - } - is = new StringBuffer(NSpaces(col)); - } - for (int p = 0; p < proc.decls.size(); p++) - { - /* - * Note: the following code is identical to the for loop - * code above for procedure variables. (Well done, Keith!) - * I realized this too late to feel like procedurizing it. - */ - AST.PVarDecl decl = (AST.PVarDecl) proc.decls.elementAt(p); - if (!mp) { - addVarDeclToTLA(decl.toVarDecl(), is); - } - else { - is.append("/\\ "); - addOneTokenToTLA(is.toString()); - addLeftParen(decl.getOrigin()); -// is.append(decl.var); - is = new StringBuffer(decl.var); -// is.append("/\\ "); -// is.append(decl.var); - - /******************************************************* - * Modified on 31 Jan 2006 by LL to add subscripts to * - * initialization expression if needed. Also replaced * - * test for "\\in" with assertion that it can't occur, * - * since it's forbidden by the grammar. * - *******************************************************/ - PcalDebug.Assert(decl.isEq); - is.append(" = "); -// Vector sv; -// if (mp) -// { -// sv = AddSubscriptsToExpr(decl.val, SubExpr(Self("procedure")), new Changed(new Vector())) -// .toStringVector(); -// } else -// { -// sv = Parenthesize(decl.val.toStringVector()); -// /************************************************* -// * Call to Parenthesize added by LL on * -// * 27 Feb 2008. See bug_08-02-18. * -// *************************************************/ -// } -// ; -// if (mp) -// { - is.append("[ self \\in ProcSet |-> "); -// } - addOneTokenToTLA(is.toString()); - addLeftParen(decl.val.getOrigin()); - addExprToTLA(AddSubscriptsToExpr( - decl.val, - SubExpr(Self("procedure")), - new Changed(new Vector()))); - addRightParen(decl.val.getOrigin()); - addOneTokenToTLA("]"); - addRightParen(decl.getOrigin()); - endCurrentLineOfTLA(); - -// int col2 = is.length(); -// is.append((String) sv.elementAt(0)); -// for (int v = 1; v < sv.size(); v++) -// { -// tlacode.addElement(is.toString()); -// is = new StringBuffer(NSpaces(col2)); -// is.append((String) sv.elementAt(v)); -// } -// if (mp) -// is.append("]"); -// tlacode.addElement(is.toString()); - } - is = new StringBuffer(NSpaces(col)); - } - } - } - if (processes != null && processes.size() > 0) - { - /* Process variables */ - for (int i = 0; i < processes.size(); i++) - { - AST.Process proc = (AST.Process) processes.elementAt(i); - if (proc.decls.size() == 0) // No variables in this procedure - continue; - is.append("(* Process "); - is.append(proc.name); - is.append(" *)"); -// tlacode.addElement(is.toString()); - addOneLineOfTLA(is.toString()); - is = new StringBuffer(NSpaces(col)); - for (int p = 0; p < proc.decls.size(); p++) - { - /* - * In the comments below, (( and )) represent - * MappingObject.LeftParen and MappingObject.RightParen - * objects. - */ - AST.VarDecl decl = (AST.VarDecl) proc.decls.elementAt(p); - is.append("/\\ "); - /* - * The following adds /\ (( to the TLA+ output. - */ - addOneTokenToTLA(is.toString()); - addLeftParen(decl.getOrigin()); - - - if (proc.isEq) { - /* - * The source is - * - * process (P = S) variables ... v @@ Val - * - * where @@ is either "=" or "\in". The TLA+ output is - * - * /\ (( v @@ (( Val )) )) - */ - is = new StringBuffer(decl.var); - if (decl.isEq) { - is.append(" = "); - } - else { - is.append(" \\in "); - } - addOneTokenToTLA(is.toString()); - addLeftParen(decl.val.getOrigin()); - addExprToTLA(decl.val); - addRightParen(decl.val.getOrigin()); - } - else { - if (decl.isEq) { - /* - * The source is - * - * process (P \in S) variables ... v = Val - * - * The TLA+ output is - * - * /\ (( v = [self \in (( S )) |-> (( ValBar )) ] )) - * - * where ValBar obtained from Val by replacing each - * variable w of the process with w[self]. - */ - is = new StringBuffer(decl.var); - is.append(" = [self \\in "); - addOneTokenToTLA(is.toString()); - addLeftParen(proc.id.getOrigin()); - addExprToTLA(proc.id); - addRightParen(proc.id.getOrigin()); - addOneTokenToTLA(" |-> " ); - addLeftParen(decl.val.getOrigin()); - addExprToTLA(AddSubscriptsToExpr( - decl.val, - SubExpr(Self("procedure")), - new Changed(new Vector()))); - addRightParen(decl.val.getOrigin()); - addOneTokenToTLA("]"); - - } - else { - /* - * The source is - * - * process (P \in S) variables ... v \in Val - * - * The TLA+ output is - * - * /\ (( v \in [ (( S )) -> (( ValBar )) ] )) - * - * where ValBar is obtained from Val by replacing each - * variable w of the process with - * - * w[CHOOSE self \in S : TRUE] - * - * We first set expr to the TLAExpr "CHOOSE self \in S : TRUE". - * (This is Keith's original code.) - */ - TLAExpr subexpr = proc.id.cloneAndNormalize(); - TLAExpr expr = new TLAExpr(); - expr.addLine(); - expr.addToken(new TLAToken("[", 0, TLAToken.BUILTIN)); - expr.addToken(new TLAToken("CHOOSE", 1, TLAToken.BUILTIN)); - expr.addToken(new TLAToken("self", 8, TLAToken.IDENT)); - expr.addToken(new TLAToken("\\in ", 13, TLAToken.BUILTIN)); - expr.normalize(); - expr.setOrigin(subexpr.getOrigin()); // see what this does. - try - { - subexpr.prepend(expr, 1); - expr = new TLAExpr(); - expr.addLine(); - expr.addToken(new TLAToken(":", 0, TLAToken.BUILTIN)); - expr.addToken(new TLAToken("TRUE", 2, TLAToken.BUILTIN)); - expr.addToken(new TLAToken("]", 6, TLAToken.BUILTIN)); - expr.prepend(subexpr, 1); - } catch (TLAExprException e) - { - throw new PcalTLAGenException(e.getMessage()); - } - - /* - * Now we output the TLA+ code. - */ - is = new StringBuffer(decl.var); - is.append(" \\in ["); - addOneTokenToTLA(is.toString()); - addLeftParen(proc.id.getOrigin()); - addExprToTLA(proc.id); - addRightParen(proc.id.getOrigin()); - addOneTokenToTLA(" -> " ); - addLeftParen(decl.val.getOrigin()); - addExprToTLA(AddSubscriptsToExpr( - decl.val, expr, new Changed(new Vector())) ); - addRightParen(decl.val.getOrigin()); - addOneTokenToTLA("]"); - } - } - /* - * This adds the final )) . - */ - addRightParen(decl.getOrigin()); - endCurrentLineOfTLA(); - is = new StringBuffer(NSpaces(col)); - -// everything from here down to the end of the for p loop should be commented out -// is.append(decl.var); -// is = new StringBuffer(decl.var); -// if (decl.isEq) -// is.append(" = "); -// else -// is.append(" \\in "); -// /******************************************************* -// * Modified on 31 Jan 2006 by LL to add subscripts to * -// * initialization expression for process set. Note * -// * tricky subscript that is added in expr for * -// * declaration of form "v \in expr". * -// * * -// * Also modified the whole method of producing the * -// * variable declaration because the original destroyed * -// * the formatting of the expression proc.id, leading * -// * to bad or incorrect formatting if the process id * -// * set expression was not trivial. * -// *******************************************************/ -// Vector sv; -// TLAExpr sve; -// if (proc.isEq) -// { -// /*************************************************** -// * No substitution unless it's a process set. * -// ***************************************************/ -// sve = decl.val; // .toStringVector(); -// } else -// { -// if (decl.isEq) -// { -// /*********************************************** -// * For declaration "v = ...", add subscript * -// * "[self]". * -// ***********************************************/ -// sve = AddSubscriptsToExpr(decl.val, SubExpr(Self("procedure")), new Changed(new Vector())); -// } else -// { -// /************************************************ -// * For declaration "v \in ...", add subscript * -// * "[CHOOSE self \in Process Id Set : TRUE]". * -// * * -// * This weird subscript is needed in the * -// * following weird case: * -// * * -// * process (P \in S) * -// * variable v \in T, w \in R(v) * -// * * -// * This produces the following conjunct in * -// * the initial predicate for w: * -// * * -// * w \in [S -> R(v[CHOOSE self \in S : TRUE])] * -// ************************************************/ -// TLAExpr subexpr = proc.id.cloneAndNormalize(); -// -// TLAExpr expr = new TLAExpr(); -// expr.addLine(); -// expr.addToken(new TLAToken("[", 0, TLAToken.BUILTIN)); -// expr.addToken(new TLAToken("CHOOSE", 1, TLAToken.BUILTIN)); -// expr.addToken(new TLAToken("self", 8, TLAToken.IDENT)); -// expr.addToken(new TLAToken("\\in ", 13, TLAToken.BUILTIN)); -// expr.normalize(); -// -// try -// { -// subexpr.prepend(expr, 1); -// expr = new TLAExpr(); -// expr.addLine(); -// expr.addToken(new TLAToken(":", 0, TLAToken.BUILTIN)); -// expr.addToken(new TLAToken("TRUE", 2, TLAToken.BUILTIN)); -// expr.addToken(new TLAToken("]", 6, TLAToken.BUILTIN)); -// expr.prepend(subexpr, 1); -// } catch (TLAExprException e) -// { -// throw new PcalTLAGenException(e.getMessage()); -// } -// -// sve = AddSubscriptsToExpr(decl.val, expr, new Changed(new Vector())); -// } -// ; -// } -// ; -// TLAExpr expr = new TLAExpr(); -// expr.addLine(); -// if (!proc.isEq) -// { -// expr.addToken(new TLAToken("[", 0, TLAToken.BUILTIN)); -// if (decl.isEq) -// { -// expr.addToken(new TLAToken("self", 1, TLAToken.IDENT)); -// expr.addToken(new TLAToken("\\in ", 6, TLAToken.BUILTIN)); -// } -// ; -// expr.normalize(); -// TLAExpr expr2 = proc.id.cloneAndNormalize(); -// try -// { -// expr2.prepend(expr, 0); -// expr = new TLAExpr(); -// expr.addLine(); -// if (decl.isEq) -// { -// expr.addToken(new TLAToken("|->", 0, TLAToken.BUILTIN)); -// } else -// { -// expr.addToken(new TLAToken("->", 0, TLAToken.BUILTIN)); -// } -// ; -// expr.prepend(expr2, 1); -// sve.prepend(expr, 1); -// } catch (TLAExprException e) -// { -// throw new PcalTLAGenException(e.getMessage()); -// } -// } -// ; -// sv = sve.toStringVector(); -// if (proc.isEq) -// { -// sv = Parenthesize(sv); -// } -// ; -// /***************************************************** -// * Call to Parenthesize added by LL on 27 Feb 2008. * -// * See bug_08-02-18. * -// *****************************************************/ -// int col2 = is.length(); -// is.append((String) sv.elementAt(0)); -// for (int v = 1; v < sv.size(); v++) -// { -// tlacode.addElement(is.toString()); -// is = new StringBuffer(NSpaces(col2)); -// is.append((String) sv.elementAt(v)); -// } -// if (!proc.isEq) -// is.append("]"); -// tlacode.addElement(is.toString()); -// is = new StringBuffer(NSpaces(col)); -// end of section to be commented out - } // end of for p loop. - } - } - - /* stack initial value */ - if (procs != null && procs.size() > 0) - { - if (mp) - is.append("/\\ stack = [self \\in ProcSet |-> << >>]"); - else - is.append("/\\ stack = << >>"); -// tlacode.addElement(is.toString()); - addOneLineOfTLA(is.toString()); - is = new StringBuffer(NSpaces(col)); - } - /* pc initial value */ - if (! ParseAlgorithm.omitPC) { - if (mp) - { - // On 4 May 2012, LL added useCase flag to inhibit adding of CASE for - // a single process or process set. - boolean useCase = st.processes.size() != 1; - if (useCase) { - is.append("/\\ pc = [self \\in ProcSet |-> CASE "); - } else { - is.append("/\\ pc = [self \\in ProcSet |-> "); - } - int colPC = is.length(); - if (boxUnderCASE) - colPC = colPC - 3; - for (int p = 0; p < st.processes.size(); p++) - { - PcalSymTab.ProcessEntry pe = (PcalSymTab.ProcessEntry) st.processes.elementAt(p); - if (useCase) { - is.append("self "); - if (pe.isEq) { - is.append("= "); - // int colExpr = is.length(); - addOneTokenToTLA(is.toString()); - addLeftParen(pe.id.getOrigin()); - addExprToTLA(pe.id); - addRightParen(pe.id.getOrigin()); - - // Vector sv = pe.id.toStringVector(); - // is.append((String) sv.elementAt(0)); - // for (int v = 1; v < sv.size(); v++) - // { - // addOneLineOfTLA(is.toString()); - // // tlacode.addElement(is.toString()); - // is = new StringBuffer(NSpaces(colExpr)); - // is.append((String) sv.elementAt(v)); - // } - } else { - is.append("\\in "); - // int colExpr = is.length(); - // Vector sv = pe.id.toStringVector(); - // is.append((String) sv.elementAt(0)); - // for (int v = 1; v < sv.size(); v++) - // { - // tlacode.addElement(is.toString()); - // is = new StringBuffer(NSpaces(colExpr)); - // is.append((String) sv.elementAt(v)); - // } - addOneTokenToTLA(is.toString()); - addLeftParen(pe.id.getOrigin()); - addExprToTLA(pe.id); - addRightParen(pe.id.getOrigin()); - - } - // is.append(" -> \""); - is = new StringBuffer(" -> \""); - is.append(pe.iPC); - if (p == st.processes.size() - 1) - is.append("\"]"); - else if (!boxUnderCASE) - is.append("\" []"); - else - is.append("\""); - } // end if (useCase) - else { - is.append("\"" + pe.iPC + "\"]"); - } -// tlacode.addElement(is.toString()); - addOneTokenToTLA(is.toString()); - endCurrentLineOfTLA(); - is = new StringBuffer(NSpaces(colPC)); - if (boxUnderCASE && p < st.processes.size() - 1) - is.append("[] "); - } - } else - { - is.append("/\\ pc = \"" + st.iPC + "\""); -// tlacode.addElement(is.toString()); - addOneLineOfTLA(is.toString()); - } - } -// tlacode.addElement(""); - addOneLineOfTLA(""); - } - - /************************************/ - /* Generate the Next == definition. */ - /************************************/ - private void GenNext() - { - // It we are omitting pc and this is a uniprocess - // algorithm, then the definition of Next has - // already been added. - if (ParseAlgorithm.omitPC && !mp) { - return; - } - Vector nextS = new Vector(); - StringBuffer sb = new StringBuffer(); - int max, col; - - // Steps with no parameter - max = wrapColumn - ("Next == \\/ ".length()); - for (int i = 0; i < nextStep.size(); i++) - { - String a = (String) nextStep.elementAt(i); - if (a.length() + " \\/ ".length() + sb.length() > max) - { - nextS.addElement(sb.toString()); - sb = new StringBuffer(); - } - if (sb.length() > 0) - sb.append(" \\/ "); - sb.append(a); - } - if (sb.length() > 0) - nextS.addElement(sb.toString()); - - // Steps with (self) from ProcSet - // These are procedures in a multiprocess algorithm - Vector nextSS = new Vector(); - String nextSSstart = "(\\E self \\in ProcSet: "; - sb = new StringBuffer(); - max = wrapColumn - ("Next == \\/ (\\E self \\in ProcSet: \\/ ".length()); - if (mp && st.procs.size() > 0) - { - for (int i = 0; i < st.procs.size(); i++) - { - PcalSymTab.ProcedureEntry p = (PcalSymTab.ProcedureEntry) st.procs.elementAt(i); - if ((p.name.length() + "(self) \\/ ".length() + sb.length()) > max) - { - nextSS.addElement(sb.toString()); - sb = new StringBuffer(); - } - if (sb.length() > 0) - sb.append(" \\/ "); - sb.append(p.name); - sb.append("(self)"); - } - if (sb.length() > 0) - nextSS.addElement(sb.toString() + ")"); - } - - // Steps with (self) from a set - // These are process sets - Vector nextSSP = new Vector(); // of Vector - if (mp && st.processes.size() > 0) - for (int i = 0; i < st.processes.size(); i++) - { - PcalSymTab.ProcessEntry p = (PcalSymTab.ProcessEntry) st.processes.elementAt(i); - if (p.isEq) - continue; - Vector vec = new Vector(); - sb = new StringBuffer(); - sb.append("(\\E self \\in "); - Vector sv = p.id.toStringVector(); - col = sb.length(); - sb.append((String) sv.elementAt(0)); - for (int j = 1; j < sv.size(); j++) - { - vec.addElement(sb.toString()); - sb = new StringBuffer(NSpaces(col)); - sb.append((String) sv.elementAt(j)); - } - sb.append(": "); - sb.append(p.name); - sb.append("(self))"); - vec.addElement(sb.toString()); - nextSSP.addElement(vec); - } - - // assemble the line from the pieces - sb = new StringBuffer("Next == "); - col = sb.length() + 2; - for (int i = 0; i < nextS.size(); i++) - { - sb.append((String) nextS.elementAt(i)); - addOneLineOfTLA(sb.toString()); -// tlacode.addElement(sb.toString()); - sb = new StringBuffer(NSpaces(col) + " \\/ "); - } - if (nextSS.size() > 0) - { - sb.append(nextSSstart); - int col2 = sb.length(); - if (nextSS.size() > 1) - sb.append(" \\/ "); - for (int i = 0; i < nextSS.size(); i++) - { - sb.append((String) nextSS.elementAt(i)); - addOneLineOfTLA(sb.toString()); -// tlacode.addElement(sb.toString()); - sb = new StringBuffer(NSpaces(col2) + " \\/ "); - } - sb = new StringBuffer(NSpaces(col) + " \\/ "); - } - if (nextSSP.size() > 0) - for (int i = 0; i < nextSSP.size(); i++) - { - Vector v = (Vector) nextSSP.elementAt(i); - for (int j = 0; j < v.size(); j++) - { - String line = (String) v.elementAt(j); - sb.append(line); - addOneLineOfTLA(sb.toString()); -// tlacode.addElement(sb.toString()); - - // The following if case was added by LL on 22 Jan 2011 - // to correct part 1 of bug bug_11_01_13. This bug occurs - // when an "\in" process's set is multi-line and that - // process's next-state action comes immediately after - // the Next == ..., with no " \/ " preceding it. To fix the - // problem, we must add 6 fewer spaces to all lines after - // the first in that process's set than in other such sets. - if ((nextS.size() == 0) && (nextSS.size() == 0) && (i == 0)) { - sb = new StringBuffer(NSpaces(col - 2)); - } else { - sb = new StringBuffer(NSpaces(col + 4)); - } - } - sb = new StringBuffer(NSpaces(col) + " \\/ "); - } - if (! (PcalParams.NoDoneDisjunct || ParseAlgorithm.omitStutteringWhenDone)) - { sb.append("(* Disjunct to prevent deadlock on termination *)"); - addOneLineOfTLA(sb.toString()); -// tlacode.addElement(sb.toString()); - sb = new StringBuffer(NSpaces(col + 4)); - if (mp) - /************************************************************ - * Bug fix by LL on 6 Sep 2007. Added parentheses to * - * change * - * * - * (*) \A self \in ProcSet: ... /\ UNCHANGED vars * - * * - * to * - * * - * (**) (\A self \in ProcSet: ...) /\ UNCHANGED vars * - * * - * thus moving the UNCHANGED vars outside the quantifier. * - * Since self does not appear in UNCHANGED vars, the two * - * expressions are equivalent except when ProcSet is the * - * empty set, in which case (*) equals TRUE and (**) equals * - * UNCHANGED vars. * - ************************************************************/ - sb.append("((\\A self \\in ProcSet: pc[self] = \"Done\") /\\ " + "UNCHANGED vars)"); - else - sb.append("(pc = \"Done\" /\\ UNCHANGED vars)"); - addOneLineOfTLA(sb.toString()); -// tlacode.addElement(sb.toString()); - } ; - addOneLineOfTLA(""); -// tlacode.addElement(""); - } - - /****************************************/ - /* Generate the Spec == ... definition. */ - /****************************************/ - /*********************************************************************** - * The spec can contain the following conjuncts * - * * - * 1. Init /\ [][Next]_vars * - * Always present * - * * - * 2. WF_var(Next) * - * present if (a) The wfNext option is specified, or * - * (b) It is a uniprocess algorithm and one of the * - * options -wf, -sf, -termination is specified. * - * * - * 3. A sequence of process fairness formulas, containing * - * one for each process for which there is a fairness condition. * - * * - * A process has * - * (a) a WF fairness condition iff * - * (i) it is preceded by the keyword "fair" and the -nof * - * option is not specified, or * - * (ii) the -wf option is specified. * - * (b) an SF fairness condition iff it is not preceded * - * by the keyword "fair" and the -sf option is specified. * - * * - * Let P be a process specified by either * - * * - * [fair] process (P = exp) ... * - * [fair] process (P \in exp) ... * - * * - * In the first case we say that P is a single process, in the second * - * that it is a process set. Let * - * * - * - p_1, ... , p_Np be the labels of P modified by "+" * - * * - * - m_1, ... , m_Nm be the set of labels of P modified by "-" * - * * - * - pSelf = IF P is a single process THEN "pname" * - * ELSE "self" * - * * - * - qSelf = IF /\ P is a single process * - * /\ pSelf a multi-line formula * - * THEN "self" * - * ELSE pSelf * - * * - * - pName = IF P is a single process THEN "P" * - * ELSE "P(self)" * - * * - * A process fairness formula is described by the following: * - * * - * XF: * - * either WF or SF depending on P's fairness condition * - * * - * prefix: * - * IF P is a single process * - * THEN IF pSelf a multi-line formula * - * THEN "LET self = pSelf IN" * - * ELSE "" * - * ELSE "\A self \in exp" * - * * - * wfFormula: * - * "XF( (pc[qSelf] \notin {"m_1", ... , "m_Np"}) /\ pName )" * - * * - * sfFormula: * - * if XF = SF * - * then null * - * else if P a single process * - * then "SF_vars(p_1) /\ ... /\ SF_vars(p_Np)" * - * else "SF_vars(p_1(self)) /\ ... * - * /\ SF_vars(p_Np(self))" * - * * - * prcdFormulas: * - * A sequence consisting of the following two formulas for each * - * procedure D called within P. Let * - * * - * - pd_1, ... , pd_Npd be the labels of D modified by "+" * - * - md_1, ... , md_Nmd be the labels of D modified by "-" * - * * - * in the formulas: * - * * - * wfFormula: * - * "XF( (pc[qSelf] \notin {"md_1", ... , "md_Nmd"}) * - * /\ D(qSelf) )" * - * * - * sfFormula: * - * if XF = SF * - * then null * - * else "SF_vars(pd_1(qSelf)) /\ ... * - * /\ SF_vars(pd_Npd(qSelf))" * - * * - * ------- * - * * - * If there is at least one fairness formula, the definition of Spec * - * will be formatted in one of two ways. If there is either a * - * WF_vars(Next) condition or a process fairness formula, then it may * - * be formatted as: * - * * - * Spec == Init /\ [][Next]_vars * - * * - * otherwise, it will be formatted as * - * * - * Spec == /\ Init /\ [][Next]_vars * - * [/\ WF_vars(Next)] * - * /\ F_1 * - * ... * - * /\ F_n * - * * - * where each F_i is a process fairness formulas. * - ***********************************************************************/ - private void GenSpec() - { String safetyFormula = "Init /\\ [][Next]_vars" ; - - if ( PcalParams.FairnessOption.equals("nof") - || (!mp && PcalParams.FairnessOption.equals(""))) { - addOneLineOfTLA("Spec == " + safetyFormula); - addOneLineOfTLA(""); -// tlacode.addElement("Spec == " + safetyFormula ); -// tlacode.addElement(""); - return; - } -//System.out.println("foo |-> " + st.UseThis(PcalSymTab.PROCEDURE, "foo", "")); -//int to = st.FindProc("foo"); -//PcalSymTab.ProcedureEntry pe = -// (PcalSymTab.ProcedureEntry) st.procs.elementAt(to); -//AST.Procedure procAst = pe.ast; - - StringBuffer sb = new StringBuffer("Spec == "); - // Generate the requested fairness conjuncts - - // wfNextConj is either null or " /\ WF_(Next)" - String wfNextConj = null; - if ( PcalParams.FairnessOption.equals("wfNext") - || PcalParams.FairAlgorithm - || (!mp && ( PcalParams.FairnessOption.equals("wf") - || PcalParams.FairnessOption.equals("sf")))) - { - // If uniprocess then wf and sf are the same as wfNext - wfNextConj = " /\\ WF_vars(Next)"; - } - - // Now compute procFairnessFormulas to equal the processes' fairness - // formulas, which is never null but may have zero length. - Vector procFairnessFormulas = new Vector() ; - if (mp) { - for (int i = 0; i < st.processes.size(); i++) { - PcalSymTab.ProcessEntry p = (PcalSymTab.ProcessEntry) st.processes.elementAt(i); - AST.Process pAst = p.ast ; - int fairness = pAst.fairness; - if (fairness != AST.UNFAIR_PROC) { - String xf = (fairness == AST.WF_PROC) ? "WF" : "SF"; - - Vector pSelf = p.id.toStringVector(); - - // makeLetIn is true iff prefix will be LET self == ... IN - boolean makeLetIn = false ; - - String qSelf = "self"; - if (p.isEq) { - if (pSelf.size() > 1) { - makeLetIn = true ; - } else { - qSelf = (String) pSelf.elementAt(0); - } - } - - Vector prefix = new Vector(); - if (makeLetIn || !p.isEq) { - int prefixSize = pSelf.size(); - String prefixBegin; - String prefixEnd; - if (p.isEq) { - prefixBegin = "LET self == "; - prefixEnd = ""; - } else { - prefixBegin = "\\A self \\in "; - prefixEnd = " : "; - } - String padding = NSpaces(prefixBegin.length()); - for (int j = 0; j < prefixSize; j++) { - String line = (String) pSelf.elementAt(j); - if (j == 0) { - line = prefixBegin + line; - } else { - line = padding + line; - } - if (j == prefixSize - 1) { - line = line + prefixEnd; - } - prefix.addElement(line); - } - if (makeLetIn) { - prefix.addElement("IN "); - } - } // end if (makeLetIn || !p.isEq) - - StringBuffer wfSB = new StringBuffer(xf + "_vars("); - if (pAst.minusLabels != null && pAst.minusLabels.size() > 0) { - wfSB.append("(pc["); - wfSB.append(qSelf); - if (pAst.minusLabels.size() == 1) { - wfSB.append("] # \""); - wfSB.append(pAst.minusLabels.elementAt(0)); - wfSB.append("\""); - } else { - wfSB.append("] \\notin {\""); - for (int j = 0; j < pAst.minusLabels.size(); j++) { - wfSB.append(pAst.minusLabels.elementAt(j)); - if (j == pAst.minusLabels.size() - 1) { - wfSB.append("\"}"); - } else { - wfSB.append("\", \""); - } - } - } - wfSB.append(") /\\ "); - } - - String pName = p.name; - if (!p.isEq) { - pName = p.name + "(self)"; - } - wfSB.append(pName); - wfSB.append(")"); - - StringBuffer sfSB = null ; - if ( xf.equals("WF") - && (pAst.plusLabels != null) - && (pAst.plusLabels.size() != 0)) { - sfSB = new StringBuffer() ; - for (int j = 0; j < pAst.plusLabels.size(); j++) { - if (j != 0) { - sfSB.append(" /\\ "); - } - sfSB.append("SF_vars("); - sfSB.append(pAst.plusLabels.elementAt(j)); - if (!p.isEq) { - sfSB.append("(self)"); - } - sfSB.append(")"); - } - } - - Vector prcdFormulas = new Vector(); - Vector procedures = pAst.proceduresCalled; - for (int k = 0; k < procedures.size(); k++) { - String originalName = (String) procedures.elementAt(k); - String name = st.UseThis(PcalSymTab.PROCEDURE, originalName, ""); - int procedureIndex = st.FindProc(name); - PcalSymTab.ProcedureEntry pe = - (PcalSymTab.ProcedureEntry) st.procs.elementAt(procedureIndex); - AST.Procedure prcAst = pe.ast; - - StringBuffer wfPrcSB = new StringBuffer(xf + "_vars("); - if (prcAst.minusLabels != null && prcAst.minusLabels.size() > 0) { - wfPrcSB.append("(pc["); - wfPrcSB.append(qSelf); - if (prcAst.minusLabels.size() == 1) { - wfPrcSB.append("] # \""); - wfPrcSB.append(prcAst.minusLabels.elementAt(0)); - wfPrcSB.append("\""); - } else { - wfPrcSB.append("] \\notin {\""); - for (int j = 0; j < prcAst.minusLabels.size(); j++) { - wfPrcSB.append(prcAst.minusLabels.elementAt(j)); - if (j == prcAst.minusLabels.size() - 1) { - wfPrcSB.append("\"}"); - } else { - wfPrcSB.append("\", \""); - } - } - } - wfPrcSB.append(") /\\ "); - } - - String prcName = pe.name + "(" + qSelf + ")"; - wfPrcSB.append(prcName); - wfPrcSB.append(")"); - - StringBuffer sfPrcSB = null; - if ( xf.equals("WF") - && (prcAst.plusLabels != null) - && (prcAst.plusLabels.size() != 0)) { - sfPrcSB = new StringBuffer() ; - for (int j = 0; j < prcAst.plusLabels.size(); j++) { - if (j != 0) { - sfPrcSB.append(" /\\ "); - } - sfPrcSB.append("SF_vars("); - sfPrcSB.append(prcAst.plusLabels.elementAt(j)); - sfPrcSB.append("(" + qSelf + ")") ; - sfPrcSB.append(")"); - } - } - prcdFormulas.addElement( - new FormulaPair( - wfPrcSB.toString(), - (sfPrcSB == null) ? null : sfPrcSB.toString()) - ) ; - } // end construction of prcdFormulas - - procFairnessFormulas.addElement( - new ProcessFairness( - xf, - prefix, - wfSB.toString(), - (sfSB == null) ? null : sfSB.toString(), - prcdFormulas) - ) ; - } // end if (fairness != AST.UNFAIR_PROC) - } - } // ends construction of procFairnessFormulas - - if (wfNextConj == null && procFairnessFormulas.size() == 0) { - addOneLineOfTLA("Spec == " + safetyFormula); - addOneLineOfTLA(""); -// tlacode.addElement("Spec == " + safetyFormula); -// tlacode.addElement(""); - return; - } - addOneLineOfTLA("Spec == /\\ " + safetyFormula); -// tlacode.addElement("Spec == /\\ " + safetyFormula) ; - int indent = "Spec == /\\ ".length(); - - if (wfNextConj != null) { - addOneLineOfTLA(" /\\ WF_vars(Next)"); -// tlacode.addElement(" /\\ WF_vars(Next)"); - } - for (int i = 0; i < procFairnessFormulas.size(); i++) { - /* - * The original code called format on the fairness formula, which can - * create a string with \n characters embedded. I've just split the - * string into its individual lines and added them to tlacode one at a time. - * However, the current and original code can both produce very long lines - * that could be wrapped. So if this change does make a difference, then - * it would be better to completely rewrite the format method (which is only - * called here). - */ - String str = - " /\\ " + - ((ProcessFairness) procFairnessFormulas.elementAt(i)).format(indent).toString(); - String [] splitStr = str.split("\n"); - for (int j = 0; j < splitStr.length; j++) { - addOneLineOfTLA(splitStr[j]); - } - -// tlacode.addElement( -// " /\\ " + -// ((ProcessFairness) procFairnessFormulas.elementAt(i)).format(indent) -// ); - } - addOneLineOfTLA(""); -// tlacode.addElement(""); - return; - } - - /************************************/ - /* Generate the Termination == */ - /************************************/ - private void GenTermination() - { - // if we're omitting the pc or omitting the stuttering-when-done - // clause of the Next action, then we shouldn't - // generate the Termination definition. - // Check of omitStutteringWhenDone added by LL on 30 Mar 2012. - if (ParseAlgorithm.omitPC || ParseAlgorithm.omitStutteringWhenDone) { - return; - } - StringBuffer sb = new StringBuffer(); - sb.append("Termination == <>("); - if (mp) - sb.append("\\A self \\in ProcSet: pc[self]"); - else - sb.append("pc"); - sb.append(" = \"Done\")"); - addOneLineOfTLA(sb.toString()); - addOneLineOfTLA(""); -// tlacode.addElement(sb.toString()); -// tlacode.addElement(""); - } - - /**********************************************************/ - /* For variables that need subscripts, add the subscript. */ - /* These are pc, stack, procedure variables, procedure */ - /* parameters, and variables defined in process sets. */ - /* Then, add primes to variables that have been changed */ - /* according to c. */ - /* exprn : the original expression. */ - /* sub : the subscript to be added (null if none) */ - /* c : the variables that have been changed (so need to */ - /* be primed. */ - /**********************************************************/ - private TLAExpr AddSubscriptsToExpr(TLAExpr exprn, TLAExpr sub, Changed c) throws PcalTLAGenException - { - /* - * For testing, throw a null pointer exception if the begin/end substitution - * mapping vectors are not properly matching in the returned expression - */ -// int[] depths = new int[1000]; - - int parenDepth = 0; - for (int i = 0; i < exprn.tokens.size(); i++) { - Vector line = (Vector) exprn.tokens.elementAt(i); - for (int j = 0; j < line.size(); j++) { - TLAToken tok = (TLAToken) line.elementAt(j); - parenDepth = parenDepth + tok.getBeginSubst().size() - tok.getEndSubst().size(); - if (parenDepth < 0) { - throw new NullPointerException("argument: begin/end Subst depth negative"); - } - } -// depths[i] = parenDepth; - } - if (parenDepth != 0) { - throw new NullPointerException("argument: Unmatched begin Subst"); - } - /* ------------------ end testing --------------------------*/ - - /* - * We now set stringVec to the sequence of identifiers that occur in exprn - * for which we need to add a subscript or a prime. - */ - Vector exprVec = new Vector(); // the substituting exprs - Vector stringVec = new Vector(); // the substituted ids - TLAExpr expr = exprn.cloneAndNormalize(); // the expression to be returned - - for (int i = 0; i < expr.tokens.size(); i++) - { - Vector tv = (Vector) expr.tokens.elementAt(i); - for (int j = 0; j < tv.size(); j++) - { - TLAToken tok = (TLAToken) tv.elementAt(j); - boolean prime = ((tok.type == TLAToken.IDENT) && c.IsChanged(tok.string)); - boolean subr = (sub != null && (tok.type == TLAToken.ADDED || (mp && (tok.type == TLAToken.IDENT) && (IsProcedureVar(tok.string) || IsProcessSetVar(tok.string))))); - if ((subr || prime) && !InVector(tok.string, stringVec)) - { - stringVec.addElement(tok.string); - TLAExpr exp = new TLAExpr(); - exp.addLine(); - /* - * 15 Dec 2011: The following code added to replace the - * - * exp.addToken(new TLAToken(tok.string, 0, TLAToken.IDENT)); - * - * that is commented out. Note that this change can add a token with - * type ADDED rather than IDENT. I don't think this matters. - */ - TLAToken newTok = tok.Clone() ; - /* - * The new token should inherit nothing from the baggage of tok, whose - * only function is to provide the name - */ - newTok.setBeginSubst(new Vector(2)); - newTok.setEndSubst(new Vector(2)); - newTok.source = null; - newTok.column = 0; - exp.addToken(newTok) ; - // exp.addToken(new TLAToken(tok.string, 0, TLAToken.IDENT)); - if (prime) { - /***************************************************** - * Modified by LL on 30 Aug 2007. The following * - * call to addTokenOffset was originally a call to * - * addToken. See the comments for * - * TLAExpr.addTokenOffset(). * - *****************************************************/ - TLAToken primeTok = new TLAToken("'", 0, TLAToken.BUILTIN, true); - // The following stuff added by LL in Dec 2011 is bogus. The - // token tok is just the first one of many in the exprn with - // the same name for which we want to substitute. The only - // useful data in the token tok is its string. - // - // if (tok.source != null) { - // primeTok.source = - // new Region(tok.source.getEnd(), tok.source.getEnd()); - // } - // if (!subr) { - // primeTok.setEndSubst(tok.getEndSubst()); - // newTok.setEndSubst(new Vector(2)); - // } - exp.addTokenOffset(primeTok, 0); - } - if (subr) - { - TLAExpr subexp = sub.cloneAndNormalize(); - - /* - * We now add the end of the origin of tok to beginSubst - * of the first token of subexp and to endSubst of the - * last token of subexp. This indicates that PCal code - * corresponding to a region of the TLA+ translation that - * includes part of the added subscript and part of the - * original expression is a portion of the source of - * exprn. - */ - // This is bogus, because we are adding the location of where - // the identifier first occurs in exprn to the substitution - // vectors of the expression that's going to be substituted in - // all instances. - // - // if (tok.source != null) { - // PCalLocation endOfTok = tok.source.getEnd(); - // subexp.firstToken().getBeginSubst().add(endOfTok); - // subexp.lastToken().getEndSubst().add(endOfTok); - // } - /* - * However, we do have to move the token's beginSubst and endSubst vectors - * to the first and lasts token of the subscript. Since the - * resulting Parens that they generate should be outside - * the ones generated by the endSubst vectors of the expression, - * we have to add them before that expression's Subst vectors. - * - * No, no! This tok is just giving us the name of the tok that - * we're going to be substituting for in the expression. It is not - * necessarily the one that we're going to substitute for. - */ - // newTok.getEndSubst().addAll(subexp.lastToken().getEndSubst()); - // subexp.lastToken().setEndSubst(newTok.getEndSubst()); - // newTok.setEndSubst(new Vector(2)); - exp.normalize(); - try - { - subexp.prepend(exp, 0); - } catch (TLAExprException e) - { - throw new PcalTLAGenException(e.getMessage()); - } - exp = subexp; - } - /********************************************************** - * Modified by LL on 31 Jan 2006 to comment out the call * - * of MakeExprPretty, since it totally screwed up the * - * formatting when substituting any string containing * - * spaces or multiple lines for a variable. * - **********************************************************/ - // MakeExprPretty(exp); - exprVec.addElement(exp); - } - } - } - if (exprVec.size() > 0) - try - { - expr.substituteForAll(exprVec, stringVec, false); - } catch (TLAExprException e) - { - throw new PcalTLAGenException(e.getMessage()); - } - /* - * For testing, throw a null pointer exception if the begin/end substitution - * mapping vectors are not properly matching in the returned expression - */ -// depths = new int[1000]; - - parenDepth = 0; - for (int i = 0; i < expr.tokens.size(); i++) { - Vector line = (Vector) expr.tokens.elementAt(i); - for (int j = 0; j < line.size(); j++) { - TLAToken tok = (TLAToken) line.elementAt(j); - parenDepth = parenDepth + tok.getBeginSubst().size() - tok.getEndSubst().size(); - if (parenDepth < 0) { - throw new NullPointerException("result: begin/end Subst depth negative"); - } - } -// depths[i] = parenDepth; - } - if (parenDepth != 0) { - throw new NullPointerException("result: Unmatched begin/subst"); - } - /* ------------------ end testing --------------------------*/ - return expr; - } - - /*********************************************************************** - * Given an expression, makes it into a subscript expr. It is called * - * only with argument Self(context), which means that it is called * - * only for a single subscript. * - * * - * If string is null, then returns null. * - * * - * Since this is used only to add "[self]", there is no need to add * - * any REPLACEMENT tokens to the expression. Moreover, the added * - * subscript's tokens have a null source field because they don't come * - * from any PCal code. The new expression is given the same origin as * - * the original one. * - ***********************************************************************/ - private static TLAExpr SubExpr(TLAExpr sub) - { - if (sub != null) - { - TLAExpr expr = sub.cloneAndNormalize(); - // This preserves the origin of the expression - for (int i = 0; i < expr.tokens.size(); i++) { - Vector tokenVec = (Vector) expr.tokens.elementAt(i); - for (int j = 0; j < tokenVec.size(); j++) { - TLAToken tok = (TLAToken) tokenVec.elementAt(j); - tok.column = tok.column + 1; - } - if (i == 0) { - /* - * Set isAppended field of the "[" and "]" to true iff the first - * token of sub has isAppended field true, which should be the - * case iff it is the "self" token. - */ - tokenVec.insertElementAt( - new TLAToken("[", 0, TLAToken.BUILTIN, sub.firstToken().isAppended()), - 0); - } - } - expr.addTokenOffset( - new TLAToken("]", 0, TLAToken.BUILTIN, sub.firstToken().isAppended()), 0); - return expr; - } else { - return null; - } - } - - /*********************************************************/ - /* Gives the string to use when subscripting a variable. */ - /*********************************************************/ - // LL comment: it appears that PcalTLAGen.self is the - // current process id if this is being called in the context - // of a process declared with `process (P = id)'. - private TLAExpr Self(String context) - { - TLAExpr s = null; - if (mp) - { - if (context.equals("procedure")) - s = selfAsExpr(); - else - s = self; - } - return s; - } - - private static TLAExpr selfAsExpr() { - /* - * This is a token that does not correspond to anything in the - * PCal code, so it should have a null source field. - * It has a true isAppended field because it is always appended - * as a subscript to a variable. - */ - TLAToken selfToken = new TLAToken("self", 0, TLAToken.IDENT, true); - Vector tokenVec = new Vector(); - tokenVec.addElement(selfToken); - Vector tokens = new Vector(); - tokens.addElement(tokenVec); - TLAExpr expr = new TLAExpr(tokens); -// expr.anchorTokens = new TLAToken[1]; -// expr.anchorTokens[0] = selfToken; -// expr.anchorTokCol = new int[1]; -// expr.anchorTokCol[0] = 0; - expr.normalize(); - return expr ; - } - /*********************************************************************** - * Comment added by LL: MakeExprPretty should never be called on an * - * expression any part of which was an expression in the input. * - * Fortunately, it is now called only for the expression "[self]", so * - * it is effectively a no-op. * - * Comment added 15 Dec 2011: In fact, it's not called at all. * - ***********************************************************************/ - public static void ObsoleteMakeExprPretty(TLAExpr expr) - { - /********************************************************************* - * Sets columns so this expr looks nice and tight. * - *********************************************************************/ - Vector line; /* Vector of TLAToken */ - boolean spread; - int nextCol = 1; - for (int i = 0; i < expr.tokens.size(); i++) - { - line = (Vector) expr.tokens.elementAt(i); - for (int j = 0; j < line.size(); j++) - { - TLAToken tok = ((TLAToken) line.elementAt(j)); - spread = tok.string.equals("="); - tok.column = nextCol + ((spread) ? 1 : 0); - nextCol = nextCol + tok.getWidth() + ((spread) ? 2 : 0); - } - } - } - - /***********************************************************/ - /* v is a sequence of SingleAssign. Return a vector of the */ - /* same SingleAssign, but sorted in terms of the lhs.var. */ - /***********************************************************/ - private static Vector SortSass(Vector vec) - { - Vector v = (Vector) vec.clone(); - Vector r = new Vector(); // The sorted version of v. - while (v.size() > 0) - { // Good old n^2 insertion sort. - AST.SingleAssign candidate = (AST.SingleAssign) v.elementAt(0); - int indexC = 0; - for (int i = 1; i < v.size(); i++) - { - AST.SingleAssign sass = (AST.SingleAssign) v.elementAt(i); - if (candidate.lhs.var.compareTo(sass.lhs.var) > 0) - { - indexC = i; - candidate = sass; - } - } - r.addElement(candidate); - v.remove(indexC); - } - return r; - } - - /*********************************************************************** - * If vec is a StringVector representing an expression, then this * - * returns the StringVector obtained by parenthesizing the expression * - * if it may need parenthesizing. This is used only to prevent * - * parsing errors when the expression appears immediately to the right * - * of an "=" in the spec. This is a rare situation, so it would be * - * nice to add the parentheses only if really necessary. For now, the * - * parentheses are added if one of the following tokens occur outside * - * parentheses and not inside a string: * - * * - * = * - * # * - * < not followed by < * - * > not followed by > or preceded by = * - * | preceded or followed by - * - * \ not followed by "o" or "X". * - * / followed by "\" * - * * - * Left parentheses are * - * * - * ( [ { << * - * * - * The handling of "\" is a simplifying hack. Lots of operators * - * beginning with "\" like "\/", "\gg" and "\subseteq" have precedence * - * greater than or equal to "=". The only commonly used ones with * - * precedence lower than "=" seem to be "\o" and "\X". It doesn't * - * seem to be worth the bother of checking for the others just to * - * avoid unnecessarily adding the parentheses when those other rare * - * operators are used. * - * * - * Perhaps the one improvement that might be worth making in this * - * procedure is to have it not add parentheses because of "dangerous" * - * operations in an IF clause--for example: * - * * - * IF x < 0 THEN ... * - * * - * This would require considering "IF" to be a left parenthesis and * - * "THEN" to be a right parenthesis. However, that's not trivial to * - * implement because of unlikely things like * - * * - * IFx := 42 ; * - * x := IFx < THENx * - ***********************************************************************/ - private static Vector Parenthesize(Vector vec) - { - /********************************************************************* - * Add the parentheses if necessary. * - *********************************************************************/ - if (NeedsParentheses(vec)) - { - vec.setElementAt("(" + ((String) vec.elementAt(0)), 0); - for (int i = 1; i < vec.size(); i++) - { - vec.setElementAt(" " + ((String) vec.elementAt(i)), i); - } - ; - int curLineNum = vec.size() - 1; - vec.setElementAt(((String) vec.elementAt(curLineNum)) + ")", curLineNum); - } - ; - return vec; - } - - /** - * As part of adding the TLA to PCal translation code, LL removedseparated - * the code that decides if parentheses are needed from the Parenthesize - * method and put it into this method. The Parenthesize method itself - * will not be needed. - */ - public static boolean NeedsParentheses(Vector vec) { - if (vec.size() == 0) - { - return false; - } - ; - /******************************************************************* - * vec shouldn't be empty, but let's not worry about what to do if * - * it is. * - *******************************************************************/ - int curCharNum = 0; - int curLineNum = 0; - int parenDepth = 0; - boolean inString = false; - boolean needParen = false; - while ((curLineNum < vec.size()) && (!needParen)) - { - String curLine = (String) vec.elementAt(0); - while ((curCharNum < curLine.length()) && (!needParen)) - { - char curChar = curLine.charAt(curCharNum); - - if (inString) - { - switch (curChar) { - case '\"': - inString = false; - break; - case '\\': - curCharNum++; - break; - } - ; // end switch - } // end if (inString) - else - { - boolean leftParen = false; - boolean rightParen = false; - boolean mayNeedParen = false; - /*************************************************************** - * Set nextChar to the next character on the line, or ' ' if * - * there is none. * - ***************************************************************/ - char nextChar = ' '; - if (curCharNum < curLine.length() - 1) - { - nextChar = curLine.charAt(curCharNum + 1); - } - switch (curChar) { - case '\"': - inString = true; - break; - case '=': - mayNeedParen = true; - break; - case '#': - mayNeedParen = true; - break; - case '<': - if (nextChar == '<') - { - curCharNum++; - leftParen = true; - } else - { - mayNeedParen = true; - } - ; - break; - case '>': - if (nextChar == '>') - { - curCharNum++; - rightParen = true; - } else - { - mayNeedParen = true; - } - ; - break; - case '|': - if ((nextChar == '-') || ((curCharNum > 0) && (curLine.charAt(curCharNum - 1) == '-'))) - { - mayNeedParen = true; - } - ; - break; - case '\\': - if (!((nextChar == ' ') || (nextChar == 'o') || (nextChar == 'X'))) - { - mayNeedParen = true; - } - ; - break; - case '/': - if (nextChar == '\\') - { - mayNeedParen = true; - } - ; - break; - case '(': - case '[': - case '{': - leftParen = true; - break; - case ')': - case ']': - case '}': - rightParen = true; - break; - } - ; - if (mayNeedParen && (parenDepth == 0)) - { - needParen = true; - } - ; - if (leftParen) - { - parenDepth++; - } - ; - if (rightParen) - { - if (parenDepth == 0) - { - needParen = true; - } - ; - parenDepth--; - } - } - ; // end else ! inString - curCharNum++; - } - ; // end while (curCharNum < curLine.length()) - - if (inString) - { - needParen = true; - } - ; - /***************************************************************** - * If there is an unmatched quote, we might as well stop here. * - *****************************************************************/ - curLineNum++; - curCharNum = 0; - } // end while (curLineNum < vec.size()) - - return needParen; - } - - /* - * The following methods are used to add code to tlacode and add the - * appropriate objects to mappingVector - */ - - /** - * Adds one token to tlacodeNextLine, and adds the appropriate - * Begin/EndTLAToken objects to mappingVectorNextLine. The - * ...TLAToken objects mark a region that excludes beginning and - * ending space characters of token--unless the token has - * only space characters. - * - * @param token - */ - private void addOneTokenToTLA(String token) { - String trimmedToken = token.trim() ; - - int numberOfLeftTrimmedTokens = - (trimmedToken.length() == 0) ? -1 : - token.indexOf(trimmedToken.charAt(0)); - - /** - * Handle a token of only space characters. - */ - if (numberOfLeftTrimmedTokens == -1) { - numberOfLeftTrimmedTokens = 0 ; - trimmedToken = token ; - } - - int objBegin = tlacodeNextLine.length() + numberOfLeftTrimmedTokens; - mappingVectorNextLine.addElement(new MappingObject.BeginTLAToken(objBegin)); - mappingVectorNextLine.addElement(new MappingObject.EndTLAToken(objBegin + trimmedToken.length())); - tlacodeNextLine = tlacodeNextLine + token; - } - - /** - * If region is non-null, then adds string str to the TLA output - * as a SourceToken object with that region. Otherwise, it adds - * it as a TLAToken, with Begin/EndTLAToken objects. - * - * @param str - * @param region - */ - private void addOneSourceTokenToTLA(String str, Region region) { - if (region == null) { - addOneTokenToTLA(str); - return; - } - - int beginCol = tlacodeNextLine.length(); - int endCol = beginCol + str.length(); - mappingVectorNextLine.addElement( - new MappingObject.SourceToken(beginCol, endCol, region)); - tlacodeNextLine = tlacodeNextLine + str; - } - /** - * Adds a complete line of TLA "code" that does not correspond to - * any PlusCal code. Adds Begin/EndTLAToken objects to the mapping - * iff the line does not equal "". - * - * @param line - */ - private void addOneLineOfTLA(String line) { -// temporarily commented out. - if(tlacode.size() != mappingVector.size()) { - PcalDebug.ReportBug("tlacode and mappingVector have different lengths") ; - } -// The following added during testing. -//if(tlacode.size() != mappingVector.size()) { -// System.out.println("tlacode and mappingVector have different lengths"); -//} - endCurrentLineOfTLA(); - if (line.length() == 0) { - mappingVector.addElement(new Vector(2)); - tlacode.addElement(""); - return; - } - addOneTokenToTLA(line); - endCurrentLineOfTLA(); - } - - /** - * If tlacodeNextLine does not equal "", then add it to tlacode - * and add mappingVectorNextLine to mappingVector. If it does equal "", - * don't add any lines, but add any potentially legal leftovers in - * mappingVectorNextLine to the previous line. - */ - private void endCurrentLineOfTLA() { - if (tlacodeNextLine.length() != 0) { - tlacode.addElement(tlacodeNextLine) ; - mappingVector.addElement(mappingVectorNextLine) ; - tlacodeNextLine = ""; - mappingVectorNextLine = new Vector() ; - } - else { - if (mappingVectorNextLine.size() != 0) { - /* - * There's something to go in the mappingVector that doesn't - * accompany any text. It should be one or more RightParen or - * LeftParen objects, (or perhaps, eventually a Break), in which - * case they should be put at the end of the previous mappingVector - * line. Anything else is a mistake. - */ - Vector lastLine = (Vector) mappingVector.elementAt(mappingVector.size()-1); - for (int i = 0; i < mappingVectorNextLine.size(); i++) { - MappingObject obj = (MappingObject) mappingVectorNextLine.elementAt(i); - if (obj.getType() == MappingObject.RIGHT_PAREN || - obj.getType() == MappingObject.LEFT_PAREN|| - obj.getType() == MappingObject.BREAK) { - lastLine.add(obj); - } - else { - PcalDebug.ReportBug("PcalTLAGen.endCurrentLineOfTLA found problem."); - } - mappingVectorNextLine = new Vector() ; - } - } - } - } - - /** - * Adds the expression to tlacode / tlacodeNextLine and its - * mapping to mappingVector / mappingVectorNextLine. It adds - * no space before the expression and leaves the last line of the - * expression (which could be its first line) at the end of - * tlacodeNextLine. - * @param expr - */ - private void addExprToTLA(TLAExpr expr) { - Vector sv = expr.toStringVector() ; - Vector exprMapping = expr.toMappingVector() ; - int indent = tlacodeNextLine.length() ; - int nextLine = 0 ; - if (indent != 0) { - /* - * Need to combine first line of expr with - * tlacodeNextLine. - */ - MappingObject.shiftMappingVector(exprMapping, indent); - tlacodeNextLine = tlacodeNextLine + ((String) sv.elementAt(0)); - mappingVectorNextLine.addAll((Vector) exprMapping.elementAt(0)); - nextLine = 1; - if (sv.size() > 1) { - endCurrentLineOfTLA(); - } - } - if (sv.size() > 1) { - String spaces = NSpaces(indent); - while (nextLine < sv.size()-1) { - tlacode.addElement(spaces + ((String) sv.elementAt(nextLine))); - mappingVector.addElement((Vector) exprMapping.elementAt(nextLine)); - nextLine++ ; - } - tlacodeNextLine = spaces + ((String) sv.elementAt(nextLine)) ; - mappingVectorNextLine = (Vector) exprMapping.elementAt(nextLine); - } - else if (indent == 0){ - /* - * If indent != 0, then we've already added the one-line expression. - */ - tlacodeNextLine = tlacodeNextLine + ((String) sv.elementAt(0)); - mappingVectorNextLine.addAll((Vector) exprMapping.elementAt(0)); - } - } - - /** - * Subroutine of GenInit that adds to the TLA translation the Init conjunct - * corresponding to the VarDecl decl for a global variable and, in a uniprocess - * algorithm for a procedure or process variable It is called with the - * StringBuffer `is' containing the text that precedes the "/\" of the - * conjunct, which will be "Init == " or just spaces. - * - * @param decl - * @param is - */ - private void addVarDeclToTLA(VarDecl decl, StringBuffer is) { - Region origin = decl.getOrigin(); - is.append("/\\ "); - addOneTokenToTLA(is.toString()); - addLeftParen(decl.getOrigin()); -// is.append(decl.var); - is = new StringBuffer(decl.var); - if (decl.isEq) - is.append(" = "); - else - is.append(" \\in "); -// int col2 = is.length(); -// Vector sv = Parenthesize(decl.val.toStringVector()); -// /********************************************************* -// * Call to Parenthesize added by LL on 27 Feb 2008. * -// * See bug_08-02-18. * -// *********************************************************/ -// is.append((String) sv.elementAt(0)); -// for (int v = 1; v < sv.size(); v++) -// { -// tlacode.addElement(is.toString()); -// is = new StringBuffer(NSpaces(col2)); -// is.append((String) sv.elementAt(v)); -// } -// tlacode.addElement(is.toString()); - addOneTokenToTLA(is.toString()); - addLeftParen(decl.val.getOrigin()); - boolean needsParens = NeedsParentheses(decl.val.toStringVector()); - if (needsParens) { - addOneTokenToTLA("("); - } - addExprToTLA(decl.val); - if (needsParens) { - addOneTokenToTLA(")"); - } - addRightParen(decl.val.getOrigin()); - addRightParen(decl.getOrigin()); - endCurrentLineOfTLA(); - } - - /** - * Adds a MappingObject.LeftParen object to the mapping vector - * for the beginning of the Region region, if it's not null. - * @param region - */ - private void addLeftParen(Region region) { - if (region != null) { - mappingVectorNextLine.addElement( - new MappingObject.LeftParen(region.getBegin())); - } - } - - /** - * Adds a MappingObject.LeftParen object to the mapping vector - * for the beginning of the Region region, if it's not null. - * @param region - */ - private void addRightParen(Region region) { - if (region != null) { - mappingVectorNextLine.addElement( - new MappingObject.RightParen(region.getEnd())); - } - } - - /** - * Like addLeftParen(ast.getOrigin()), except that it uses - * loc the location if it is not null. It is called by - * GenLabeledStmt and ast.getOrigin() should never be null. - * However, if it is, then we don't add a Paren; this insures - * that the matching calls of addLeftParenV and addRightParenV - * both either do or don't add a Paren. - * - * @param ast - */ - private void addLeftParenV(AST ast, PCalLocation loc) { - if (ast.getOrigin() == null) { - return; - } - if (loc != null) { - mappingVectorNextLine.addElement( - new MappingObject.LeftParen(loc)); - } - else { - addLeftParen(ast.getOrigin()); - } - } - - /** - * Like addRightParen(ast.getOrigin()), except that it uses - * loc as the location if it is not null. It is called by - * GenLabeledStmt and ast.getOrigin() should never be null. - * However, if it is, then we don't add a Paren; this insures - * that the matching calls of addLeftParenV and addRightParenV - * both either do or don't add a Paren. - * - * @param ast - */ - private void addRightParenV(AST ast, PCalLocation loc) { - if (ast.getOrigin() == null) { - return; - } - if (loc!= null) { - mappingVectorNextLine.addElement( - new MappingObject.RightParen(loc)); - } - else { - addRightParen(ast.getOrigin()); - } - } -/* -------------------------------------------------------------------------- */ - /* - * The following methods and classes of objects are used in GenSpec(). - * See the comments preceding that method above. - */ - - /** - * A FormulaPair should never have wf = null, but might have sf = null. - */ - public static class FormulaPair { - public String wf ; - public String sf ; - - public FormulaPair(String wfVal, String sfVal) { - this.wf = wfVal; - this.sf = sfVal; - } - - /** - * The string wf /\ sf , or just wf if sf is null. - * @return - */ - public String singleLine() { - if (sf == null) { - return wf ; - } - return wf + " /\\ " + sf ; - } - - /** - * The width of the singleLine representation of the - * conjunction of the formlas. - * - * @return - */ - public int singleLineWidth() { - if (sf == null) { - return wf.length() ; - } - return wf.length() + " /\\ ".length() + sf.length() ; - } - - /** - * The representation of the conjunction of the formulas with - * prefix /\s, where the first /\ appears in column col (Java - * numbering), witout any ending "\n" - * - * @return - */ - public String multiLine(int col) { - String val = "/\\ " + wf ; - if (sf == null) { - return val; - } - return val + "\n" + NSpaces(col) + "/\\ " + sf; - } - } - - /** - * Describes a process fairness formula, as described in the comments - * preceding the GetSpec() method above. - * @author lamport - * - */ - public static class ProcessFairness { - public String xf ; // either "WF" or "SF" - public Vector prefix ; - // StringVector either "\A self \in exp : " or - // "LET self == exp \n IN " (note the ending space) or "" - public FormulaPair bodyFormulas ; // fairness conditions for the proc's body - public Vector prcdFormulas ; // fairness conditions for the procedure - - /** - * The constructor - * @param xfVal - * @param prefixVal - * @param bodyWF : can be null if bodySF is also null - * @param bodySF : can be null - * @param prcdVal - */ - public ProcessFairness (String xfVal, Vector prefixVal, String bodyWF, - String bodySF, Vector prcdVal) { - xf = xfVal; - prefix = prefixVal; - bodyFormulas = null ; - if (bodyWF != null) { - bodyFormulas = new FormulaPair(bodyWF, bodySF); - } - prcdFormulas = prcdVal; - } - /** - * The width of the fairness formula written as a "single-line" - * formula. Single-line means that it is not written as a - * conjunction list (with a leading /\). It will actually - * occupy multiple lines if prefix is a multi-line formula. - * - * @return - */ - public int singleLineWidth() { - // Set maxPrefixWidth to length of longest non-final - // line of prefix, width to lenght of final line - int maxPrefixWidth = 0 ; - int width = 0 ; - if (prefix != null && prefix.size() > 0) { - for (int i = 0; i < prefix.size() - 1; i++) { - String line = (String) prefix.elementAt(i); - if (line.length() > maxPrefixWidth) { - maxPrefixWidth = line.length(); - } - String lastLine = (String) prefix.elementAt(prefix.size()-1); - width = lastLine.length(); - } - } - width = width + bodyFormulas.wf.length(); - if (bodyFormulas.sf != null) { - width = width + bodyFormulas.sf.length(); - } - if (prcdFormulas != null) { - for (int i = 0 ; i < prcdFormulas.size(); i++) { - width = width + ((FormulaPair) prcdFormulas.elementAt(i)).singleLineWidth(); - } - } - if (maxPrefixWidth > width) { - return maxPrefixWidth; - } - return width ; - } - - /** - * Returns the prefix as a StringBuffer, assuming it starts - * in column col. That is, all but the first line is indented - * with col spaces, and all but the last line is ended with - * a \n . - * - * @param col - * @return - */ - private StringBuffer prefixAsStringBuffer(int col) { - StringBuffer val = new StringBuffer(); - if (prefix != null && prefix.size() > 0) { - for (int i = 0; i < prefix.size(); i++) { - String line = (String) prefix.elementAt(i); - if (i != 0) { - val.append(NSpaces(col)); - } - val.append(line) ; - if (i != prefix.size()-1) { - val.append("\n") ; - } - } - } - return val; - } - /** - * The process fairness condition written as a single-line formula, - * starting in column col. - * @return - */ - public StringBuffer singleLine(int col) { - StringBuffer val = prefixAsStringBuffer(col); - val.append(bodyFormulas.wf); - if (bodyFormulas.sf != null) { - val.append(" /\\ "); - val.append(bodyFormulas.sf); - } - if (prcdFormulas != null) { - for (int i = 0 ; i < prcdFormulas.size(); i++) { - val.append(" /\\ "); - val.append(((FormulaPair) prcdFormulas.elementAt(i)).singleLine()); - } - } - return val ; - } - - /** - * Returns true iff format(col) should return a single-line version - * of the formula. - * - * @param col - * @return - */ - private boolean fitsAsSingleLine(int col) { - return (col + singleLineWidth() <= PcalTLAGen.wrapColumn) - || (bodyFormulas.sf == null - && (prcdFormulas == null || prcdFormulas.size() == 0)); - } - /** - * The process fairness condition written as a formula that - * begins in column col (Java numbering) and ends with "\n". - * It is formatted to try to extend no further than column - * PcalTLAGen.wrapColumn, but no individual formula is split - * across lines. - * - * @param col - * @return - */ - public StringBuffer format(int col) { - int singleLineWidth = this.singleLineWidth(); - /* - * Return the single-line form if either it fits on the - * line or if it consists of only the wf formula (so it can't - * be put on multiple lines). - */ - if (fitsAsSingleLine(col)) { - return this.singleLine(col); - } - StringBuffer val = prefixAsStringBuffer(col); - int prefixWidth = 0; - if (prefix != null && prefix.size() > 0) { - prefixWidth = ((String) prefix.elementAt(prefix.size()-1)).length(); - } - int curCol = col + prefixWidth; - String line = this.bodyFormulas.singleLine(); - if (curCol + line.length() + 3 <= PcalTLAGen.wrapColumn) { - val.append("/\\ " + line); - } else { - val.append(this.bodyFormulas.multiLine(curCol)); - } - if (prcdFormulas == null) { - return val; - } - for (int i = 0; i < this.prcdFormulas.size(); i++) { - FormulaPair form = (FormulaPair) this.prcdFormulas.elementAt(i) ; - line = form.singleLine(); - // On 2 Apr 2013, LL discovered the following totally bizarre - // line of code, which inserted copies of "THIS_EXTRA_SPACE_INSERTED" into - // the translation, which of course then didn't parse. Apparently some - // change was made and never tested. The conjuncts being inserted here - // seem to be the fairness formulas for procedures in a fair process. - // - //val.append("\nTHIS_EXTRA_SPACE_INSERTED"); - - // One experiment seems to indicate that the following statement is needed - // to put the first of the procedures' liveness formulas where it belongs. - // However, I don't understand the code so I have no idea what actually - // should be done. LL 2 Apr 2013 - // - if (i == 0) { - val.append("\n") ; - } - val.append(NSpaces(curCol)); - if (curCol + line.length() + 3 <= PcalTLAGen.wrapColumn) { - val.append("/\\ " + line + "\n"); - } else { - val.append(form.multiLine(curCol)); - } - } - return val; - } - - - } -} +package pcal; + +import java.util.Vector; + +import pcal.AST.VarDecl; +import pcal.exception.PcalTLAGenException; +import pcal.exception.TLAExprException; +import tla2tex.Debug; + +/**************************************************************************** + * Given an exploded and disambiguated AST, generate the equivalent TLA+. + * <br> + * {@link PcalTLAGen#generate(AST, PcalSymTab)} returns a vector of Strings, one entry per line of generated TLA+. + * + * @version $Id$ + * @author Leslie Lamport (modified on Thu 6 March 2008 at 10:16:22 PST) + * (minor change on 9 December 2009) + * @author keith (modified on Mon 3 Oct 2005 at 21:43:09 UT) + * + ****************************************************************************/ +public class PcalTLAGen +{ + // Constants that control formatting + public final static boolean boxUnderCASE = true; /* else [] at end of line */ + + // The following two variables made non-final on 9 Dec 2009 so they can + // be set by options. They are initialized in PcalParams.resetParams(). + public static int wrapColumn ; + /* If the line width will be greater than this, then try to wrap */ + public static int ssWrapColumn ; + // I think that this is used as follows: + // when translating an assignment statement (or multiassignment?) + // to var' = [var EXCEPT ...], it begins the ... on a new line + // iff the ... would begin in a column > ssWrapColumn. + // For the time being, it is set to wrapColumn - 33. We may want + // to do something cleverer or else make it a user option. + + // Private class variables + /** The tlacode field accumulates the translation as it is constructed. It + * should be a vector of separate lines. Keiths original implementation put + * multiple lines in a single element of tlacode in: + * + * GenVarsAndDefs + * GenVarDecl + */ + private Vector tlacode = new Vector(); /* of lines */ + + /** + * The tlacodeNextLine field accumulates characters for the next + * line of tlacode. It is always a string. It is assumed that + * when it equals "", then a new line can be started without + * adding the current string in tlacodeNextLine as a new line. + */ + private String tlacodeNextLine = "" ; + + /** + * mappingVector is a local pointer to {@link TLAtoPCalMapping#mappingVector}, + * which is used to accumulate the TLA+ to PlusCal mapping. It approximately + * reflects the TLA+ that has been inserted in the {@link PcalTLAGen#tlacode} + * vector. It is set in the {@link TLAtoPCalMapping#generate} method. + */ + private Vector mappingVector; + + /** + * mappingVectorNextLine contains the sequence of MappingObject objects + * that correspond to the strings added to tlacodeNextLine. + */ + private Vector mappingVectorNextLine = new Vector() ; + + /** + * The self field is set to "self" by GenProcess when called for a single process + * (rather than a process set) and by GenProcedure for a multiprocess algorithm. + * It is set to the process id by GenProcess when called for a single process. + * selfIsSelf is set to true when self is set to "self", and to false when self is + * set to a process id. The self field never seems to be reset to null. + */ + private TLAExpr self = null; // changed by LL on 22 jan 2011 from: private String self = null; /* for current process */ + private boolean selfIsSelf = false; + + private final Vector<String> vars = new Vector<String>(); /* list of all disambiguated vars */ + private Vector pcV = new Vector(); /* sublist of vars of variables representing + procedure parameters and procedure variables */ + private Vector psV = new Vector(); /* sublist of vars local to a process set */ + private PcalSymTab st = null; /* symbol table */ + private boolean mp = false; /* true if multiprocess, else unip */ + private Vector nextStep = new Vector(); /* unparam actions */ // For multiprocess alg, these are the individual (=) processes + private Vector nextStepSelf = new Vector(); /* param actions */ // These are process sets (\in processes) and procedures + // Following added to keep track of the length of the "lbl... == /\ " + // that precedes all the statements in the definition of a label's action + // because Keith screwed up and handled the assignment to the pc different + // from that of all other variables, forgetting that the subscript exp + // in pc[exp] := ... can be multi-line. + private int kludgeToFixPCHandlingBug ; + /** + * The public method: generate TLA+ as a vector of strings. + * @param ast the AST of the PCal + * @param symtab the symbol table + * @return the vector of strings with TLA+ code + * @throws PcalTLAGenException on any unrecoverable methods + */ + + /* + * The string currentProcName is the name of the current process (for a multiprocess algorithm) + * or "Next" for a uniprocess algorithm. When ParseAlgorithm.omitPC is true, this is used + * instead of the label when generating the process's or the entire algorithm's next-state + * action. Thus, with a single label lbl, this generates + * Next == Xlation + * instead of + * lbl == Xlation + * Next == lbl + */ + private String currentProcName ; + + /** + * Generates the translation. + * + * @param ast The AST produced by parsing and exploding. + * @param symtab The symbol table. + * @param report A vector of strings, containing the reports of renaming. + * @return A vector of strings. + * @throws PcalTLAGenException + */ + public Vector<String> generate(AST ast, PcalSymTab symtab, Vector report) throws PcalTLAGenException + { + TLAtoPCalMapping map = PcalParams.tlaPcalMapping; + mappingVector = new Vector<String>(50); + /* + * Add the reports of renaming to the output. + */ + for (int i = 0; i < report.size(); i++) { + addOneLineOfTLA((String) report.elementAt(i)); + } + + st = symtab; + GenSym(ast, ""); + + /* + * We put at the beginning and end of mappingVector a LeftParen + * and RightParen with location (0, 0), so that location will + * be found by the TLA+ to PCal translation algorithm if the + * user selects the entire algorithm, in which case it will + * return the null region to GotoPCalSourceHandler.execute. + */ + PCalLocation ZeroLocation = new PCalLocation(0, 0); + ((Vector) mappingVector.elementAt(0)). + add(0, new MappingObject.LeftParen(ZeroLocation)); + Vector lastLine = (Vector) mappingVector.elementAt(mappingVector.size()-1); + lastLine.add(lastLine.size(), new MappingObject.RightParen(ZeroLocation)); + + /* + * For testing, throw a null pointer exception if the parentheses are not + * properly matching in mappingVector. + */ + //int[] depths = new int[10000]; + + int parenDepth = 0; + for (int i = 0; i < mappingVector.size(); i++) { + Vector line = (Vector) mappingVector.elementAt(i); + for (int j = 0; j < line.size(); j++) { + MappingObject obj = (MappingObject) line.elementAt(j); + if (obj.getType() == MappingObject.LEFT_PAREN) { + parenDepth++; + } + else if (obj.getType() == MappingObject.RIGHT_PAREN) { + parenDepth--; + if (parenDepth < 0) { + throw new NullPointerException("paren depth < 0"); + } + } + } + // depths[i] = parenDepth; + } + if (parenDepth != 0) { + throw new NullPointerException("Unmatched Left Paren"); + } + /* ------------------ end testing --------------------------*/ + Vector nonredundantMappingVector = + TLAtoPCalMapping.RemoveRedundantParens(mappingVector); + map.makeMapping(nonredundantMappingVector); + +//System.out.println("Original mappingvector:"); +//MappingObject.printMappingVector(mappingVector); +//System.out.println("RemoveRedundantParens(mappingVector)"); +//MappingObject.printMappingVector(TLAtoPCalMapping.RemoveRedundantParens(mappingVector)); +//System.out.println("Should be original mappingvector:"); +//MappingObject.printMappingVector(mappingVector); +// Debugging +//for (int i = 0; i < tlacode.size(); i++) { +//System.out.println("\nline " + i); +//System.out.println((String) tlacode.elementAt(i)) ; +//} +//MappingObject.printMappingVector(mappingVector); + + return tlacode; + } + + /****************************************************************/ + /* Returns whether the string is present in a vector of string. */ + /****************************************************************/ + private static boolean InVector(String var, Vector v) + { + for (int i = 0; i < v.size(); i++) + if (var.equals((String) v.elementAt(i))) + return true; + return false; + } + + /******************************************************/ + /* True if var is in the list of procedure variables. */ + /******************************************************/ + private boolean IsProcedureVar(String var) + { + return InVector(var, pcV); + } + + /****************************************************/ + /* True if var is in the list of process variables. */ + /****************************************************/ + private boolean IsProcessSetVar(String var) + { + return InVector(var, psV); + } + + /**********************************************/ + /* Returns a string of length n of all spaces */ + /**********************************************/ + private static String NSpaces(int n) + { + StringBuffer sb = new StringBuffer(); + AddSpaces(sb, n); + return sb.toString(); + } + + /*********************************************/ + /* Appends n spaces to the string buffer sb. */ + /*********************************************/ + private static void AddSpaces(StringBuffer sb, int num) + { + for (int i = 0; i < num; i++) + sb.append(" "); + } + + /****************************************/ + /* True if expr is an empty expression. */ + /****************************************/ + private static boolean EmptyExpr(TLAExpr expr) + { + if (expr == null) + return true; + if (expr.tokens == null || expr.tokens.size() == 0) + return true; + return false; + } + + /*****************************************************************/ + /* Top level routines. Context is "", "procedure", or "process". */ + /** + ****************************************************************/ + private void GenSym(AST ast, String context) throws PcalTLAGenException + { + if (ast.getClass().equals(AST.UniprocessObj.getClass())) + GenUniprocess((AST.Uniprocess) ast, context); + else if (ast.getClass().equals(AST.MultiprocessObj.getClass())) + GenMultiprocess((AST.Multiprocess) ast, context); + else if (ast.getClass().equals(AST.ProcedureObj.getClass())) + GenProcedure((AST.Procedure) ast, context); + else if (ast.getClass().equals(AST.ProcessObj.getClass())) + GenProcess((AST.Process) ast, context); + else if (ast.getClass().equals(AST.LabeledStmtObj.getClass())) + GenLabeledStmt((AST.LabeledStmt) ast, context); + } + + private void GenUniprocess(AST.Uniprocess ast, String context) throws PcalTLAGenException + { + mp = false; + currentProcName = "Next"; + GenVarsAndDefs(ast.decls, ast.prcds, null, ast.defs); + GenInit(ast.decls, ast.prcds, null); + for (int i = 0; i < ast.prcds.size(); i++) + GenProcedure((AST.Procedure) ast.prcds.elementAt(i), ""); + for (int i = 0; i < ast.body.size(); i++) + { + AST.LabeledStmt ls = (AST.LabeledStmt) ast.body.elementAt(i); + /* Add this step to the disjunct of steps */ + nextStep.addElement(ls.label); + GenLabeledStmt(ls, ""); + } + GenNext(); + GenSpec(); + GenTermination(); + } + + private void GenMultiprocess(AST.Multiprocess ast, String context) throws PcalTLAGenException + { + mp = true; + GenVarsAndDefs(ast.decls, ast.prcds, ast.procs, ast.defs); + GenProcSet(); + GenInit(ast.decls, ast.prcds, ast.procs); + for (int i = 0; i < ast.prcds.size(); i++) + GenProcedure((AST.Procedure) ast.prcds.elementAt(i), ""); + for (int i = 0; i < ast.procs.size(); i++) + GenProcess((AST.Process) ast.procs.elementAt(i), ""); + GenNext(); + GenSpec(); + GenTermination(); + } + + private void GenProcedure(AST.Procedure ast, String context) throws PcalTLAGenException { + /* + * First, generate the body's actions. Must set self and selfIsSelf (?) for + * use by GenLabeledStmt. + */ + if (mp) { + + self = selfAsExpr(); // subscript for variables is "self" + selfIsSelf = true; +// /* Add this step to the disjunct of steps with (self) */ + nextStepSelf.addElement(ast.name + "(self)"); + } else + { + /* Add this step to the disjunct of steps */ + nextStep.addElement(ast.name); + } + for (int i = 0; i < ast.body.size(); i++) { + AST.LabeledStmt stmt = (AST.LabeledStmt) ast.body.elementAt(i); + GenLabeledStmt(stmt, "procedure"); + } + + /* + * Next add the definition of the procedure--e.g., + * + * procedureName(self) == label_1(self) \/ ... \/ label_k(self) + * + * We put Left/RightParens for the entire procedure around the entire + * definition, and Left/RightParens around each disjunction for + * the labeled statement. + */ + addLeftParen(ast.getOrigin()); + String argument = (mp) ? "(self)" : ""; + StringBuffer buf = new StringBuffer(ast.name + argument + " == "); + addOneTokenToTLA(buf.toString()); + String indentSpaces = NSpaces(buf.length() + 2); + for (int i = 0; i < ast.body.size(); i++) { + AST.LabeledStmt stmt = (AST.LabeledStmt) ast.body.elementAt(i); + String disjunct = stmt.label + argument; + if ( i != 0 + && tlacodeNextLine.length() + 7 /* the 7 was obtained empirically */ + + disjunct.length() > wrapColumn) { + endCurrentLineOfTLA(); + } + if (i != 0) { + addOneTokenToTLA(((tlacodeNextLine.length() == 0)? indentSpaces : "") + " \\/ "); + } + addLeftParen(stmt.getOrigin()); + addOneTokenToTLA(disjunct); + addRightParen(stmt.getOrigin()); + } + addRightParen(ast.getOrigin()); + addOneLineOfTLA(""); + +// The previous version was very convoluted just to avoid having to go through the +// list of labeled statements twice. It seemed easier to just reimplement from +// scratch. +// /* ns and nsV accumulate the disjunct of the steps of the procedure, where +// * ns contains the contents of the current line and nsV is the vector of +// * already accumulated lines. +// * +// */ +// StringBuffer ns = new StringBuffer(); +// Vector nsV = new Vector(); +// +// int nsC = ast.name.length() + ((mp) ? "(self)".length() : 0) + " == ".length(); +// if (mp) +// { +// self = selfAsExpr(); // subscript for variables is "self" +// selfIsSelf = true; +// /* Add this step to the disjunct of steps with (self) */ +// nextStepSelf.addElement(ast.name + "(self)"); +// } else +// { +// /* Add this step to the disjunct of steps */ +// nextStep.addElement(ast.name); +// } +// for (int i = 0; i < ast.body.size(); i++) +// { +// AST.LabeledStmt stmt = (AST.LabeledStmt) ast.body.elementAt(i); +// if ((ns.length() + stmt.label.length() + " \\/ ".length() + ((mp) ? "(self)".length() : 0)) > wrapColumn +// - nsC - " \\/ ".length()) +// { +// nsV.addElement(ns.toString()); +// ns = new StringBuffer(); +// } +// if (ns.length() > 0) +// ns.append(" \\/ "); +// ns.append(stmt.label); +// if (mp) +// ns.append("(self)"); +// GenLabeledStmt(stmt, "procedure"); +// } +// nsV.addElement(ns.toString()); +// // Generate definition of procedure steps +// ns = new StringBuffer(); +// ns.append(ast.name); +// if (mp) +// ns.append("(self)"); +// ns.append(" == "); +// ns.append((String) nsV.elementAt(0)); +// tlacode.addElement(ns.toString()); +// for (int i = 1; i < nsV.size(); i++) +// { +// ns = new StringBuffer(NSpaces(nsC + 2)); +// ns.append(" \\/ "); +// ns.append((String) nsV.elementAt(i)); +// tlacode.addElement(ns.toString()); +// } +// tlacode.addElement(""); + } + + private void GenProcess(AST.Process ast, String context) throws PcalTLAGenException + { + currentProcName = ast.name; + + /* + * Generate the body's actions. Must set self and selfIsSelf (?) for + * use by GenLabeledStmt. + */ + boolean isSet = true; + /************************************************************/ + /* Decide if it is a process set or not. If so, set self to */ + /* the string "self"; otherwise set self to the process id. */ + /************************************************************/ + if (ast.isEq) + { + self = ast.id ; + selfIsSelf = false; + isSet = false; + } else { + self = selfAsExpr(); + selfIsSelf = true; + } + + if (isSet) + { + nextStepSelf.addElement(ast.name + "(self)"); + } else + nextStep.addElement(ast.name); + + for (int i = 0; i < ast.body.size(); i++) { + AST.LabeledStmt stmt = (AST.LabeledStmt) ast.body.elementAt(i); + GenLabeledStmt(stmt, "process"); + } + + /* + * Next add the definition of the process--e.g., + * + * processName(self) == label_1(self) \/ ... \/ label_k(self) + * + * We put Left/RightParens for the entire procedure around the entire + * definition, and Left/RightParens around each disjunction for + * the labeled statement. + * + * However, we don't add this definition if we are omitting the pc, + * because we have already defined the process name to equal the + * only label action. + */ + + if (! ParseAlgorithm.omitPC) { + addLeftParen(ast.getOrigin()); + String argument = (isSet) ? "(self)" : ""; + StringBuffer buf = new StringBuffer(ast.name + argument + " == "); + addOneTokenToTLA(buf.toString()); + String indentSpaces = NSpaces(buf.length() + 2); + for (int i = 0; i < ast.body.size(); i++) { + AST.LabeledStmt stmt = (AST.LabeledStmt) ast.body.elementAt(i); + String disjunct = stmt.label + argument; + if ( i != 0 + && tlacodeNextLine.length() + 7 /* the 7 was obtained empirically */ + + disjunct.length() > wrapColumn) { + endCurrentLineOfTLA(); + } + if (i != 0) { + addOneTokenToTLA(((tlacodeNextLine.length() == 0)? indentSpaces : "") + " \\/ "); + } + addLeftParen(stmt.getOrigin()); + addOneTokenToTLA(disjunct); + addRightParen(stmt.getOrigin()); + } + addRightParen(ast.getOrigin()); + addOneLineOfTLA(""); + } + + +// As with GenProcedure, the original implementation was quite convoluted, so +// it was rewritten. The code above was copied with modifications from +// the rewritten GenProcedure code. +// /* ns accumulates the disjunt of the steps of the process */ +// StringBuffer ns = new StringBuffer(); +// Vector nsV = new Vector(); +// boolean isSet = true; +// /************************************************************/ +// /* Decide if it is a process set or not. If so, set self to */ +// /* the string "self"; otherwise set self to the process id. */ +// /************************************************************/ +// if (ast.isEq) +// { +// self = ast.id ; +// selfIsSelf = false; +// isSet = false; +// } else { +// self = selfAsExpr(); +// selfIsSelf = true; +// } +// +// int nsC = ast.name.length() + ((isSet) ? "(self)".length() : 0) + " == ".length(); +// if (isSet) +// { +// nextStepSelf.addElement(ast.name + "(self)"); +// } else +// nextStep.addElement(ast.name); +// for (int i = 0; i < ast.body.size(); i++) +// { +// AST.LabeledStmt stmt = (AST.LabeledStmt) ast.body.elementAt(i); +// if ((ns.length() + stmt.label.length() + " \\/ ".length() + ((isSet) ? "(self)".length() : 0)) > wrapColumn +// - nsC - " \\/ ".length()) +// { +// nsV.addElement(ns.toString()); +// ns = new StringBuffer(); +// } +// if (ns.length() > 0) +// ns.append(" \\/ "); +// ns.append(stmt.label); +// if (isSet) +// ns.append("(self)"); +// GenLabeledStmt(stmt, "process"); +// } +// nsV.addElement(ns.toString()); +// // Generate definition of process steps +// // This apparently defines the process name +// // to equal the disjunction of all the individual +// // label-named actions. If we are omitting +// // the pc, we have already defined the process name +// // to equal the only label action, so we skip +// // this. +// if (! ParseAlgorithm.omitPC) { +// ns = new StringBuffer(); +// ns.append(ast.name); +// if (isSet) +// ns.append("(self)"); +// ns.append(" == "); +// ns.append((String) nsV.elementAt(0)); +// tlacode.addElement(ns.toString()); +// for (int i = 1; i < nsV.size(); i++) +// { +// ns = new StringBuffer(NSpaces(nsC + 2)); +// ns.append(" \\/ "); +// ns.append((String) nsV.elementAt(i)); +// tlacode.addElement(ns.toString()); +// } +// } +// tlacode.addElement(""); + } + + /*****************************************************/ + /* Generates an action with name equal to the label. */ + /** + ****************************************************/ + private void GenLabeledStmt(AST.LabeledStmt ast, String context) throws PcalTLAGenException + { + // Set actionName to the name of the action being defined. + // This is the label, except when we are omitting the PC, + // in which case it is "Next" for a uniprocess algorithm + // and the process name for a multiprocess algorithm. + String actionName = ast.label; + if (ParseAlgorithm.omitPC) { + actionName = currentProcName; + } + StringBuffer sb = new StringBuffer(actionName); + /* c is used to determine which vars are in UNCHANGED. */ + Changed c = new Changed(vars); + if (mp && (context.equals("procedure") || selfIsSelf)) { // self.equals("self"))) + sb.append("(self)"); + } + sb.append(" == "); + int col = sb.length(); + kludgeToFixPCHandlingBug = col; + // There's a problem here. If ast.stmts.size() = 1, then we don't preface + // the statement's translation with "/\". However, that means that if we + // then add an UNCHANGED conjunct, we wind up with + // A + // /\ UNCHANGED ... + // where A is the statement's translation. This looks bad and could wind up + // putting the UNCHANGED inside prefix operator--e.g., + // x' = CHOOSE t : ... + // /\ UNCHANGED ... + // This is seems to be a problem only when omitPC = true, since otherwise the + // testing and setting of pc ensures that there is more than one element in ast.stmts. + // What we do is always add the "/\ ", but remove it afterwards if there's only + // a single statement in ast.stmts and there is no UNCHANGED clause. + // The code for doing this is based on the observation that the contents of + // StringBuffer sb begin the next line added to tlacode. + // + /* if (ast.stmts.size() > 1) { */ + sb.append("/\\ "); + kludgeToFixPCHandlingBug = kludgeToFixPCHandlingBug + 3; + /* } */ + + // We set defStartLine to the index of the next line added to tlacode and + // colAfterAnd to the column position in that line immediately following + // the added "/\ ". This gives us the information needed to remove the + // "/\ " later from tlacode. + int defStartLine = tlacode.size(); + int colAfterAnd = sb.length(); + + /* + * Note: it would make sense for this method to insert sb into the tlacode + * output, but it seems safer to maintain the current structure in which + * each GenX for each statement type X does that. + */ + + /* + * We set macroBeginLeft to the macroOriginBegin field of the first statement + * in ast.stmts with a non-null origin, and macroEndRight to the macroOriginEnd + * field of the last statement in ast.stmts with a non-null origin. + */ + PCalLocation macroBeginLeft = null; + PCalLocation macroEndRight = null; + boolean nonNullNotFound = true; + for (int i = 0 ; i < ast.stmts.size(); i++) { + AST stmt = (AST) ast.stmts.elementAt(i); + if (stmt.getOrigin() != null) { + if (nonNullNotFound) { + nonNullNotFound = false; + macroBeginLeft = stmt.macroOriginBegin; + } + macroEndRight = stmt.macroOriginEnd; + } + } + + /* + * addLeftParenV used instead of addLeftParen because if the first statement + * that came from PlusCal code arose from a macro call, then we want the + * location of the macro call rather than that of the macro's code. + */ + addLeftParenV(ast, macroBeginLeft); + for (int i = 0; i < ast.stmts.size(); i++) + { + GenStmt((AST) ast.stmts.elementAt(i), c, context, sb.toString(), sb.length()); + sb = new StringBuffer(NSpaces(col)); + sb.append("/\\ "); + } + + /* + * Since the UNCHANGED conjunct just consists of TLATokens, with no + * SourceTokens, we can just use the old code, simply replacing each + * tlacode.addElement call with a call of addOneLineOfTLA--except that + * the last one is replaced with a call of addOneTokenToTLA so we can + * put the RightParen object in mappingVector. + */ + Vector unc = c.Unchanged(wrapColumn - col - "/\\ UNCHANGED << ".length()); + if (c.NumUnchanged() > 1) + { + sb = new StringBuffer(NSpaces(col)); + sb.append("/\\ UNCHANGED << "); + int here = sb.length(); + sb.append((String) unc.elementAt(0)); + for (int i = 1; i < unc.size(); i++) + { +// tlacode.addElement(sb.toString()); + addOneLineOfTLA(sb.toString()); + sb = new StringBuffer(NSpaces(here)); + sb.append((String) unc.elementAt(i)); + } + sb.append(" >>"); +// tlacode.addElement(sb.toString()); + addOneTokenToTLA(sb.toString()); + } else if (c.NumUnchanged() == 1) { + // Change made by LL on 16 Mar 2011 so that, if there is a single + // unchanged variable v, it produces v' = v if v is a short variable, + // otherwise it produces UNCHANGED v + if (c.Unchanged().length() > 5) { +// tlacode.addElement(NSpaces(col) + "/\\ UNCHANGED " + c.Unchanged()); + addOneTokenToTLA(NSpaces(col) + "/\\ UNCHANGED " + c.Unchanged()); + } else { +// tlacode.addElement(NSpaces(col) + "/\\ " + c.Unchanged() + "' = " +// + c.Unchanged()); + addOneTokenToTLA(NSpaces(col) + "/\\ " + c.Unchanged() + "' = " + + c.Unchanged()); + } + } else { + // No unchanged. If there was only one conjunction, remove it. + // To do that, we must remove the "/\ " and then remove three spaces + // from all other lines that were added. We must also modify the + // TLAToken objects appropriately in the corresponding lines of + // mappingVector + if (ast.stmts.size() == 1) { + for (int i = defStartLine; i < tlacode.size(); i++) { + String line = (String) tlacode.elementAt(i); + if (i == defStartLine) { + // remove the "/\ " added + tlacode.setElementAt(line.substring(0, colAfterAnd-3) + + line.substring(colAfterAnd, line.length()) , i); + shiftMappingVectorTokensLeft(i, colAfterAnd, 3); + + } else { + // Remove three blanks from any following lines. We test the length + // of the line just in case one or more short (hopefully blank) lines + // have been added. + if (line.length() > 3) { + tlacode.setElementAt(line.substring(3, line.length()) , i); + shiftMappingVectorTokensLeft(i, colAfterAnd, 3); + } + } + } + } + } + /* + * We call addRightParenV rather than addRightParen because it the last statement + * that came from the PCal code arose from the expansion of a macro call, then we + * want the RightParen's location to be the end of the call, not the end of the + * macro's code. + */ + addRightParenV(ast, macroEndRight); + addOneLineOfTLA(""); +// tlacode.addElement(""); + } + + /** + * Adjusts the objects in line lineNum of mappingVector so all column + * numbers starting with startCol are decreased by `shift'. If any Begin/EndTLAToken + * pairs are changed to have a non-positive width, a bug is reported. + * + * Note: It is assumed that there is no aliasing of MappingTokens in mappingVector. + * That is, other than in transient local variables, the only pointer to a + * MappingToken in mappingVector is the single one in its line of mappingVector. + * I can't see how any aliasing of MappingTokens could arise. + * + * This method is called only by GenLabeledStmts. + * + * @param lineNum + * @param startCol + * @param shift + */ + private void shiftMappingVectorTokensLeft(int lineNum, int startCol, int shift) { + boolean lastWasBeginTLAToken = false; + int lastBeginTLATokCol = -777; // to keep the compiler happy. + Vector line = (Vector) mappingVector.elementAt(lineNum); + for (int i = 0; i < line.size(); i++) { + MappingObject obj = (MappingObject) line.elementAt(i); + if (obj.getType() == MappingObject.BEGIN_TLATOKEN) { + MappingObject.BeginTLAToken tobj = (MappingObject.BeginTLAToken) obj; + int col = tobj.getColumn(); + if (col >= startCol) { + tobj.setColumn(col - shift); + } + lastWasBeginTLAToken = true; + lastBeginTLATokCol = tobj.getColumn(); + } + else { + if (obj.getType() == MappingObject.END_TLATOKEN) { + MappingObject.EndTLAToken tobj = (MappingObject.EndTLAToken) obj; + int col = tobj.getColumn(); + if (col >= startCol) { + tobj.setColumn(col - shift); + } + if (lastWasBeginTLAToken && tobj.getColumn() <= lastBeginTLATokCol) { + PcalDebug.ReportBug( + "PcalTLAGen.shiftMappingVectorTokensLeft created a null TLA Token"); + } + } + else if (obj.getType() == MappingObject.SOURCE_TOKEN) { + MappingObject.SourceToken tobj = (MappingObject.SourceToken) obj; + int col = tobj.getBeginColumn(); + if (col >= startCol) { + tobj.setBeginColumn(col - shift); + } + col = tobj.getEndColumn(); + if (col >= startCol) { + tobj.setEndColumn(col - shift); + } + + lastWasBeginTLAToken = false; + } + } + } + + + } + + /*************************************************************************** + * LL Comment added 27 Jan 2006: * + * * + * There is a basic flaw in the way GenStmt works. It now generates the * + * output on the fly. This means that * + * * + * - There is no way to avoid the prefix /\ on a one-element conjunct * + * because GenStmt has no way of knowing if there's another conjunct * + * coming. * + * * + * - The handling of the UNCHANGEDs of the THEN and ELSE clauses of * + * an IF is a kludge, because the UNCHANGED of the THEN clause is * + * output before it can be known. * + * * + * The correct way of doing things is to define GenStmt so it returns a * + * sequence (vector) of string vectors, each string vector being a * + * conjunction expression (without a leading /\ or any leading spaces) and * + * the new Changed object (which it can do as it now does by modifying its * + * Changed object argument). It would also be useful to define a * + * GenStmtSeq that simply calls GenStmt iteratively on a sequence of * + * simple statements. The method that calls GenStmtSeq would then add the * + * Unchanged conjunct and call a method that returns a sequence of * + * conjuncts and a prefix into a string vector containing the prefix and * + * the necessary /\s. * + ***************************************************************************/ + + /*****************************************************************/ + /* General entry for generating the TLA+ for a simple statement. */ + /* Prefix is the prefix of the first line. Col is where to start */ + /* subsequent lines (I think we could replace it with the length */ + /* of prefix). */ + /* */ + /* And what on earth are `c' and `context'? LL */ + /** + ****************************************************************/ + private void GenStmt(AST ast, Changed c, String context, String prefix, int col) throws PcalTLAGenException + { + if (ast.getClass().equals(AST.AssignObj.getClass())) + GenAssign((AST.Assign) ast, c, context, prefix, col); + else if (ast.getClass().equals(AST.IfObj.getClass())) + GenIf((AST.If) ast, c, context, prefix, col); + // Either case added by LL on 27 Jan 2006 + else if (ast.getClass().equals(AST.EitherObj.getClass())) + GenEither((AST.Either) ast, c, context, prefix, col); + else if (ast.getClass().equals(AST.WithObj.getClass())) + GenWith((AST.With) ast, c, context, prefix, col); + else if (ast.getClass().equals(AST.WhenObj.getClass())) + GenWhen((AST.When) ast, c, context, prefix, col); + else if (ast.getClass().equals(AST.PrintSObj.getClass())) + GenPrintS((AST.PrintS) ast, c, context, prefix, col); + else if (ast.getClass().equals(AST.AssertObj.getClass())) + GenAssert((AST.Assert) ast, c, context, prefix, col); + else if (ast.getClass().equals(AST.SkipObj.getClass())) + GenSkip((AST.Skip) ast, c, context, prefix, col); + else + PcalDebug.ReportBug("Unexpected AST type " + ast.toString()); + } + + /*****************************************************************/ + /* Generates a sequence of single assigns. Since all of them are */ + /* executed "at the same time", we accumulate the changes in a */ + /* separate Changed cThis, and use c to determine which vars in */ + /* the right hand side are primed. */ + /** + * ***************************************************************/ + + /** + * @param ast + * @param c + * @param context + * @param prefix + * @param col + * @throws PcalTLAGenException + */ + private void GenAssign(AST.Assign ast, Changed c, String context, String prefix, int col) + throws PcalTLAGenException + { + Changed cThis = new Changed(c); + StringBuffer sb = new StringBuffer(); +// Vector vlines = new Vector(); + /* + * Sort the vector ast.ass so that assignments to the same variable + * follow one another. + */ + ast.ass = SortSass(ast.ass); + + addOneTokenToTLA(prefix); + addLeftParen(ast.getOrigin()); + + int i = 0; + int numAssigns = 0; + /* + * hasMultipleVars set true iff the assignment assigns values to + * more than one variable, and hence the statement's translation + * has multiple conjuncts. + */ + boolean hasMultipleVars = false; + while (i < ast.ass.size()) + { + AST.SingleAssign sF = (AST.SingleAssign) ast.ass.elementAt(i); + + /* + * Added by LL and MK on 16 May 2018: + * Report an error if the variable being assigned is not a + * variable declared in the algorithm (either not declared + * at all or is a constant, bound identifier, ...). + */ + if (!this.vars.contains(sF.lhs.var)) { + throw new PcalTLAGenException("Assignment to undeclared variable " + sF.lhs.var, sF); + } + + int iFirst = i; + int iLast = i; + boolean hasAssignmentWithNoSubscript = false; + boolean lastAssignmentHasNoSubscript = EmptyExpr(sF.lhs.sub); + AST.SingleAssign sL = (AST.SingleAssign) ast.ass.elementAt(i); + while (iLast < ast.ass.size() && sF.lhs.var.equals(sL.lhs.var)) + { + if (lastAssignmentHasNoSubscript) { + hasAssignmentWithNoSubscript = true; + } + iLast = iLast + 1; + if (iLast < ast.ass.size()) { + sL = (AST.SingleAssign) ast.ass.elementAt(iLast); + if (EmptyExpr(sL.lhs.sub)) { + lastAssignmentHasNoSubscript = true; + } + } + } + + /* + * If there are assignments to multiple variables, then this sets + * hasMultiplevars true on the first execution of the outer while loop. + */ + if (iLast != ast.ass.size()) { + hasMultipleVars = true; + } + + iLast = iLast - 1; + // All statements from iFirst to iLast are to the same variable + + /* + * Throws an error if there are multiple assignments to the variable + * in different statements, or if there are multiple assignments to + * the variable in this statement and at least one of them has no + * subscript. + */ + if (cThis.Set(sF.lhs.var) > 1 || + (iLast - iFirst > 0 && hasAssignmentWithNoSubscript)) { + /*********************************************************** + * The following was changed by LL on 3 Mar 06 to use * + * AST.location to properly report the location of an * + * error in a line created by expanding a macro. * + * However, it doesn't work very well otherwise. This * + * should be fixed. * + ***********************************************************/ + throw new PcalTLAGenException("Multiple assignment to " + sF.lhs.var, ast /* sF */); + } + numAssigns = numAssigns + 1; + Vector lines = new Vector(); // For collecting generated lines + + if (hasMultipleVars) { + sb.append("/\\ "); + } + if (iFirst == iLast) + { + /* + * This is a single assignment to the variable. + */ + AST.SingleAssign sass = sF; + + addLeftParen(sass.getOrigin()); + TLAExpr sub = AddSubscriptsToExpr(sass.lhs.sub, SubExpr(Self(context)), c); + TLAExpr rhs = AddSubscriptsToExpr(sass.rhs, SubExpr(Self(context)), c); + if (mp + && (sass.lhs.var.equals("pc") || IsProcedureVar(sass.lhs.var) || IsProcessSetVar(sass.lhs.var) || sass.lhs.var + .equals("stack"))) + { + /* Generate single assignment to variable with self subscript */ + sb.append(sass.lhs.var); + sb.append("' = ["); + int wrapCol = sb.length() + 2; + sb.append(sass.lhs.var); + sb.append(" EXCEPT "); + + Vector selfAsSV = self.toStringVector(); + + // The test for selfAsSV size added by LL on 22 Jan 2011 + // because wrapping screws up the kludgeToFixPCHandlingBug + // hack. + if ( (sb.length() + prefix.length() > ssWrapColumn) + && (selfAsSV.size() == 0)) + { +// lines.addElement(sb.toString()); + addOneLineOfTLA(sb.toString()); + sb = new StringBuffer(NSpaces(wrapCol)); + } + sb.append("!["); + addOneTokenToTLA(sb.toString()); + addLeftParen(self.getOrigin()); + addExprToTLA(self); + addRightParen(self.getOrigin()); + +// +// // following code was modified by LL on 22 Jan 2011 as part of +// // fixing bug 11_01_13, which required modifications to handle +// // the case where self is a multi-line formula, which can happen +// // for a "process (P = exp)" when exp is multi-line. +// int here = sb.length(); +// for (int idx = 0; idx < selfAsSV.size(); idx++) { +// if (idx > 0) { +// sb.append("\n"); +// sb.append(NSpaces(here + kludgeToFixPCHandlingBug)); +// } +// sb.append((String) selfAsSV.elementAt(idx)) ; +// } +//// sb.append(self); +// sb.append("]"); +// here = here + ((String) selfAsSV.elementAt(selfAsSV.size()-1)).length() + 1; + addOneTokenToTLA("]"); + Vector sv = sub.toStringVector(); + /***************************************************** + * Was * + * * + * Vector sv = sass.lhs.sub.toStringVector(); * + * * + * Changed by Chi Ho on 3 Aug 2006 to add * + * subscript. See bug_06_08_03. * + *****************************************************/ + if (sv.size() > 0) + { + addLeftParen(sub.getOrigin()); + addExprToTLA(sub); + addRightParen(sub.getOrigin()); + +// sb.append((String) sv.elementAt(0)); +// for (int v = 1; v < sv.size(); v++) +// { +// lines.addElement(sb.toString()); +// sb = new StringBuffer(NSpaces(here)); +// sb.append((String) sv.elementAt(v)); +// } + } + addOneTokenToTLA(" = ");; + addLeftParen(rhs.getOrigin()); + addExprToTLA(rhs); + addRightParen(rhs.getOrigin()); + addOneTokenToTLA("]"); +// sb.append(" = "); +// here = sb.length(); +// sv = rhs.toStringVector(); +// sb.append((String) sv.elementAt(0)); +// for (int v = 1; v < sv.size(); v++) +// { +// lines.addElement(sb.toString()); +// sb = new StringBuffer(NSpaces(here)); +// sb.append((String) sv.elementAt(v)); +// } +// sb.append("]"); +// lines.addElement(sb.toString()); + sb = new StringBuffer(); + } else if (!EmptyExpr(sass.lhs.sub)) + { + /* + * Generate single assignment to variable with no [self] subscript + * but with an explicit subscript. + */ + sb.append(sass.lhs.var); + sb.append("' = ["); + sb.append(sass.lhs.var); + sb.append(" EXCEPT !"); + addOneTokenToTLA(sb.toString()); + addLeftParen(sub.getOrigin()); + addExprToTLA(sub); + addRightParen(sub.getOrigin()); + addOneTokenToTLA(" = "); + addLeftParen(rhs.getOrigin()); + addExprToTLA(rhs); + addRightParen(rhs.getOrigin()); + addOneTokenToTLA("]"); +// +// int here = sb.length(); +// Vector sv = sub.toStringVector(); +// sb.append((String) sv.elementAt(0)); +// for (int v = 1; v < sv.size(); v++) +// { +// lines.addElement(sb.toString()); +// sb = new StringBuffer(NSpaces(here)); +// sb.append((String) sv.elementAt(v)); +// } +// sb.append(" = "); +// here = sb.length(); +// sv = rhs.toStringVector(); +// sb.append((String) sv.elementAt(0)); +// for (int v = 1; v < sv.size(); v++) +// { +// lines.addElement(sb.toString()); +// sb = new StringBuffer(NSpaces(here)); +// sb.append((String) sv.elementAt(v)); +// } +// sb.append("]"); +// lines.addElement(sb.toString()); + sb = new StringBuffer(); + } else + { + /* + * Generate assignment to a variable with no subscript at all. + */ + sb.append(sass.lhs.var); + sb.append("' = "); +// int here = sb.length(); + boolean needsParens = NeedsParentheses(rhs.toStringVector()); + if (needsParens) { + sb.append("("); + } + addOneTokenToTLA(sb.toString()); + addLeftParen(rhs.getOrigin()); + addExprToTLA(rhs); + addRightParen(rhs.getOrigin()); + if (needsParens) { + addOneTokenToTLA(")"); + } + +// Vector sv = Parenthesize(rhs.toStringVector()); +// /******************************************************* +// * Call of Parenthesize added by LL on 27 Feb 2008. * +// * See bug_08-02-18. * +// *******************************************************/ +// for (int v = 0; v < sv.size(); v++) +// { +// sb.append((String) sv.elementAt(v)); +// lines.addElement(sb.toString()); +// sb = new StringBuffer(NSpaces(here)); +// } +// Debugging +//Vector exprVec = rhs.toMappingVector(); +//MappingObject.shiftMappingVector(exprVec, here); +//MappingObject.printMappingVector(exprVec); +//System.out.println("origin: " + rhs.getOrigin().toString() ); + + sb = new StringBuffer(); + } + addRightParen(sass.getOrigin()); + } else + { + /* + * Multiple assignments to the same variable, which must therefore + * each have a user-specified subscript. + */ + AST.SingleAssign sass = sF; + sb.append(sass.lhs.var); + sb.append("' = ["); + sb.append(sass.lhs.var); + sb.append(" EXCEPT "); + int cc = sb.length(); + /* + * If this the first variable, so i = 0, then sb does not contain + * any spaces to compensate for the missing prefix; otherwise it + * does. + */ + if (i == 0) { + cc = cc + prefix.length(); + } + boolean subscript = (mp && (IsProcedureVar(sass.lhs.var) || IsProcessSetVar(sass.lhs.var))); + while (iFirst <= iLast) + { + sass = (AST.SingleAssign) ast.ass.elementAt(iFirst); + TLAExpr sub = AddSubscriptsToExpr(sass.lhs.sub, SubExpr(Self(context)), c); + TLAExpr rhs = AddSubscriptsToExpr(sass.rhs, SubExpr(Self(context)), c); + addLeftParen(sass.getOrigin()); + sb.append("!"); + + // On 21 Jan 2011, LL moved the following statement to below the if + // to correct part 3 of bug_11_01_13. + // +// int here = sb.length(); + if (subscript) { + /* + * This variable has a "self" subscript in addition to its user-specified + * subscript. + */ + sb.append("["); + addOneTokenToTLA(sb.toString()); + TLAExpr self = Self(context); + addLeftParen(self.getOrigin()); + addExprToTLA(self); + addOneTokenToTLA("]"); + +// Vector selfAsSV = Self(context).toStringVector(); +// for (int idx = 0; idx < selfAsSV.size(); idx++) { +// String start = " "; +// if (idx == 0) { +// sb.append("["); +// } else { +// sb.append("\n"); +// sb.append(NSpaces(here + 1)); +// } +// sb.append((String) selfAsSV.elementAt(idx)); +// } +// sb.append("]"); +// here = here + ((String) selfAsSV.elementAt(selfAsSV.size()-1)).length() + 2; + } + else { + addOneTokenToTLA(sb.toString()); + } + + addLeftParen(sub.getOrigin()); + addExprToTLA(sub); + addRightParen(sub.getOrigin()); + addOneTokenToTLA(" = "); + addLeftParen(rhs.getOrigin()); + addExprToTLA(rhs); + addRightParen(rhs.getOrigin()); + addRightParen(sass.getOrigin()); + addOneTokenToTLA((iFirst == iLast) ? "]" : ","); +// Vector sv = sub.toStringVector(); +// if (sv.size() > 0) +// { +// sb.append((String) sv.elementAt(0)); +// for (int v = 1; v < sv.size(); v++) +// { +// lines.addElement(sb.toString()); +// sb = new StringBuffer(NSpaces(here)); +// sb.append((String) sv.elementAt(v)); +// } +// } +// sb.append(" = "); +// here = sb.length(); +// sv = rhs.toStringVector(); +// sb.append((String) sv.elementAt(0)); +// for (int v = 1; v < sv.size(); v++) +// { +// lines.addElement(sb.toString()); +// sb = new StringBuffer(NSpaces(here)); +// sb.append((String) sv.elementAt(v)); +// } +// sb.append(((iFirst == iLast) ? "]" : ",")); +// lines.addElement(sb.toString()); + sb = new StringBuffer(); + if (iFirst < iLast) { + endCurrentLineOfTLA(); + AddSpaces(sb, cc); + } + iFirst = iFirst + 1; + } + } + +// vlines.addElement(lines); + i = iLast + 1; + if (i < ast.ass.size()) { + endCurrentLineOfTLA(); + AddSpaces(sb, prefix.length()); + } + } + addRightParen(ast.getOrigin()); + endCurrentLineOfTLA(); + + c.Merge(cThis); + // Append generated code to tlacode +// sb = new StringBuffer(prefix); +// col = sb.length(); +// if (numAssigns > 1) +// sb.append("/\\ "); +// if (vlines.size() > 0) +// { +// for (int v1 = 0; v1 < vlines.size(); v1++) +// { +// Vector vl = (Vector) vlines.elementAt(v1); +// for (int v2 = 0; v2 < vl.size(); v2++) +// { +// sb.append((String) vl.elementAt(v2)); +// tlacode.addElement(sb.toString()); +// sb = new StringBuffer(NSpaces(col)); +// if ((v1 > 0 || numAssigns > 1) && (v2 != vl.size() - 1)) +// sb.append(" "); +// } +// sb.append("/\\ "); +// } +// } + } + + /** + * Generate TLA+ for if statement. Each branch has its own + * UNCHANGED that lists variables that were changed in the + * other branch. This is a little difficult since we don't + * know the UNCHANGED for the Then branch until the code + * for the Else branch is generated. So, we fix the + * line in the Then branch after the Else branch is done. + * The corresponding mappingVector line also has to be changed, + * but that's not a problem because the UNCHANGED is a TLA+ + * token with no corresponding source. + */ + private void GenIf(AST.If ast, Changed c, String context, String prefix, int col) throws PcalTLAGenException + { + Changed cThen = new Changed(c); + Changed cElse = new Changed(c); + int lineUncThen; + StringBuffer sb = new StringBuffer(prefix); + TLAExpr test = null; + test = AddSubscriptsToExpr(ast.test, SubExpr(Self(context)), c); +// Vector sv = test.toStringVector(); + sb.append("IF "); + int here = sb.length(); + /************************************************************* + * LL removed a bogus "- 1" here on 31 Jan 2006. * + *************************************************************/ + addLeftParen(ast.getOrigin()); + addOneTokenToTLA(sb.toString()); + addExprToTLA(test); + endCurrentLineOfTLA(); + +// sb.append((String) sv.elementAt(0)); +// for (int v = 1; v < sv.size(); v++) +// { +// tlacode.addElement(sb.toString()); +// sb = new StringBuffer(NSpaces(here)); +// sb.append((String) sv.elementAt(v)); +// } +// tlacode.addElement(sb.toString()); + + sb = new StringBuffer(NSpaces(here)); + sb.append("THEN "); + here = sb.length(); + + sb.append("/\\ "); + for (int i = 0; i < ast.Then.size(); i++) + { + GenStmt((AST) ast.Then.elementAt(i), cThen, context, sb.toString(), + /******************************************************************* + * LL added the +3 on 18 Feb 2006 to take account of the * + * indentation of the "IF ". * + *******************************************************************/ + here + 3); + sb = new StringBuffer(NSpaces(here) + "/\\ "); + } + lineUncThen = tlacode.size(); +// tlacode.addElement(sb.toString()); + addOneLineOfTLA(sb.toString()); + sb = new StringBuffer(NSpaces(here - "THEN ".length()) + "ELSE "); + here = sb.length(); + if (ast.Else.size() == 0) + { + sb.append("/\\ TRUE"); +// tlacode.addElement(sb.toString()); + addOneLineOfTLA(sb.toString()); + + sb = new StringBuffer(NSpaces(here) + "/\\ "); + } else + { + sb.append("/\\ "); + for (int i = 0; i < ast.Else.size(); i++) + { + GenStmt((AST) ast.Else.elementAt(i), cElse, context, sb.toString(), + /******************************************************************* + * LL added the +3 on 18 Feb 2006 to take account of the * + * indentation of the "IF ". * + *******************************************************************/ + here + 3); + sb = new StringBuffer(NSpaces(here) + "/\\ "); + } + } + // Generate UNCHANGED for the ELSE branch + if (cElse.NumUnchanged(cThen) > 1) + { + Vector uncElse = cElse.Unchanged(cThen, wrapColumn - sb.length() - "UNCHANGED << ".length()); + sb.append("UNCHANGED << "); + int cc = sb.length(); + sb.append((String) uncElse.elementAt(0)); + for (int i = 1; i < uncElse.size(); i++) + { +// tlacode.addElement(sb.toString()); + addOneLineOfTLA(sb.toString()); + sb = new StringBuffer(NSpaces(cc)); + sb.append((String) uncElse.elementAt(i)); + } + sb.append(" >>"); +// tlacode.addElement(sb.toString()); + addOneTokenToTLA(sb.toString()); + addRightParen(ast.getOrigin()); + endCurrentLineOfTLA(); + } else if (cElse.NumUnchanged(cThen) == 1) + { // Change made by LL on 16 Mar 2011 so that, if there is a single + // unchanged variable v, it produces v' = v if v is a short variable, + // otherwise it produces UNCHANGED v + // + // sb.append("UNCHANGED " + cElse.Unchanged(cThen)); + String uc = cElse.Unchanged(cThen); + if (uc.length() > 5) { + sb.append("UNCHANGED " + uc); + } else { + sb.append(uc + "' = " + uc); + } +// tlacode.addElement(sb.toString()); + addOneTokenToTLA(sb.toString()); + addRightParen(ast.getOrigin()); + endCurrentLineOfTLA(); + } else + { + /* + * There is no UNCHANGED after the ELSE, so we have to put + * the RightParen for the whole if statement at the end of + * the last line already generated + */ + ((Vector) mappingVector.elementAt(mappingVector.size()-1)) + .add(new MappingObject.RightParen(ast.getOrigin().getEnd())); + } + + // Patch up the UNCHANGED for the THEN branch + sb = new StringBuffer((String) tlacode.elementAt(lineUncThen)); + tlacode.removeElementAt(lineUncThen); + mappingVector.removeElementAt(lineUncThen); + if (cThen.NumUnchanged(cElse) > 1) + { + Vector uncThen = cThen.Unchanged(cElse, wrapColumn - sb.length() - "UNCHANGED << ".length()); + sb.append("UNCHANGED << "); + int cc = sb.length(); + sb.append((String) uncThen.elementAt(0)); + for (int i = 1; i < uncThen.size(); i++) + { + tlacode.insertElementAt(sb.toString(), lineUncThen); + + //set the mappingVector entry + mappingVector.insertElementAt(stringToTLATokens(sb.toString()), lineUncThen); + + lineUncThen = lineUncThen + 1; + sb = new StringBuffer(NSpaces(cc)); + sb.append((String) uncThen.elementAt(i)); + } + sb.append(" >>"); + tlacode.insertElementAt(sb.toString(), lineUncThen); + Vector vec = stringToTLATokens(sb.toString()); + + // The following is bogus because the RightParen for the + // entire procedure is inserted after (or instead of) the + // ELSE's UNCHANGED + // vec.add(new MappingObject.RightParen(ast.getOrigin().getEnd())); + + mappingVector.insertElementAt(vec, lineUncThen); + + } else if (cThen.NumUnchanged(cElse) == 1) + { // Change made by LL on 16 Mar 2011 so that, if there is a single + // unchanged variable v, it produces v' = v if v is a short variable, + // otherwise it produces UNCHANGED v + // + // sb.append("UNCHANGED "); + // sb.append(cThen.Unchanged(cElse)); + String uc = cThen.Unchanged(cElse); + if (uc.length() > 5) { + sb.append("UNCHANGED " + uc); + } else { + sb.append(uc + "' = " + uc); + } + tlacode.insertElementAt(sb.toString(), lineUncThen); + Vector vec = stringToTLATokens(sb.toString()); + // The following is bogus because the RightParen for the + // entire procedure is inserted after (or instead of) the + // ELSE's UNCHANGED + // vec.add(new MappingObject.RightParen(ast.getOrigin().getEnd())); + mappingVector.insertElementAt(vec, lineUncThen); + } + + // Merge the change lists together + c.Merge(cThen); + c.Merge(cElse); + } + + /** + * Returns the vector of MappingObjects containing the BeginTLAToken and + * EndTLAToken that are put in the mappingVector by a call of addOneLineOfTLA. + * The code was essentially copied from addOneTokenToTLA. + * + * @param token + * @return + */ + private Vector stringToTLATokens(String token) { + Vector result = new Vector(3); + + String trimmedToken = token.trim() ; + + int numberOfLeftTrimmedTokens = + (trimmedToken.length() == 0) ? -1 : + token.indexOf(trimmedToken.charAt(0)); + + /** + * Handle a token of only space characters. + */ + if (numberOfLeftTrimmedTokens == -1) { + numberOfLeftTrimmedTokens = 0 ; + trimmedToken = token ; + } + + int objBegin = numberOfLeftTrimmedTokens; + result.addElement(new MappingObject.BeginTLAToken(objBegin)); + result.addElement(new MappingObject.EndTLAToken(objBegin + trimmedToken.length())); + return result; + } + + /*********************************************************************** + * Added by LL on 30 Jan 2006. * + * * + * Generate TLA+ for the `either' statement. This performs the same * + * sort of hackery as for the `if' statement, necessitated by the * + * design flaw commented on above. + ** + ***********************************************************************/ + private void GenEither(AST.Either ast, Changed c, String context, String prefix, int col) + throws PcalTLAGenException + { + Changed allC = new Changed(c); + /******************************************************************* + * Accumulates the variable changes of all the clauses. * + *******************************************************************/ + Changed[] cOrs = new Changed[ast.ors.size()]; + /******************************************************************* + * cOrs[i] is the Changed vector for the i-th `or' clause. * + *******************************************************************/ + int[] ucLocs = new int[ast.ors.size()]; // location of unchangeds. + /****************************************************************** + * tlaout.elementAt(ucLocs[i]) is the UNCHANGED clause for the * + * i-th `or' clause. * + ******************************************************************/ + StringBuffer sb = new StringBuffer(prefix); + int prefixIndent = sb.length(); + sb.append("\\/ "); + int here = sb.length(); + /******************************************************************* + * The number of columns to the left of the code generated for * + * each `or' clause. * + *******************************************************************/ + + /* + * Add the left paren for the statement. + */ + addLeftParen(ast.getOrigin()); + /********************************************************************* + * Produce the output for the clauses, but with a dummy line in * + * place of the UNCHANGED clause, and compute allC, cOrs, and * + * ucLocs. * + *********************************************************************/ + for (int i = 0; i < ast.ors.size(); i++) + { + if (i != 0) + { + sb = new StringBuffer(NSpaces(prefixIndent) + "\\/ "); + } + ; + sb.append("/\\ "); + Vector orClause = (Vector) ast.ors.elementAt(i); + Changed cC = new Changed(c); + for (int j = 0; j < orClause.size(); j++) + { + /*********************************************************** + * On 6 Jun 2010, LL added the "+3" in the following call * + * of GenStmt. This seems to fix a bug which caused * + * * + * either when \/ A * + * \/ B * + * or ... * + * * + * to produce * + * \/ /\ \/ A * + * \/ B * + * \/ ... * + ***********************************************************/ + GenStmt((AST) orClause.elementAt(j), cC, context, sb.toString(), here + 3); + sb = new StringBuffer(NSpaces(here) + "/\\ "); + } + ; + cOrs[i] = cC; + allC.Merge(cC); + ucLocs[i] = tlacode.size(); +// tlacode.addElement("Replace by UNCHANGED"); // + addOneLineOfTLA("Replace by UNCHANGED"); + } + ; // End of for i + + /********************************************************************** + * Insert real UNCHANGED clauses. Note that we have to go through * + * loop backwards since we will remove a line of output for each `or' * + * clause that doesn't get an UNCHANGED. * + **********************************************************************/ + int i = ast.ors.size(); + while (i > 0) + { + i = i - 1; + tlacode.removeElementAt(ucLocs[i]); + mappingVector.removeElementAt(ucLocs[i]); + int numUnchanged = cOrs[i].NumUnchanged(allC); + String NotChanged = cOrs[i].Unchanged(allC); + if (numUnchanged > 1) + { + /* + * The line should be wrapped if it's too long. + */ + String line = NSpaces(here) + "/\\ UNCHANGED <<" + NotChanged + ">>"; + tlacode.insertElementAt(line, ucLocs[i]); + mappingVector.insertElementAt(stringToTLATokens(line), ucLocs[i]); + } else if (numUnchanged == 1) + { // Change made by LL on 16 Mar 2011 so that, if there is a single + // unchanged variable v, it produces v' = v if v is a short variable, + // otherwise it produces UNCHANGED v + // + // tlacode.insertElementAt(NSpaces(here) + "/\\ UNCHANGED " + NotChanged, ucLocs[i]); + if (NotChanged.length() > 5) { + String line = NSpaces(here) + "/\\ UNCHANGED " + NotChanged; + tlacode.insertElementAt(line, ucLocs[i]); + mappingVector.insertElementAt(stringToTLATokens(line), ucLocs[i]); +// tlacode.insertElementAt(NSpaces(here) + "/\\ UNCHANGED " + NotChanged, ucLocs[i]); + } else { + String line = NSpaces(here) + "/\\ " + NotChanged + "' = " + NotChanged; + tlacode.insertElementAt(line, ucLocs[i]); + mappingVector.insertElementAt(stringToTLATokens(line), ucLocs[i]); +// tlacode.insertElementAt(NSpaces(here) + "/\\ " + NotChanged + "' = " +// + NotChanged, ucLocs[i]); + } + } + } + ; + /* + * Add the right paren for the entire statement. + */ + ((Vector) mappingVector.elementAt(mappingVector.size()-1)) + .add(new MappingObject.RightParen(ast.getOrigin().getEnd())); + /********************************************************************** + * Add the statement's unchangeds to c. * + **********************************************************************/ + c.Merge(allC); + } + + private void GenWith(AST.With ast, Changed c, String context, String prefix, int col) throws PcalTLAGenException + { + addLeftParen(ast.getOrigin()); + StringBuffer sb = new StringBuffer(prefix); + TLAExpr exp = AddSubscriptsToExpr(ast.exp, SubExpr(Self(context)), c); +// Vector sv = exp.toStringVector(); + if (ast.isEq) + { + /* generate LET statement */ + sb.append("LET "); + sb.append(ast.var); + sb.append(" == "); + addOneTokenToTLA(sb.toString()); + addLeftParen(exp.getOrigin()); + addExprToTLA(exp); + addRightParen(exp.getOrigin()); +// int here = sb.length(); +// sb.append((String) sv.elementAt(0)); +// for (int v = 1; v < sv.size(); v++) +// { +// tlacode.addElement(sb.toString()); +// sb = new StringBuffer(NSpaces(here)); +// sb.append((String) sv.elementAt(v)); +// } + addOneTokenToTLA(" IN"); + endCurrentLineOfTLA(); +// sb.append(" IN"); +// tlacode.addElement(sb.toString()); + sb = new StringBuffer(NSpaces(col + 2)); + /************************************************************* + * LL changed "col + 4" to "col + 2" here to correct an * + * alignment problem on 31 Jan 2006. * + *************************************************************/ + if (ast.Do.size() > 1) + sb.append("/\\ "); + } else + { + /* generate \E statement */ + sb.append("\\E "); + sb.append(ast.var); + sb.append(" \\in "); + addOneTokenToTLA(sb.toString()); + addLeftParen(exp.getOrigin()); + addExprToTLA(exp); + addRightParen(exp.getOrigin()); +// int here = sb.le + addOneTokenToTLA(":"); + endCurrentLineOfTLA(); +// sb.append(":"); +// tlacode.addElement(sb.toString()); + sb = new StringBuffer(NSpaces(col + 2)); + if (ast.Do.size() > 1) + sb.append("/\\ "); + } + for (int i = 0; i < ast.Do.size(); i++) + { + GenStmt((AST) ast.Do.elementAt(i), c, context, sb.toString(), sb.length()); + sb = new StringBuffer(NSpaces(col + 2) + "/\\ "); + } + // tlacode.addElement(NSpaces(col) + ")"); + + /* + * Add the right paren for the entire statement. + */ + ((Vector) mappingVector.elementAt(mappingVector.size()-1)) + .add(new MappingObject.RightParen(ast.getOrigin().getEnd())); + } + + private void GenWhen(AST.When ast, Changed c, String context, String prefix, int col) throws PcalTLAGenException + { + addOneTokenToTLA(prefix); + +// StringBuffer sb = new StringBuffer(prefix); + TLAExpr exp = AddSubscriptsToExpr(ast.exp, SubExpr(Self(context)), c); + addLeftParen(exp.getOrigin()); + addExprToTLA(exp); + addRightParen(exp.getOrigin()); + endCurrentLineOfTLA(); +// Vector sv = exp.toStringVector(); +// +//// Debugging +////Vector vec = exp.toMappingVector(); +////System.out.println("Original vec:"); +////MappingObject.printMappingVector(vec); +////System.out.println("RemoveRedundantParens(vec)"); +////MappingObject.printMappingVector(TLAtoPCalMapping.RemoveRedundantParens(vec)); +////System.out.println("Should be original mappingvector:"); +////MappingObject.printMappingVector(vec); +// +// sb.append((String) sv.elementAt(0)); +// for (int v = 1; v < sv.size(); v++) +// { +// tlacode.addElement(sb.toString()); +// sb = new StringBuffer(NSpaces(col)); +// sb.append((String) sv.elementAt(v)); +// } +// tlacode.addElement(sb.toString()); + } + + private void GenPrintS(AST.PrintS ast, Changed c, String context, String prefix, int col) + throws PcalTLAGenException + { + StringBuffer sb = new StringBuffer(prefix); + TLAExpr exp = AddSubscriptsToExpr(ast.exp, SubExpr(Self(context)), c); + addLeftParen(ast.getOrigin()); + addOneTokenToTLA(prefix + "PrintT("); + addExprToTLA(exp); + addOneTokenToTLA(")"); + addRightParen(ast.getOrigin()); + endCurrentLineOfTLA(); + +// Vector sv = exp.toStringVector(); +// // The following modified 19 Nov 05 by LL to use PrintT instead of Print +// sb.append("PrintT("); +// sb.append((String) sv.elementAt(0)); +// for (int v = 1; v < sv.size(); v++) +// { +// tlacode.addElement(sb.toString()); +// sb = new StringBuffer(NSpaces(col + "PrintT(".length())); +// sb.append((String) sv.elementAt(v)); +// } +// sb.append(")"); +// tlacode.addElement(sb.toString()); + } + + /********************************************************/ + /* Assert(ast.expr, "Failure of assertion at... ") */ + /** + *******************************************************/ + private void GenAssert(AST.Assert ast, Changed c, String context, String prefix, int col) + throws PcalTLAGenException + { + addLeftParen(ast.getOrigin()); + StringBuffer sb = new StringBuffer(prefix); + StringBuffer sc = new StringBuffer(); + TLAExpr exp = AddSubscriptsToExpr(ast.exp, SubExpr(Self(context)), c); +// Vector sv = exp.toStringVector(); + sb.append("Assert("); + addOneTokenToTLA(sb.toString()); + addLeftParen(exp.getOrigin()); + addExprToTLA(exp); + addRightParen(exp.getOrigin()); + int here = sb.length(); +// sb.append((String) sv.elementAt(0)); +// for (int v = 1; v < sv.size(); v++) +// { +// tlacode.addElement(sb.toString()); +// sb = new StringBuffer(NSpaces(col + "Assert(".length())); +// sb.append((String) sv.elementAt(v)); +// } +// sb.append(", "); + sb = new StringBuffer(", "); + sc.append("\"Failure of assertion at "); + sc.append(ast.location()); + // modified on 23 Mar 2006 by LL to use location() instead of + // ast.line and ast.col + sc.append(".\")"); + if (tlacodeNextLine.length() + sb.length() + sc.length() < wrapColumn) { + addOneTokenToTLA(sb.toString() + sc.toString()); + } +// if (sb.length() + sc.length() < wrapColumn) +// tlacode.addElement(sb.toString() + sc.toString()); + else + { + addOneTokenToTLA(sb.toString()); + endCurrentLineOfTLA(); + addOneTokenToTLA(NSpaces(here) + sc.toString()); +// tlacode.addElement(sb.toString()); +// tlacode.addElement(NSpaces(here) + sc.toString()); + } + addRightParen(ast.getOrigin()); + endCurrentLineOfTLA(); + } + + /********************************************************/ + /* I generate a TRUE conjunct, which is useless, but so */ + /* is a skip statement. */ + /********************************************************/ + private void GenSkip(AST.Skip ast, Changed c, String context, String prefix, int col) + { +// tlacode.addElement(prefix + "TRUE"); + addOneTokenToTLA(prefix); + addLeftParen(ast.getOrigin()); + addOneTokenToTLA("TRUE"); + addRightParen(ast.getOrigin()); + endCurrentLineOfTLA(); + } + + /*********************************************************************** + * Generate the VARIABLES declaration(s), output the TLA+ "code" from * + * a `define' statement, if any, and generate the definition of * + * `vars'. * + * * + * Method renamed from GenVars and given the defs argument by LL on * + * 25 Jan 2006 to handle the `define' statement. * + ***********************************************************************/ + private void GenVarsAndDefs(Vector globals, Vector procs, Vector processes, TLAExpr defs) + throws PcalTLAGenException + { + /******************************************************************* + * lVars and gVars are vectors of strings, each element being a * + * variable name. They hold the local and global variables, * + * respectively. * + *******************************************************************/ + Vector lVars = new Vector(); + Vector gVars = new Vector(); + + /** + * lVarsSource and gVarsSource are vectors of AST.VarDecl objects that + * generated the elements of lVars and gVars, where PVarDecl objects + * are converted to VarDecl objects. + */ + Vector lVarsSource = new Vector(); + Vector gVarsSource = new Vector(); + + /******************************************************************* + * Set gVars to the global variables, including pc and `stack' if * + * there are procedures, and add these variables to vars. * + *******************************************************************/ + if (globals != null) + for (int i = 0; i < globals.size(); i++) + { + AST.VarDecl decl = (AST.VarDecl) globals.elementAt(i); + gVars.addElement(decl.var); + gVarsSource.addElement(decl); + vars.addElement(decl.var); + } + if (! ParseAlgorithm.omitPC) { + gVars.addElement("pc"); + /** + * For added variables, create a VarDecl with null origin. + */ + AST.VarDecl pcVarDecl = new AST.VarDecl(); + pcVarDecl.var = "pc"; + gVarsSource.addElement(pcVarDecl); + vars.addElement("pc"); + } + if (procs != null && procs.size() > 0) + { + gVars.addElement("stack"); + /** + * For added variables, create a VarDecl with null origin. + */ + AST.VarDecl pcVarDecl = new AST.VarDecl(); + pcVarDecl.var = "stack"; + gVarsSource.addElement(pcVarDecl); + vars.addElement("stack"); + } + /******************************************************************* + * Add local procedure variables to lVars, vars, and pcV. * + *******************************************************************/ + if (procs != null) + for (int i = 0; i < procs.size(); i++) + { + AST.Procedure proc = (AST.Procedure) procs.elementAt(i); + if (proc.params != null) + for (int p = 0; p < proc.params.size(); p++) + { + AST.PVarDecl decl = (AST.PVarDecl) proc.params.elementAt(p); + lVars.addElement(decl.var); + lVarsSource.addElement(decl.toVarDecl()) ; + vars.addElement(decl.var); + pcV.addElement(decl.var); + } + if (proc.decls != null) + for (int p = 0; p < proc.decls.size(); p++) + { + AST.PVarDecl decl = (AST.PVarDecl) proc.decls.elementAt(p); + lVars.addElement(decl.var); + lVarsSource.addElement(decl.toVarDecl()) ; + vars.addElement(decl.var); + pcV.addElement(decl.var); + } + } + + /******************************************************************* + * Add local process variables to lVars, vars, and psV for * + * variables local to process sets. * + *******************************************************************/ + if (processes != null) + for (int i = 0; i < processes.size(); i++) + { + AST.Process proc = (AST.Process) processes.elementAt(i); + if (proc.decls != null) + for (int p = 0; p < proc.decls.size(); p++) + { + AST.VarDecl decl = (AST.VarDecl) proc.decls.elementAt(p); + lVars.addElement(decl.var); + lVarsSource.addElement(decl); + vars.addElement(decl.var); + if (!proc.isEq) + psV.addElement(decl.var); + } + } + + /******************************************************************** + * Add a declaration of the constant defaultInitValue if it is * + * used. (Added by LL on 22 Aug 2007.) * + ********************************************************************/ + if (ParseAlgorithm.hasDefaultInitialization) + { + addOneLineOfTLA("CONSTANT defaultInitValue"); + } + ; + + if (EmptyExpr(defs)) + { + /****************************************************************** + * There is no `define' statement. In this case, generate a * + * single VARIABLES statement and set gVars to vector of all * + * variables. * + ******************************************************************/ + gVars.addAll(lVars); + gVarsSource.addAll(lVarsSource) ; + GenVarDecl(gVars, gVarsSource); + } else + { + /****************************************************************** + * There is a `define' statement. In this case, must declare * + * global and local variables separately. Also, set gVars to * + * vector of all variables. * + ******************************************************************/ + GenVarDecl(gVars, gVarsSource); + addOneLineOfTLA(""); + addOneLineOfTLA("(* define statement *)"); + addExprToTLA(defs); +// Vector sv = defs.toStringVector(); +// for (int i = 0; i < sv.size(); i++) +// { +// tlacode.addElement((String) sv.elementAt(i)); +// } + ; + addOneLineOfTLA(""); + GenVarDecl(lVars, lVarsSource); // to be fixed + gVars.addAll(lVars); + gVarsSource.addAll(lVarsSource); + } + ; + addOneLineOfTLA(""); + + /* + * We check for the unlikely case in which there are no variables. + * Without this check, the Init is not generated but appears in + * the definition of Spec. + */ + if (gVars.size() == 0) { + throw new PcalTLAGenException("The algorithm has no variables."); + } + /******************************************************************* + * Generate definition of var. * + *******************************************************************/ +// StringBuffer var = new StringBuffer("vars == << "); +// StringBuffer curLine = new StringBuffer("vars == << "); + addOneTokenToTLA("vars == << ") ; + int indent = tlacodeNextLine.length(); + for (int i = 0; i < gVars.size(); i++) + { + if (i > 0) + { +// var.append(", "); +// curLine.append(", "); +// tlacodeNextLine = tlacodeNextLine + ", "; + addOneTokenToTLA(", "); + } + ; + String vbl = (String) gVars.elementAt(i); + AST.VarDecl vblDecl = (AST.VarDecl) gVarsSource.elementAt(i); + Region vblOrigin = vblDecl.getOrigin(); +// if (curLine.length() + vbl.length() + 1 > wrapColumn) + if (tlacodeNextLine.length() + vbl.length() + 1 > wrapColumn) + { +// curLine = new StringBuffer("vars == << "); +// var.append("\n" + NSpaces("vars == << ".length())); + endCurrentLineOfTLA(); + tlacodeNextLine = NSpaces(indent); + } +// var.append(vbl); +// curLine.append(vbl); + addOneSourceTokenToTLA(vbl, vblOrigin); + } +// if (curLine.length() + " >>".length() + 1 > wrapColumn) + if (tlacodeNextLine.length() + " >>".length() + 1 > wrapColumn) + { +// var.append("\n" + NSpaces("vars ==".length())); + endCurrentLineOfTLA() ; + tlacodeNextLine = NSpaces("vars ==".length()); + } + ; +// var.append(" >>"); +// tlacodeNextLine = tlacodeNextLine + " >>"; + addOneTokenToTLA(" >>"); +// tlacode.addElement(var.toString()); + addOneLineOfTLA(""); + } + + /** + * Generate a VARIABLE(S) declarations. The varVec argument is a vector of + * strings that are the variables to be declared. It does nothing if + * the vector has length 0. The varVecSource argument is a vector + * of the same size as varVec that contains the AST.VarDecl objects. + * <p> + * Method added by LL on 25 Jan 2006. + * + * Modified 16 Dec 2011 to add varVecSource argument and generate TLA to + * PCal mapping. + * + * @param varVec A vector of strings. + * + * @param varVecSource A vector of AST.VarDecl objects. + */ + public void GenVarDecl(Vector varVec, Vector varVecSource) + { +// StringBuffer res = new StringBuffer(); +// StringBuffer curLine = new StringBuffer("VARIABLES "); + // for measuring length + if (varVec.size() == 0) + { + return; + } + ; + if (varVec.size() > 1) + { +// res.append("VARIABLES "); + addOneTokenToTLA("VARIABLES "); + } else + { +// res.append("VARIABLE "); + addOneTokenToTLA("VARIABLE "); + } + ; + for (int i = 0; i < varVec.size(); i++) + { + if (i > 0) + { +// res.append(", "); +// curLine.append(", "); + addOneTokenToTLA(", "); + } + ; + String vbl = (String) varVec.elementAt(i); + AST vblsource = (AST) varVecSource.elementAt(i); +// if (curLine.length() + vbl.length() + 1 > wrapColumn) + if (tlacodeNextLine.length() + vbl.length() + 1 > wrapColumn) + { +// curLine = new String + endCurrentLineOfTLA(); + if (varVec.size() > 1) + { +// res.append(NSpaces("VARIABLES ".length())); + tlacodeNextLine = tlacodeNextLine + NSpaces("VARIABLES ".length()); + } else + { +// res.append(NSpaces("VARIABLE ".length())); + tlacodeNextLine = tlacodeNextLine + NSpaces("VARIABLE ".length()); + } + ; + } + ; +// res.append(vbl); +// curLine.append(vbl); + addOneSourceTokenToTLA(vbl, vblsource.getOrigin()); + } + ; +// tlacode.addElement(res.toString()); + endCurrentLineOfTLA(); + } + + /** + * Generates the "ProcSet == ..." output. It is just a union of all the + * process sets, all on one line (except if a process set is a multi-line + * expression). It wouldn't be too hard to break long lines, but that + * should be done later, if desired, after the TLA to PCal translation + * is finished. + */ + public void GenProcSet() + { + StringBuffer ps = new StringBuffer(); + if (st.processes == null || st.processes.size() == 0) + return; +// ps.append("ProcSet == "); + addOneTokenToTLA("ProcSet == "); + for (int i = 0; i < st.processes.size(); i++) + { + PcalSymTab.ProcessEntry proc = (PcalSymTab.ProcessEntry) st.processes.elementAt(i); +// Vector sv = proc.id.toStringVector(); + if (i > 0) { +// ps.append(" \\cup "); + addOneTokenToTLA(" \\cup "); + } + addLeftParen(proc.id.getOrigin()); + if (proc.isEq) { +// ps.append("{"); + addOneTokenToTLA("{"); + } + else { +// ps.append("("); + addOneTokenToTLA("("); + } + int col = ps.length(); +// ps.append((String) sv.elementAt(0)); +// for (int v = 1; v < sv.size(); v++) +// { +// tlacode.addElement(ps.toString()); +// ps = new StringBuffer(NSpaces(col)); +// ps.append((String) sv.elementAt(v)); +// } + addExprToTLA(proc.id); + if (proc.isEq) { +// ps.append("}"); + addOneTokenToTLA("}"); + } + else { +// ps.append(")"); + addOneTokenToTLA(")"); + } + addRightParen(proc.id.getOrigin()); + } +// tlacode.addElement(ps.toString()); +// tlacode.addElement(""); + endCurrentLineOfTLA(); + addOneLineOfTLA(""); + } + + /***********************************/ + /* Generate the Init == statement. */ + /** + **********************************/ + private void GenInit(Vector globals, Vector procs, Vector processes) throws PcalTLAGenException + { + int col = "Init == ".length(); + StringBuffer is = new StringBuffer(); + is.append("Init == "); + + /* Global variables */ + if (globals != null && globals.size() > 0) + { + is.append("(* Global variables *)"); +// tlacode.addElement(is.toString()); + addOneLineOfTLA(is.toString()) ; + is = new StringBuffer(NSpaces(col)); + for (int i = 0; i < globals.size(); i++) + { + AST.VarDecl decl = (AST.VarDecl) globals.elementAt(i); + addVarDeclToTLA(decl, is); + is = new StringBuffer(NSpaces(col)); + } + } + if (procs != null && procs.size() > 0) + { + /* Procedure variables and parameters */ + for (int i = 0; i < procs.size(); i++) + { + AST.Procedure proc = (AST.Procedure) procs.elementAt(i); + if (proc.params.size() == 0 && proc.decls.size() == 0) + // No parameters or procedure variables in this procedure + continue; + is.append("(* Procedure "); + is.append(proc.name); + is.append(" *)"); +// tlacode.addElement(is.toString()); + addOneLineOfTLA(is.toString()); + is = new StringBuffer(NSpaces(col)); + for (int p = 0; p < proc.params.size(); p++) + { + AST.PVarDecl decl = (AST.PVarDecl) proc.params.elementAt(p); + if (!mp) { + addVarDeclToTLA(decl.toVarDecl(), is); + } + else { + is.append("/\\ "); + addOneTokenToTLA(is.toString()); + addLeftParen(decl.getOrigin()); +// is.append(decl.var); + is = new StringBuffer(decl.var); + /******************************************************* + * Modified on 31 Jan 2006 by LL to add subscripts to * + * initialization expression if needed. Also replaced * + * test for "\\in" with assertion that it can't occur, * + * since it's forbidden by the grammar. * + *******************************************************/ + PcalDebug.Assert(decl.isEq); + is.append(" = "); + +// Vector sv; +// if (mp) +// { +// sv = AddSubscriptsToExpr(decl.val, +// SubExpr(Self("procedure")), new Changed(new Vector())) +// .toStringVector(); +// } else +// { +// sv = Parenthesize(decl.val.toStringVector()); +// /************************************************* +// * Call to Parenthesize added by LL on 27 Feb 2008. * +// * See bug_08-02-18. * +// *************************************************/ +// } +// ; +// if (mp) +// { + is.append("[ self \\in ProcSet |-> "); +// } + addOneTokenToTLA(is.toString()); + addLeftParen(decl.val.getOrigin()); + addExprToTLA( + AddSubscriptsToExpr(decl.val, + SubExpr(Self("procedure")), + new Changed(new Vector()))); + addRightParen(decl.val.getOrigin()); + addOneTokenToTLA("]"); + addRightParen(decl.getOrigin()); + endCurrentLineOfTLA(); + +// int col2 = is.length(); +// is.append((String) sv.elementAt(0)); +// for (int v = 1; v < sv.size(); v++) +// { +// tlacode.addElement(is.toString()); +// is = new StringBuffer(NSpaces(col2)); +// is.append((String) sv.elementAt(v)); +// } +// if (mp) +// is.append("]"); +// tlacode.addElement(is.toString()); + } + is = new StringBuffer(NSpaces(col)); + } + for (int p = 0; p < proc.decls.size(); p++) + { + /* + * Note: the following code is identical to the for loop + * code above for procedure variables. (Well done, Keith!) + * I realized this too late to feel like procedurizing it. + */ + AST.PVarDecl decl = (AST.PVarDecl) proc.decls.elementAt(p); + if (!mp) { + addVarDeclToTLA(decl.toVarDecl(), is); + } + else { + is.append("/\\ "); + addOneTokenToTLA(is.toString()); + addLeftParen(decl.getOrigin()); +// is.append(decl.var); + is = new StringBuffer(decl.var); +// is.append("/\\ "); +// is.append(decl.var); + + /******************************************************* + * Modified on 31 Jan 2006 by LL to add subscripts to * + * initialization expression if needed. Also replaced * + * test for "\\in" with assertion that it can't occur, * + * since it's forbidden by the grammar. * + *******************************************************/ + PcalDebug.Assert(decl.isEq); + is.append(" = "); +// Vector sv; +// if (mp) +// { +// sv = AddSubscriptsToExpr(decl.val, SubExpr(Self("procedure")), new Changed(new Vector())) +// .toStringVector(); +// } else +// { +// sv = Parenthesize(decl.val.toStringVector()); +// /************************************************* +// * Call to Parenthesize added by LL on * +// * 27 Feb 2008. See bug_08-02-18. * +// *************************************************/ +// } +// ; +// if (mp) +// { + is.append("[ self \\in ProcSet |-> "); +// } + addOneTokenToTLA(is.toString()); + addLeftParen(decl.val.getOrigin()); + addExprToTLA(AddSubscriptsToExpr( + decl.val, + SubExpr(Self("procedure")), + new Changed(new Vector()))); + addRightParen(decl.val.getOrigin()); + addOneTokenToTLA("]"); + addRightParen(decl.getOrigin()); + endCurrentLineOfTLA(); + +// int col2 = is.length(); +// is.append((String) sv.elementAt(0)); +// for (int v = 1; v < sv.size(); v++) +// { +// tlacode.addElement(is.toString()); +// is = new StringBuffer(NSpaces(col2)); +// is.append((String) sv.elementAt(v)); +// } +// if (mp) +// is.append("]"); +// tlacode.addElement(is.toString()); + } + is = new StringBuffer(NSpaces(col)); + } + } + } + if (processes != null && processes.size() > 0) + { + /* Process variables */ + for (int i = 0; i < processes.size(); i++) + { + AST.Process proc = (AST.Process) processes.elementAt(i); + if (proc.decls.size() == 0) // No variables in this procedure + continue; + is.append("(* Process "); + is.append(proc.name); + is.append(" *)"); +// tlacode.addElement(is.toString()); + addOneLineOfTLA(is.toString()); + is = new StringBuffer(NSpaces(col)); + for (int p = 0; p < proc.decls.size(); p++) + { + /* + * In the comments below, (( and )) represent + * MappingObject.LeftParen and MappingObject.RightParen + * objects. + */ + AST.VarDecl decl = (AST.VarDecl) proc.decls.elementAt(p); + is.append("/\\ "); + /* + * The following adds /\ (( to the TLA+ output. + */ + addOneTokenToTLA(is.toString()); + addLeftParen(decl.getOrigin()); + + + if (proc.isEq) { + /* + * The source is + * + * process (P = S) variables ... v @@ Val + * + * where @@ is either "=" or "\in". The TLA+ output is + * + * /\ (( v @@ (( Val )) )) + */ + is = new StringBuffer(decl.var); + if (decl.isEq) { + is.append(" = "); + } + else { + is.append(" \\in "); + } + addOneTokenToTLA(is.toString()); + addLeftParen(decl.val.getOrigin()); + addExprToTLA(decl.val); + addRightParen(decl.val.getOrigin()); + } + else { + if (decl.isEq) { + /* + * The source is + * + * process (P \in S) variables ... v = Val + * + * The TLA+ output is + * + * /\ (( v = [self \in (( S )) |-> (( ValBar )) ] )) + * + * where ValBar obtained from Val by replacing each + * variable w of the process with w[self]. + */ + is = new StringBuffer(decl.var); + is.append(" = [self \\in "); + addOneTokenToTLA(is.toString()); + addLeftParen(proc.id.getOrigin()); + addExprToTLA(proc.id); + addRightParen(proc.id.getOrigin()); + addOneTokenToTLA(" |-> " ); + addLeftParen(decl.val.getOrigin()); + addExprToTLA(AddSubscriptsToExpr( + decl.val, + SubExpr(Self("procedure")), + new Changed(new Vector()))); + addRightParen(decl.val.getOrigin()); + addOneTokenToTLA("]"); + + } + else { + /* + * The source is + * + * process (P \in S) variables ... v \in Val + * + * The TLA+ output is + * + * /\ (( v \in [ (( S )) -> (( ValBar )) ] )) + * + * where ValBar is obtained from Val by replacing each + * variable w of the process with + * + * w[CHOOSE self \in S : TRUE] + * + * We first set expr to the TLAExpr "CHOOSE self \in S : TRUE". + * (This is Keith's original code.) + */ + TLAExpr subexpr = proc.id.cloneAndNormalize(); + TLAExpr expr = new TLAExpr(); + expr.addLine(); + expr.addToken(new TLAToken("[", 0, TLAToken.BUILTIN)); + expr.addToken(new TLAToken("CHOOSE", 1, TLAToken.BUILTIN)); + expr.addToken(new TLAToken("self", 8, TLAToken.IDENT)); + expr.addToken(new TLAToken("\\in ", 13, TLAToken.BUILTIN)); + expr.normalize(); + expr.setOrigin(subexpr.getOrigin()); // see what this does. + try + { + subexpr.prepend(expr, 1); + expr = new TLAExpr(); + expr.addLine(); + expr.addToken(new TLAToken(":", 0, TLAToken.BUILTIN)); + expr.addToken(new TLAToken("TRUE", 2, TLAToken.BUILTIN)); + expr.addToken(new TLAToken("]", 6, TLAToken.BUILTIN)); + expr.prepend(subexpr, 1); + } catch (TLAExprException e) + { + throw new PcalTLAGenException(e.getMessage()); + } + + /* + * Now we output the TLA+ code. + */ + is = new StringBuffer(decl.var); + is.append(" \\in ["); + addOneTokenToTLA(is.toString()); + addLeftParen(proc.id.getOrigin()); + addExprToTLA(proc.id); + addRightParen(proc.id.getOrigin()); + addOneTokenToTLA(" -> " ); + addLeftParen(decl.val.getOrigin()); + addExprToTLA(AddSubscriptsToExpr( + decl.val, expr, new Changed(new Vector())) ); + addRightParen(decl.val.getOrigin()); + addOneTokenToTLA("]"); + } + } + /* + * This adds the final )) . + */ + addRightParen(decl.getOrigin()); + endCurrentLineOfTLA(); + is = new StringBuffer(NSpaces(col)); + +// everything from here down to the end of the for p loop should be commented out +// is.append(decl.var); +// is = new StringBuffer(decl.var); +// if (decl.isEq) +// is.append(" = "); +// else +// is.append(" \\in "); +// /******************************************************* +// * Modified on 31 Jan 2006 by LL to add subscripts to * +// * initialization expression for process set. Note * +// * tricky subscript that is added in expr for * +// * declaration of form "v \in expr". * +// * * +// * Also modified the whole method of producing the * +// * variable declaration because the original destroyed * +// * the formatting of the expression proc.id, leading * +// * to bad or incorrect formatting if the process id * +// * set expression was not trivial. * +// *******************************************************/ +// Vector sv; +// TLAExpr sve; +// if (proc.isEq) +// { +// /*************************************************** +// * No substitution unless it's a process set. * +// ***************************************************/ +// sve = decl.val; // .toStringVector(); +// } else +// { +// if (decl.isEq) +// { +// /*********************************************** +// * For declaration "v = ...", add subscript * +// * "[self]". * +// ***********************************************/ +// sve = AddSubscriptsToExpr(decl.val, SubExpr(Self("procedure")), new Changed(new Vector())); +// } else +// { +// /************************************************ +// * For declaration "v \in ...", add subscript * +// * "[CHOOSE self \in Process Id Set : TRUE]". * +// * * +// * This weird subscript is needed in the * +// * following weird case: * +// * * +// * process (P \in S) * +// * variable v \in T, w \in R(v) * +// * * +// * This produces the following conjunct in * +// * the initial predicate for w: * +// * * +// * w \in [S -> R(v[CHOOSE self \in S : TRUE])] * +// ************************************************/ +// TLAExpr subexpr = proc.id.cloneAndNormalize(); +// +// TLAExpr expr = new TLAExpr(); +// expr.addLine(); +// expr.addToken(new TLAToken("[", 0, TLAToken.BUILTIN)); +// expr.addToken(new TLAToken("CHOOSE", 1, TLAToken.BUILTIN)); +// expr.addToken(new TLAToken("self", 8, TLAToken.IDENT)); +// expr.addToken(new TLAToken("\\in ", 13, TLAToken.BUILTIN)); +// expr.normalize(); +// +// try +// { +// subexpr.prepend(expr, 1); +// expr = new TLAExpr(); +// expr.addLine(); +// expr.addToken(new TLAToken(":", 0, TLAToken.BUILTIN)); +// expr.addToken(new TLAToken("TRUE", 2, TLAToken.BUILTIN)); +// expr.addToken(new TLAToken("]", 6, TLAToken.BUILTIN)); +// expr.prepend(subexpr, 1); +// } catch (TLAExprException e) +// { +// throw new PcalTLAGenException(e.getMessage()); +// } +// +// sve = AddSubscriptsToExpr(decl.val, expr, new Changed(new Vector())); +// } +// ; +// } +// ; +// TLAExpr expr = new TLAExpr(); +// expr.addLine(); +// if (!proc.isEq) +// { +// expr.addToken(new TLAToken("[", 0, TLAToken.BUILTIN)); +// if (decl.isEq) +// { +// expr.addToken(new TLAToken("self", 1, TLAToken.IDENT)); +// expr.addToken(new TLAToken("\\in ", 6, TLAToken.BUILTIN)); +// } +// ; +// expr.normalize(); +// TLAExpr expr2 = proc.id.cloneAndNormalize(); +// try +// { +// expr2.prepend(expr, 0); +// expr = new TLAExpr(); +// expr.addLine(); +// if (decl.isEq) +// { +// expr.addToken(new TLAToken("|->", 0, TLAToken.BUILTIN)); +// } else +// { +// expr.addToken(new TLAToken("->", 0, TLAToken.BUILTIN)); +// } +// ; +// expr.prepend(expr2, 1); +// sve.prepend(expr, 1); +// } catch (TLAExprException e) +// { +// throw new PcalTLAGenException(e.getMessage()); +// } +// } +// ; +// sv = sve.toStringVector(); +// if (proc.isEq) +// { +// sv = Parenthesize(sv); +// } +// ; +// /***************************************************** +// * Call to Parenthesize added by LL on 27 Feb 2008. * +// * See bug_08-02-18. * +// *****************************************************/ +// int col2 = is.length(); +// is.append((String) sv.elementAt(0)); +// for (int v = 1; v < sv.size(); v++) +// { +// tlacode.addElement(is.toString()); +// is = new StringBuffer(NSpaces(col2)); +// is.append((String) sv.elementAt(v)); +// } +// if (!proc.isEq) +// is.append("]"); +// tlacode.addElement(is.toString()); +// is = new StringBuffer(NSpaces(col)); +// end of section to be commented out + } // end of for p loop. + } + } + + /* stack initial value */ + if (procs != null && procs.size() > 0) + { + if (mp) + is.append("/\\ stack = [self \\in ProcSet |-> << >>]"); + else + is.append("/\\ stack = << >>"); +// tlacode.addElement(is.toString()); + addOneLineOfTLA(is.toString()); + is = new StringBuffer(NSpaces(col)); + } + /* pc initial value */ + if (! ParseAlgorithm.omitPC) { + if (mp) + { + // On 4 May 2012, LL added useCase flag to inhibit adding of CASE for + // a single process or process set. + boolean useCase = st.processes.size() != 1; + if (useCase) { + is.append("/\\ pc = [self \\in ProcSet |-> CASE "); + } else { + is.append("/\\ pc = [self \\in ProcSet |-> "); + } + int colPC = is.length(); + if (boxUnderCASE) + colPC = colPC - 3; + for (int p = 0; p < st.processes.size(); p++) + { + PcalSymTab.ProcessEntry pe = (PcalSymTab.ProcessEntry) st.processes.elementAt(p); + if (useCase) { + is.append("self "); + if (pe.isEq) { + is.append("= "); + // int colExpr = is.length(); + addOneTokenToTLA(is.toString()); + addLeftParen(pe.id.getOrigin()); + addExprToTLA(pe.id); + addRightParen(pe.id.getOrigin()); + + // Vector sv = pe.id.toStringVector(); + // is.append((String) sv.elementAt(0)); + // for (int v = 1; v < sv.size(); v++) + // { + // addOneLineOfTLA(is.toString()); + // // tlacode.addElement(is.toString()); + // is = new StringBuffer(NSpaces(colExpr)); + // is.append((String) sv.elementAt(v)); + // } + } else { + is.append("\\in "); + // int colExpr = is.length(); + // Vector sv = pe.id.toStringVector(); + // is.append((String) sv.elementAt(0)); + // for (int v = 1; v < sv.size(); v++) + // { + // tlacode.addElement(is.toString()); + // is = new StringBuffer(NSpaces(colExpr)); + // is.append((String) sv.elementAt(v)); + // } + addOneTokenToTLA(is.toString()); + addLeftParen(pe.id.getOrigin()); + addExprToTLA(pe.id); + addRightParen(pe.id.getOrigin()); + + } + // is.append(" -> \""); + is = new StringBuffer(" -> \""); + is.append(pe.iPC); + if (p == st.processes.size() - 1) + is.append("\"]"); + else if (!boxUnderCASE) + is.append("\" []"); + else + is.append("\""); + } // end if (useCase) + else { + is.append("\"" + pe.iPC + "\"]"); + } +// tlacode.addElement(is.toString()); + addOneTokenToTLA(is.toString()); + endCurrentLineOfTLA(); + is = new StringBuffer(NSpaces(colPC)); + if (boxUnderCASE && p < st.processes.size() - 1) + is.append("[] "); + } + } else + { + is.append("/\\ pc = \"" + st.iPC + "\""); +// tlacode.addElement(is.toString()); + addOneLineOfTLA(is.toString()); + } + } +// tlacode.addElement(""); + addOneLineOfTLA(""); + } + + /************************************/ + /* Generate the Next == definition. */ + /************************************/ + private void GenNext() + { + // It we are omitting pc and this is a uniprocess + // algorithm, then the definition of Next has + // already been added. + if (ParseAlgorithm.omitPC && !mp) { + return; + } + Vector nextS = new Vector(); + StringBuffer sb = new StringBuffer(); + int max, col; + + // Steps with no parameter + max = wrapColumn - ("Next == \\/ ".length()); + for (int i = 0; i < nextStep.size(); i++) + { + String a = (String) nextStep.elementAt(i); + if (a.length() + " \\/ ".length() + sb.length() > max) + { + nextS.addElement(sb.toString()); + sb = new StringBuffer(); + } + if (sb.length() > 0) + sb.append(" \\/ "); + sb.append(a); + } + if (sb.length() > 0) + nextS.addElement(sb.toString()); + + // Steps with (self) from ProcSet + // These are procedures in a multiprocess algorithm + Vector nextSS = new Vector(); + String nextSSstart = "(\\E self \\in ProcSet: "; + sb = new StringBuffer(); + max = wrapColumn - ("Next == \\/ (\\E self \\in ProcSet: \\/ ".length()); + if (mp && st.procs.size() > 0) + { + for (int i = 0; i < st.procs.size(); i++) + { + PcalSymTab.ProcedureEntry p = (PcalSymTab.ProcedureEntry) st.procs.elementAt(i); + if ((p.name.length() + "(self) \\/ ".length() + sb.length()) > max) + { + nextSS.addElement(sb.toString()); + sb = new StringBuffer(); + } + if (sb.length() > 0) + sb.append(" \\/ "); + sb.append(p.name); + sb.append("(self)"); + } + if (sb.length() > 0) + nextSS.addElement(sb.toString() + ")"); + } + + // Steps with (self) from a set + // These are process sets + Vector nextSSP = new Vector(); // of Vector + if (mp && st.processes.size() > 0) + for (int i = 0; i < st.processes.size(); i++) + { + PcalSymTab.ProcessEntry p = (PcalSymTab.ProcessEntry) st.processes.elementAt(i); + if (p.isEq) + continue; + Vector vec = new Vector(); + sb = new StringBuffer(); + sb.append("(\\E self \\in "); + Vector sv = p.id.toStringVector(); + col = sb.length(); + sb.append((String) sv.elementAt(0)); + for (int j = 1; j < sv.size(); j++) + { + vec.addElement(sb.toString()); + sb = new StringBuffer(NSpaces(col)); + sb.append((String) sv.elementAt(j)); + } + sb.append(": "); + sb.append(p.name); + sb.append("(self))"); + vec.addElement(sb.toString()); + nextSSP.addElement(vec); + } + + // assemble the line from the pieces + sb = new StringBuffer("Next == "); + col = sb.length() + 2; + for (int i = 0; i < nextS.size(); i++) + { + sb.append((String) nextS.elementAt(i)); + addOneLineOfTLA(sb.toString()); +// tlacode.addElement(sb.toString()); + sb = new StringBuffer(NSpaces(col) + " \\/ "); + } + if (nextSS.size() > 0) + { + sb.append(nextSSstart); + int col2 = sb.length(); + if (nextSS.size() > 1) + sb.append(" \\/ "); + for (int i = 0; i < nextSS.size(); i++) + { + sb.append((String) nextSS.elementAt(i)); + addOneLineOfTLA(sb.toString()); +// tlacode.addElement(sb.toString()); + sb = new StringBuffer(NSpaces(col2) + " \\/ "); + } + sb = new StringBuffer(NSpaces(col) + " \\/ "); + } + if (nextSSP.size() > 0) + for (int i = 0; i < nextSSP.size(); i++) + { + Vector v = (Vector) nextSSP.elementAt(i); + for (int j = 0; j < v.size(); j++) + { + String line = (String) v.elementAt(j); + sb.append(line); + addOneLineOfTLA(sb.toString()); +// tlacode.addElement(sb.toString()); + + // The following if case was added by LL on 22 Jan 2011 + // to correct part 1 of bug bug_11_01_13. This bug occurs + // when an "\in" process's set is multi-line and that + // process's next-state action comes immediately after + // the Next == ..., with no " \/ " preceding it. To fix the + // problem, we must add 6 fewer spaces to all lines after + // the first in that process's set than in other such sets. + if ((nextS.size() == 0) && (nextSS.size() == 0) && (i == 0)) { + sb = new StringBuffer(NSpaces(col - 2)); + } else { + sb = new StringBuffer(NSpaces(col + 4)); + } + } + sb = new StringBuffer(NSpaces(col) + " \\/ "); + } + if (! (PcalParams.NoDoneDisjunct || ParseAlgorithm.omitStutteringWhenDone)) + { sb.append("(* Disjunct to prevent deadlock on termination *)"); + addOneLineOfTLA(sb.toString()); +// tlacode.addElement(sb.toString()); + sb = new StringBuffer(NSpaces(col + 4)); + if (mp) + /************************************************************ + * Bug fix by LL on 6 Sep 2007. Added parentheses to * + * change * + * * + * (*) \A self \in ProcSet: ... /\ UNCHANGED vars * + * * + * to * + * * + * (**) (\A self \in ProcSet: ...) /\ UNCHANGED vars * + * * + * thus moving the UNCHANGED vars outside the quantifier. * + * Since self does not appear in UNCHANGED vars, the two * + * expressions are equivalent except when ProcSet is the * + * empty set, in which case (*) equals TRUE and (**) equals * + * UNCHANGED vars. * + ************************************************************/ + sb.append("((\\A self \\in ProcSet: pc[self] = \"Done\") /\\ " + "UNCHANGED vars)"); + else + sb.append("(pc = \"Done\" /\\ UNCHANGED vars)"); + addOneLineOfTLA(sb.toString()); +// tlacode.addElement(sb.toString()); + } ; + addOneLineOfTLA(""); +// tlacode.addElement(""); + } + + /****************************************/ + /* Generate the Spec == ... definition. */ + /****************************************/ + /*********************************************************************** + * The spec can contain the following conjuncts * + * * + * 1. Init /\ [][Next]_vars * + * Always present * + * * + * 2. WF_var(Next) * + * present if (a) The wfNext option is specified, or * + * (b) It is a uniprocess algorithm and one of the * + * options -wf, -sf, -termination is specified. * + * * + * 3. A sequence of process fairness formulas, containing * + * one for each process for which there is a fairness condition. * + * * + * A process has * + * (a) a WF fairness condition iff * + * (i) it is preceded by the keyword "fair" and the -nof * + * option is not specified, or * + * (ii) the -wf option is specified. * + * (b) an SF fairness condition iff it is not preceded * + * by the keyword "fair" and the -sf option is specified. * + * * + * Let P be a process specified by either * + * * + * [fair] process (P = exp) ... * + * [fair] process (P \in exp) ... * + * * + * In the first case we say that P is a single process, in the second * + * that it is a process set. Let * + * * + * - p_1, ... , p_Np be the labels of P modified by "+" * + * * + * - m_1, ... , m_Nm be the set of labels of P modified by "-" * + * * + * - pSelf = IF P is a single process THEN "pname" * + * ELSE "self" * + * * + * - qSelf = IF /\ P is a single process * + * /\ pSelf a multi-line formula * + * THEN "self" * + * ELSE pSelf * + * * + * - pName = IF P is a single process THEN "P" * + * ELSE "P(self)" * + * * + * A process fairness formula is described by the following: * + * * + * XF: * + * either WF or SF depending on P's fairness condition * + * * + * prefix: * + * IF P is a single process * + * THEN IF pSelf a multi-line formula * + * THEN "LET self = pSelf IN" * + * ELSE "" * + * ELSE "\A self \in exp" * + * * + * wfFormula: * + * "XF( (pc[qSelf] \notin {"m_1", ... , "m_Np"}) /\ pName )" * + * * + * sfFormula: * + * if XF = SF * + * then null * + * else if P a single process * + * then "SF_vars(p_1) /\ ... /\ SF_vars(p_Np)" * + * else "SF_vars(p_1(self)) /\ ... * + * /\ SF_vars(p_Np(self))" * + * * + * prcdFormulas: * + * A sequence consisting of the following two formulas for each * + * procedure D called within P. Let * + * * + * - pd_1, ... , pd_Npd be the labels of D modified by "+" * + * - md_1, ... , md_Nmd be the labels of D modified by "-" * + * * + * in the formulas: * + * * + * wfFormula: * + * "XF( (pc[qSelf] \notin {"md_1", ... , "md_Nmd"}) * + * /\ D(qSelf) )" * + * * + * sfFormula: * + * if XF = SF * + * then null * + * else "SF_vars(pd_1(qSelf)) /\ ... * + * /\ SF_vars(pd_Npd(qSelf))" * + * * + * ------- * + * * + * If there is at least one fairness formula, the definition of Spec * + * will be formatted in one of two ways. If there is either a * + * WF_vars(Next) condition or a process fairness formula, then it may * + * be formatted as: * + * * + * Spec == Init /\ [][Next]_vars * + * * + * otherwise, it will be formatted as * + * * + * Spec == /\ Init /\ [][Next]_vars * + * [/\ WF_vars(Next)] * + * /\ F_1 * + * ... * + * /\ F_n * + * * + * where each F_i is a process fairness formulas. * + ***********************************************************************/ + private void GenSpec() + { String safetyFormula = "Init /\\ [][Next]_vars" ; + + if ( PcalParams.FairnessOption.equals("nof") + || (!mp && PcalParams.FairnessOption.equals(""))) { + addOneLineOfTLA("Spec == " + safetyFormula); + addOneLineOfTLA(""); +// tlacode.addElement("Spec == " + safetyFormula ); +// tlacode.addElement(""); + return; + } +//System.out.println("foo |-> " + st.UseThis(PcalSymTab.PROCEDURE, "foo", "")); +//int to = st.FindProc("foo"); +//PcalSymTab.ProcedureEntry pe = +// (PcalSymTab.ProcedureEntry) st.procs.elementAt(to); +//AST.Procedure procAst = pe.ast; + + StringBuffer sb = new StringBuffer("Spec == "); + // Generate the requested fairness conjuncts + + // wfNextConj is either null or " /\ WF_(Next)" + String wfNextConj = null; + if ( PcalParams.FairnessOption.equals("wfNext") + || PcalParams.FairAlgorithm + || (!mp && ( PcalParams.FairnessOption.equals("wf") + || PcalParams.FairnessOption.equals("sf")))) + { + // If uniprocess then wf and sf are the same as wfNext + wfNextConj = " /\\ WF_vars(Next)"; + } + + // Now compute procFairnessFormulas to equal the processes' fairness + // formulas, which is never null but may have zero length. + Vector procFairnessFormulas = new Vector() ; + if (mp) { + for (int i = 0; i < st.processes.size(); i++) { + PcalSymTab.ProcessEntry p = (PcalSymTab.ProcessEntry) st.processes.elementAt(i); + AST.Process pAst = p.ast ; + int fairness = pAst.fairness; + if (fairness != AST.UNFAIR_PROC) { + String xf = (fairness == AST.WF_PROC) ? "WF" : "SF"; + + Vector pSelf = p.id.toStringVector(); + + // makeLetIn is true iff prefix will be LET self == ... IN + boolean makeLetIn = false ; + + String qSelf = "self"; + if (p.isEq) { + if (pSelf.size() > 1) { + makeLetIn = true ; + } else { + qSelf = (String) pSelf.elementAt(0); + } + } + + Vector prefix = new Vector(); + if (makeLetIn || !p.isEq) { + int prefixSize = pSelf.size(); + String prefixBegin; + String prefixEnd; + if (p.isEq) { + prefixBegin = "LET self == "; + prefixEnd = ""; + } else { + prefixBegin = "\\A self \\in "; + prefixEnd = " : "; + } + String padding = NSpaces(prefixBegin.length()); + for (int j = 0; j < prefixSize; j++) { + String line = (String) pSelf.elementAt(j); + if (j == 0) { + line = prefixBegin + line; + } else { + line = padding + line; + } + if (j == prefixSize - 1) { + line = line + prefixEnd; + } + prefix.addElement(line); + } + if (makeLetIn) { + prefix.addElement("IN "); + } + } // end if (makeLetIn || !p.isEq) + + StringBuffer wfSB = new StringBuffer(xf + "_vars("); + if (pAst.minusLabels != null && pAst.minusLabels.size() > 0) { + wfSB.append("(pc["); + wfSB.append(qSelf); + if (pAst.minusLabels.size() == 1) { + wfSB.append("] # \""); + wfSB.append(pAst.minusLabels.elementAt(0)); + wfSB.append("\""); + } else { + wfSB.append("] \\notin {\""); + for (int j = 0; j < pAst.minusLabels.size(); j++) { + wfSB.append(pAst.minusLabels.elementAt(j)); + if (j == pAst.minusLabels.size() - 1) { + wfSB.append("\"}"); + } else { + wfSB.append("\", \""); + } + } + } + wfSB.append(") /\\ "); + } + + String pName = p.name; + if (!p.isEq) { + pName = p.name + "(self)"; + } + wfSB.append(pName); + wfSB.append(")"); + + StringBuffer sfSB = null ; + if ( xf.equals("WF") + && (pAst.plusLabels != null) + && (pAst.plusLabels.size() != 0)) { + sfSB = new StringBuffer() ; + for (int j = 0; j < pAst.plusLabels.size(); j++) { + if (j != 0) { + sfSB.append(" /\\ "); + } + sfSB.append("SF_vars("); + sfSB.append(pAst.plusLabels.elementAt(j)); + if (!p.isEq) { + sfSB.append("(self)"); + } + sfSB.append(")"); + } + } + + Vector prcdFormulas = new Vector(); + Vector procedures = pAst.proceduresCalled; + for (int k = 0; k < procedures.size(); k++) { + String originalName = (String) procedures.elementAt(k); + String name = st.UseThis(PcalSymTab.PROCEDURE, originalName, ""); + int procedureIndex = st.FindProc(name); + PcalSymTab.ProcedureEntry pe = + (PcalSymTab.ProcedureEntry) st.procs.elementAt(procedureIndex); + AST.Procedure prcAst = pe.ast; + + StringBuffer wfPrcSB = new StringBuffer(xf + "_vars("); + if (prcAst.minusLabels != null && prcAst.minusLabels.size() > 0) { + wfPrcSB.append("(pc["); + wfPrcSB.append(qSelf); + if (prcAst.minusLabels.size() == 1) { + wfPrcSB.append("] # \""); + wfPrcSB.append(prcAst.minusLabels.elementAt(0)); + wfPrcSB.append("\""); + } else { + wfPrcSB.append("] \\notin {\""); + for (int j = 0; j < prcAst.minusLabels.size(); j++) { + wfPrcSB.append(prcAst.minusLabels.elementAt(j)); + if (j == prcAst.minusLabels.size() - 1) { + wfPrcSB.append("\"}"); + } else { + wfPrcSB.append("\", \""); + } + } + } + wfPrcSB.append(") /\\ "); + } + + String prcName = pe.name + "(" + qSelf + ")"; + wfPrcSB.append(prcName); + wfPrcSB.append(")"); + + StringBuffer sfPrcSB = null; + if ( xf.equals("WF") + && (prcAst.plusLabels != null) + && (prcAst.plusLabels.size() != 0)) { + sfPrcSB = new StringBuffer() ; + for (int j = 0; j < prcAst.plusLabels.size(); j++) { + if (j != 0) { + sfPrcSB.append(" /\\ "); + } + sfPrcSB.append("SF_vars("); + sfPrcSB.append(prcAst.plusLabels.elementAt(j)); + sfPrcSB.append("(" + qSelf + ")") ; + sfPrcSB.append(")"); + } + } + prcdFormulas.addElement( + new FormulaPair( + wfPrcSB.toString(), + (sfPrcSB == null) ? null : sfPrcSB.toString()) + ) ; + } // end construction of prcdFormulas + + procFairnessFormulas.addElement( + new ProcessFairness( + xf, + prefix, + wfSB.toString(), + (sfSB == null) ? null : sfSB.toString(), + prcdFormulas) + ) ; + } // end if (fairness != AST.UNFAIR_PROC) + } + } // ends construction of procFairnessFormulas + + if (wfNextConj == null && procFairnessFormulas.size() == 0) { + addOneLineOfTLA("Spec == " + safetyFormula); + addOneLineOfTLA(""); +// tlacode.addElement("Spec == " + safetyFormula); +// tlacode.addElement(""); + return; + } + addOneLineOfTLA("Spec == /\\ " + safetyFormula); +// tlacode.addElement("Spec == /\\ " + safetyFormula) ; + int indent = "Spec == /\\ ".length(); + + if (wfNextConj != null) { + addOneLineOfTLA(" /\\ WF_vars(Next)"); +// tlacode.addElement(" /\\ WF_vars(Next)"); + } + for (int i = 0; i < procFairnessFormulas.size(); i++) { + /* + * The original code called format on the fairness formula, which can + * create a string with \n characters embedded. I've just split the + * string into its individual lines and added them to tlacode one at a time. + * However, the current and original code can both produce very long lines + * that could be wrapped. So if this change does make a difference, then + * it would be better to completely rewrite the format method (which is only + * called here). + */ + String str = + " /\\ " + + ((ProcessFairness) procFairnessFormulas.elementAt(i)).format(indent).toString(); + String [] splitStr = str.split("\n"); + for (int j = 0; j < splitStr.length; j++) { + addOneLineOfTLA(splitStr[j]); + } + +// tlacode.addElement( +// " /\\ " + +// ((ProcessFairness) procFairnessFormulas.elementAt(i)).format(indent) +// ); + } + addOneLineOfTLA(""); +// tlacode.addElement(""); + return; + } + + /************************************/ + /* Generate the Termination == */ + /************************************/ + private void GenTermination() + { + // if we're omitting the pc or omitting the stuttering-when-done + // clause of the Next action, then we shouldn't + // generate the Termination definition. + // Check of omitStutteringWhenDone added by LL on 30 Mar 2012. + if (ParseAlgorithm.omitPC || ParseAlgorithm.omitStutteringWhenDone) { + return; + } + StringBuffer sb = new StringBuffer(); + sb.append("Termination == <>("); + if (mp) + sb.append("\\A self \\in ProcSet: pc[self]"); + else + sb.append("pc"); + sb.append(" = \"Done\")"); + addOneLineOfTLA(sb.toString()); + addOneLineOfTLA(""); +// tlacode.addElement(sb.toString()); +// tlacode.addElement(""); + } + + /**********************************************************/ + /* For variables that need subscripts, add the subscript. */ + /* These are pc, stack, procedure variables, procedure */ + /* parameters, and variables defined in process sets. */ + /* Then, add primes to variables that have been changed */ + /* according to c. */ + /* exprn : the original expression. */ + /* sub : the subscript to be added (null if none) */ + /* c : the variables that have been changed (so need to */ + /* be primed. */ + /**********************************************************/ + private TLAExpr AddSubscriptsToExpr(TLAExpr exprn, TLAExpr sub, Changed c) throws PcalTLAGenException + { + /* + * For testing, throw a null pointer exception if the begin/end substitution + * mapping vectors are not properly matching in the returned expression + */ +// int[] depths = new int[1000]; + + int parenDepth = 0; + for (int i = 0; i < exprn.tokens.size(); i++) { + Vector line = (Vector) exprn.tokens.elementAt(i); + for (int j = 0; j < line.size(); j++) { + TLAToken tok = (TLAToken) line.elementAt(j); + parenDepth = parenDepth + tok.getBeginSubst().size() - tok.getEndSubst().size(); + if (parenDepth < 0) { + throw new NullPointerException("argument: begin/end Subst depth negative"); + } + } +// depths[i] = parenDepth; + } + if (parenDepth != 0) { + throw new NullPointerException("argument: Unmatched begin Subst"); + } + /* ------------------ end testing --------------------------*/ + + /* + * We now set stringVec to the sequence of identifiers that occur in exprn + * for which we need to add a subscript or a prime. + */ + Vector exprVec = new Vector(); // the substituting exprs + Vector stringVec = new Vector(); // the substituted ids + TLAExpr expr = exprn.cloneAndNormalize(); // the expression to be returned + + for (int i = 0; i < expr.tokens.size(); i++) + { + Vector tv = (Vector) expr.tokens.elementAt(i); + for (int j = 0; j < tv.size(); j++) + { + TLAToken tok = (TLAToken) tv.elementAt(j); + boolean prime = ((tok.type == TLAToken.IDENT) && c.IsChanged(tok.string)); + boolean subr = (sub != null && (tok.type == TLAToken.ADDED || (mp && (tok.type == TLAToken.IDENT) && (IsProcedureVar(tok.string) || IsProcessSetVar(tok.string))))); + if ((subr || prime) && !InVector(tok.string, stringVec)) + { + stringVec.addElement(tok.string); + TLAExpr exp = new TLAExpr(); + exp.addLine(); + /* + * 15 Dec 2011: The following code added to replace the + * + * exp.addToken(new TLAToken(tok.string, 0, TLAToken.IDENT)); + * + * that is commented out. Note that this change can add a token with + * type ADDED rather than IDENT. I don't think this matters. + */ + TLAToken newTok = tok.Clone() ; + /* + * The new token should inherit nothing from the baggage of tok, whose + * only function is to provide the name + */ + newTok.setBeginSubst(new Vector(2)); + newTok.setEndSubst(new Vector(2)); + newTok.source = null; + newTok.column = 0; + exp.addToken(newTok) ; + // exp.addToken(new TLAToken(tok.string, 0, TLAToken.IDENT)); + if (prime) { + /***************************************************** + * Modified by LL on 30 Aug 2007. The following * + * call to addTokenOffset was originally a call to * + * addToken. See the comments for * + * TLAExpr.addTokenOffset(). * + *****************************************************/ + TLAToken primeTok = new TLAToken("'", 0, TLAToken.BUILTIN, true); + // The following stuff added by LL in Dec 2011 is bogus. The + // token tok is just the first one of many in the exprn with + // the same name for which we want to substitute. The only + // useful data in the token tok is its string. + // + // if (tok.source != null) { + // primeTok.source = + // new Region(tok.source.getEnd(), tok.source.getEnd()); + // } + // if (!subr) { + // primeTok.setEndSubst(tok.getEndSubst()); + // newTok.setEndSubst(new Vector(2)); + // } + exp.addTokenOffset(primeTok, 0); + } + if (subr) + { + TLAExpr subexp = sub.cloneAndNormalize(); + + /* + * We now add the end of the origin of tok to beginSubst + * of the first token of subexp and to endSubst of the + * last token of subexp. This indicates that PCal code + * corresponding to a region of the TLA+ translation that + * includes part of the added subscript and part of the + * original expression is a portion of the source of + * exprn. + */ + // This is bogus, because we are adding the location of where + // the identifier first occurs in exprn to the substitution + // vectors of the expression that's going to be substituted in + // all instances. + // + // if (tok.source != null) { + // PCalLocation endOfTok = tok.source.getEnd(); + // subexp.firstToken().getBeginSubst().add(endOfTok); + // subexp.lastToken().getEndSubst().add(endOfTok); + // } + /* + * However, we do have to move the token's beginSubst and endSubst vectors + * to the first and lasts token of the subscript. Since the + * resulting Parens that they generate should be outside + * the ones generated by the endSubst vectors of the expression, + * we have to add them before that expression's Subst vectors. + * + * No, no! This tok is just giving us the name of the tok that + * we're going to be substituting for in the expression. It is not + * necessarily the one that we're going to substitute for. + */ + // newTok.getEndSubst().addAll(subexp.lastToken().getEndSubst()); + // subexp.lastToken().setEndSubst(newTok.getEndSubst()); + // newTok.setEndSubst(new Vector(2)); + exp.normalize(); + try + { + subexp.prepend(exp, 0); + } catch (TLAExprException e) + { + throw new PcalTLAGenException(e.getMessage()); + } + exp = subexp; + } + /********************************************************** + * Modified by LL on 31 Jan 2006 to comment out the call * + * of MakeExprPretty, since it totally screwed up the * + * formatting when substituting any string containing * + * spaces or multiple lines for a variable. * + **********************************************************/ + // MakeExprPretty(exp); + exprVec.addElement(exp); + } + } + } + if (exprVec.size() > 0) + try + { + expr.substituteForAll(exprVec, stringVec, false); + } catch (TLAExprException e) + { + throw new PcalTLAGenException(e.getMessage()); + } + /* + * For testing, throw a null pointer exception if the begin/end substitution + * mapping vectors are not properly matching in the returned expression + */ +// depths = new int[1000]; + + parenDepth = 0; + for (int i = 0; i < expr.tokens.size(); i++) { + Vector line = (Vector) expr.tokens.elementAt(i); + for (int j = 0; j < line.size(); j++) { + TLAToken tok = (TLAToken) line.elementAt(j); + parenDepth = parenDepth + tok.getBeginSubst().size() - tok.getEndSubst().size(); + if (parenDepth < 0) { + throw new NullPointerException("result: begin/end Subst depth negative"); + } + } +// depths[i] = parenDepth; + } + if (parenDepth != 0) { + throw new NullPointerException("result: Unmatched begin/subst"); + } + /* ------------------ end testing --------------------------*/ + return expr; + } + + /*********************************************************************** + * Given an expression, makes it into a subscript expr. It is called * + * only with argument Self(context), which means that it is called * + * only for a single subscript. * + * * + * If string is null, then returns null. * + * * + * Since this is used only to add "[self]", there is no need to add * + * any REPLACEMENT tokens to the expression. Moreover, the added * + * subscript's tokens have a null source field because they don't come * + * from any PCal code. The new expression is given the same origin as * + * the original one. * + ***********************************************************************/ + private static TLAExpr SubExpr(TLAExpr sub) + { + if (sub != null) + { + TLAExpr expr = sub.cloneAndNormalize(); + // This preserves the origin of the expression + for (int i = 0; i < expr.tokens.size(); i++) { + Vector tokenVec = (Vector) expr.tokens.elementAt(i); + for (int j = 0; j < tokenVec.size(); j++) { + TLAToken tok = (TLAToken) tokenVec.elementAt(j); + tok.column = tok.column + 1; + } + if (i == 0) { + /* + * Set isAppended field of the "[" and "]" to true iff the first + * token of sub has isAppended field true, which should be the + * case iff it is the "self" token. + */ + tokenVec.insertElementAt( + new TLAToken("[", 0, TLAToken.BUILTIN, sub.firstToken().isAppended()), + 0); + } + } + expr.addTokenOffset( + new TLAToken("]", 0, TLAToken.BUILTIN, sub.firstToken().isAppended()), 0); + return expr; + } else { + return null; + } + } + + /*********************************************************/ + /* Gives the string to use when subscripting a variable. */ + /*********************************************************/ + // LL comment: it appears that PcalTLAGen.self is the + // current process id if this is being called in the context + // of a process declared with `process (P = id)'. + private TLAExpr Self(String context) + { + TLAExpr s = null; + if (mp) + { + if (context.equals("procedure")) + s = selfAsExpr(); + else + s = self; + } + return s; + } + + private static TLAExpr selfAsExpr() { + /* + * This is a token that does not correspond to anything in the + * PCal code, so it should have a null source field. + * It has a true isAppended field because it is always appended + * as a subscript to a variable. + */ + TLAToken selfToken = new TLAToken("self", 0, TLAToken.IDENT, true); + Vector tokenVec = new Vector(); + tokenVec.addElement(selfToken); + Vector tokens = new Vector(); + tokens.addElement(tokenVec); + TLAExpr expr = new TLAExpr(tokens); +// expr.anchorTokens = new TLAToken[1]; +// expr.anchorTokens[0] = selfToken; +// expr.anchorTokCol = new int[1]; +// expr.anchorTokCol[0] = 0; + expr.normalize(); + return expr ; + } + /*********************************************************************** + * Comment added by LL: MakeExprPretty should never be called on an * + * expression any part of which was an expression in the input. * + * Fortunately, it is now called only for the expression "[self]", so * + * it is effectively a no-op. * + * Comment added 15 Dec 2011: In fact, it's not called at all. * + ***********************************************************************/ + public static void ObsoleteMakeExprPretty(TLAExpr expr) + { + /********************************************************************* + * Sets columns so this expr looks nice and tight. * + *********************************************************************/ + Vector line; /* Vector of TLAToken */ + boolean spread; + int nextCol = 1; + for (int i = 0; i < expr.tokens.size(); i++) + { + line = (Vector) expr.tokens.elementAt(i); + for (int j = 0; j < line.size(); j++) + { + TLAToken tok = ((TLAToken) line.elementAt(j)); + spread = tok.string.equals("="); + tok.column = nextCol + ((spread) ? 1 : 0); + nextCol = nextCol + tok.getWidth() + ((spread) ? 2 : 0); + } + } + } + + /***********************************************************/ + /* v is a sequence of SingleAssign. Return a vector of the */ + /* same SingleAssign, but sorted in terms of the lhs.var. */ + /***********************************************************/ + private static Vector SortSass(Vector vec) + { + Vector v = (Vector) vec.clone(); + Vector r = new Vector(); // The sorted version of v. + while (v.size() > 0) + { // Good old n^2 insertion sort. + AST.SingleAssign candidate = (AST.SingleAssign) v.elementAt(0); + int indexC = 0; + for (int i = 1; i < v.size(); i++) + { + AST.SingleAssign sass = (AST.SingleAssign) v.elementAt(i); + if (candidate.lhs.var.compareTo(sass.lhs.var) > 0) + { + indexC = i; + candidate = sass; + } + } + r.addElement(candidate); + v.remove(indexC); + } + return r; + } + + /*********************************************************************** + * If vec is a StringVector representing an expression, then this * + * returns the StringVector obtained by parenthesizing the expression * + * if it may need parenthesizing. This is used only to prevent * + * parsing errors when the expression appears immediately to the right * + * of an "=" in the spec. This is a rare situation, so it would be * + * nice to add the parentheses only if really necessary. For now, the * + * parentheses are added if one of the following tokens occur outside * + * parentheses and not inside a string: * + * * + * = * + * # * + * < not followed by < * + * > not followed by > or preceded by = * + * | preceded or followed by - * + * \ not followed by "o" or "X". * + * / followed by "\" * + * * + * Left parentheses are * + * * + * ( [ { << * + * * + * The handling of "\" is a simplifying hack. Lots of operators * + * beginning with "\" like "\/", "\gg" and "\subseteq" have precedence * + * greater than or equal to "=". The only commonly used ones with * + * precedence lower than "=" seem to be "\o" and "\X". It doesn't * + * seem to be worth the bother of checking for the others just to * + * avoid unnecessarily adding the parentheses when those other rare * + * operators are used. * + * * + * Perhaps the one improvement that might be worth making in this * + * procedure is to have it not add parentheses because of "dangerous" * + * operations in an IF clause--for example: * + * * + * IF x < 0 THEN ... * + * * + * This would require considering "IF" to be a left parenthesis and * + * "THEN" to be a right parenthesis. However, that's not trivial to * + * implement because of unlikely things like * + * * + * IFx := 42 ; * + * x := IFx < THENx * + ***********************************************************************/ + private static Vector Parenthesize(Vector vec) + { + /********************************************************************* + * Add the parentheses if necessary. * + *********************************************************************/ + if (NeedsParentheses(vec)) + { + vec.setElementAt("(" + ((String) vec.elementAt(0)), 0); + for (int i = 1; i < vec.size(); i++) + { + vec.setElementAt(" " + ((String) vec.elementAt(i)), i); + } + ; + int curLineNum = vec.size() - 1; + vec.setElementAt(((String) vec.elementAt(curLineNum)) + ")", curLineNum); + } + ; + return vec; + } + + /** + * As part of adding the TLA to PCal translation code, LL removedseparated + * the code that decides if parentheses are needed from the Parenthesize + * method and put it into this method. The Parenthesize method itself + * will not be needed. + */ + public static boolean NeedsParentheses(Vector vec) { + if (vec.size() == 0) + { + return false; + } + ; + /******************************************************************* + * vec shouldn't be empty, but let's not worry about what to do if * + * it is. * + *******************************************************************/ + int curCharNum = 0; + int curLineNum = 0; + int parenDepth = 0; + boolean inString = false; + boolean needParen = false; + while ((curLineNum < vec.size()) && (!needParen)) + { + String curLine = (String) vec.elementAt(0); + while ((curCharNum < curLine.length()) && (!needParen)) + { + char curChar = curLine.charAt(curCharNum); + + if (inString) + { + switch (curChar) { + case '\"': + inString = false; + break; + case '\\': + curCharNum++; + break; + } + ; // end switch + } // end if (inString) + else + { + boolean leftParen = false; + boolean rightParen = false; + boolean mayNeedParen = false; + /*************************************************************** + * Set nextChar to the next character on the line, or ' ' if * + * there is none. * + ***************************************************************/ + char nextChar = ' '; + if (curCharNum < curLine.length() - 1) + { + nextChar = curLine.charAt(curCharNum + 1); + } + switch (curChar) { + case '\"': + inString = true; + break; + case '=': + mayNeedParen = true; + break; + case '#': + mayNeedParen = true; + break; + case '<': + if (nextChar == '<') + { + curCharNum++; + leftParen = true; + } else + { + mayNeedParen = true; + } + ; + break; + case '>': + if (nextChar == '>') + { + curCharNum++; + rightParen = true; + } else + { + mayNeedParen = true; + } + ; + break; + case '|': + if ((nextChar == '-') || ((curCharNum > 0) && (curLine.charAt(curCharNum - 1) == '-'))) + { + mayNeedParen = true; + } + ; + break; + case '\\': + if (!((nextChar == ' ') || (nextChar == 'o') || (nextChar == 'X'))) + { + mayNeedParen = true; + } + ; + break; + case '/': + if (nextChar == '\\') + { + mayNeedParen = true; + } + ; + break; + case '(': + case '[': + case '{': + leftParen = true; + break; + case ')': + case ']': + case '}': + rightParen = true; + break; + } + ; + if (mayNeedParen && (parenDepth == 0)) + { + needParen = true; + } + ; + if (leftParen) + { + parenDepth++; + } + ; + if (rightParen) + { + if (parenDepth == 0) + { + needParen = true; + } + ; + parenDepth--; + } + } + ; // end else ! inString + curCharNum++; + } + ; // end while (curCharNum < curLine.length()) + + if (inString) + { + needParen = true; + } + ; + /***************************************************************** + * If there is an unmatched quote, we might as well stop here. * + *****************************************************************/ + curLineNum++; + curCharNum = 0; + } // end while (curLineNum < vec.size()) + + return needParen; + } + + /* + * The following methods are used to add code to tlacode and add the + * appropriate objects to mappingVector + */ + + /** + * Adds one token to tlacodeNextLine, and adds the appropriate + * Begin/EndTLAToken objects to mappingVectorNextLine. The + * ...TLAToken objects mark a region that excludes beginning and + * ending space characters of token--unless the token has + * only space characters. + * + * @param token + */ + private void addOneTokenToTLA(String token) { + String trimmedToken = token.trim() ; + + int numberOfLeftTrimmedTokens = + (trimmedToken.length() == 0) ? -1 : + token.indexOf(trimmedToken.charAt(0)); + + /** + * Handle a token of only space characters. + */ + if (numberOfLeftTrimmedTokens == -1) { + numberOfLeftTrimmedTokens = 0 ; + trimmedToken = token ; + } + + int objBegin = tlacodeNextLine.length() + numberOfLeftTrimmedTokens; + mappingVectorNextLine.addElement(new MappingObject.BeginTLAToken(objBegin)); + mappingVectorNextLine.addElement(new MappingObject.EndTLAToken(objBegin + trimmedToken.length())); + tlacodeNextLine = tlacodeNextLine + token; + } + + /** + * If region is non-null, then adds string str to the TLA output + * as a SourceToken object with that region. Otherwise, it adds + * it as a TLAToken, with Begin/EndTLAToken objects. + * + * @param str + * @param region + */ + private void addOneSourceTokenToTLA(String str, Region region) { + if (region == null) { + addOneTokenToTLA(str); + return; + } + + int beginCol = tlacodeNextLine.length(); + int endCol = beginCol + str.length(); + mappingVectorNextLine.addElement( + new MappingObject.SourceToken(beginCol, endCol, region)); + tlacodeNextLine = tlacodeNextLine + str; + } + /** + * Adds a complete line of TLA "code" that does not correspond to + * any PlusCal code. Adds Begin/EndTLAToken objects to the mapping + * iff the line does not equal "". + * + * @param line + */ + private void addOneLineOfTLA(String line) { +// temporarily commented out. + if(tlacode.size() != mappingVector.size()) { + PcalDebug.ReportBug("tlacode and mappingVector have different lengths") ; + } +// The following added during testing. +//if(tlacode.size() != mappingVector.size()) { +// System.out.println("tlacode and mappingVector have different lengths"); +//} + endCurrentLineOfTLA(); + if (line.length() == 0) { + mappingVector.addElement(new Vector(2)); + tlacode.addElement(""); + return; + } + addOneTokenToTLA(line); + endCurrentLineOfTLA(); + } + + /** + * If tlacodeNextLine does not equal "", then add it to tlacode + * and add mappingVectorNextLine to mappingVector. If it does equal "", + * don't add any lines, but add any potentially legal leftovers in + * mappingVectorNextLine to the previous line. + */ + private void endCurrentLineOfTLA() { + if (tlacodeNextLine.length() != 0) { + tlacode.addElement(tlacodeNextLine) ; + mappingVector.addElement(mappingVectorNextLine) ; + tlacodeNextLine = ""; + mappingVectorNextLine = new Vector() ; + } + else { + if (mappingVectorNextLine.size() != 0) { + /* + * There's something to go in the mappingVector that doesn't + * accompany any text. It should be one or more RightParen or + * LeftParen objects, (or perhaps, eventually a Break), in which + * case they should be put at the end of the previous mappingVector + * line. Anything else is a mistake. + */ + Vector lastLine = (Vector) mappingVector.elementAt(mappingVector.size()-1); + for (int i = 0; i < mappingVectorNextLine.size(); i++) { + MappingObject obj = (MappingObject) mappingVectorNextLine.elementAt(i); + if (obj.getType() == MappingObject.RIGHT_PAREN || + obj.getType() == MappingObject.LEFT_PAREN|| + obj.getType() == MappingObject.BREAK) { + lastLine.add(obj); + } + else { + PcalDebug.ReportBug("PcalTLAGen.endCurrentLineOfTLA found problem."); + } + mappingVectorNextLine = new Vector() ; + } + } + } + } + + /** + * Adds the expression to tlacode / tlacodeNextLine and its + * mapping to mappingVector / mappingVectorNextLine. It adds + * no space before the expression and leaves the last line of the + * expression (which could be its first line) at the end of + * tlacodeNextLine. + * @param expr + */ + private void addExprToTLA(TLAExpr expr) { + Vector sv = expr.toStringVector() ; + Vector exprMapping = expr.toMappingVector() ; + int indent = tlacodeNextLine.length() ; + int nextLine = 0 ; + if (indent != 0) { + /* + * Need to combine first line of expr with + * tlacodeNextLine. + */ + MappingObject.shiftMappingVector(exprMapping, indent); + tlacodeNextLine = tlacodeNextLine + ((String) sv.elementAt(0)); + mappingVectorNextLine.addAll((Vector) exprMapping.elementAt(0)); + nextLine = 1; + if (sv.size() > 1) { + endCurrentLineOfTLA(); + } + } + if (sv.size() > 1) { + String spaces = NSpaces(indent); + while (nextLine < sv.size()-1) { + tlacode.addElement(spaces + ((String) sv.elementAt(nextLine))); + mappingVector.addElement((Vector) exprMapping.elementAt(nextLine)); + nextLine++ ; + } + tlacodeNextLine = spaces + ((String) sv.elementAt(nextLine)) ; + mappingVectorNextLine = (Vector) exprMapping.elementAt(nextLine); + } + else if (indent == 0){ + /* + * If indent != 0, then we've already added the one-line expression. + */ + tlacodeNextLine = tlacodeNextLine + ((String) sv.elementAt(0)); + mappingVectorNextLine.addAll((Vector) exprMapping.elementAt(0)); + } + } + + /** + * Subroutine of GenInit that adds to the TLA translation the Init conjunct + * corresponding to the VarDecl decl for a global variable and, in a uniprocess + * algorithm for a procedure or process variable It is called with the + * StringBuffer `is' containing the text that precedes the "/\" of the + * conjunct, which will be "Init == " or just spaces. + * + * @param decl + * @param is + */ + private void addVarDeclToTLA(VarDecl decl, StringBuffer is) { + Region origin = decl.getOrigin(); + is.append("/\\ "); + addOneTokenToTLA(is.toString()); + addLeftParen(decl.getOrigin()); +// is.append(decl.var); + is = new StringBuffer(decl.var); + if (decl.isEq) + is.append(" = "); + else + is.append(" \\in "); +// int col2 = is.length(); +// Vector sv = Parenthesize(decl.val.toStringVector()); +// /********************************************************* +// * Call to Parenthesize added by LL on 27 Feb 2008. * +// * See bug_08-02-18. * +// *********************************************************/ +// is.append((String) sv.elementAt(0)); +// for (int v = 1; v < sv.size(); v++) +// { +// tlacode.addElement(is.toString()); +// is = new StringBuffer(NSpaces(col2)); +// is.append((String) sv.elementAt(v)); +// } +// tlacode.addElement(is.toString()); + addOneTokenToTLA(is.toString()); + addLeftParen(decl.val.getOrigin()); + boolean needsParens = NeedsParentheses(decl.val.toStringVector()); + if (needsParens) { + addOneTokenToTLA("("); + } + addExprToTLA(decl.val); + if (needsParens) { + addOneTokenToTLA(")"); + } + addRightParen(decl.val.getOrigin()); + addRightParen(decl.getOrigin()); + endCurrentLineOfTLA(); + } + + /** + * Adds a MappingObject.LeftParen object to the mapping vector + * for the beginning of the Region region, if it's not null. + * @param region + */ + private void addLeftParen(Region region) { + if (region != null) { + mappingVectorNextLine.addElement( + new MappingObject.LeftParen(region.getBegin())); + } + } + + /** + * Adds a MappingObject.LeftParen object to the mapping vector + * for the beginning of the Region region, if it's not null. + * @param region + */ + private void addRightParen(Region region) { + if (region != null) { + mappingVectorNextLine.addElement( + new MappingObject.RightParen(region.getEnd())); + } + } + + /** + * Like addLeftParen(ast.getOrigin()), except that it uses + * loc the location if it is not null. It is called by + * GenLabeledStmt and ast.getOrigin() should never be null. + * However, if it is, then we don't add a Paren; this insures + * that the matching calls of addLeftParenV and addRightParenV + * both either do or don't add a Paren. + * + * @param ast + */ + private void addLeftParenV(AST ast, PCalLocation loc) { + if (ast.getOrigin() == null) { + return; + } + if (loc != null) { + mappingVectorNextLine.addElement( + new MappingObject.LeftParen(loc)); + } + else { + addLeftParen(ast.getOrigin()); + } + } + + /** + * Like addRightParen(ast.getOrigin()), except that it uses + * loc as the location if it is not null. It is called by + * GenLabeledStmt and ast.getOrigin() should never be null. + * However, if it is, then we don't add a Paren; this insures + * that the matching calls of addLeftParenV and addRightParenV + * both either do or don't add a Paren. + * + * @param ast + */ + private void addRightParenV(AST ast, PCalLocation loc) { + if (ast.getOrigin() == null) { + return; + } + if (loc!= null) { + mappingVectorNextLine.addElement( + new MappingObject.RightParen(loc)); + } + else { + addRightParen(ast.getOrigin()); + } + } +/* -------------------------------------------------------------------------- */ + /* + * The following methods and classes of objects are used in GenSpec(). + * See the comments preceding that method above. + */ + + /** + * A FormulaPair should never have wf = null, but might have sf = null. + */ + public static class FormulaPair { + public String wf ; + public String sf ; + + public FormulaPair(String wfVal, String sfVal) { + this.wf = wfVal; + this.sf = sfVal; + } + + /** + * The string wf /\ sf , or just wf if sf is null. + * @return + */ + public String singleLine() { + if (sf == null) { + return wf ; + } + return wf + " /\\ " + sf ; + } + + /** + * The width of the singleLine representation of the + * conjunction of the formlas. + * + * @return + */ + public int singleLineWidth() { + if (sf == null) { + return wf.length() ; + } + return wf.length() + " /\\ ".length() + sf.length() ; + } + + /** + * The representation of the conjunction of the formulas with + * prefix /\s, where the first /\ appears in column col (Java + * numbering), witout any ending "\n" + * + * @return + */ + public String multiLine(int col) { + String val = "/\\ " + wf ; + if (sf == null) { + return val; + } + return val + "\n" + NSpaces(col) + "/\\ " + sf; + } + } + + /** + * Describes a process fairness formula, as described in the comments + * preceding the GetSpec() method above. + * @author lamport + * + */ + public static class ProcessFairness { + public String xf ; // either "WF" or "SF" + public Vector prefix ; + // StringVector either "\A self \in exp : " or + // "LET self == exp \n IN " (note the ending space) or "" + public FormulaPair bodyFormulas ; // fairness conditions for the proc's body + public Vector prcdFormulas ; // fairness conditions for the procedure + + /** + * The constructor + * @param xfVal + * @param prefixVal + * @param bodyWF : can be null if bodySF is also null + * @param bodySF : can be null + * @param prcdVal + */ + public ProcessFairness (String xfVal, Vector prefixVal, String bodyWF, + String bodySF, Vector prcdVal) { + xf = xfVal; + prefix = prefixVal; + bodyFormulas = null ; + if (bodyWF != null) { + bodyFormulas = new FormulaPair(bodyWF, bodySF); + } + prcdFormulas = prcdVal; + } + /** + * The width of the fairness formula written as a "single-line" + * formula. Single-line means that it is not written as a + * conjunction list (with a leading /\). It will actually + * occupy multiple lines if prefix is a multi-line formula. + * + * @return + */ + public int singleLineWidth() { + // Set maxPrefixWidth to length of longest non-final + // line of prefix, width to lenght of final line + int maxPrefixWidth = 0 ; + int width = 0 ; + if (prefix != null && prefix.size() > 0) { + for (int i = 0; i < prefix.size() - 1; i++) { + String line = (String) prefix.elementAt(i); + if (line.length() > maxPrefixWidth) { + maxPrefixWidth = line.length(); + } + String lastLine = (String) prefix.elementAt(prefix.size()-1); + width = lastLine.length(); + } + } + width = width + bodyFormulas.wf.length(); + if (bodyFormulas.sf != null) { + width = width + bodyFormulas.sf.length(); + } + if (prcdFormulas != null) { + for (int i = 0 ; i < prcdFormulas.size(); i++) { + width = width + ((FormulaPair) prcdFormulas.elementAt(i)).singleLineWidth(); + } + } + if (maxPrefixWidth > width) { + return maxPrefixWidth; + } + return width ; + } + + /** + * Returns the prefix as a StringBuffer, assuming it starts + * in column col. That is, all but the first line is indented + * with col spaces, and all but the last line is ended with + * a \n . + * + * @param col + * @return + */ + private StringBuffer prefixAsStringBuffer(int col) { + StringBuffer val = new StringBuffer(); + if (prefix != null && prefix.size() > 0) { + for (int i = 0; i < prefix.size(); i++) { + String line = (String) prefix.elementAt(i); + if (i != 0) { + val.append(NSpaces(col)); + } + val.append(line) ; + if (i != prefix.size()-1) { + val.append("\n") ; + } + } + } + return val; + } + /** + * The process fairness condition written as a single-line formula, + * starting in column col. + * @return + */ + public StringBuffer singleLine(int col) { + StringBuffer val = prefixAsStringBuffer(col); + val.append(bodyFormulas.wf); + if (bodyFormulas.sf != null) { + val.append(" /\\ "); + val.append(bodyFormulas.sf); + } + if (prcdFormulas != null) { + for (int i = 0 ; i < prcdFormulas.size(); i++) { + val.append(" /\\ "); + val.append(((FormulaPair) prcdFormulas.elementAt(i)).singleLine()); + } + } + return val ; + } + + /** + * Returns true iff format(col) should return a single-line version + * of the formula. + * + * @param col + * @return + */ + private boolean fitsAsSingleLine(int col) { + return (col + singleLineWidth() <= PcalTLAGen.wrapColumn) + || (bodyFormulas.sf == null + && (prcdFormulas == null || prcdFormulas.size() == 0)); + } + /** + * The process fairness condition written as a formula that + * begins in column col (Java numbering) and ends with "\n". + * It is formatted to try to extend no further than column + * PcalTLAGen.wrapColumn, but no individual formula is split + * across lines. + * + * @param col + * @return + */ + public StringBuffer format(int col) { + int singleLineWidth = this.singleLineWidth(); + /* + * Return the single-line form if either it fits on the + * line or if it consists of only the wf formula (so it can't + * be put on multiple lines). + */ + if (fitsAsSingleLine(col)) { + return this.singleLine(col); + } + StringBuffer val = prefixAsStringBuffer(col); + int prefixWidth = 0; + if (prefix != null && prefix.size() > 0) { + prefixWidth = ((String) prefix.elementAt(prefix.size()-1)).length(); + } + int curCol = col + prefixWidth; + String line = this.bodyFormulas.singleLine(); + if (curCol + line.length() + 3 <= PcalTLAGen.wrapColumn) { + val.append("/\\ " + line); + } else { + val.append(this.bodyFormulas.multiLine(curCol)); + } + if (prcdFormulas == null) { + return val; + } + for (int i = 0; i < this.prcdFormulas.size(); i++) { + FormulaPair form = (FormulaPair) this.prcdFormulas.elementAt(i) ; + line = form.singleLine(); + // On 2 Apr 2013, LL discovered the following totally bizarre + // line of code, which inserted copies of "THIS_EXTRA_SPACE_INSERTED" into + // the translation, which of course then didn't parse. Apparently some + // change was made and never tested. The conjuncts being inserted here + // seem to be the fairness formulas for procedures in a fair process. + // + //val.append("\nTHIS_EXTRA_SPACE_INSERTED"); + + // One experiment seems to indicate that the following statement is needed + // to put the first of the procedures' liveness formulas where it belongs. + // However, I don't understand the code so I have no idea what actually + // should be done. LL 2 Apr 2013 + // + if (i == 0) { + val.append("\n") ; + } + val.append(NSpaces(curCol)); + if (curCol + line.length() + 3 <= PcalTLAGen.wrapColumn) { + val.append("/\\ " + line + "\n"); + } else { + val.append(form.multiLine(curCol)); + } + } + return val; + } + + + } +} diff --git a/tlatools/src/pcal/PcalTranslate.java b/tlatools/src/pcal/PcalTranslate.java index f77ae608e5b6b8a59a3d769c8c12d68049c0e89d..8a586a35d2352826283c0d12875685846506315e 100644 --- a/tlatools/src/pcal/PcalTranslate.java +++ b/tlatools/src/pcal/PcalTranslate.java @@ -556,6 +556,10 @@ public class PcalTranslate { result1.removeElementAt(result1.size()-1); result1.addAll(ExplodeCallReturn((AST.CallReturn) last, next)); } + else if (last.getClass().equals(AST.CallGotoObj.getClass())) { + result1.removeElementAt(result1.size()-1); + result1.addAll(ExplodeCallGoto((AST.CallGoto) last, next)); + } else if (last.getClass().equals(AST.IfObj.getClass())) { AST.If If = (AST.If) last; Vector p1 = CopyAndExplodeLastStmt(If.Then, next); @@ -1479,4 +1483,18 @@ public class PcalTranslate { result.addElement(UpdatePC(peTo.iPC)); return result; } + + /*********************************************************************** + * Generate sequence of statements corresponding to call followed by a * + * goto. * + ***********************************************************************/ + private static Vector ExplodeCallGoto(AST.CallGoto ast, String next) throws PcalTranslateException { + AST.Call call = new AST.Call(); + call.to = ast.to; + call.args = ast.args; + call.line = ast.line; + call.col = ast.col; + call.setOrigin(ast.getOrigin()); + return ExplodeCall(call, ast.after); + } } diff --git a/tlatools/src/pcal/Translator.java b/tlatools/src/pcal/Translator.java index cc67c5e367341782adf444ac9e95cf9abef90247..5e118d7cb069e2f2148a5de4105b22f29b9c798b 100644 --- a/tlatools/src/pcal/Translator.java +++ b/tlatools/src/pcal/Translator.java @@ -1,64 +1,162 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Simon Zambrowski - initial API and implementation + * Markus Alexander Kuppe - Refactoring + ******************************************************************************/ package pcal; import java.util.List; import java.util.Vector; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import util.ToolIO; /** * Launcher for the PCal Translator for running out-of-the-tool * @author Simon Zambrovski - * @version $Id$ */ public class Translator { - /** - * Resets the Tool IO - */ - public void init() - { - ToolIO.reset(); - ToolIO.setMode(ToolIO.TOOL); + private String output; + + private final String input; + + public Translator(final String anInput, final String[] args) { + this.input = anInput; + ToolIO.reset(); + ToolIO.setMode(ToolIO.TOOL); + PcalParams.resetParams(); + PcalParams.tlaPcalMapping = new TLAtoPCalMapping(); + trans.parseAndProcessArguments(args); + } + + public Translator(final String anInput, final List<String> args) { + this(anInput, args.toArray(new String[args.size()])); } /** * delegates the call to the {@link trans#main()} * @param args + * @return */ -// public int runTranslation(String[] args) - public TLAtoPCalMapping runTranslation(String[] args) - { - init(); -// int status = trans.runMe(args); - TLAtoPCalMapping status = trans.runMe(args); - return status; - } + public boolean translate() { + final Vector<String> in = new Vector<String>(); + final String[] lines = input.split(System.getProperty("line.separator")); + for (String line : lines) { + in.add(line); + } + + final Vector<String> out = trans.runMe(in, PcalParams.tlaPcalMapping); + if (out != null) { + final StringBuffer buf = new StringBuffer(out.size()); + for (String line : out) { + buf.append(line); + buf.append(System.getProperty("line.separator")); + } + output = buf.toString(); + } + + return output != null && PcalParams.tlaPcalMapping != null; + } + + public String getOutput() { + return output; + } + + public boolean hasChanged() { + return !input.equals(output); + } + + public TLAtoPCalMapping getMapping() { + return PcalParams.tlaPcalMapping; + } /** * Retrieves the errors recorded during the execution * @return */ - public List getErrorMessages() - { - String[] messages = ToolIO.getAllMessages(); - Vector errorMessages = new Vector(); - System.out.println("Found " + messages.length + " messages"); - int position; - String cleanMessage = null; - for (int i = 0; i < messages.length; i++) - { - position = messages[i].indexOf(PcalDebug.UNRECOVERABLE_ERROR); - if (position != -1) - { - cleanMessage = messages[i].substring(position, messages[i].length() - PcalDebug.ERROR_POSTFIX.length()); - errorMessages.add(cleanMessage); - } else - { - cleanMessage = messages[i]; - // unknown error format - System.out.println(cleanMessage); - } - } - return errorMessages; - } + public List<Error> getErrors() { + final String[] messages = ToolIO.getAllMessages(); + final Vector<Error> errorMessages = new Vector<Error>(); + for (int i = 0; i < messages.length; i++) { + int position = messages[i].indexOf(PcalDebug.UNRECOVERABLE_ERROR); + if (position != -1) { + errorMessages.add(new Error(messages[i].substring(position, + messages[i].length() - PcalDebug.ERROR_POSTFIX.length()))); + } + } + return errorMessages; + } + + public static class Error { + + private static final String LINE = "line "; + private static final String COLUMN = ", column "; + + private final String error; + + public Error(String anError) { + this.error = anError; + } + + /* (non-Javadoc) + * @see java.lang.Object#toString() + */ + public String toString() { + return error; + } + + public int[] getLocation() { + final int lineStarts = error.indexOf(LINE); + final int lineEnds = error.indexOf(COLUMN); + if (lineStarts != -1 && lineEnds != -1) { + final String line = error.substring(lineStarts + LINE.length(), lineEnds); + /* + * afterColumnString is the substring of message that comes after the first + * occurance of ", column" in message. + */ + final String afterColumnString = error.substring(lineEnds + COLUMN.length()); + // match any number of white spaces followed by the first string of digits. + final Matcher matcher = Pattern.compile("\\s*\\d+").matcher(afterColumnString); + matcher.find(); + // the column string that should be a parsable int + final String column = matcher.group().trim(); + + int lineNumber = -1; + int columnNumber = -1; + try { + lineNumber = Integer.parseInt(line); + } catch (final NumberFormatException e) { + } + try { + columnNumber = Integer.parseInt(column); + } catch (final NumberFormatException e) { + } + return new int[] { lineNumber, columnNumber, lineNumber, columnNumber + 1 }; + } + return new int[] { -1, -1, -1, -1 }; + } + } } diff --git a/tlatools/src/pcal/trans.java b/tlatools/src/pcal/trans.java index 5f872f71bd0ba0e1e612de128207b3e0d4e496ef..31c9fe976e875c0b79d818a1647c81e1966c163a 100644 --- a/tlatools/src/pcal/trans.java +++ b/tlatools/src/pcal/trans.java @@ -10,7 +10,6 @@ import java.io.IOException; import java.io.InputStreamReader; import java.util.Vector; -import pcal.MappingObject.Break; import pcal.exception.FileToStringVectorException; import pcal.exception.ParseAlgorithmException; import pcal.exception.PcalResourceFileReaderException; @@ -18,7 +17,6 @@ import pcal.exception.RemoveNameConflictsException; import pcal.exception.StringVectorToFileException; import pcal.exception.TLCTranslationException; import pcal.exception.UnrecoverableException; -import tla2tex.Debug; import util.ToolIO; /*************************************************************************** @@ -358,7 +356,7 @@ class trans * contents, where inputVec[i] is the string containing the contents * * of line i+1 of the input file. * *********************************************************************/ - Vector inputVec = null; + Vector<String> inputVec = null; try { inputVec = fileToStringVector(PcalParams.TLAInputFile + /* (PcalParams.fromPcalFile ? ".pcal" : */".tla" /*)*/); @@ -374,8 +372,216 @@ class trans * which was not always the case in the aborted version 1.31. * *********************************************************************/ // Vector outputVec = PcalParams.fromPcalFile ? new Vector() : inputVec; - Vector outputVec = inputVec; + final Vector<String> outputVec = runMe(inputVec, mapping); + if (outputVec == null) { + return null; + } + + /********************************************************************* + * For .tla input: * + * Rename the old file by changing its extension from "tla" to "old". * + *********************************************************************/ + // if (!PcalParams.fromPcalFile) + // { + File file; + try + { + file = new File(PcalParams.TLAInputFile + ".old"); + if (file.exists()) + { + file.delete(); + } + ; + file = new File(PcalParams.TLAInputFile + ".tla"); + file.renameTo(new File(PcalParams.TLAInputFile + ".old")); + } catch (Exception e) + { + PcalDebug.reportError("Could not rename input file " + PcalParams.TLAInputFile + ".tla" + " to " + + PcalParams.TLAInputFile + ".old"); +// return exitWithStatus(STATUS_EXIT_WITH_ERRORS); + return null ; // added for testing + } + ; + // } + + /********************************************************************* + * Code from aborted version 1.31. * + * For .pcal input, set outputSuffixLoc and add the rest of the * + * input file to the output. * + *********************************************************************/ + // if (PcalParams.fromPcalFile) + // { + // PcalParams.outputSuffixLoc = new IntPair(outputVec.size(), 0); + // // if there's stuff in the suffix on the same line with the + // // end of the algorithm, write it on a separate line. + // IntPair curLoc = new IntPair(PcalParams.inputSuffixLoc.one, PcalParams.inputSuffixLoc.two); + // if (curLoc.one < untabInputVec.size()) + // { + // String lastLine = (String) untabInputVec.elementAt(curLoc.one); + // if (curLoc.two < lastLine.length()) + // { + // outputVec.addElement(lastLine.substring(curLoc.two)); + // } + // curLoc.one++; + // } + // // Copy the rest of the input file into the output file. + // for (int ii = curLoc.one; ii < untabInputVec.size(); ii++) + // { + // outputVec.addElement((String) untabInputVec.elementAt(ii)); + // } + // } + /********************************************************************* + * Write the output file. * + *********************************************************************/ + try + { + WriteStringVectorToFile(outputVec, PcalParams.TLAInputFile + ".tla"); + } catch (StringVectorToFileException e) + { + PcalDebug.reportError(e); +// return exitWithStatus(STATUS_EXIT_WITH_ERRORS); + return null ; // added for testing + } + + PcalDebug.reportInfo("New file " + PcalParams.TLAInputFile + ".tla" + " written."); + + /********************************************************************* + * Write the cfg file, unless the -nocfg option is used. * + *********************************************************************/ + File cfgFile = new File(PcalParams.TLAInputFile + ".cfg"); + Vector<String> cfg = null; + boolean writeCfg = !PcalParams.Nocfg; + if (writeCfg && cfgFile.exists()) + { + if (cfgFile.canRead()) + { + try + { + cfg = fileToStringVector(PcalParams.TLAInputFile + ".cfg"); + } catch (FileToStringVectorException e) + { + PcalDebug.reportError(e); +// return exitWithStatus(STATUS_EXIT_WITH_ERRORS); + return null ; // added for testing + } + } else + { + /************************************************************* + * cfg file is read-only. * + *************************************************************/ + writeCfg = false; + PcalDebug.reportInfo("File " + PcalParams.TLAInputFile + ".cfg is read only, new version not written."); + } + } else + { + cfg = new Vector<String>(); + cfg.addElement(PcalParams.CfgFileDelimiter); + } + ; + + /********************************************************************* + * Delete previously written part of cfg file. * + *********************************************************************/ + if (writeCfg) + { + int j = 0; + boolean done = false; + while ((!done) && (cfg.size() > j)) + { + if (((String) cfg.elementAt(j)).indexOf(PcalParams.CfgFileDelimiter) == -1) + { + j = j + 1; + } else + { + done = true; + } + } + if (done) + { + /************************************************************* + * Delete all lines before the delimiting comment string. * + *************************************************************/ + while (j > 0) + { + cfg.removeElementAt(0); + j = j - 1; + } + } else + { + /************************************************************* + * The delimiting comment string written by the translator * + * not found in the cfg file, so presumably the user created * + * the cfg file before running the translator on the input * + * file. We insert the delimiter. * + *************************************************************/ + cfg.add(0, PcalParams.CfgFileDelimiter); + } + ; + + /****************************************************************** + * If defaultInitValue is used, add a CONSTANT statement setting * + * it to a model value of the same name. * + * (Added 22 Aug 2007 by LL.) * + ******************************************************************/ + if (PcalParams.tlcTranslation() || ParseAlgorithm.hasDefaultInitialization) + { + cfg.add(0, "CONSTANT defaultInitValue = defaultInitValue"); + } + ; + /****************************************************************** + * Insert the `PROPERTY Termination' line if requested. * + ******************************************************************/ + if (PcalParams.CheckTermination) + { + cfg.add(0, "PROPERTY Termination"); + } + ; + /****************************************************************** + * Insert the SPECIFICATION line if there isn't already one. * + ******************************************************************/ + j = 0; + boolean hasSpec = false; + while (j < cfg.size()) + { + String thisLine = (String) cfg.elementAt(j); + if ((thisLine.indexOf("SPECIFICATION") != -1) + && ((thisLine.indexOf("\\*") == -1) || (thisLine.indexOf("\\*") > thisLine + .indexOf("SPECIFICATION")))) + { + hasSpec = true; + } + ; + j = j + 1; + } + ; + if (hasSpec) + { + PcalDebug.reportInfo("File " + PcalParams.TLAInputFile + + ".cfg already contains SPECIFICATION statement," + "\n so new one not written."); + } else + { + cfg.add(0, "SPECIFICATION Spec"); + } + ; + try + { + WriteStringVectorToFile(cfg, PcalParams.TLAInputFile + ".cfg"); + } catch (StringVectorToFileException e) + { + PcalDebug.reportError(e); +// return exitWithStatus(STATUS_EXIT_WITH_ERRORS); + return null ; // added for testing + } + PcalDebug.reportInfo("New file " + PcalParams.TLAInputFile + ".cfg" + " written."); + } + ; + +// return exitWithStatus(STATUS_EXIT_WITHOUT_ERROR); + return PcalParams.tlaPcalMapping ; // added for testing + } // END main + + public static Vector<String> runMe(final Vector<String> inputVec, final TLAtoPCalMapping mapping) { /********************************************************************* * Set untabInputVec to be the vector of strings obtained from * * inputVec by replacing tabs with spaces. * @@ -393,7 +599,7 @@ class trans * translator are copied from inputVec, so any tabs the user wants * * are kept. * *********************************************************************/ - Vector untabInputVec = removeTabs(inputVec); + Vector<String> untabInputVec = removeTabs(inputVec); /** * Look through the file for PlusCal options. They are put anywhere @@ -750,11 +956,9 @@ class trans * do the translation by calling TLC. Otherwise, call the ordinary * * Translate method. * *********************************************************************/ - Vector translation = null; - boolean tlcTranslation = PcalParams.SpecOption || PcalParams.MyspecOption || PcalParams.Spec2Option - || PcalParams.Myspec2Option; + Vector<String> translation = null; - if (tlcTranslation) + if (PcalParams.tlcTranslation()) { try { @@ -779,228 +983,28 @@ class trans } ; - PcalDebug.reportInfo("Translation completed."); -// tla-pcal Debugging -//System.exit(0); - /********************************************************************* - * For .tla input: * - * Rename the old file by changing its extension from "tla" to "old". * - *********************************************************************/ - // if (!PcalParams.fromPcalFile) - // { - File file; - try - { - file = new File(PcalParams.TLAInputFile + ".old"); - if (file.exists()) - { - file.delete(); - } - ; - file = new File(PcalParams.TLAInputFile + ".tla"); - file.renameTo(new File(PcalParams.TLAInputFile + ".old")); - } catch (Exception e) - { - PcalDebug.reportError("Could not rename input file " + PcalParams.TLAInputFile + ".tla" + " to " - + PcalParams.TLAInputFile + ".old"); -// return exitWithStatus(STATUS_EXIT_WITH_ERRORS); - return null ; // added for testing - } - ; - // } - /********************************************************************* * Add the translation to outputVec. * *********************************************************************/ int i = 0; while (i < translation.size()) { - outputVec.insertElementAt(translation.elementAt(i), i + translationLine + 1); + inputVec.insertElementAt(translation.elementAt(i), i + translationLine + 1); i = i + 1; } - /********************************************************************* - * Code from aborted version 1.31. * - * For .pcal input, set outputSuffixLoc and add the rest of the * - * input file to the output. * - *********************************************************************/ - // if (PcalParams.fromPcalFile) - // { - // PcalParams.outputSuffixLoc = new IntPair(outputVec.size(), 0); - // // if there's stuff in the suffix on the same line with the - // // end of the algorithm, write it on a separate line. - // IntPair curLoc = new IntPair(PcalParams.inputSuffixLoc.one, PcalParams.inputSuffixLoc.two); - // if (curLoc.one < untabInputVec.size()) - // { - // String lastLine = (String) untabInputVec.elementAt(curLoc.one); - // if (curLoc.two < lastLine.length()) - // { - // outputVec.addElement(lastLine.substring(curLoc.two)); - // } - // curLoc.one++; - // } - // // Copy the rest of the input file into the output file. - // for (int ii = curLoc.one; ii < untabInputVec.size(); ii++) - // { - // outputVec.addElement((String) untabInputVec.elementAt(ii)); - // } - // } - /********************************************************************* - * Write the output file. * - *********************************************************************/ - try - { - WriteStringVectorToFile(outputVec, PcalParams.TLAInputFile + ".tla"); - } catch (StringVectorToFileException e) - { - PcalDebug.reportError(e); -// return exitWithStatus(STATUS_EXIT_WITH_ERRORS); - return null ; // added for testing - } - - PcalDebug.reportInfo("New file " + PcalParams.TLAInputFile + ".tla" + " written."); - - /********************************************************************* - * Write the cfg file, unless the -nocfg option is used. * - *********************************************************************/ - File cfgFile = new File(PcalParams.TLAInputFile + ".cfg"); - Vector cfg = null; - boolean writeCfg = !PcalParams.Nocfg; - if (writeCfg && cfgFile.exists()) - { - if (cfgFile.canRead()) - { - try - { - cfg = fileToStringVector(PcalParams.TLAInputFile + ".cfg"); - } catch (FileToStringVectorException e) - { - PcalDebug.reportError(e); -// return exitWithStatus(STATUS_EXIT_WITH_ERRORS); - return null ; // added for testing - } - } else - { - /************************************************************* - * cfg file is read-only. * - *************************************************************/ - writeCfg = false; - PcalDebug.reportInfo("File " + PcalParams.TLAInputFile + ".cfg is read only, new version not written."); - } - } else - { - cfg = new Vector(); - cfg.addElement(PcalParams.CfgFileDelimiter); - } - ; - - /********************************************************************* - * Delete previously written part of cfg file. * - *********************************************************************/ - if (writeCfg) - { - i = 0; - boolean done = false; - while ((!done) && (cfg.size() > i)) - { - if (((String) cfg.elementAt(i)).indexOf(PcalParams.CfgFileDelimiter) == -1) - { - i = i + 1; - } else - { - done = true; - } - } - if (done) - { - /************************************************************* - * Delete all lines before the delimiting comment string. * - *************************************************************/ - while (i > 0) - { - cfg.removeElementAt(0); - i = i - 1; - } - } else - { - /************************************************************* - * The delimiting comment string written by the translator * - * not found in the cfg file, so presumably the user created * - * the cfg file before running the translator on the input * - * file. We insert the delimiter. * - *************************************************************/ - cfg.add(0, PcalParams.CfgFileDelimiter); - } - ; - - /****************************************************************** - * If defaultInitValue is used, add a CONSTANT statement setting * - * it to a model value of the same name. * - * (Added 22 Aug 2007 by LL.) * - ******************************************************************/ - if (tlcTranslation || ParseAlgorithm.hasDefaultInitialization) - { - cfg.add(0, "CONSTANT defaultInitValue = defaultInitValue"); - } - ; - /****************************************************************** - * Insert the `PROPERTY Termination' line if requested. * - ******************************************************************/ - if (PcalParams.CheckTermination) - { - cfg.add(0, "PROPERTY Termination"); - } - ; - - /****************************************************************** - * Insert the SPECIFICATION line if there isn't already one. * - ******************************************************************/ - i = 0; - boolean hasSpec = false; - while (i < cfg.size()) - { - String thisLine = (String) cfg.elementAt(i); - if ((thisLine.indexOf("SPECIFICATION") != -1) - && ((thisLine.indexOf("\\*") == -1) || (thisLine.indexOf("\\*") > thisLine - .indexOf("SPECIFICATION")))) - { - hasSpec = true; - } - ; - i = i + 1; - } - ; - if (hasSpec) - { - PcalDebug.reportInfo("File " + PcalParams.TLAInputFile - + ".cfg already contains SPECIFICATION statement," + "\n so new one not written."); - } else - { - cfg.add(0, "SPECIFICATION Spec"); - } - ; - try - { - WriteStringVectorToFile(cfg, PcalParams.TLAInputFile + ".cfg"); - } catch (StringVectorToFileException e) - { - PcalDebug.reportError(e); -// return exitWithStatus(STATUS_EXIT_WITH_ERRORS); - return null ; // added for testing - } - PcalDebug.reportInfo("New file " + PcalParams.TLAInputFile + ".cfg" + " written."); - } - ; - -// return exitWithStatus(STATUS_EXIT_WITHOUT_ERROR); - return PcalParams.tlaPcalMapping ; // added for testing - } // END main + PcalDebug.reportInfo("Translation completed."); + return inputVec; +// tla-pcal Debugging +//System.exit(0); + } - /** + /** * If run in the system mode, exits the program, in tool mode returns the status * @param status */ - private static int exitWithStatus(int status) + @SuppressWarnings("unused") + private static int exitWithStatus(int status) { if (ToolIO.getMode() == ToolIO.SYSTEM) { @@ -1015,7 +1019,7 @@ class trans /********************** Writing the AST ************************************/ private static boolean WriteAST(AST ast) { - Vector astFile = new Vector(); + Vector<String> astFile = new Vector<String>(); astFile.addElement("------ MODULE AST -------"); astFile.addElement("EXTENDS TLC"); astFile.addElement("fairness == \"" + PcalParams.FairnessOption + "\""); @@ -1037,7 +1041,7 @@ class trans /************************* THE TLC TRANSLATION *****************************/ - private static Vector TLCTranslate(AST ast) throws TLCTranslationException + private static Vector<String> TLCTranslate(AST ast) throws TLCTranslationException /*********************************************************************** * The result is a translation of the algorithm represented by ast * * obtained by using TLC to execute the definition of Translation(ast) * @@ -1079,7 +1083,7 @@ class trans { try { - Vector parseFile = PcalResourceFileReader.ResourceFileToStringVector(PcalParams.SpecFile + ".tla"); + Vector<String> parseFile = PcalResourceFileReader.ResourceFileToStringVector(PcalParams.SpecFile + ".tla"); WriteStringVectorToFile(parseFile, PcalParams.SpecFile + ".tla"); parseFile = PcalResourceFileReader.ResourceFileToStringVector(PcalParams.SpecFile + ".cfg"); @@ -1235,14 +1239,14 @@ class trans * Wrap the translated string into approximately 80 character lines * *******************************************************************/ transl = WrapString(transl, 78); - Vector result = new Vector(); + Vector<String> result = new Vector<String>(); result.addElement(transl); return result; } /***************** METHODS FOR READING AND WRITING FILES *****************/ - private static void WriteStringVectorToFile(Vector inputVec, String fileName) throws StringVectorToFileException + private static void WriteStringVectorToFile(Vector<String> inputVec, String fileName) throws StringVectorToFileException /*********************************************************************** * Writes the Vector of strings inputVec to file named fileName, with * * each element of inputVec written on a new line. * @@ -1283,13 +1287,13 @@ class trans } - private static Vector fileToStringVector(String fileName) throws FileToStringVectorException + private static Vector<String> fileToStringVector(String fileName) throws FileToStringVectorException /*********************************************************************** * Reads file fileName into a StringVector, a vector in which each * * element is a line of the file. * ***********************************************************************/ { - Vector inputVec = new Vector(100); + Vector<String> inputVec = new Vector<String>(100); try { BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream(fileName))); @@ -1813,7 +1817,7 @@ class trans */ private static boolean OutputHelpMessage() { - Vector helpVec = null; + Vector<String> helpVec = null; try { helpVec = PcalResourceFileReader.ResourceFileToStringVector("help.txt"); @@ -1860,7 +1864,7 @@ class trans return STATUS_EXIT_WITH_ERRORS; } - private static int findTokenPair(Vector vec, int lineNum, String tok1, String tok2) + private static int findTokenPair(Vector<String> vec, int lineNum, String tok1, String tok2) /********************************************************************* * Returns the number of the first line at or after lineNum in the * * vector of strings vec containing tok1 followed by 1 or more * @@ -1870,7 +1874,7 @@ class trans int i = lineNum; while (i < vec.size()) { - String line = (String) vec.elementAt(i); + String line = vec.elementAt(i); int col = line.indexOf(tok1); int nextcol = col + tok1.length(); if (col != -1) @@ -1894,7 +1898,7 @@ class trans /************************** RemoveTabs *********************************/ - public static Vector removeTabs(Vector vec) + public static Vector<String> removeTabs(Vector<String> vec) { /******************************************************************** * Returns a string vector obtained from the string vector vec by * @@ -1905,7 +1909,7 @@ class trans * Emacs does when told to remove tabs, which makes it good enough * * for me. * ********************************************************************/ - Vector newVec = new Vector(); + Vector<String> newVec = new Vector<String>(); int i = 0; while (i < vec.size()) { diff --git a/tlatools/src/tla2sany/StandardModules/Bags.tla b/tlatools/src/tla2sany/StandardModules/Bags.tla index 7be7a4420403141009471a0c2c3804cf12a28615..265045e3a0842f467419ca02b51cecba5e1aac85 100644 --- a/tlatools/src/tla2sany/StandardModules/Bags.tla +++ b/tlatools/src/tla2sany/StandardModules/Bags.tla @@ -8,6 +8,13 @@ (* subset of the positive integers. An element e belongs to bag B iff e *) (* is in the domain of B, in which case bag B contains B[e] copies of e. *) (**************************************************************************) +(**************************************************************************) +(* All these definitions other than SubBag are overridden by TLC in the *) +(* Java class tlc2.module.Bags. Each operator is overridden by the Java *) +(* method with the same name, except that the mapping for TLA+ infix *) +(* operators is defined in the static block at the beginning of the Java *) +(* class. *) +(**************************************************************************) EXTENDS TLC LOCAL INSTANCE Naturals @@ -22,7 +29,7 @@ BagToSet(B) == DOMAIN B (* The set of elements at least one copy of which is in B. *) (************************************************************************) -SetToBag(S) == [e \in S |-> 1] +SetToBag(S) == [e \in S |-> 1] (************************************************************************) (* The bag that contains one copy of every element of the set S. *) (************************************************************************) @@ -42,7 +49,7 @@ B1 (+) B2 == (IF e \in DOMAIN B1 THEN B1[e] ELSE 0) + (IF e \in DOMAIN B2 THEN B2[e] ELSE 0) ] -B1 (-) B2 == +B1 (-) B2 == (************************************************************************) (* The bag B1 with the elements of B2 removed--that is, with one copy *) (* of an element removed from B1 for each copy of the same element in *) diff --git a/tlatools/src/tla2sany/StandardModules/FiniteSets.tla b/tlatools/src/tla2sany/StandardModules/FiniteSets.tla index 57ac40235075b64119e4ab2ddf92abeab9120a5a..601ab16beeab8c7fea1f137f8b626771ee262753 100644 --- a/tlatools/src/tla2sany/StandardModules/FiniteSets.tla +++ b/tlatools/src/tla2sany/StandardModules/FiniteSets.tla @@ -1,4 +1,9 @@ ---------------------------- MODULE FiniteSets ----------------------------- +(***************************************************************************) +(* The two definitions in this standard module are overridden by TLC in *) +(* the Java class tlc2.module.FiniteSets. Each operator is overridden by *) +(* the Java method with the same name. *) +(***************************************************************************) LOCAL INSTANCE Naturals LOCAL INSTANCE Sequences (*************************************************************************) diff --git a/tlatools/src/tla2sany/StandardModules/Integers.tla b/tlatools/src/tla2sany/StandardModules/Integers.tla index 2df47a87a219821e9bbd243defdc826992636431..2dd1cc9daa3b2ca327ac098604793293eef4e070 100644 --- a/tlatools/src/tla2sany/StandardModules/Integers.tla +++ b/tlatools/src/tla2sany/StandardModules/Integers.tla @@ -1,10 +1,23 @@ -------------------------------- MODULE Integers ---------------------------- (***************************************************************************) -(* A dummy module that declares the operators that are defined in the *) -(* real Integers module. *) +(* This module provides dummy definitions of the operators that are *) +(* defined by the real Integers module. It is expected that any tool will *) +(* provide its own implementations of these operators. See the book *) +(* "Specifying Systems" for the real Integers module. *) +(***************************************************************************) +(***************************************************************************) +(* The two definitions here and the definitions imported from the Naturals *) +(* module are overridden by TLC in the Java class tlc2.module.Integers. *) +(* Each operator is overridden by the Java method with the same name, *) +(* except that the mappings for the prefix - operator and the TLA+ infix *) +(* operators are defined in the static block at the beginning of the Java *) +(* class. *) (***************************************************************************) EXTENDS Naturals Int == { } +(***************************************************************************) +(* This defines the prefix - operator. *) +(***************************************************************************) -. a == 0 - a ============================================================================= diff --git a/tlatools/src/tla2sany/StandardModules/Naturals.tla b/tlatools/src/tla2sany/StandardModules/Naturals.tla index 6dc13fea6ae556e21f74d4f0322d0f7751c6a448..4c4de1defdba8624d2f296f839d810fe3faab92a 100644 --- a/tlatools/src/tla2sany/StandardModules/Naturals.tla +++ b/tlatools/src/tla2sany/StandardModules/Naturals.tla @@ -1,18 +1,35 @@ -------------------------------- MODULE Naturals ---------------------------- (***************************************************************************) -(* A dummy module that defines the operators that are defined by the *) -(* real Naturals module. *) +(* This module provides dummy definitions of the operators that are *) +(* defined by the real Naturals module. It is expected that any tool will *) +(* provide its own implementations of these operators. See the book *) +(* "Specifying Systems" for the real Naturals module. *) +(***************************************************************************) +(***************************************************************************) +(* These definitions are all overridden by TLC in the Java class *) +(* tlc2.module.Naturals. Each operator is overridden by the Java method *) +(* with the same name, except that the mapping for TLA+ infix operators *) +(* is defined in the static block at the beginning of the Java class. *) (***************************************************************************) - Nat == { } a+b == {a, b} -a-b == {a, b} -a*b == {a, b} + +a-b == CHOOSE n : b + n = a +a*b == TRUE a^b == {a, b} a<b == a = b a>b == a = b a \leq b == a = b a \geq b == a = b +(***************************************************************************) +(* a .. b is defined to equal {i \in Int : (a \leq i) /\ (i \leq b)} *) +(* where Int is the set of all integers. *) +(* *) +(* a % b and a \div b are defined so that for any integers a and b *) +(* with b > 0 , the following formula is true: *) +(* *) +(* a = b * (a \div b) + (a % b) *) +(***************************************************************************) a % b == {a, b} a \div b == {a, b} a .. b == {a, b} diff --git a/tlatools/src/tla2sany/StandardModules/Randomization.tla b/tlatools/src/tla2sany/StandardModules/Randomization.tla new file mode 100644 index 0000000000000000000000000000000000000000..a1266fee4f6067a0b8c857f3dd2a31298f3bec71 --- /dev/null +++ b/tlatools/src/tla2sany/StandardModules/Randomization.tla @@ -0,0 +1,64 @@ +-------------------------- MODULE Randomization------------------------------ +(***************************************************************************) +(* This module defines operators for choosing pseudo-random subsets of a *) +(* set. It is useful for inductive invariance checking, where the *) +(* operators appear only in the initial predicate. However, it may have *) +(* other uses. *) +(* *) +(* In breadth-first search model checking, the pseudo-random choices made *) +(* when computing possible steps satisfying the next-state relation are *) +(* determined by the first state of the step. Thus, the choices made for *) +(* a particular state will be the same in successive runs of TLC. This is *) +(* done to permit TLC to generate an error trace if an error is found. *) +(* This applies only when TLC is run in breadth-first search mode. In *) +(* particular, the choices made in simulation mode are independent of the *) +(* state for which they are made. *) +(***************************************************************************) + +(***************************************************************************) +(* Except for TestRandomSetOfSubsets, all these definitions are overridden *) +(* by TLC in the Java class tlc2.module.Randomization. Each operator is *) +(* overridden by the Java method with the same name. *) +(***************************************************************************) +LOCAL INSTANCE Naturals +LOCAL INSTANCE FiniteSets + +(***************************************************************************) +(* RandomSubset(k, S) equals a randomly chosen subset of S containing k *) +(* elements, where 0 < k < Cardinality(S). *) +(***************************************************************************) +RandomSubset(k, S) == CHOOSE T \in SUBSET S : Cardinality(T) = T + +(***************************************************************************) +(* RandomSetOfSubsets(k, n, S) equals a pseudo-randomly chosen set of *) +(* subsets of S -- that is, a randomly chosen subset of SUBSET S . Thus, *) +(* each element T of this set is a subset of S. Each such T is chosen so *) +(* that each element of S has a probability n / Cardinality(S) of being in *) +(* T. Thus, the average number of elements in each chosen subset T is n. *) +(* The set RandomSetOfSubsets(k, n, S) is obtained by making k such *) +(* choices of T . Because this can produce duplicate choices, the number *) +(* of elements T in this set may be less than k. The average number of *) +(* elements in RandomSetOfSubsets(k, n, S) seems to be difficult to *) +(* compute in general. However, there is very little variation in the *) +(* actual number of elements in the chosen set for fixed values of k, n, *) +(* and Cardinality(S). You can therefore use the operator *) +(* TestRandomSetOfSubsets defined below to find out approximately how *) +(* close to k the cardinality of the chosen set of subsets is. *) +(***************************************************************************) +RandomSetOfSubsets(k, n, S) == CHOOSE T \in SUBSET SUBSET S : + Cardinality(T) \leq k + +(***************************************************************************) +(* The value of TestRandomSetOfSubsets(k, n, S) is a sequence of five *) +(* values that are the cardinality of the set of subsets produced by five *) +(* executions of RandomSetOfSubsets(k, n, S). For constant values of k, *) +(* n, and S, you can enter TestRandomSetOfSubsets(k, n, S) in the Evaluate *) +(* Constant Expression section of a TLC model in the TLA+ Toolbox. *) +(* Running TLC will then tell you the approximate number of elements in *) +(* the set of subsets produced by RandomSetOfSubsets for these parameters. *) +(* You can then choose k to obtain a set of the desired size. *) +(***************************************************************************) +TestRandomSetOfSubsets(k, n, S) == + [i \in 1..5 |-> Cardinality(RandomSetOfSubsets(k, n, S))] + +============================================================================= diff --git a/tlatools/src/tla2sany/StandardModules/RealTime.tla b/tlatools/src/tla2sany/StandardModules/RealTime.tla index 1026c66a4b853a896a3b6f3374b02292f0562753..c326bfa0a0075428864f425f6c741fc13ac11810 100644 --- a/tlatools/src/tla2sany/StandardModules/RealTime.tla +++ b/tlatools/src/tla2sany/StandardModules/RealTime.tla @@ -1,4 +1,9 @@ ----------------------------- MODULE RealTime ------------------------------- +(***************************************************************************) +(* This standard module is described in Chapter 9 of the book "Specifying *) +(* Systems". The type of specification described there cannot be handled *) +(* by the TLC model checker. *) +(***************************************************************************) EXTENDS Reals VARIABLE now diff --git a/tlatools/src/tla2sany/StandardModules/Reals.tla b/tlatools/src/tla2sany/StandardModules/Reals.tla index f7aa44677fcb75da6c0717f71188d65886a8fa84..c63cd93dbea6a35ca6152cf24aba396fc2c90fe3 100644 --- a/tlatools/src/tla2sany/StandardModules/Reals.tla +++ b/tlatools/src/tla2sany/StandardModules/Reals.tla @@ -1,8 +1,14 @@ -------------------------------- MODULE Reals ------------------------------- (***************************************************************************) -(* A dummy module that declares the operators that are defined in the *) -(* real Reals module. It should produce an error if TLC tries to *) -(* evaluate these operators when it shouldn't. *) +(* This module provides dummy definitions of the operators that are *) +(* defined by the real Reals module. It is expected that any tool that *) +(* handles specifications that use real numbers will provide its own *) +(* implementations of these operators. TLC currently does not handle real *) +(* numbers and produces an error if a specification requires TLC to *) +(* evaluate the operators defined here or to evaluate any operator defined *) +(* in the Integers module that is applied to non-integer real numbers. *) +(* *) +(* See the book "Specifying Systems" for the real Reals module. *) (***************************************************************************) EXTENDS Integers diff --git a/tlatools/src/tla2sany/StandardModules/Sequences.tla b/tlatools/src/tla2sany/StandardModules/Sequences.tla index df77a97facdf6d62ce44aa6d4dd304894742fc1d..d179cf8a59913d24c0c56dbe61493fd892a11a1d 100644 --- a/tlatools/src/tla2sany/StandardModules/Sequences.tla +++ b/tlatools/src/tla2sany/StandardModules/Sequences.tla @@ -5,10 +5,16 @@ (* {1, 2, ... , n}). This is also how TLA+ defines an n-tuple, so *) (* tuples are sequences. *) (***************************************************************************) +(***************************************************************************) +(* These definitions are all overridden by TLC in the Java class *) +(* tlc2.module.Sequences. Each operator is overridden by the Java method *) +(* with the same name, except that the mapping for TLA+ infix operators *) +(* is defined in the static block at the beginning of the Java class. *) +(***************************************************************************) LOCAL INSTANCE Naturals (*************************************************************************) - (* Imports the definitions from Naturals, but don't export them. *) + (* Imports the definitions from Naturals, but doesn't export them. *) (*************************************************************************) Seq(S) == UNION {[1..n -> S] : n \in Nat} @@ -51,7 +57,7 @@ SelectSeq(s, Test(_)) == (*************************************************************************) LET F[i \in 0..Len(s)] == (*******************************************************************) - (* F[i] equals SelectSeq(SubSeq(s, 1, i), Test] *) + (* F[i] equals SelectSeq(SubSeq(s, 1, i), Test) . *) (*******************************************************************) IF i = 0 THEN << >> ELSE IF Test(s[i]) THEN Append(F[i-1], s[i]) diff --git a/tlatools/src/tla2sany/StandardModules/TLC.tla b/tlatools/src/tla2sany/StandardModules/TLC.tla index a9567ac5272fc5fcd620e58e13a9f1652510b3bd..0f0b40f3d7be94c2676d41ab7f405dbc03e4ed50 100644 --- a/tlatools/src/tla2sany/StandardModules/TLC.tla +++ b/tlatools/src/tla2sany/StandardModules/TLC.tla @@ -1,12 +1,63 @@ ------------------------------- MODULE TLC ---------------------------------- +(***************************************************************************) +(* This is a standard module for use with the TLC model checker. *) +(* Operators not explained by comments here are explained in the book *) +(* "Specifying Systems". *) +(* *) +(* The definitions of all the operators in this module are overridden by *) +(* TLC with methods defined in the Java class tlc2.module.TLC. Each *) +(* definition is overridden with the method of the same name, except that *) +(* the mapping from infix operators to Java methods is specified in the *) +(* static block at the beginning of the Java class. *) +(***************************************************************************) LOCAL INSTANCE Naturals LOCAL INSTANCE Sequences +LOCAL INSTANCE FiniteSets ----------------------------------------------------------------------------- Print(out, val) == val PrintT(out) == TRUE + (************************************************************************) + (* This expression equals TRUE, but evaluating it causes TLC to print *) + (* the value of out. *) + (************************************************************************) + Assert(val, out) == IF val = TRUE THEN TRUE ELSE CHOOSE v : TRUE JavaTime == CHOOSE n : n \in Nat + +(***************************************************************************) +(* TLC can read and set a special list of values while evaluating *) +(* expressions using the operators TLCSet and TLCGet. When TLC evaluates *) +(* TLCSet(i,v), for any positive integer i and arbitrary value v, it *) +(* obtains the value TRUE and sets element number i of the list to v. *) +(* When TLC evaluates TLCGet(i), the value it obtains is the current value *) +(* of the element number i of this list. *) +(* *) +(* One use of this feature is to check TLC's progress during long *) +(* computations. For example, suppose TLC is evaluating a formula *) +(* \A x \in S : P where S is a large set, so it evaluates P many times. *) +(* You can use TLCGet, TLCSet, and Print to print something after every *) +(* 1000 times TLC evaluates P. *) +(* *) +(* As explained in the description of the TLCEval operator below, you may *) +(* also want to use this feature to count how many times TLC is evaluating *) +(* an expression e. To use value number i as the counter, just replace e *) +(* by *) +(* *) +(* IF TLCSet(i, TLCGet(i)+1) THEN e ELSE 42 *) +(* *) +(* (The ELSE expression is never evaluated.) *) +(* *) +(* For reasons of efficiency, TLCGet and TLCSet behave somewhat strangely *) +(* when TLC is run with multiple worker threads. Each worker thread *) +(* maintains its own individual copy of the list of values on which it *) +(* evaluates TLCGet and TLCSet. The worker threads are activated only *) +(* after the computation and invariance checking of the initial states. *) +(* Before then, evaluating TLCSet(i,v) sets the element i of the list *) +(* maintained by all threads. Thus, the lists of all the worker threads *) +(* can be initialized by putting the appropriate TLCSet expression in an *) +(* ASSUME expression or in the initial predicate. *) +(***************************************************************************) TLCGet(i) == CHOOSE n : TRUE TLCSet(i, v) == TRUE ----------------------------------------------------------------------------- @@ -26,11 +77,57 @@ SortSeq(s, Op(_, _)) == (i < j) => Op(s[p[i]], s[p[j]]) \/ (s[p[i]] = s[p[j]]) IN [i \in 1..Len(s) |-> s[Perm[i]]] +(***************************************************************************) +(* TLC evaluates RandomElement(S) to be a pseudo-randomly chosen element *) +(* of the set S, where each element of S is chosen with equal probability. *) +(* This feature was added to enable the computation of statistical *) +(* properties of a specification's executions by running TLC in simulation *) +(* mode. We don't know if anyone has ever done this. *) +(* *) +(* In breadth-first search model checking, the pseudo-random choices made *) +(* when computing possible steps satisfying the next-state relation are *) +(* determined by the first state of the step. Thus, the choices made for *) +(* a particular state will be the same in successive runs of TLC. This is *) +(* done to permit TLC to generate an error trace if an error is found. *) +(* This applies only when TLC is run in breadth-first search mode. The *) +(* random choices made in simulation mode are independent of the state for *) +(* which they are made. *) +(***************************************************************************) RandomElement(s) == CHOOSE x \in s : TRUE +(***************************************************************************) +(* The constant value Any has the special property that, for any value v, *) +(* TLC evaluates the expression v \in Any to equal TRUE. The special *) +(* value Any was introduced because TLA+ originally allowed only functions *) +(* to be defined recursively, and it was sometimes convenient to define a *) +(* function with domain Any. It is retained for backwards compatibility. *) +(***************************************************************************) Any == CHOOSE x : TRUE ToString(v) == (CHOOSE x \in [a : v, b : STRING] : TRUE).b + (************************************************************************) + (* This equals a string that is the TLA+ representation of the value *) + (* that TLC obtains by evaluating v. *) + (************************************************************************) +(***************************************************************************) +(* TLC often uses lazy evaluation. For example, it may not enumerate the *) +(* elements of a set of the form {x \in T : P(x)} unless it has to; and it *) +(* doesn't have to if it only needs to check if an element e is in that *) +(* set. (TLC can do that by evaluating x \in T and P(e).) TLC uses *) +(* heuristics to determine when it should completely evaluate an *) +(* expression. Those heuristics work well most of the time. However, *) +(* sometimes lazy evaluation can result in the expression ultimately being *) +(* evaluated multiple times instead of just once. This can especially be *) +(* a problem when evaluating a recursively defined operator. You can get *) +(* TLC to fully evaluate an expression exp and not use lazy evaluation by *) +(* replacing exp with TLCEval(exp). *) +(* *) +(* If TLC is taking a long time to evaluate something, you can check if *) +(* lazy evaluation is the source of the problem by using the TLCSet and *) +(* TLCGet operators to count how many times expressions are being *) +(* evaluated. *) +(***************************************************************************) TLCEval(v) == v -============================================================================= + +============================================================================= \ No newline at end of file diff --git a/tlatools/src/tla2sany/modanalyzer/ParseUnit.java b/tlatools/src/tla2sany/modanalyzer/ParseUnit.java index 1e5f83216ea7556ef3875b5d08a8bae561de03f7..5c853180875fccf73b96f86f84889f93da38e686 100644 --- a/tlatools/src/tla2sany/modanalyzer/ParseUnit.java +++ b/tlatools/src/tla2sany/modanalyzer/ParseUnit.java @@ -255,10 +255,10 @@ public class ParseUnit { ***********************************************************************/ if (ToolIO.getMode() == ToolIO.SYSTEM) { - ToolIO.out.printf("Parsing file %s\n", absoluteResolvedPath); + ToolIO.out.println(String.format("Parsing file %s", absoluteResolvedPath)); } else { - ToolIO.out.printf("Parsing module %s in file %s\n", nis.getModuleName(), absoluteResolvedPath); + ToolIO.out.println(String.format("Parsing module %s in file %s", nis.getModuleName(), absoluteResolvedPath)); } boolean parseSuccess; diff --git a/tlatools/src/tla2sany/modanalyzer/SpecObj.java b/tlatools/src/tla2sany/modanalyzer/SpecObj.java index a9aaa0ab1a9df9ce0e32dc596646c06f01cfa1b3..95139ba6083fb9b43677761ca4aaf63af56a905f 100644 --- a/tlatools/src/tla2sany/modanalyzer/SpecObj.java +++ b/tlatools/src/tla2sany/modanalyzer/SpecObj.java @@ -10,6 +10,7 @@ import java.util.Set; import tla2sany.semantic.AbortException; import tla2sany.semantic.Errors; import tla2sany.semantic.ExternalModuleTable; +import tla2sany.semantic.ModuleNode; import tla2sany.st.TreeNode; import tla2sany.utilities.Vector; import util.FileUtil; @@ -160,6 +161,10 @@ public class SpecObj { return primaryFileName; } + + public final ModuleNode getRootModule() { + return getExternalModuleTable().getRootModule(); + } /** * Returns the ExternalModuleTable object that contains all of the diff --git a/tlatools/src/tla2sany/semantic/AnyDefNode.java b/tlatools/src/tla2sany/semantic/AnyDefNode.java index fe0201b3a7fff9a755e529facf31227e33144c74..629e4e0b332d36d7cfa1523ae4ebe86320b16e5a 100644 --- a/tlatools/src/tla2sany/semantic/AnyDefNode.java +++ b/tlatools/src/tla2sany/semantic/AnyDefNode.java @@ -49,4 +49,5 @@ public interface AnyDefNode { public HashSet<ArgLevelParam> getArgLevelParams() ; public SetOfArgLevelConstraints getArgLevelConstraints() ; public FormalParamNode[] getParams() ; + public AnyDefNode getSource(); } diff --git a/tlatools/src/tla2sany/semantic/Context.java b/tlatools/src/tla2sany/semantic/Context.java index 0f7f8e3e538574cc617b40af71230e776f80c271..78e7cd418e5cf26ddff14437fafa92c8d0144be0 100644 --- a/tlatools/src/tla2sany/semantic/Context.java +++ b/tlatools/src/tla2sany/semantic/Context.java @@ -216,7 +216,7 @@ public class Context implements ExploreNode { * Returns Enumeration of the elements of the Hashtable "Table", * which are pair of the form (Pair link, SymbolNode sn) */ - public Enumeration content() { + public Enumeration<Pair> content() { return table.elements(); } diff --git a/tlatools/src/tla2sany/semantic/ModuleNode.java b/tlatools/src/tla2sany/semantic/ModuleNode.java index ee1ec7a711b669fb9ce839cd8502bb9e1910b545..768f4041d52f030e8aec37dc92e147710d710bbc 100644 --- a/tlatools/src/tla2sany/semantic/ModuleNode.java +++ b/tlatools/src/tla2sany/semantic/ModuleNode.java @@ -12,11 +12,20 @@ package tla2sany.semantic; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Enumeration; import java.util.HashSet; import java.util.Hashtable; import java.util.Iterator; +import java.util.List; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; import tla2sany.explorer.ExploreNode; +import tla2sany.semantic.Context.Pair; import tla2sany.st.TreeNode; import tla2sany.utilities.Strings; import tla2sany.utilities.Vector; @@ -24,9 +33,6 @@ import tla2sany.xml.SymbolContext; import util.UniqueString; import util.WrongInvocationException; -import org.w3c.dom.Document; -import org.w3c.dom.Element; - public class ModuleNode extends SymbolNode { /*************************************************************************** @@ -1022,6 +1028,23 @@ final void addAssumption(TreeNode stn, ExprNode ass, SymbolTable st, // Otherwise this module is a constant module return true; } + + // TODO Change to take an action/operation that is to be executed on matching + // symbols. That way, clients don't have to iterate the result set again. + public Collection<SymbolNode> getSymbols(final SymbolMatcher symbolMatcher) { + final List<SymbolNode> result = new ArrayList<SymbolNode>(); // TreeSet to order result. + + final Enumeration<Pair> content = this.ctxt.content(); + while (content.hasMoreElements()) { + final SymbolNode aSymbol = content.nextElement().getSymbol(); + if (symbolMatcher.matches(aSymbol)) { + result.add(aSymbol); + } + } + + Collections.sort(result); + return result; + } /** * walkGraph, levelDataToString, and toString methods to implement diff --git a/tlatools/src/tla2sany/semantic/OpApplNode.java b/tlatools/src/tla2sany/semantic/OpApplNode.java index 905354a747d9be24e7450af621fda67c3216e140..049a97bb6970f7dbab355dda3bb57fd678417580 100644 --- a/tlatools/src/tla2sany/semantic/OpApplNode.java +++ b/tlatools/src/tla2sany/semantic/OpApplNode.java @@ -19,17 +19,20 @@ package tla2sany.semantic; import java.util.HashSet; import java.util.Hashtable; import java.util.Iterator; +import java.util.TreeSet; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; import tla2sany.explorer.ExploreNode; import tla2sany.parser.SyntaxTreeNode; import tla2sany.st.TreeNode; import tla2sany.utilities.Strings; import tla2sany.xml.SymbolContext; +import tlc2.value.TupleValue; +import tlc2.value.Value; import util.UniqueString; -import org.w3c.dom.Document; -import org.w3c.dom.Element; - /** * OpApplNodes represent all kinds of operator applications in TLA+, * including the application of builtin @@ -1235,6 +1238,37 @@ public class OpApplNode extends ExprNode implements ExploreNode { + toStringBody(depth) + sEO ; } + @Override + public String toString(final Value aValue) { + if (aValue instanceof TupleValue && allParams.size() == ((TupleValue) aValue).size()) { + final StringBuffer result = new StringBuffer(); + + // The values in aValue are ordered by the varloc of the variable names (see + // tlc2.tool.TLCStateMut.bind(UniqueString, Value, SemanticNode). Thus, sort + // allParams - which are unordered - under same varloc order. + final TreeSet<SymbolNode> s = new TreeSet<SymbolNode>(new java.util.Comparator<SymbolNode>() { + @Override + public int compare(SymbolNode o1, SymbolNode o2) { + return Integer.compare(o1.getName().getVarLoc(), o2.getName().getVarLoc()); + } + }); + s.addAll(allParams); + + int idx = 0; + for (final SymbolNode sn : s) { + result.append("/\\ "); + result.append(sn.getName().toString()); + + final Value value = ((TupleValue) aValue).elems[idx++]; + result.append(" = "); + result.append(Value.ppr(value)); + result.append("\n"); + } + return result.toString(); + } + return super.toString(aValue); + } + @Override protected Element getLevelElement(Document doc, SymbolContext context) { Element e = doc.createElement("OpApplNode"); diff --git a/tlatools/src/tla2sany/semantic/OpDeclNode.java b/tlatools/src/tla2sany/semantic/OpDeclNode.java index e516b459dcbeece5638d47e0f6e8b897b8ffa26c..4820867ef14a49926a1ea903f21e6ec29095b1d9 100644 --- a/tlatools/src/tla2sany/semantic/OpDeclNode.java +++ b/tlatools/src/tla2sany/semantic/OpDeclNode.java @@ -146,6 +146,16 @@ public class OpDeclNode extends OpDefOrDeclNode { semNodesTable.put(uid, this); } + @Override + public String getHumanReadableImage() { + if (getKind() == 2) { + return super.getName().toString() + " CONSTANT"; + } else if (getKind() == 3) { + return super.getName().toString() + " VARIABLE"; + } + return super.getHumanReadableImage(); + } + @Override public final String toString (int depth) { if (depth <= 0) return ""; diff --git a/tlatools/src/tla2sany/semantic/OpDefNode.java b/tlatools/src/tla2sany/semantic/OpDefNode.java index 0d94c1baa5ce84f347e9b47913445763da2bca59..b18d843c1a15d46dcd92072fcdaedaf154de2ff6 100644 --- a/tlatools/src/tla2sany/semantic/OpDefNode.java +++ b/tlatools/src/tla2sany/semantic/OpDefNode.java @@ -35,6 +35,9 @@ import java.util.HashSet; import java.util.Hashtable; import java.util.Iterator; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + import tla2sany.explorer.ExploreNode; import tla2sany.parser.SyntaxTreeNode; import tla2sany.st.Location; @@ -45,9 +48,6 @@ import tla2sany.xml.SymbolContext; import util.UniqueString; import util.WrongInvocationException; -import org.w3c.dom.Document; -import org.w3c.dom.Element; - /** * An OpDefNode can have one of the following kinds: * @@ -1238,6 +1238,31 @@ public class OpDefNode extends OpDefOrDeclNode if (stepNode != null) stepNode.walkGraph(semNodesTable); } + @Override + public String getSignature() { + final StringBuffer buf = new StringBuffer(); + buf.append(getName().toString()); + if (getArity() > 0 && getKind() != ASTConstants.BuiltInKind) { + buf.append("("); + //TODO This hack doesn't work for infix operators + final FormalParamNode[] params = getParams(); + for (int i = 0; i < params.length - 1; i++) { + final FormalParamNode formalParamNode = params[i]; + if (formalParamNode.getTreeNode() != null) { + final SyntaxTreeNode treeNode = (SyntaxTreeNode) formalParamNode.getTreeNode(); + buf.append(treeNode.getHumanReadableImage()); + buf.append(", "); + } + } + if (params[params.length - 1].getTreeNode() != null) { + final TreeNode treeNode = params[params.length - 1].getTreeNode(); + buf.append(treeNode.getHumanReadableImage()); + } + buf.append(")"); + } + return buf.toString(); + } + /** * Displays this node as a String, implementing ExploreNode * interface; depth parameter is a bound on the depth of the portion @@ -1318,6 +1343,25 @@ public class OpDefNode extends OpDefOrDeclNode return ret; } + @Override + public String getHumanReadableImage() { + // This ony gets pre-comments (directly in front of the operator definition). + // In-line comments - e.g. found in the standard modules - are not pre-comments. + final String comment = getComment(); + + final StringBuffer buf = new StringBuffer(comment); + buf.append("\n"); + + TreeNode[] ones = getTreeNode().one(); + for (TreeNode treeNode : ones) { + // TODO This omits all whitespaces from the definition and is thus hard to read. + // I couldn't figure out a better way to obtain the original image though. + buf.append(treeNode.getHumanReadableImage()); + buf.append(" "); + } + return buf.toString().trim(); + } + protected String getNodeRef() { switch (getKind()) { case UserDefinedOpKind: diff --git a/tlatools/src/tla2sany/semantic/OpDefOrDeclNode.java b/tlatools/src/tla2sany/semantic/OpDefOrDeclNode.java index d174b3fb54c84c53fd893b410d87893319374437..adb581946e9dc2a60ff1dbd6ddca1892568c7132 100644 --- a/tlatools/src/tla2sany/semantic/OpDefOrDeclNode.java +++ b/tlatools/src/tla2sany/semantic/OpDefOrDeclNode.java @@ -81,5 +81,17 @@ public abstract class OpDefOrDeclNode extends SymbolNode { ? originallyDefinedInModule.getName().toString() : "<null>" ); } - + + public String getComment() { + final StringBuffer buf = new StringBuffer(); + + //TODO Support in-line comments found in the standard modules. + final String[] preComments = getPreComments(); + for (String string : preComments) { + buf.append(string); + buf.append("\n"); + } + + return buf.toString().replace("\n$", "").trim(); + } } diff --git a/tlatools/src/tla2sany/semantic/SemanticNode.java b/tlatools/src/tla2sany/semantic/SemanticNode.java index a421bdfd3aade8b8cdff42053afc3a27d321234b..45068ff61b594ed5323e920981d471ef8eaca780 100644 --- a/tlatools/src/tla2sany/semantic/SemanticNode.java +++ b/tlatools/src/tla2sany/semantic/SemanticNode.java @@ -15,6 +15,7 @@ import tla2sany.parser.SyntaxTreeNode; import tla2sany.st.Location; import tla2sany.st.TreeNode; import tla2sany.xml.XMLExportable; +import tlc2.value.Value; import util.ToolIO; /** @@ -253,6 +254,14 @@ public abstract class SemanticNode return this.getLocation().toString(); } + public String getHumanReadableImage() { + return getLocation().toString(); + } + + public String toString(final Value aValue) { + return Value.ppr(aValue.toString()); + } + /** * August 2014 - TL * All nodes inherit from semantic node, which just attach location to the returned node diff --git a/tlatools/src/tla2sany/semantic/SymbolMatcher.java b/tlatools/src/tla2sany/semantic/SymbolMatcher.java new file mode 100644 index 0000000000000000000000000000000000000000..2866761da704b34b4371e7acd8e0a1ce77c6e0f9 --- /dev/null +++ b/tlatools/src/tla2sany/semantic/SymbolMatcher.java @@ -0,0 +1,97 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tla2sany.semantic; + +import java.util.HashSet; +import java.util.Set; + +public interface SymbolMatcher { + + /** + * @return true if the given {@link SymbolNode} matches this predicate. + */ + boolean matches(final SymbolNode aSymbol); + + public static class NameAndTypeMatcher implements SymbolMatcher { + + private String prefix; + + //** Invoked by clients of ModuleNode#getSymbols **// + + public NameAndTypeMatcher setPrefix(final String aPrefix) { + this.prefix = aPrefix; + return this; + } + + //** Invoked by ModuleNode, overridden by clients **// + + /* (non-Javadoc) + * @see tla2sany.semantic.SymbolMatcher#matches(tla2sany.semantic.SymbolNode) + */ + @Override + public boolean matches(final SymbolNode aSymbol) { + if (!matchesAnyType() && !matchTypes().contains(aSymbol.getClass())) { + // TODO Better test for isAssignableFrom(aSymbol.getClass()), but would require + // looping over matchTypes. + return false; + } + if (aSymbol.getKind() == ASTConstants.BuiltInKind && aSymbol.getName().toString().startsWith("$")) { + // Do not match internal built-in operators. + return false; + } + + final String symbolName = aSymbol.getName().toString(); + if (matchCaseSensitive() && !symbolName.startsWith(getPrefix())) { + return false; + } else if (!symbolName.toLowerCase().startsWith(getPrefix().toLowerCase())){ + return false; + } + + return true; + } + + //** Invoked by matches, subclasses may override **// + + /** + * @return A Set of SymbolNodes to match. + */ + protected Set<Class<? extends SymbolNode>> matchTypes() { + return new HashSet<>(); + } + + protected boolean matchesAnyType() { + return matchTypes().isEmpty(); + } + + protected boolean matchCaseSensitive() { + return false; + } + + protected String getPrefix() { + return prefix; + } + } +} diff --git a/tlatools/src/tla2sany/semantic/SymbolNode.java b/tlatools/src/tla2sany/semantic/SymbolNode.java index 82e7b074b918422d8cbae9684de9122342462b33..907e7af38585de542964efd09bb97073455ca4e8 100644 --- a/tlatools/src/tla2sany/semantic/SymbolNode.java +++ b/tlatools/src/tla2sany/semantic/SymbolNode.java @@ -73,6 +73,10 @@ public abstract class SymbolNode extends LevelNode { return (this instanceof OpDeclNode || this instanceof FormalParamNode); } + + public String getSignature() { + return getName().toString(); + } /** * Returns true iff this node and otherNode are both OpDefOrDeclNode objects or diff --git a/tlatools/src/tla2sany/st/TreeNode.java b/tlatools/src/tla2sany/st/TreeNode.java index 7c7bb106ab5f1872619fced4462a2157563d6a3d..e80cc8c547ea2fdaaa8edc2702e06b57168ed117 100644 --- a/tlatools/src/tla2sany/st/TreeNode.java +++ b/tlatools/src/tla2sany/st/TreeNode.java @@ -20,4 +20,5 @@ public interface TreeNode { // public String[] getPostComments(); // always returns an array, never null public boolean local(); public void printST(int indentation); + public String getHumanReadableImage(); } diff --git a/tlatools/src/tlc2/Generator.java b/tlatools/src/tlc2/Generator.java deleted file mode 100644 index 096be20ef479a84b5b36a2764871fcff285a6533..0000000000000000000000000000000000000000 --- a/tlatools/src/tlc2/Generator.java +++ /dev/null @@ -1,189 +0,0 @@ -// Copyright (c) 2003 Compaq Corporation. All rights reserved. -// Portions Copyright (c) 2003 Microsoft Corporation. All rights reserved. -// Last modified on Mon 30 Apr 2007 at 16:11:13 PST by lamport -// modified on Fri Jun 1 15:26:01 PDT 2001 by yuanyu - -package tlc2; - -import tlc2.output.EC; -import tlc2.output.MP; -import tlc2.tool.Simulator; -import tlc2.util.RandomGenerator; -import util.ToolIO; - -public class Generator { - /* - * This TLA trace generator generates random execution traces: - * srcjava tlc.Generator spec[.tla] - * - * The command line provides the following options: - * o -deadlock: do not check for deadlock. - * Defaults to checking deadlock if not specified - * o -f file: the file storing the traces. Defaults to spec_trace - * o -d num: the max length of the trace. Defaults to 10 - * o -config file: the config file. Defaults to spec.cfg - * o -coverage seconds: collect coverage information on the spec, - * print out the information every seconds - * Defaults to no coverage if not specified - * o -n num: the max number of traces. Defaults to 10 - * o -s: the seed for random simulation - * Defaults to a random seed if not specified - * o -aril num: Adjust the seed for random simulation - * Defaults to 0 if not specified - */ - public static void main(String[] args) { - System.out.println("TLC trace generator, " + TLCGlobals.versionOfTLC); - - String mainFile = null; - String traceFile = null; - boolean deadlock = true; - String configFile = null; - int traceDepth = 10; - int traceNum = 10; - boolean noSeed = true; - long seed = 0; - long aril = 0; - - int index = 0; - while (index < args.length) { - if (args[index].equals("-f")) { - index++; - if (index >= args.length) { - printErrorMsg("Error: no argument given for -f option."); - return; - } - traceFile = args[index++]; - } - else if (args[index].equals("-deadlock")) { - index++; - deadlock = false; - } - else if (args[index].equals("-d")) { - index++; - if (index >= args.length) { - printErrorMsg("Error: no argument given for -d option."); - return; - } - traceDepth = Integer.parseInt(args[index]); - index++; - } - else if (args[index].equals("-n")) { - index++; - if (index >= args.length) { - printErrorMsg("Error: no argument given for -n option."); - return; - } - traceNum = Integer.parseInt(args[index]); - index++; - } - else if (args[index].equals("-coverage")) { - index++; - if (index < args.length) { - try { - TLCGlobals.coverageInterval = Integer.parseInt(args[index]) * 60 * 1000; - if (TLCGlobals.coverageInterval < 0) { - printErrorMsg("Error: expect a nonnegative integer for -coverage option."); - return; - } - index++; - } - catch (Exception e) { - printErrorMsg("Error: An integer for coverage report interval required." + - " But encountered " + args[index]); - return; - } - } - else { - printErrorMsg("Error: coverage report interval required."); - return; - } - } - else if (args[index].equals("-s")) { - index++; - if (index < args.length) { - seed = Long.parseLong(args[index++]); - noSeed = false; - } - else { - printErrorMsg("Error: seed required."); - return; - } - } - else if (args[index].equals("-aril")) { - index++; - if (index < args.length) { - aril = Long.parseLong(args[index++]); - } - else { - printErrorMsg("Error: aril required."); - return; - } - } - else if (args[index].equals("-config")) { - index++; - if (index < args.length) { - configFile = args[index]; - int len = configFile.length(); - if (configFile.startsWith(".cfg", len-4)) { - configFile = configFile.substring(0, len-4); - } - index++; - } - else { - printErrorMsg("Error: config file required."); - return; - } - } - else { - if (args[index].charAt(0) == '-') { - printErrorMsg("Error: unrecognized option: " + args[index]); - return; - } - if (mainFile != null) { - printErrorMsg("Error: more than one input files: " + mainFile - + " and " + args[index]); - return; - } - mainFile = args[index++]; - int len = mainFile.length(); - if (mainFile.startsWith(".tla", len-4)) { - mainFile = mainFile.substring(0, len-4); - } - } - } - if (mainFile == null) { - printErrorMsg("Error: Missing input TLA+ module."); - return; - } - if (traceFile == null) traceFile = mainFile + "_trace"; - if (configFile == null) configFile = mainFile; - - // Start generating traces: - try { - RandomGenerator rng = new RandomGenerator(); - if (noSeed) { - seed = rng.nextLong(); - rng.setSeed(seed); - } - else { - rng.setSeed(seed, aril); - } - ToolIO.out.println("Generating random traces with seed " + seed + "."); - Simulator simulator = new Simulator(mainFile, configFile, traceFile, - deadlock, traceDepth, traceNum, - rng, seed, true, null, /* no spec obj */ null); - simulator.simulate(); - } - catch (Exception e) { - // Assert.printStack(e); - MP.printError(EC.GENERAL, "generating traces", e); // LL changed call 7 April 2012 - } - //System.exit(0); //SZ: no-op removed - } - - // TODO replace - private static void printErrorMsg(String msg) { - MP.printError(EC.WRONG_COMMANDLINE_PARAMS_SIMULATOR, msg); - } - -} diff --git a/tlatools/src/tlc2/TLC.java b/tlatools/src/tlc2/TLC.java index 7c1d147c5a98924cf7b3009489b62ec8a41c5bf4..0b63b84ddcb982a7453d2edb2f293cc7d5d70eb1 100644 --- a/tlatools/src/tlc2/TLC.java +++ b/tlatools/src/tlc2/TLC.java @@ -11,6 +11,7 @@ import java.io.FileWriter; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.Date; import java.util.Enumeration; import java.util.List; import java.util.TimeZone; @@ -30,8 +31,13 @@ import tlc2.tool.fp.FPSet; import tlc2.tool.fp.FPSetConfiguration; import tlc2.tool.management.ModelCheckerMXWrapper; import tlc2.tool.management.TLCStandardMBean; +import tlc2.util.DotStateWriter; import tlc2.util.FP64; +import tlc2.util.IStateWriter; +import tlc2.util.NoopStateWriter; import tlc2.util.RandomGenerator; +import tlc2.util.StateWriter; +import tlc2.value.EnumerableValue; import tlc2.value.Value; import util.DebugPrinter; import util.FileUtil; @@ -47,7 +53,6 @@ import util.UniqueString; * @author Yuan Yu * @author Leslie Lamport * @author Simon Zambrovski - * @version $Id$ */ public class TLC { @@ -63,21 +68,24 @@ public class TLC private boolean noSeed; private long seed; private long aril; + + private long startTime; private String mainFile; private String configFile; - private String dumpFile; + private String metadir; /** - * If true, the dumpFile will be written in dot format to be processed by - * GraphViz. + * If instantiated with a non-Noop* instance, the trace will be written to the + * user provided file (-dump paramter). * <p> - * Contrary to plain -dump, -dot will also write out transitions from state - * s to s' if s' is already known. Thus, the resulting graph shows all - * successors of s instead of just s's unexplored ones. + * Contrary to plain -dump, -dot will also write out transitions from state s to + * s' if s' is already known. Thus, the resulting graph shows all successors of + * s instead of just s's unexplored ones. * <p> - * Off/False by default. + * Off (NoopStateWriter) by default. */ - private boolean asDot; + private IStateWriter stateWriter = new NoopStateWriter(); + private String fromChkpt; private int fpIndex; @@ -85,6 +93,7 @@ public class TLC * The number of traces/behaviors to generate in simulation mode */ public static long traceNum = Long.MAX_VALUE; + private String traceFile = null; private int traceDepth; private FilenameToStream resolver; private SpecObj specObj; @@ -114,8 +123,6 @@ public class TLC mainFile = null; configFile = null; - dumpFile = null; - asDot = false; fromChkpt = null; resolver = null; @@ -235,11 +242,16 @@ public class TLC * This method handles parameter arguments and prepares the actual call * <strong>Note:</strong> This method set ups the static TLCGlobals variables * @return status of parsing: true iff parameter check was ok, false otherwise + * @throws IOException */ // SZ Feb 23, 2009: added return status to indicate the error in parsing - @SuppressWarnings("deprecation") public boolean handleParameters(String[] args) { + String dumpFile = null; + boolean asDot = false; + boolean colorize = false; + boolean actionLabels = false; + // SZ Feb 20, 2009: extracted this method to separate the // parameter handling from the actual processing int index = 0; @@ -249,6 +261,26 @@ public class TLC { isSimulate = true; index++; + + // Simulation args can be: + // file=/path/to/file,num=4711 or num=4711,file=/path/to/file or num=4711 or + // file=/path/to/file + // "file=..." and "num=..." are only relevant for simulation which is why they + // are args to "-simulate". + if (index + 1 < args.length && (args[index].contains("file=") || args[index].contains("num="))) { + final String[] simArgs = args[index].split(","); + index++; // consume simulate args + for (String arg : simArgs) { + if (arg.startsWith("num=")) { + traceNum = Integer.parseInt(arg.replace("num=", "")); + } else if (arg.startsWith("file=")) { + traceFile = arg.replace("file=", ""); + } + } + for (int i = 0; i < simArgs.length; i++) { + + } + } } else if (args[index].equals("-modelcheck")) { isSimulate = false; @@ -328,26 +360,19 @@ public class TLC } } else if (args[index].equals("-dump")) { - String suffix = ".dump"; - - index++; - if (index < args.length && args[index].equals("dot")) + index++; // consume "-dump". + if (index + 1 < args.length && args[index].startsWith("dot")) { - asDot = true; - suffix = ".dot"; - index++; + final String dotArgs = args[index].toLowerCase(); + index++; // consume "dot...". + asDot = true; + colorize = dotArgs.contains("colorize"); + actionLabels = dotArgs.contains("actionlabels"); + dumpFile = getDumpFile(args[index++], ".dot"); } - if (index < args.length) + else if (index < args.length) { - dumpFile = args[index]; - // Require a $suffix file extension unless already given. It - // is not clear why this is enforced. - int len = dumpFile.length(); - if (!(dumpFile.startsWith(suffix, len - suffix.length()))) - { - dumpFile = dumpFile + suffix; - } - index++; + dumpFile = getDumpFile(args[index++], ".dump"); } else { printErrorMsg("Error: A file name for dumping states required."); @@ -518,7 +543,7 @@ public class TLC if (index < args.length) { try { - // Most problems will only show we TLC eventually tries + // Most problems will only show when TLC eventually tries // to write to the file. tlc2.module.TLC.OUTPUT = new BufferedWriter(new FileWriter(new File(args[index++]))); } catch (IOException e) { @@ -719,6 +744,35 @@ public class TLC { configFile = mainFile; } + + startTime = System.currentTimeMillis(); + + // Check if mainFile is an absolute or relative file system path. If it is + // absolute, the parent gets used as TLC's meta directory (where it stores + // states...). Otherwise, no meta dir is set causing states etc. to be stored in + // the current directory. + final File f = new File(mainFile); + metadir = FileUtil.makeMetaDir(new Date(startTime), f.isAbsolute() ? f.getParent() : "", fromChkpt); + + if (dumpFile != null) { + if (dumpFile.startsWith("${metadir}")) { + // prefix dumpfile with the known value of this.metadir. There + // is no way to determine the actual value of this.metadir + // before TLC startup and thus it's impossible to make the + // dumpfile end up in the metadir if desired. + dumpFile = dumpFile.replace("${metadir}", metadir); + } + try { + if (asDot) { + this.stateWriter = new DotStateWriter(dumpFile, colorize, actionLabels); + } else { + this.stateWriter = new StateWriter(dumpFile); + } + } catch (IOException e) { + printErrorMsg(String.format("Error: Given file name %s for dumping states invalid.", dumpFile)); + return false; + } + } if (TLCGlobals.debug) { @@ -740,14 +794,23 @@ public class TLC return true; } - - /** + + /** + * Require a $suffix file extension unless already given. It is not clear why + * this is enforced. + */ + private static String getDumpFile(String dumpFile, String suffix) { + if (dumpFile.endsWith(suffix)) { + return dumpFile; + } + return dumpFile + suffix; + } + + /** * The processing method */ public void process() { - long startTime = System.currentTimeMillis(); - ToolIO.cleanToolObjects(TLCGlobals.ToolId); // UniqueString.initialize(); @@ -787,11 +850,11 @@ public class TLC final String osVersion = System.getProperty("os.version"); final String osArch = System.getProperty("os.arch"); + final RandomGenerator rng = new RandomGenerator(); // Start checking: if (isSimulate) { // random simulation - RandomGenerator rng = new RandomGenerator(); if (noSeed) { seed = rng.nextLong(); @@ -804,7 +867,7 @@ public class TLC new String[] { String.valueOf(seed), String.valueOf(TLCGlobals.getNumWorkers()), TLCGlobals.getNumWorkers() == 1 ? "" : "s", cores, osName, osVersion, osArch, vendor, version, arch, Long.toString(heapMemory), Long.toString(offHeapMemory) }); - Simulator simulator = new Simulator(mainFile, configFile, null, deadlock, traceDepth, + Simulator simulator = new Simulator(mainFile, configFile, traceFile, deadlock, traceDepth, traceNum, rng, seed, true, resolver, specObj); TLCGlobals.simulator = simulator; // The following statement moved to Spec.processSpec by LL on 10 March 2011 @@ -813,21 +876,27 @@ public class TLC simulator.simulate(); } else { - final String[] parameters = new String[] { String.valueOf(TLCGlobals.getNumWorkers()), - TLCGlobals.getNumWorkers() == 1 ? "" : "s", cores, osName, osVersion, osArch, vendor, - version, arch, Long.toString(heapMemory), Long.toString(offHeapMemory) }; + if (noSeed) { + seed = rng.nextLong(); + } + EnumerableValue.setRandom(seed); + + final String[] parameters = new String[] { String.valueOf(TLCGlobals.getNumWorkers()), + TLCGlobals.getNumWorkers() == 1 ? "" : "s", cores, osName, osVersion, osArch, vendor, version, + arch, Long.toString(heapMemory), Long.toString(offHeapMemory), + Long.toString(EnumerableValue.getRandomSeed()) }; // model checking AbstractChecker mc = null; if (TLCGlobals.DFIDMax == -1) { MP.printMessage(EC.TLC_MODE_MC, parameters); - mc = new ModelChecker(mainFile, configFile, dumpFile, asDot, deadlock, fromChkpt, resolver, specObj, fpSetConfiguration); + mc = new ModelChecker(mainFile, configFile, metadir, stateWriter, deadlock, fromChkpt, resolver, specObj, fpSetConfiguration); modelCheckerMXWrapper = new ModelCheckerMXWrapper((ModelChecker) mc, this); } else { MP.printMessage(EC.TLC_MODE_MC_DFS, parameters); - mc = new DFIDModelChecker(mainFile, configFile, dumpFile, asDot, deadlock, fromChkpt, true, resolver, specObj); + mc = new DFIDModelChecker(mainFile, configFile, metadir, stateWriter, deadlock, fromChkpt, true, resolver, specObj); } TLCGlobals.mainChecker = mc; // The following statement moved to Spec.processSpec by LL on 10 March 2011 diff --git a/tlatools/src/tlc2/TLCGlobals.java b/tlatools/src/tlc2/TLCGlobals.java index 0e646f6abd2b07c9402d29afb1a5fd21a27a62ef..f5c9c75cb76ffcbf7273c8bd7693728f98088896 100644 --- a/tlatools/src/tlc2/TLCGlobals.java +++ b/tlatools/src/tlc2/TLCGlobals.java @@ -22,11 +22,11 @@ public class TLCGlobals { // The current version of TLC - public static String versionOfTLC = "Version 2.12 of 29 January 2018"; + public static String versionOfTLC = "Version 2.13 of 18 July 2018"; // The bound for set enumeration, used for pretty printing public static int enumBound = 2000; - + // The bound for the cardinality of a set public static int setBound = 1000000; @@ -54,7 +54,7 @@ public class TLCGlobals return !lnCheck.equals("final"); } - public synchronized static void setNumWorkers(int n) + public synchronized static void setNumWorkers(int n) { numWorkers = n; } diff --git a/tlatools/src/tlc2/module/Bags.java b/tlatools/src/tlc2/module/Bags.java index bdf1fdb08bb0b67ded3acf448b0361a726c6f296..81fddf3aa8279449005cef3a50eb7702c20e7725 100644 --- a/tlatools/src/tlc2/module/Bags.java +++ b/tlatools/src/tlc2/module/Bags.java @@ -18,6 +18,7 @@ import tlc2.value.SetEnumValue; import tlc2.value.Value; import tlc2.value.ValueConstants; import tlc2.value.ValueVec; +import util.Assert; public class Bags implements ValueConstants { @@ -25,9 +26,13 @@ public class Bags implements ValueConstants static { - TLARegistry.put("BagCup", "\\oplus"); - TLARegistry.put("BagDiff", "\\ominus"); - TLARegistry.put("SqSubseteq", "\\sqsubseteq"); + // The following entries in TLARegistry each defines a mapping from a TLA+ infix + // operator to a Java method, e.g. the TLA+ infix operator \\oplus (which is the + // same as (+) ) is mapped to and thus implemented by the Java method + // tlc2.module.Bags.BagCup(Value, Value) below. + Assert.check(TLARegistry.put("BagCup", "\\oplus") == null, EC.TLC_REGISTRY_INIT_ERROR, "BagCup"); + Assert.check(TLARegistry.put("BagDiff", "\\ominus") == null, EC.TLC_REGISTRY_INIT_ERROR, "BagDiff"); + Assert.check(TLARegistry.put("SqSubseteq", "\\sqsubseteq") == null, EC.TLC_REGISTRY_INIT_ERROR, "SqSubseteq"); } public static Value EmptyBag() @@ -35,18 +40,20 @@ public class Bags implements ValueConstants return EmptyFcn; } - public static BoolValue IsABag(Value b) + public static BoolValue IsABag(final Value b) { - FcnRcdValue fcn = FcnRcdValue.convert(b); + final FcnRcdValue fcn = FcnRcdValue.convert(b); if (fcn == null) { - throw new EvalException(EC.TLC_MODULE_APPLYING_TO_WRONG_VALUE, new String[] { "IsBag", - "a function with a finite domain", Value.ppr(b.toString()) }); + // MAK 02/23/2018 Changed to return ValFalse instead of exception when Value is not a bag. + //throw new EvalException(EC.TLC_MODULE_APPLYING_TO_WRONG_VALUE, new String[] { "IsBag", + // "a function with a finite domain", Value.ppr(b.toString()) }); + return ValFalse; } - Value[] vals = fcn.values; + final Value[] vals = fcn.values; for (int i = 0; i < vals.length; i++) { - if (!(vals[i] instanceof IntValue) || ((IntValue) vals[i]).val < 0) + if (!(vals[i] instanceof IntValue) || ((IntValue) vals[i]).val <= 0) { return ValFalse; } @@ -86,12 +93,11 @@ public class Bags implements ValueConstants return IntValue.gen(num); } - public static BoolValue BagIn(Value e, Value b) + public static BoolValue BagIn(final Value e, final Value b) { - FcnRcdValue fcn = FcnRcdValue.convert(b); - Value[] domain = fcn.domain; - Value[] values = fcn.values; - // Value val; // SZ: variable never read locally + final FcnRcdValue fcn = FcnRcdValue.convert(b); + final Value[] values = fcn.values; + final Value[] domain = fcn.getDomainAsValues(); for (int i = 0; i < domain.length; i++) { if (e.equals(domain[i])) @@ -107,12 +113,11 @@ public class Bags implements ValueConstants return ValFalse; } - public static IntValue CopiesIn(Value e, Value b) + public static IntValue CopiesIn(final Value e, final Value b) { - FcnRcdValue fcn = FcnRcdValue.convert(b); - Value[] domain = fcn.domain; - Value[] values = fcn.values; - // Value val; // SZ: variable never read locally + final FcnRcdValue fcn = FcnRcdValue.convert(b); + final Value[] values = fcn.values; + final Value[] domain = fcn.getDomainAsValues(); for (int i = 0; i < domain.length; i++) { if (e.equals(domain[i])) @@ -142,9 +147,9 @@ public class Bags implements ValueConstants throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR, new String[] { "second", "(+)", "bag", Value.ppr(b2.toString()) }); } - Value[] domain1 = fcn1.domain; + Value[] domain1 = fcn1.getDomainAsValues(); Value[] values1 = fcn1.values; - Value[] domain2 = fcn2.domain; + Value[] domain2 = fcn2.getDomainAsValues(); Value[] values2 = fcn2.values; Vect dVec = new Vect(domain1.length); Vect vVec = new Vect(domain1.length); @@ -197,9 +202,9 @@ public class Bags implements ValueConstants throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR, new String[] { "second", "(-)", "bag", Value.ppr(b2.toString()) }); } - Value[] domain1 = fcn1.domain; + Value[] domain1 = fcn1.getDomainAsValues(); Value[] values1 = fcn1.values; - Value[] domain2 = fcn2.domain; + Value[] domain2 = fcn2.getDomainAsValues(); Value[] values2 = fcn2.values; Vect dVec = new Vect(domain1.length); Vect vVec = new Vect(domain1.length); @@ -231,20 +236,29 @@ public class Bags implements ValueConstants return new FcnRcdValue(domain, values, fcn1.isNormalized()); } - public static Value BagUnion(Value s) + public static Value BagUnion(final Value s) { - SetEnumValue s1 = SetEnumValue.convert(s); + final SetEnumValue s1 = SetEnumValue.convert(s); if (s1 == null) { throw new EvalException(EC.TLC_MODULE_APPLYING_TO_WRONG_VALUE, new String[] { "BagUnion", "a finite enumerable set", Value.ppr(s.toString()) }); } + // MAK 02/20/2018: + // Need to normalize s in cases where it is an unnormalized set of identical + // bags, such as h == [ i \in 1..3 |-> 1 ] and BagUnion({h, h}). In other + // words, let b be a bag, BagUnion({b,b}) = b and not b (+) b. This + // unfortunately degrades performance due to sorting s1's elements. + s1.normalize(); + ValueVec elems = s1.elems; int sz = elems.size(); - if (sz == 0) - return EmptyFcn; - if (sz == 1) - return elems.elementAt(0); + if (sz == 0) { + return EmptyFcn; + } + if (sz == 1) { + return elems.elementAt(0); + } ValueVec dVec = new ValueVec(); ValueVec vVec = new ValueVec(); FcnRcdValue fcn = FcnRcdValue.convert(elems.elementAt(0)); @@ -252,7 +266,7 @@ public class Bags implements ValueConstants { throw new EvalException(EC.TLC_MODULE_BAG_UNION1, Value.ppr(s.toString())); } - Value[] domain = fcn.domain; + Value[] domain = fcn.getDomainAsValues(); Value[] values = fcn.values; for (int i = 0; i < domain.length; i++) { @@ -267,7 +281,7 @@ public class Bags implements ValueConstants throw new EvalException(EC.TLC_MODULE_BAG_UNION1, Value.ppr(s.toString())); } - domain = fcn.domain; + domain = fcn.getDomainAsValues(); values = fcn.values; for (int j = 0; j < domain.length; j++) { @@ -315,9 +329,9 @@ public class Bags implements ValueConstants throw new EvalException(EC.TLC_MODULE_APPLYING_TO_WRONG_VALUE, new String[] { "\\sqsubseteq", "a function with a finite domain", Value.ppr(b2.toString()) }); } - Value[] domain1 = fcn1.domain; + Value[] domain1 = fcn1.getDomainAsValues(); Value[] values1 = fcn1.values; - Value[] domain2 = fcn2.domain; + Value[] domain2 = fcn2.getDomainAsValues(); Value[] values2 = fcn2.values; for (int i = 0; i < domain1.length; i++) { @@ -353,7 +367,7 @@ public class Bags implements ValueConstants Applicable ff = (Applicable) f; ValueVec dVec = new ValueVec(); ValueVec vVec = new ValueVec(); - Value[] domain = fcn.domain; + Value[] domain = fcn.getDomainAsValues(); Value[] values = fcn.values; Value[] args = new Value[1]; for (int i = 0; i < domain.length; i++) diff --git a/tlatools/src/tlc2/module/BuiltInModuleHelper.java b/tlatools/src/tlc2/module/BuiltInModuleHelper.java index ac0d789c7762064354e84942af9ceb9266312806..8b62e2b08e4e23e57442eb55aed1d1ffebfdeef7 100644 --- a/tlatools/src/tlc2/module/BuiltInModuleHelper.java +++ b/tlatools/src/tlc2/module/BuiltInModuleHelper.java @@ -26,10 +26,16 @@ package tlc2.module; +import java.io.File; import java.lang.reflect.Field; public class BuiltInModuleHelper { + public static final String BUNDLE_ID = "org.lamport.tlatools"; + + public static final String STANDARD_MODULES = "StandardModules"; + public static final String STANDARD_MODULES_PATH = File.separator + "tla2sany" + File.separator; + private BuiltInModuleHelper() { // no instantiation } @@ -60,6 +66,8 @@ public class BuiltInModuleHelper { return true; } else if (clazz == TransitiveClosure.class && value == TransitiveClosure.serialVersionUID) { return true; + } else if (clazz == Randomization.class && value == Randomization.serialVersionUID) { + return true; } } } catch (SecurityException e) { diff --git a/tlatools/src/tlc2/module/Integers.java b/tlatools/src/tlc2/module/Integers.java index aa12d836990a6f06faabb69e6733d2fc618bff05..db0a17d4f25c210c8984f20481caa905b0558a6e 100644 --- a/tlatools/src/tlc2/module/Integers.java +++ b/tlatools/src/tlc2/module/Integers.java @@ -23,6 +23,11 @@ public class Integers extends UserObj implements ValueConstants static { + // The following entries in TLARegistry each define a mapping from a TLA+ infix + // operator to a Java method, e.g. the TLA+ infix operator "+" is mapped to and + // thus implemented by the Java method tlc2.module.Integers.Plus(IntValue, + // IntValue) below. + //TODO Why does tlc2.module.Naturals define identical mappings? TLARegistry.put("Plus", "+"); TLARegistry.put("Minus", "-"); TLARegistry.put("Times", "*"); diff --git a/tlatools/src/tlc2/module/Naturals.java b/tlatools/src/tlc2/module/Naturals.java index 233c97abf52fb621a8dc6d91a2ba4ae7cf3d2de2..1add6f45b66018cb93afcfbbe31a04533ffbc17d 100644 --- a/tlatools/src/tlc2/module/Naturals.java +++ b/tlatools/src/tlc2/module/Naturals.java @@ -23,6 +23,11 @@ public class Naturals extends UserObj implements ValueConstants static { + // The following entries in TLARegistry each define a mapping from a TLA+ infix + // operator to a Java method, e.g. the TLA+ infix operator "+" is mapped to and + // thus implemented by the Java method tlc2.module.Naturals.Plus(IntValue, + // IntValue) below. + //TODO Why does tlc2.module.Integers define identical mappings? TLARegistry.put("Plus", "+"); TLARegistry.put("Minus", "-"); TLARegistry.put("Times", "*"); diff --git a/tlatools/src/tlc2/module/Randomization.java b/tlatools/src/tlc2/module/Randomization.java new file mode 100644 index 0000000000000000000000000000000000000000..04bb449d25e8a91e5c40658353e9791998abcf32 --- /dev/null +++ b/tlatools/src/tlc2/module/Randomization.java @@ -0,0 +1,147 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.module; + +import tlc2.output.EC; +import tlc2.tool.EvalException; +import tlc2.value.Enumerable; +import tlc2.value.EnumerableValue; +import tlc2.value.IntValue; +import tlc2.value.StringValue; +import tlc2.value.SubsetValue; +import tlc2.value.Value; +import tlc2.value.ValueConstants; + +public class Randomization implements ValueConstants { + + public static final long serialVersionUID = 20180618L; + + public static Value RandomSubset(final Value v1, final Value v2) { + if (!(v1 instanceof IntValue)) { + throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR, + new String[] { "first", "RandomSubset", "nonnegative integer", Value.ppr(v1.toString()) }); + } + if (!(v2 instanceof Enumerable)) { + throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR, + new String[] { "second", "RandomSubset", "a finite set", Value.ppr(v2.toString()) }); + } + return ((Enumerable) v2).getRandomSubset(((IntValue) v1).val); + } + + public static Value RandomSetOfSubsets(final Value v1, final Value v2, final Value v3) { + // first parameter + if (!(v1 instanceof IntValue)) { + throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR, + new String[] { "first", "RandomSetOfSubsets", "nonnegative integer", Value.ppr(v1.toString()) }); + } + final int numberOfPicks = ((IntValue) v1).val; + if (numberOfPicks < 0) { + throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR, + new String[] { "first", "RandomSetOfSubsets", "nonnegative integer", Value.ppr(v1.toString()) }); + } + // second parameter + if (!(v2 instanceof IntValue)) { + throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR, + new String[] { "second", "RandomSetOfSubsets", "nonnegative integer", Value.ppr(v2.toString()) }); + } + final int n = ((IntValue) v2).val; + if (n < 0) { + throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR, + new String[] { "second", "RandomSetOfSubsets", "nonnegative integer", Value.ppr(v2.toString()) }); + } + // third parameter + if (!(v3 instanceof Enumerable)) { + throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR, + new String[] { "third", "RandomSetOfSubsets", "finite set", Value.ppr(v3.toString()) }); + } + final EnumerableValue ev = (EnumerableValue) v3; + if (31 - Integer.numberOfLeadingZeros(numberOfPicks) + 1 > ev.size() && numberOfPicks > (1 << ev.size())) { + // First compare exponents before explicit calculating size of subset. The + // calculated value which is the subset's size then won't overflow. + throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR, + new String[] { "first", "RandomSetOfSubsets", + "nonnegative integer that is smaller than the subset's size of 2^" + ev.size(), + Integer.toString(numberOfPicks) }); + } + // second parameter (now that we know third is enumerable) + if (ev.size() < n) { + throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR, + new String[] { "second", "RandomSetOfSubsets", "nonnegative integer in range 0..Cardinality(S)", Value.ppr(v2.toString()) }); + } + final double probability = (1d * n) / ev.size(); + if (probability < 0d || 1d < probability) { + throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR, + new String[] { "second", "RandomSetOfSubsets", "nonnegative integer in range 0..Cardinality(S)", Value.ppr(v2.toString()) }); + } + return new SubsetValue(ev).getRandomSetOfSubsets(numberOfPicks, probability); + } + + public static Value RandomSubsetSet(final Value v1, final Value v2, final Value v3) { + // first parameter + if (!(v1 instanceof IntValue)) { + throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR, + new String[] { "first", "RandomSubsetSetProbability", "nonnegative integer", Value.ppr(v1.toString()) }); + } + final int numberOfPicks = ((IntValue) v1).val; + if (numberOfPicks < 0) { + throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR, + new String[] { "first", "RandomSubsetSetProbability", "nonnegative integer", Value.ppr(v1.toString()) }); + } + // second parameter + if (!(v2 instanceof StringValue)) { + throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR, + new String[] { "second", "RandomSubsetSetProbability", "string literal representing a probability", Value.ppr(v2.toString()) }); + + } + double probability; + try { + probability = Double.valueOf(((StringValue) v2).getVal().toString()); + } catch (NumberFormatException nfe) { + throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR, + new String[] { "second", "RandomSubsetSetProbability", "string literal does not represent a parsable probability", Value.ppr(v2.toString()) }); + } + if (probability < 0d || 1d < probability) { + throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR, + new String[] { "second", "RandomSubsetSetProbability", "string literal does not represent a parsable probability", Value.ppr(v2.toString()) }); + } + // third parameter + if (!(v3 instanceof Enumerable)) { + throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR, + new String[] { "third", "RandomSubsetSetProbability", "finite set", Value.ppr(v3.toString()) }); + } + final EnumerableValue ev = (EnumerableValue) v3; + if (31 - Integer.numberOfLeadingZeros(numberOfPicks) + 1 > ev.size() && numberOfPicks > (1 << ev.size())) { + // First compare exponents before explicit calculating size of subset. The + // calculated value which is the subset's size then won't overflow. + throw new EvalException(EC.TLC_MODULE_ARGUMENT_ERROR, + new String[] { "first", "RandomSubsetSetProbability", + "nonnegative integer that is smaller than the subset's size of 2^" + ev.size(), + Integer.toString(numberOfPicks) }); + } + + return new SubsetValue(ev).getRandomSetOfSubsets(numberOfPicks, probability); + } +} diff --git a/tlatools/src/tlc2/module/Sequences.java b/tlatools/src/tlc2/module/Sequences.java index 58eb10489b556708d216a74f3bd413b7a2855771..858837d12ddb95ab4c832d71db38b1fa42c342f2 100644 --- a/tlatools/src/tlc2/module/Sequences.java +++ b/tlatools/src/tlc2/module/Sequences.java @@ -40,7 +40,9 @@ public class Sequences extends UserObj implements ValueConstants static { - // SZ Jul 13, 2009: added message for initialization assertion + // This entry in TLARegistry defines a mapping from TLA+' infix + // operator \o to the Java method tlc2.module.Sequences.Concat(Value, Value) + // below. Assert.check(TLARegistry.put("Concat", "\\o") == null, EC.TLC_REGISTRY_INIT_ERROR, "Concat"); } diff --git a/tlatools/src/tlc2/module/TLC.java b/tlatools/src/tlc2/module/TLC.java index 797c5edf4b8ddcbbad78b15dc74eb7efaa1c5b34..5cdd4bcc9f49a47c269a0c15bf2cebf2b24add93 100644 --- a/tlatools/src/tlc2/module/TLC.java +++ b/tlatools/src/tlc2/module/TLC.java @@ -15,7 +15,6 @@ import tlc2.tool.EvalControl; import tlc2.tool.EvalException; import tlc2.tool.TLARegistry; import tlc2.util.IdThread; -import tlc2.util.RandomGenerator; import tlc2.value.Applicable; import tlc2.value.BoolValue; import tlc2.value.FcnRcdValue; @@ -38,14 +37,16 @@ public class TLC implements ValueConstants { public static final long serialVersionUID = 20160822L; - private static RandomGenerator rng; public static BufferedWriter OUTPUT; static { + // The following two entries in TLARegistry define a mapping from a TLA+ infix + // operator to a Java method, e.g. the TLA+ infix operator "@@" is mapped to and + // thus implemented by the Java method tlc2.module.TLC.CombineFcn(Value, Value) + // below. Assert.check(TLARegistry.put("MakeFcn", ":>") == null, EC.TLC_REGISTRY_INIT_ERROR, "MakeFcn"); Assert.check(TLARegistry.put("CombineFcn", "@@") == null, EC.TLC_REGISTRY_INIT_ERROR, "CombineFcn"); - rng = new RandomGenerator(); } /** @@ -337,6 +338,7 @@ public class TLC implements ValueConstants Value.ppr(res.toString()) }); } + // Returns a set of size n! where n = |s|. public static Value Permutations(Value s) { SetEnumValue s1 = SetEnumValue.convert(s); @@ -354,20 +356,19 @@ public class TLC implements ValueConstants return new SetEnumValue(elems1, true); } + int factorial = 1; Value[] domain = new Value[len]; - for (int i = 0; i < len; i++) - { - domain[i] = elems.elementAt(i); - } int[] idxArray = new int[len]; boolean[] inUse = new boolean[len]; for (int i = 0; i < len; i++) { + domain[i] = elems.elementAt(i); idxArray[i] = i; inUse[i] = true; + factorial = factorial * (i + 1); } - ValueVec fcns = new ValueVec(); + ValueVec fcns = new ValueVec(factorial); _done: while (true) { Value[] vals = new Value[len]; @@ -391,10 +392,12 @@ public class TLC implements ValueConstants break; } } - if (found) + if (found) { break; - if (i == 0) + } + if (i == 0) { break _done; + } inUse[idxArray[i]] = false; } for (int j = i + 1; j < len; j++) @@ -463,9 +466,7 @@ public class TLC implements ValueConstants throw new EvalException(EC.TLC_MODULE_APPLYING_TO_WRONG_VALUE, new String[] { "RandomElement", "a finite set", Value.ppr(val.toString()) }); } - int sz = enumVal.size(); - int index = (int) Math.floor(rng.nextDouble() * sz); - return enumVal.elems.elementAt(index); + return enumVal.randomElement(); } } } diff --git a/tlatools/src/tlc2/output/EC.java b/tlatools/src/tlc2/output/EC.java index 9af7acc06458b578801476e330aed3020afe529c..a64038cddcd05e58ff039d4a9aea526a4ac71f68 100644 --- a/tlatools/src/tlc2/output/EC.java +++ b/tlatools/src/tlc2/output/EC.java @@ -181,6 +181,7 @@ public interface EC public static final int TLC_MODE_MC_DFS = 2271; public static final int TLC_MODE_SIMU = 2188; public static final int TLC_COMPUTING_INIT = 2189; + public static final int TLC_COMPUTING_INIT_PROGRESS = 2269; public static final int TLC_INIT_GENERATED1 = 2190; public static final int TLC_INIT_GENERATED2 = 2191; public static final int TLC_INIT_GENERATED3 = 2207; diff --git a/tlatools/src/tlc2/output/MP.java b/tlatools/src/tlc2/output/MP.java index 2f415833ea6dbfec6f4e08588f18f5a1c91cdb52..dfc9fd956bd7a0f68a4ca7a21fe42e63801fbae5 100644 --- a/tlatools/src/tlc2/output/MP.java +++ b/tlatools/src/tlc2/output/MP.java @@ -129,7 +129,7 @@ public class MP private static MP instance = null; private static MPRecorder recorder = new MPRecorder(); - private Set warningHistory; + private final Set warningHistory; private static final String CONFIG_FILE_ERROR = "TLC found an error in the configuration file at line %1%\n"; private static final SimpleDateFormat SDF = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); //$NON-NLS-1$ private static final DecimalFormat df = new DecimalFormat("###,###.###"); @@ -359,7 +359,15 @@ public class MP break; case EC.TLC_STATE_NOT_COMPLETELY_SPECIFIED_NEXT: - b.append("Successor state is not completely specified by the" + " next-state action.\n"); + if (parameters.length == 3) { + b.append( + "Successor state is not completely specified by action %1% of the next-state relation. The following variable%2% not assigned: %3%.\n"); + } else if (parameters.length == 2) { + b.append( + "Successor state is not completely specified by the next-state action. The following variable%1% not assigned: %2%.\n"); + } else { + b.append("Successor state is not completely specified by the next-state action.\n"); + } break; case EC.TLC_INVARIANT_VIOLATED_BEHAVIOR: b.append("Invariant %1% is violated."); @@ -684,7 +692,11 @@ public class MP b.append("Implied-temporal checking--satisfiability problem has %1% branches."); break; case EC.TLC_LIVE_CANNOT_HANDLE_FORMULA: - b.append("TLC cannot handle the temporal formula %1%"); + if (parameters.length > 1) { + b.append("TLC cannot handle the temporal formula %1%:\n%2%"); + } else { + b.append("TLC cannot handle the temporal formula %1%"); + } break; case EC.TLC_LIVE_WRONG_FORMULA_FORMAT: b.append("Temporal formulas containing actions must be of forms <>[]A or []<>A."); @@ -797,10 +809,10 @@ public class MP b.append("Finished in %1% at (").append(SDF.format(new Date())).append(")"); break; case EC.TLC_MODE_MC: - b.append("Running breadth-first search Model-Checking with %1% worker%2% on %3% cores with %10%MB heap and %11%MB offheap memory (%4% %5% %6%, %7% %8% %9%)."); + b.append("Running breadth-first search Model-Checking with seed %12% with %1% worker%2% on %3% cores with %10%MB heap and %11%MB offheap memory (%4% %5% %6%, %7% %8% %9%)."); break; case EC.TLC_MODE_MC_DFS: - b.append("Running depth-first search Model-Checking with %1% worker%2% on %3% cores with %10%MB heap and %11%MB offheap memory (%4% %5% %6%, %7% %8% %9%)."); + b.append("Running depth-first search Model-Checking with seed %12% with %1% worker%2% on %3% cores with %10%MB heap and %11%MB offheap memory (%4% %5% %6%, %7% %8% %9%)."); break; case EC.TLC_MODE_SIMU: b.append("Running Random Simulation with seed %1% with %2% worker%3% on %4% cores with %11%MB heap and %12%MB offheap memory (%5% %6% %7%, %8% %9% %10%)."); @@ -808,6 +820,9 @@ public class MP case EC.TLC_COMPUTING_INIT: b.append("Computing initial states..."); break; + case EC.TLC_COMPUTING_INIT_PROGRESS: + b.append("Computed %1% initial states..."); + break; case EC.TLC_INIT_GENERATED1: b.append("Finished computing initial states: %1% distinct state%2% generated."); break; @@ -1089,7 +1104,9 @@ public class MP // post processing switch (messageClass) { case WARNING: - b.append("\n(Use the -nowarning option to disable this warning.)"); + if (instance.warningHistory.isEmpty()) { + b.append("\n(Use the -nowarning option to disable this warning.)"); + } break; case ERROR: if (TLCGlobals.tool) @@ -1134,7 +1151,7 @@ public class MP */ public static String getError(int errorCode, String[] parameters) { - recorder.record(errorCode, parameters); + recorder.record(errorCode, (Object[]) parameters); return getMessage(ERROR, errorCode, parameters); } @@ -1165,7 +1182,7 @@ public class MP */ public static String getMessage(int errorCode, String[] parameters) { - recorder.record(errorCode, parameters); + recorder.record(errorCode, (Object[]) parameters); return getMessage(NONE, errorCode, parameters); } diff --git a/tlatools/src/tlc2/tool/AbstractChecker.java b/tlatools/src/tlc2/tool/AbstractChecker.java index 805841275422e1e4b08ce8f129f1ae610bdc7eb1..86fdd34dff6eb040b27b101dbfcd61a46ab71699 100644 --- a/tlatools/src/tlc2/tool/AbstractChecker.java +++ b/tlatools/src/tlc2/tool/AbstractChecker.java @@ -1,5 +1,6 @@ package tlc2.tool; +import java.io.File; import java.io.IOException; import java.util.Hashtable; @@ -15,17 +16,14 @@ import tlc2.tool.liveness.ILiveCheck; import tlc2.tool.liveness.LiveCheck; import tlc2.tool.liveness.Liveness; import tlc2.tool.liveness.NoOpLiveCheck; -import tlc2.util.DotStateWriter; import tlc2.util.IStateWriter; -import tlc2.util.NoopStateWriter; +import tlc2.util.IdThread; import tlc2.util.ObjLongTable; -import tlc2.util.StateWriter; import tlc2.util.statistics.ConcurrentBucketStatistics; import tlc2.util.statistics.DummyBucketStatistics; import tlc2.util.statistics.IBucketStatistics; import tlc2.value.Value; import util.DebugPrinter; -import util.FileUtil; import util.FilenameToStream; /** @@ -83,18 +81,15 @@ public abstract class AbstractChecker implements Cancelable * @param resolver * @param spec - pre-built specification object (e.G. from calling SANY from the tool previously) */ - public AbstractChecker(String specFile, String configFile, String dumpFile, final boolean asDot, boolean deadlock, String fromChkpt, + public AbstractChecker(String specFile, String configFile, String metadir, final IStateWriter stateWriter, boolean deadlock, String fromChkpt, boolean preprocess, FilenameToStream resolver, SpecObj spec) throws EvalException, IOException { this.cancellationFlag = false; this.checkDeadlock = deadlock; - int lastSep = specFile.lastIndexOf(FileUtil.separatorChar); - String specDir = (lastSep == -1) ? "" : specFile.substring(0, lastSep + 1); - specFile = specFile.substring(lastSep + 1); - - this.tool = new Tool(specDir, specFile, configFile, resolver); + final File f = new File(specFile); + this.tool = new Tool(f.isAbsolute() ? f.getParent() : "", specFile, configFile, resolver); this.specObj = this.tool.init(preprocess, spec); this.checkLiveness = !this.tool.livenessIsTrue(); @@ -102,7 +97,7 @@ public abstract class AbstractChecker implements Cancelable OutputCollector.setModuleNode(this.tool.rootModule); // moved to file utilities - this.metadir = FileUtil.makeMetaDir(specDir, fromChkpt); + this.metadir = metadir; this.errState = null; this.predErrState = null; @@ -110,25 +105,8 @@ public abstract class AbstractChecker implements Cancelable this.keepCallStack = false; this.fromChkpt = fromChkpt; - - // Initialize dumpFile: - if (dumpFile != null) - { - if (dumpFile.startsWith("${metadir}")) { - // prefix dumpfile with the known value of this.metadir. There - // is no way to determine the actual value of this.metadir - // before TLC startup and thus it's impossible to make the - // dumpfile end up in the metadir if desired. - dumpFile = dumpFile.replace("${metadir}", this.metadir); - } - if (asDot) { - this.allStateWriter = new DotStateWriter(dumpFile); - } else { - this.allStateWriter = new StateWriter(dumpFile); - } - } else { - this.allStateWriter = new NoopStateWriter(); - } + + this.allStateWriter = stateWriter; this.impliedInits = this.tool.getImpliedInits(); // implied-inits to be checked this.invariants = this.tool.getInvariants(); // invariants to be checked @@ -150,7 +128,7 @@ public abstract class AbstractChecker implements Cancelable if (LIVENESS_TESTING_IMPLEMENTATION) { this.liveCheck = new AddAndCheckLiveCheck(this.tool, this.actions, this.metadir, stats); } else { - this.liveCheck = new LiveCheck(this.tool, this.actions, this.metadir, stats, dumpFile); + this.liveCheck = new LiveCheck(this.tool, this.actions, this.metadir, stats, stateWriter); } report("liveness checking initialized"); } else { @@ -172,6 +150,7 @@ public abstract class AbstractChecker implements Cancelable assert Thread.holdsLock(this) : "Caller thread has to hold monitor!"; if (!TLCGlobals.continuation && this.done) return false; + IdThread.resetCurrentState(); this.predErrState = curState; this.errState = (succState == null) ? curState : succState; this.done = true; diff --git a/tlatools/src/tlc2/tool/Action.java b/tlatools/src/tlc2/tool/Action.java index 621fc27fabf7d490e80764b6947877e8a4946400..f3afd7edee48fcf79207766616a2eba61f940402 100644 --- a/tlatools/src/tlc2/tool/Action.java +++ b/tlatools/src/tlc2/tool/Action.java @@ -10,6 +10,8 @@ import tlc2.util.Context; import util.UniqueString; public final class Action implements ToolGlobals, Serializable { + public static final UniqueString UNNAMED_ACTION = UniqueString.uniqueStringOf("UnnamedAction"); + /* A TLA+ action. */ /* Fields */ @@ -19,7 +21,7 @@ public final class Action implements ToolGlobals, Serializable { /* Constructors */ public Action(SemanticNode pred, Context con) { - this(pred, con, (UniqueString) null); + this(pred, con, UNNAMED_ACTION); } public Action(SemanticNode pred, Context con, UniqueString actionName) { @@ -34,10 +36,17 @@ public final class Action implements ToolGlobals, Serializable { } public final String getLocation() { - if (actionName != null && !"".equals(actionName.toString())) { + if (actionName != UNNAMED_ACTION && actionName != null && !"".equals(actionName.toString())) { // If known, print the action name instead of the generic string "Action". return "<" + actionName + " " + pred.getLocation() + ">"; } return "<Action " + pred.getLocation() + ">"; } + + /** + * @return The name of this action. Can be {@link Action#UNNAMED_ACTION}. + */ + public final UniqueString getName() { + return actionName; + } } diff --git a/tlatools/src/tlc2/tool/CheckImpl.java b/tlatools/src/tlc2/tool/CheckImpl.java index 38752e42b5f58bb86711ee85ebf6fb11cb47af4b..4c36423eff9e8600bf720eb959f9daff9707dadb 100644 --- a/tlatools/src/tlc2/tool/CheckImpl.java +++ b/tlatools/src/tlc2/tool/CheckImpl.java @@ -11,6 +11,7 @@ import tlc2.tool.fp.FPSet; import tlc2.tool.fp.FPSetConfiguration; import tlc2.tool.fp.FPSetFactory; import tlc2.tool.queue.DiskStateQueue; +import tlc2.util.NoopStateWriter; import util.ToolIO; /** @@ -30,11 +31,11 @@ public abstract class CheckImpl extends ModelChecker { * @param fpMemSize : This parameter added by Yuan Yu on 6 Apr 2010 * because same parameter was added to the ModelChecker constructor. */ - public CheckImpl(String specFile, String configFile, boolean deadlock, + public CheckImpl(String specFile, String configFile, String metadir, boolean deadlock, int depth, String fromChkpt, final FPSetConfiguration fpSetConfig) throws IOException { // SZ Feb 20, 2009: patched due to changes to ModelCheker - super(specFile, configFile, null, false, deadlock, fromChkpt, null, null, fpSetConfig); // no name resolver and no specobj + super(specFile, configFile, metadir, new NoopStateWriter(), deadlock, fromChkpt, null, null, fpSetConfig); // no name resolver and no specobj this.depth = depth; this.curState = null; this.coverSet = FPSetFactory.getFPSet(); diff --git a/tlatools/src/tlc2/tool/CheckImplFile.java b/tlatools/src/tlc2/tool/CheckImplFile.java index 25cd86063dc689fd1fdeee36334d3b23f1eff9d7..bfc563898676cc3d844e564f8e14ec102e2b8b28 100644 --- a/tlatools/src/tlc2/tool/CheckImplFile.java +++ b/tlatools/src/tlc2/tool/CheckImplFile.java @@ -39,10 +39,10 @@ public class CheckImplFile extends CheckImpl * to ModelChecker constructor. * */ - public CheckImplFile(String specFile, String configFile, boolean deadlock, int depth, String fromChkpt, + public CheckImplFile(String specFile, String configFile, String metadir, boolean deadlock, int depth, String fromChkpt, String traceFile, final FPSetConfiguration fpSetConfig) throws IOException { - super(specFile, configFile, deadlock, depth, fromChkpt, fpSetConfig); + super(specFile, configFile, metadir, deadlock, depth, fromChkpt, fpSetConfig); this.traceFile = traceFile; this.states = null; this.sidx = 0; @@ -299,6 +299,9 @@ public class CheckImplFile extends CheckImpl if (configFile == null) configFile = mainFile; if (traceFile == null) traceFile = mainFile + "_trace"; + final File f = new File(mainFile); + String metadir = FileUtil.makeMetaDir(f.isAbsolute() ? f.getParent() : "", fromChkpt); + try { // Initialize: if (fromChkpt != null) { @@ -308,7 +311,7 @@ public class CheckImplFile extends CheckImpl FP64.Init(0); // Start the checker: - CheckImplFile checker = new CheckImplFile(mainFile, configFile, deadlock, + CheckImplFile checker = new CheckImplFile(mainFile, configFile, metadir, deadlock, depth, fromChkpt, traceFile, new FPSetConfiguration()); checker.init(); while (true) { diff --git a/tlatools/src/tlc2/tool/DFIDModelChecker.java b/tlatools/src/tlc2/tool/DFIDModelChecker.java index 05c096038abf261a80901dee8c8fa9b5601a8c94..f79042e7a9650e0b08416b8434a89d18a3cd0279 100644 --- a/tlatools/src/tlc2/tool/DFIDModelChecker.java +++ b/tlatools/src/tlc2/tool/DFIDModelChecker.java @@ -3,10 +3,13 @@ package tlc2.tool; import java.io.IOException; +import java.util.Set; import java.util.concurrent.atomic.AtomicLong; +import java.util.stream.Collectors; import tla2sany.modanalyzer.SpecObj; import tla2sany.semantic.ExprNode; +import tla2sany.semantic.OpDeclNode; import tlc2.TLCGlobals; import tlc2.output.EC; import tlc2.output.MP; @@ -43,11 +46,11 @@ public class DFIDModelChecker extends AbstractChecker * Constructor for running DFID * @param resolver */ - public DFIDModelChecker(String specFile, String configFile, String dumpFile, boolean asDot, boolean deadlock, String fromChkpt, + public DFIDModelChecker(String specFile, String configFile, String metadir, final IStateWriter stateWriter, boolean deadlock, String fromChkpt, boolean preprocess, FilenameToStream resolver, SpecObj specObj) throws EvalException, IOException { // call the abstract constructor - super(specFile, configFile, dumpFile, asDot, deadlock, fromChkpt, preprocess, resolver, specObj); + super(specFile, configFile, metadir, stateWriter, deadlock, fromChkpt, preprocess, resolver, specObj); this.theInitStates = null; this.theInitFPs = null; @@ -371,7 +374,20 @@ public class DFIDModelChecker extends AbstractChecker { synchronized (this) { if (this.setErrState(curState, succState, false)) { - this.printTrace(EC.TLC_STATE_NOT_COMPLETELY_SPECIFIED_NEXT, null, curState, succState); + final Set<OpDeclNode> unassigned = succState.getUnassigned(); + String[] parameters; + if (this.actions.length == 1) { + parameters = new String[] { unassigned.size() > 1 ? "s are" : " is", + unassigned.stream().map(n -> n.getName().toString()) + .collect(Collectors.joining(", ")) }; + } else { + parameters = new String[] { this.actions[i].getName().toString(), + unassigned.size() > 1 ? "s are" : " is", + unassigned.stream().map(n -> n.getName().toString()) + .collect(Collectors.joining(", ")) }; + } + this.printTrace(EC.TLC_STATE_NOT_COMPLETELY_SPECIFIED_NEXT, + parameters, curState, succState); } } return allSuccNonLeaf; diff --git a/tlatools/src/tlc2/tool/ModelChecker.java b/tlatools/src/tlc2/tool/ModelChecker.java index 0f052f5797aaa994533a0923e17a208926491bae..4c0e7589301c8f01aa5669fa823c87c5cca51d62 100644 --- a/tlatools/src/tlc2/tool/ModelChecker.java +++ b/tlatools/src/tlc2/tool/ModelChecker.java @@ -7,9 +7,12 @@ package tlc2.tool; import java.io.IOException; +import java.util.Set; +import java.util.stream.Collectors; import tla2sany.modanalyzer.SpecObj; import tla2sany.semantic.ExprNode; +import tla2sany.semantic.OpDeclNode; import tlc2.TLCGlobals; import tlc2.output.EC; import tlc2.output.MP; @@ -24,6 +27,7 @@ import tlc2.util.IStateWriter; import tlc2.util.ObjLongTable; import tlc2.util.SetOfStates; import tlc2.util.statistics.BucketStatistics; +import util.Assert; import util.DebugPrinter; import util.FileUtil; import util.FilenameToStream; @@ -73,11 +77,11 @@ public class ModelChecker extends AbstractChecker * @param specObj external SpecObj added to enable to work on existing specification * Modified on 6 Apr 2010 by Yuan Yu to add fpMemSize parameter. */ - public ModelChecker(String specFile, String configFile, String dumpFile, final boolean asDot, boolean deadlock, String fromChkpt, + public ModelChecker(String specFile, String configFile, String metadir, final IStateWriter stateWriter, boolean deadlock, String fromChkpt, FilenameToStream resolver, SpecObj specObj, final FPSetConfiguration fpSetConfig) throws EvalException, IOException { // call the abstract constructor - super(specFile, configFile, dumpFile, asDot, deadlock, fromChkpt, true, resolver, specObj); + super(specFile, configFile, metadir, stateWriter, deadlock, fromChkpt, true, resolver, specObj); // SZ Feb 20, 2009: this is a selected alternative this.theStateQueue = new DiskStateQueue(this.metadir); @@ -190,6 +194,7 @@ public class ModelChecker extends AbstractChecker } report("init processed"); + // Finished if there is no next state predicate: if (this.actions.length == 0) { @@ -340,13 +345,23 @@ public class ModelChecker extends AbstractChecker // allocating memory for StateVec (which depending on the number of init // states can grow to be GBs) and the subsequent loop over StateVec. final DoInitFunctor functor = new DoInitFunctor(); - this.tool.getInitStates(functor); + try { + this.tool.getInitStates(functor); + } catch (DoInitFunctor.InvariantViolatedException ive) { + this.errState = functor.errState; + return functor.returnValue; + } catch (Assert.TLCRuntimeException e) { + this.errState = functor.errState; + throw e; + } // Iff one of the init states' checks violates any properties, the // functor will record it. if (functor.errState != null) { this.errState = functor.errState; - throw functor.e; + if (functor.e != null) { + throw functor.e; + } } // Return whatever the functor has recorded. @@ -409,13 +424,27 @@ public class ModelChecker extends AbstractChecker SUCCESSORS: for (int j = 0; j < sz; j++) { succState = nextStates.elementAt(j); + succState.level = (short) ((short) 1 + curState.level); + assert succState.level >= 1; // Check if succState is a legal state. if (!this.tool.isGoodState(succState)) { synchronized (this) { if (this.setErrState(curState, succState, false)) { - MP.printError(EC.TLC_STATE_NOT_COMPLETELY_SPECIFIED_NEXT); + final Set<OpDeclNode> unassigned = succState.getUnassigned(); + if (this.actions.length == 1) { + MP.printError(EC.TLC_STATE_NOT_COMPLETELY_SPECIFIED_NEXT, + new String[] { unassigned.size() > 1 ? "s are" : " is", + unassigned.stream().map(n -> n.getName().toString()) + .collect(Collectors.joining(", ")) }); + } else { + MP.printError(EC.TLC_STATE_NOT_COMPLETELY_SPECIFIED_NEXT, + new String[] { this.actions[i].getName().toString(), + unassigned.size() > 1 ? "s are" : " is", + unassigned.stream().map(n -> n.getName().toString()) + .collect(Collectors.joining(", ")) }); + } this.trace.printTrace(curState, succState); this.theStateQueue.finishAll(); this.notify(); @@ -435,7 +464,7 @@ public class ModelChecker extends AbstractChecker long fp = succState.fingerPrint(); seen = this.theFPSet.put(fp); // Write out succState when needed: - this.allStateWriter.writeState(curState, succState, !seen); + this.allStateWriter.writeState(curState, succState, !seen, this.actions[i]); if (!seen) { // Write succState to trace only if it satisfies the @@ -983,6 +1012,10 @@ public class ModelChecker extends AbstractChecker */ private class DoInitFunctor implements IStateFunctor { + @SuppressWarnings("serial") + public class InvariantViolatedException extends RuntimeException { + } + /** * Non-Null iff a violation occurred. */ @@ -1000,6 +1033,9 @@ public class ModelChecker extends AbstractChecker * @see tlc2.tool.IStateFunctor#addElement(tlc2.tool.TLCState) */ public Object addElement(final TLCState curState) { + if (Long.bitCount(numberOfInitialStates) == 1 && numberOfInitialStates > 1) { + MP.printMessage(EC.TLC_COMPUTING_INIT_PROGRESS, Long.toString(numberOfInitialStates)); + } numberOfInitialStates++; // getInitStates() does not support aborting init state generation @@ -1016,7 +1052,9 @@ public class ModelChecker extends AbstractChecker // Check if the state is a legal state if (!tool.isGoodState(curState)) { MP.printError(EC.TLC_INITIAL_STATE, new String[]{ "current state is not a legal state", curState.toString() }); - return returnValue; + this.errState = curState; + returnValue = false; + throw new InvariantViolatedException(); } boolean inModel = tool.isInModel(curState); boolean seen = false; @@ -1043,8 +1081,9 @@ public class ModelChecker extends AbstractChecker MP.printError(EC.TLC_INVARIANT_VIOLATED_INITIAL, new String[] { tool.getInvNames()[j].toString(), curState.toString() }); if (!TLCGlobals.continuation) { + this.errState = curState; returnValue = false; - return returnValue; + throw new InvariantViolatedException(); } } } @@ -1053,18 +1092,25 @@ public class ModelChecker extends AbstractChecker // We get here because of implied-inits violation: MP.printError(EC.TLC_PROPERTY_VIOLATED_INITIAL, new String[] { tool.getImpliedInitNames()[j], curState.toString() }); + this.errState = curState; returnValue = false; - return returnValue; + throw new InvariantViolatedException(); } } } + } catch (InvariantViolatedException | Assert.TLCRuntimeException e) { + // IVE gets thrown above when an Invariant is violated. TLCRuntimeException gets + // thrown when Tool fails to evaluate a statement because of e.g. too large sets + // or type errors such as in DoInitFunctorInvariantMinimalErrorStackTest test. + this.errState = curState; + this.e = e; + throw e; + } catch (OutOfMemoryError e) { + MP.printError(EC.SYSTEM_OUT_OF_MEMORY_TOO_MANY_INIT); + returnValue = false; + return returnValue; } catch (Throwable e) { // Assert.printStack(e); - if (e instanceof OutOfMemoryError) { - MP.printError(EC.SYSTEM_OUT_OF_MEMORY_TOO_MANY_INIT); - returnValue = false; - return returnValue; - } this.errState = curState; this.e = e; } @@ -1072,3 +1118,4 @@ public class ModelChecker extends AbstractChecker } } } + \ No newline at end of file diff --git a/tlatools/src/tlc2/tool/Spec.java b/tlatools/src/tlc2/tool/Spec.java index c671f792da93291e9356568b199d82a235e31645..8fb1fce24bd37e877414af490fbc88b6352d0429 100644 --- a/tlatools/src/tlc2/tool/Spec.java +++ b/tlatools/src/tlc2/tool/Spec.java @@ -184,7 +184,6 @@ public class Spec implements ValueConstants, ToolGlobals, Serializable } // The following statement moved here by LL on 11 March 2011 MP.printMessage(EC.TLC_STARTING); - } // SZ Feb 20, 2009: diff --git a/tlatools/src/tlc2/tool/TLCState.java b/tlatools/src/tlc2/tool/TLCState.java index c7a4e96c2ed8b934e6f23b538589c0e8e4f4429e..4203c5bd274280329fec852456b0d3adad78596c 100644 --- a/tlatools/src/tlc2/tool/TLCState.java +++ b/tlatools/src/tlc2/tool/TLCState.java @@ -7,6 +7,9 @@ package tlc2.tool; import java.io.IOException; import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; import tla2sany.semantic.OpDeclNode; import tla2sany.semantic.SemanticNode; @@ -18,6 +21,7 @@ import util.UniqueString; public abstract class TLCState implements Cloneable, Serializable { public long uid = -1; // Must be set to a non-negative number + public short level = 0; // Set by subclasses. Cannot set until we know what the variables are. public static TLCState Empty = null; @@ -41,10 +45,13 @@ public abstract class TLCState implements Cloneable, Serializable { public void read(ValueInputStream vis) throws IOException { this.uid = vis.readLongNat(); + this.level = vis.readShortNat(); + assert this.level >= 0; // Should never overflow. } public void write(ValueOutputStream vos) throws IOException { vos.writeLongNat(this.uid); + vos.writeShortNat(this.level); } public abstract TLCState bind(UniqueString name, Value value, SemanticNode expr); @@ -58,8 +65,26 @@ public abstract class TLCState implements Cloneable, Serializable { public abstract void deepNormalize(); public abstract long fingerPrint(); public abstract boolean allAssigned(); + public abstract Set<OpDeclNode> getUnassigned(); public abstract TLCState createEmpty(); + + /** + * Returns a mapping of variable names to their assigned values in this state. + */ + public Map<UniqueString, Value> getVals() { + final Map<UniqueString, Value> valMap = new HashMap<UniqueString, Value>(); + for(int i = 0; i < vars.length; i++) { + UniqueString key = vars[i].getName(); + Value val = this.lookup(key); + valMap.put(key, val); + } + return valMap; + } + public boolean isInitial() { + return this.level == 0; + } + /* Returns a string representation of this state. */ public abstract String toString(); public abstract String toString(TLCState lastState); diff --git a/tlatools/src/tlc2/tool/TLCStateFun.java b/tlatools/src/tlc2/tool/TLCStateFun.java index 5c8c50c1831729e231b430f1d1b9510a56ae6a18..8f5470a40fdac8d16bbe607062c0c2aee375028b 100644 --- a/tlatools/src/tlc2/tool/TLCStateFun.java +++ b/tlatools/src/tlc2/tool/TLCStateFun.java @@ -6,7 +6,10 @@ package tlc2.tool; import java.io.IOException; +import java.util.HashSet; +import java.util.Set; +import tla2sany.semantic.OpDeclNode; import tla2sany.semantic.SemanticNode; import tla2sany.semantic.SymbolNode; import tlc2.util.Context; @@ -80,6 +83,8 @@ public final class TLCStateFun extends TLCState { } public final boolean allAssigned() { return true; } + + public final Set<OpDeclNode> getUnassigned() { return new HashSet<OpDeclNode>(); } public final Context addToContext(Context c) { Context c1 = c; diff --git a/tlatools/src/tlc2/tool/TLCStateInfo.java b/tlatools/src/tlc2/tool/TLCStateInfo.java index 9bcb2d8bd0a8e90f089da16b14e16a4916340f8b..b2dc8216438a6335a7de146f98cc30acf389dff7 100644 --- a/tlatools/src/tlc2/tool/TLCStateInfo.java +++ b/tlatools/src/tlc2/tool/TLCStateInfo.java @@ -12,6 +12,13 @@ public class TLCStateInfo { public Object info; public Long fp; + public TLCStateInfo(TLCState initialState) { + this.state = initialState; + this.info = "<Initial predicate>"; + this.stateNumber = 1; + this.fp = initialState.fingerPrint(); + } + public TLCStateInfo(TLCState s, Object info) { this.state = s; this.info = info; diff --git a/tlatools/src/tlc2/tool/TLCStateMut.java b/tlatools/src/tlc2/tool/TLCStateMut.java index ba6d9f7ba4a336b8f5a0b84341988bc0804860d6..883fef603431cda120a84949a0064888df4959e8 100644 --- a/tlatools/src/tlc2/tool/TLCStateMut.java +++ b/tlatools/src/tlc2/tool/TLCStateMut.java @@ -7,7 +7,11 @@ package tlc2.tool; import java.io.IOException; import java.io.Serializable; +import java.util.Comparator; +import java.util.Set; +import java.util.TreeSet; +import tla2sany.semantic.OpDeclNode; import tla2sany.semantic.SemanticNode; import tla2sany.semantic.SymbolNode; import tlc2.TLCGlobals; @@ -78,6 +82,7 @@ public final class TLCStateMut extends TLCState implements Cloneable, Serializab } public final TLCState bind(UniqueString name, Value value, SemanticNode expr) { + // Note, tla2sany.semantic.OpApplNode.toString(Value) relies on this ordering. int loc = name.getVarLoc(); this.values[loc] = value; return this; @@ -149,19 +154,44 @@ public final class TLCStateMut extends TLCState implements Cloneable, Serializab public final long fingerPrint() { int sz = this.values.length; + // TLC supports symmetry reduction. Symmetry reduction works by defining classes + // of symmetrically equivalent states for which TLC only checks a + // single representative of the equivalence class (orbit). E.g. in a two + // process mutual exclusion problem, the process ids are - most of the time - + // not relevant with regards to mutual exclusion: We don't care if process A or + // B is in the critical section as long as only a single process is in CS. Thus + // two states are symmetric that only differ in the process id variable value. + // Symmetry can also be observed graphically in the state graph s.t. subgraphs + // are isomorphic (Graph Isomorphism). Instead of enumerating the complete state + // graph, TLC enumerates one of the isomorphic subgraphs whose state correspond + // to the representatives. With respect to the corresponding Kripke structure M, + // the resulting Kripke M' is called the "quotient structure" (see "Exploiting + // Symmetry in Temporal Logic Model Checking" by Clarke et al). + // + // The definition of equivalence classes (orbits) is provided manually by the + // user at startup by defining 1 to n symmetry sets. Thus TLC has to find + // representative at runtime only which happens below. Given any state s, TLC + // evaluates rep(s) to find the lexicographically smallest state ss = rep(s) + // with regards to the variable values. The state ss is then fingerprint instead + // of s. + // + // Evaluating rep(s) - to reduce s to ss - requires to apply all permutations in + // the group this.perms (derived from the user-defined orbit). This is known as + // the constructive orbit problem and is NP-hard. The loop has O(|perms| * |this.values|) + // with |prems| = |symmetry set 1|! * |symmetry set 2|! * ... * |symmetry set n|. + // // minVals is what is used to calculate/generate the fingerprint below. - // If this state is part of a symmetry permutation and not the smallest - // member, its current minVals will be replaced temporarily with the - // values of the smallest state for the calculation of the fingerprint. + // If this state is not the lexicographically smallest state ss, its current + // minVals will be replaced temporarily with the values of ss for the + // calculation of the fingerprint. Value[] minVals = this.values; if (perms != null) { Value[] vals = new Value[sz]; - // Find the "smallest" state under the symmetry permutations. - // The following for loop converges to the smallest state under - // symmetry by looping over all permutations applying each. If the - // outcome turns out to be smaller than the current smallest, it - // replaces it. Once all permutations (perms) have been seen, we - // know we have found the smallest state. + // The following for loop converges to the smallest state ss under symmetry by + // looping over all permutations applying each. If the outcome turns out to be + // lexicographically smaller than the currently smallest, it replaces the + // current smallest. Once all permutations (perms) have been processed, we know + // we have found the smallest state. NEXT_PERM: for (int i = 0; i < perms.length; i++) { int cmp = 0; // For each value in values succinctly permute the current value @@ -231,6 +261,23 @@ public final class TLCStateMut extends TLCState implements Cloneable, Serializab } return true; } + + public final Set<OpDeclNode> getUnassigned() { + // Return sorted set (lexicographical). + final Set<OpDeclNode> unassignedVars = new TreeSet<OpDeclNode>(new Comparator<OpDeclNode>() { + @Override + public int compare(OpDeclNode o1, OpDeclNode o2) { + return o1.getName().toString().compareTo(o2.getName().toString()); + } + }); + int len = this.values.length; + for (int i = 0; i < len; i++) { + if (values[i] == null) { + unassignedVars.add(vars[i]); + } + } + return unassignedVars; + } public final void read(ValueInputStream vis) throws IOException { super.read(vis); @@ -252,25 +299,27 @@ public final class TLCStateMut extends TLCState implements Cloneable, Serializab public final String toString() { if (TLCGlobals.useView && viewMap != null) { Value val = mytool.eval(viewMap, Context.Empty, this); - return Value.ppr(val.toString()); + return viewMap.toString(val); } StringBuffer result = new StringBuffer(); int vlen = vars.length; if (vlen == 1) { UniqueString key = vars[0].getName(); Value val = this.lookup(key); - String val_str = (val == null) ? "null" : Value.ppr(val.toString()); result.append(key.toString()); - result.append(" = " + val_str + "\n"); + result.append(" = "); + result.append(Value.ppr(val)); + result.append("\n"); } else { for (int i = 0; i < vlen; i++) { UniqueString key = vars[i].getName(); Value val = this.lookup(key); - String val_str = (val == null) ? "null" : Value.ppr(val.toString()); result.append("/\\ "); result.append(key.toString()); - result.append(" = " + val_str + "\n"); + result.append(" = "); + result.append(Value.ppr(val)); + result.append("\n"); } } return result.toString(); @@ -287,9 +336,8 @@ public final class TLCStateMut extends TLCState implements Cloneable, Serializab Value val = this.lookup(key); Value lstateVal = lstate.lookup(key); if (!lstateVal.equals(val)) { - String val_str = (val == null) ? "null" : Value.ppr(val.toString()); result.append(key.toString()); - result.append(" = " + val_str + "\n"); + result.append(" = " + Value.ppr(val) + "\n"); } } else { @@ -298,10 +346,9 @@ public final class TLCStateMut extends TLCState implements Cloneable, Serializab Value val = this.lookup(key); Value lstateVal = lstate.lookup(key); if (!lstateVal.equals(val)) { - String val_str = (val == null) ? "null" : Value.ppr(val.toString()); result.append("/\\ "); result.append(key.toString()); - result.append(" = " + val_str + "\n"); + result.append(" = " + Value.ppr(val) + "\n"); } } } diff --git a/tlatools/src/tlc2/tool/TLCStateMutSource.java b/tlatools/src/tlc2/tool/TLCStateMutSource.java index e7bb54f62dfb608aa5f38ddd3155066440617eea..2df3b9249ea4619364efe97ab06210eeacefccb4 100644 --- a/tlatools/src/tlc2/tool/TLCStateMutSource.java +++ b/tlatools/src/tlc2/tool/TLCStateMutSource.java @@ -9,7 +9,11 @@ import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; +import java.util.Comparator; +import java.util.Set; +import java.util.TreeSet; +import tla2sany.semantic.OpDeclNode; import tla2sany.semantic.SemanticNode; import tla2sany.semantic.SymbolNode; import tlc2.TLCGlobals; @@ -243,6 +247,23 @@ implements Cloneable, Serializable { return true; } + public final Set<OpDeclNode> getUnassigned() { + // Return sorted set (lexicographical). + final Set<OpDeclNode> unassignedVars = new TreeSet<OpDeclNode>(new Comparator<OpDeclNode>() { + @Override + public int compare(OpDeclNode o1, OpDeclNode o2) { + return o1.getName().toString().compareTo(o2.getName().toString()); + } + }); + int len = this.values.length; + for (int i = 0; i < len; i++) { + if (values[i] == null) { + unassignedVars.add(vars[i]); + } + } + return unassignedVars; + } + public final void read(ValueInputStream vis) throws IOException { super.read(vis); int len = this.values.length; @@ -263,25 +284,27 @@ implements Cloneable, Serializable { public final String toString() { if (TLCGlobals.useView && viewMap != null) { Value val = mytool.eval(viewMap, Context.Empty, this); - return Value.ppr(val.toString()); + return viewMap.toString(val); } StringBuffer result = new StringBuffer(); int vlen = vars.length; if (vlen == 1) { UniqueString key = vars[0].getName(); Value val = lookup(key); - String val_str = (val == null) ? "null" : Value.ppr(val.toString()); result.append(key.toString()); - result.append(" = " + val_str + "\n"); + result.append(" = "); + result.append(Value.ppr(val)); + result.append("\n"); } else { for (int i = 0; i < vlen; i++) { UniqueString key = vars[i].getName(); Value val = lookup(key); - String val_str = (val == null) ? "null" : Value.ppr(val.toString()); result.append("/\\ "); result.append(key.toString()); - result.append(" = " + val_str + "\n"); + result.append(" = "); + result.append(Value.ppr(val)); + result.append("\n"); } } return result.toString(); @@ -298,9 +321,8 @@ implements Cloneable, Serializable { Value val = this.lookup(key); Value lstateVal = lstate.lookup(key); if (val == null || !val.equals(lstateVal)) { - String val_str = (val == null) ? "null" : Value.ppr(val.toString()); result.append(key.toString()); - result.append(" = " + val_str + "\n"); + result.append(" = " + Value.ppr(val) + "\n"); } } else { @@ -309,10 +331,9 @@ implements Cloneable, Serializable { Value val = this.lookup(key); Value lstateVal = lstate.lookup(key); if (val == null || !val.equals(lstateVal)) { - String val_str = (val == null) ? "null" : Value.ppr(val.toString()); result.append("/\\ "); result.append(key.toString()); - result.append(" = " + val_str + "\n"); + result.append(" = " + Value.ppr(val) + "\n"); } } } diff --git a/tlatools/src/tlc2/tool/TLCTrace.java b/tlatools/src/tlc2/tool/TLCTrace.java index bbdb903fc37a9e7f029b3c983591f5ccd0ef9b07..ce69ae367d3105eaeef4d5aeb2ed9f0f2a1cf676 100644 --- a/tlatools/src/tlc2/tool/TLCTrace.java +++ b/tlatools/src/tlc2/tool/TLCTrace.java @@ -22,6 +22,7 @@ import tlc2.output.OutputCollector; import tlc2.output.StatePrinter; import tlc2.util.BufferedRandomAccessFile; import tlc2.util.LongVec; +import tlc2.value.EnumerableValue; import util.FileUtil; public class TLCTrace { @@ -352,7 +353,32 @@ public class TLCTrace { public synchronized final void printTrace(final TLCState s1, final TLCState s2) throws IOException, WorkerException { + // Re-Initialize the rng with the seed value recorded and used during the model + // checking phase. Otherwise, we won't be able to reconstruct the error trace + // because the set of initial states is likely to be different. + // This is only necessary though, if TLCGlobals.enumFraction was < 1 during + // the generation of inits. + EnumerableValue.resetRandom(); + ArrayList<TLCStateInfo> trace = new ArrayList<TLCStateInfo>(); // collecting the whole error trace + + if (s1.isInitial()) { + // Do not recreate the potentially expensive error trace - e.g. when the set of + // initial states is huge such as during inductive invariant checking. Instead + // use the two states s1 and s2 directly. + MP.printError(EC.TLC_BEHAVIOR_UP_TO_THIS_POINT); + TLCStateInfo s1Info = new TLCStateInfo(s1); + StatePrinter.printState(s1Info); + trace.add(s1Info); + if (s2 != null) { + // Create TLCStateInfo instance to include corresponding action in output. + TLCStateInfo s2Info = this.tool.getState(s2, s1); + StatePrinter.printState(s2Info, s1, 2); + trace.add(s2Info); + } + OutputCollector.setTrace(trace); + return; + } MP.printError(EC.TLC_BEHAVIOR_UP_TO_THIS_POINT); // Print the prefix leading to s1: diff --git a/tlatools/src/tlc2/tool/Tool.java b/tlatools/src/tlc2/tool/Tool.java index f31392c0162c0f3129b042291d65d07c35f6cc3c..b88cd660c99a1506187105d252d84f929e7866e2 100644 --- a/tlatools/src/tlc2/tool/Tool.java +++ b/tlatools/src/tlc2/tool/Tool.java @@ -29,6 +29,7 @@ import tlc2.TLCGlobals; import tlc2.output.EC; import tlc2.output.MP; import tlc2.util.Context; +import tlc2.util.IdThread; import tlc2.util.Vect; import tlc2.value.Applicable; import tlc2.value.BoolValue; @@ -72,8 +73,6 @@ import util.UniqueString; * It's instance serves as a spec handle * This is one of two places in TLC, where not all messages are retrieved from the message printer, * but constructed just here in the code. - * - * @version $Id$ */ public class Tool extends Spec @@ -166,7 +165,7 @@ public class Tool } private final void getActions(SemanticNode next, Context con) { - this.getActions(next, con, null); + this.getActions(next, con, Action.UNNAMED_ACTION); } private final void getActions(SemanticNode next, Context con, final UniqueString actionName) { @@ -415,15 +414,36 @@ public class Tool } private final void getInitStates(ActionItemList acts, TLCState ps, IStateFunctor states) { - if (acts.isEmpty()) { - states.addElement(ps.copy()); - } - else { - // Assert.check(act.kind > 0 || act.kind == -1); - ActionItemList acts1 = acts.cdr(); - this.getInitStates(acts.carPred(), acts1, acts.carContext(), ps, states); - } - } + if (acts.isEmpty()) { + states.addElement(ps.copy()); + return; + } else if (ps.allAssigned()) { + // MAK 05/25/2018: If all values of the initial state have already been + // assigned, there is no point in further trying to assign values. Instead, all + // remaining statements (ActionItemList) can just be evaluated for their boolean + // value. + // This optimization is especially useful to check inductive invariants which + // require TLC to generate a very large set of initial states. + while (!acts.isEmpty()) { + final Value bval = this.eval(acts.carPred(), acts.carContext(), ps, TLCState.Empty, EvalControl.Init); + if (!(bval instanceof BoolValue)) { + //TODO Choose more fitting error message. + Assert.fail(EC.TLC_EXPECTED_EXPRESSION_IN_COMPUTING, + new String[] { "initial states", "boolean", bval.toString(), acts.pred.toString() }); + } + if (!((BoolValue) bval).val) { + return; + } + // Move on to the next action in the ActionItemList. + acts = acts.cdr(); + } + states.addElement(ps.copy()); + return; + } + // Assert.check(act.kind > 0 || act.kind == -1); + ActionItemList acts1 = acts.cdr(); + this.getInitStates(acts.carPred(), acts1, acts.carContext(), ps, states); + } private final void getInitStatesAppl(OpApplNode init, ActionItemList acts, Context c, TLCState ps, IStateFunctor states) { @@ -804,37 +824,66 @@ public class Tool } } - private final TLCState getNextStates(ActionItemList acts, TLCState s0, TLCState s1, - StateVec nss) { - TLCState resState = s1; - + private final TLCState getNextStates(ActionItemList acts, final TLCState s0, final TLCState s1, + final StateVec nss) { + int kind = acts.carKind(); if (acts.isEmpty()) { nss.addElement(s1); - resState = s1.copy(); - } - else { - int kind = acts.carKind(); + return s1.copy(); + } else if (s1.allAssigned()) { SemanticNode pred = acts.carPred(); Context c = acts.carContext(); - ActionItemList acts1 = acts.cdr(); - if (kind > 0) { - resState = this.getNextStates(pred, acts1, c, s0, s1, nss); - } - else if (kind == -1) { - resState = this.getNextStates(pred, acts1, c, s0, s1, nss); - } - else if (kind == -2) { - resState = this.processUnchanged(pred, acts1, c, s0, s1, nss); - } - else { - Value v1 = this.eval(pred, c, s0); - Value v2 = this.eval(pred, c, s1); - if (!v1.equals(v2)) { - resState = this.getNextStates(acts1, s0, s1, nss); - } + while (!acts.isEmpty()) { + if (kind > 0 || kind == -1) { + final Value bval = this.eval(pred, c, s0, s1, EvalControl.Clear); + if (!(bval instanceof BoolValue)) { + // TODO Choose more fitting error message. + Assert.fail(EC.TLC_EXPECTED_EXPRESSION_IN_COMPUTING, + new String[] { "next states", "boolean", bval.toString(), acts.pred.toString() }); + } + if (!((BoolValue) bval).val) { + return s1; + } + } else if (kind == -2) { + // Identical to default handling below (line 876). Ignored during this optimization. + return this.processUnchanged(pred, acts.cdr(), c, s0, s1, nss); + } else { + final Value v1 = this.eval(pred, c, s0); + final Value v2 = this.eval(pred, c, s1); + if (v1.equals(v2)) { + return s1; + } + } + // Move on to the next action in the ActionItemList. + acts = acts.cdr(); + pred = acts.carPred(); + c = acts.carContext(); + kind = acts.carKind(); + } + nss.addElement(s1); + return s1.copy(); + } + + SemanticNode pred = acts.carPred(); + Context c = acts.carContext(); + ActionItemList acts1 = acts.cdr(); + if (kind > 0) { + return this.getNextStates(pred, acts1, c, s0, s1, nss); + } + else if (kind == -1) { + return this.getNextStates(pred, acts1, c, s0, s1, nss); + } + else if (kind == -2) { + return this.processUnchanged(pred, acts1, c, s0, s1, nss); + } + else { + Value v1 = this.eval(pred, c, s0); + Value v2 = this.eval(pred, c, s1); + if (!v1.equals(v2)) { + return this.getNextStates(acts1, s0, s1, nss); } } - return resState; + return s1; } private final TLCState getNextStatesAppl(OpApplNode pred, ActionItemList acts, Context c, @@ -2981,6 +3030,7 @@ public class Tool /* Reconstruct the next state of state s whose fingerprint is fp. */ public final TLCStateInfo getState(long fp, TLCState s) { + IdThread.setCurrentState(s); for (int i = 0; i < this.actions.length; i++) { Action curAction = this.actions[i]; StateVec nextStates = this.getNextStates(curAction, s); @@ -2997,6 +3047,7 @@ public class Tool /* Reconstruct the info for s1. */ public final TLCStateInfo getState(TLCState s1, TLCState s) { + IdThread.setCurrentState(s); for (int i = 0; i < this.actions.length; i++) { Action curAction = this.actions[i]; StateVec nextStates = this.getNextStates(curAction, s); @@ -3012,21 +3063,22 @@ public class Tool /* Return the set of all permutations under the symmetry assumption. */ public final MVPerm[] getSymmetryPerms() { - String name = this.config.getSymmetry(); - if (name.length() == 0) return null; - Object symm = this.defns.get(name); + final String name = this.config.getSymmetry(); + if (name.length() == 0) { return null; } + final Object symm = this.defns.get(name); if (symm == null) { Assert.fail(EC.TLC_CONFIG_SPECIFIED_NOT_DEFINED, new String[] { "symmetry function", name}); } if (!(symm instanceof OpDefNode)) { Assert.fail("The symmetry function " + name + " must specify a set of permutations."); } - Value fcns = this.eval(((OpDefNode)symm).getBody(), Context.Empty, TLCState.Empty); + // This calls tlc2.module.TLC.Permutations(Value) and returns a Value of |fcns| + // = n! where n is the capacity of the symmetry set. + final Value fcns = this.eval(((OpDefNode)symm).getBody(), Context.Empty, TLCState.Empty); if (!(fcns instanceof Enumerable)) { Assert.fail("The symmetry operator must specify a set of functions."); } - ValueEnumeration Enum = ((Enumerable)fcns).elements(); - return MVPerm.permutationSubgroup(Enum); + return MVPerm.permutationSubgroup((Enumerable) fcns); } public boolean hasSymmetry() { diff --git a/tlatools/src/tlc2/tool/Worker.java b/tlatools/src/tlc2/tool/Worker.java index 2d8bbbf89a02bef1b65e2811212e4d917981660f..be2d92a47baf05a2216149383cc58e194c60b89c 100644 --- a/tlatools/src/tlc2/tool/Worker.java +++ b/tlatools/src/tlc2/tool/Worker.java @@ -59,12 +59,15 @@ public class Worker extends IdThread implements IWorker { this.squeue.finishAll(); return; } - if (this.tlc.doNext(curState, this.astCounts, this)) + setCurrentState(curState); + if (this.tlc.doNext(curState, this.astCounts, this)) { return; + } } } catch (Throwable e) { // Something bad happened. Quit ... // Assert.printStack(e); + resetCurrentState(); synchronized (this.tlc) { if (this.tlc.setErrState(curState, null, true)) { MP.printError(EC.GENERAL, e); // LL changed call 7 April diff --git a/tlatools/src/tlc2/tool/fp/DiskFPSet.java b/tlatools/src/tlc2/tool/fp/DiskFPSet.java index f29aacb04958bb5961ef97428be2986627b300cf..b7fdb65ff37cebc3817d4932d7c9b67e5afc5cdb 100644 --- a/tlatools/src/tlc2/tool/fp/DiskFPSet.java +++ b/tlatools/src/tlc2/tool/fp/DiskFPSet.java @@ -1097,7 +1097,7 @@ public abstract class DiskFPSet extends FPSet implements FPSetStatistic { try { FileUtil.replaceFile(tmpFilename, fpFilename); } catch (IOException e) { - Assert.fail(EC.SYSTEM_UNABLE_NOT_RENAME_FILE); + Assert.fail(EC.SYSTEM_UNABLE_NOT_RENAME_FILE, e); } // reopen a BufferedRAF for each thread diff --git a/tlatools/src/tlc2/tool/fp/MultiFPSetConfiguration.java b/tlatools/src/tlc2/tool/fp/MultiFPSetConfiguration.java index 7969b2de35c1f5fe938d69e792a6341c59e1ca79..7bd34763870cbf8e558f15d145b7bb136b2b8bd7 100644 --- a/tlatools/src/tlc2/tool/fp/MultiFPSetConfiguration.java +++ b/tlatools/src/tlc2/tool/fp/MultiFPSetConfiguration.java @@ -37,6 +37,10 @@ class MultiFPSetConfiguration extends FPSetConfiguration { * @see tlc2.tool.fp.FPSetConfiguration#getMemoryInFingerprintCnt() */ public long getMemoryInFingerprintCnt() { - return super.getMemoryInFingerprintCnt() / getMultiFPSetCnt(); + // No need to divide by getMultiFPSetCnt because calls to + // super.getMemoryInFingerprintCnt eventually calls getMemoryInBytes above. + // Dividing by getMultiFPSetCnt here again will waste half the + // available memory. + return super.getMemoryInFingerprintCnt(); } } \ No newline at end of file diff --git a/tlatools/src/tlc2/tool/fp/NoopFPSet.java b/tlatools/src/tlc2/tool/fp/NoopFPSet.java new file mode 100644 index 0000000000000000000000000000000000000000..b03633fe64944111ed49b2dec69b5b15abc87693 --- /dev/null +++ b/tlatools/src/tlc2/tool/fp/NoopFPSet.java @@ -0,0 +1,128 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.tool.fp; + +import java.io.IOException; +import java.rmi.RemoteException; + +/** + * An FPSet whose methods are all no-ops. + */ +@SuppressWarnings("serial") +public class NoopFPSet extends FPSet { + + protected NoopFPSet(FPSetConfiguration fpSetConfig) throws RemoteException { + super(fpSetConfig); + } + + /* (non-Javadoc) + * @see tlc2.tool.fp.FPSet#init(int, java.lang.String, java.lang.String) + */ + @Override + public void init(int numThreads, String metadir, String filename) throws IOException { + } + + /* (non-Javadoc) + * @see tlc2.tool.fp.FPSet#size() + */ + @Override + public long size() { + return 0; + } + + /* (non-Javadoc) + * @see tlc2.tool.fp.FPSet#put(long) + */ + @Override + public boolean put(long fp) throws IOException { + return false; + } + + /* (non-Javadoc) + * @see tlc2.tool.fp.FPSet#contains(long) + */ + @Override + public boolean contains(long fp) throws IOException { + return false; + } + + /* (non-Javadoc) + * @see tlc2.tool.fp.FPSet#checkFPs() + */ + @Override + public double checkFPs() throws IOException { + return 0; + } + + /* (non-Javadoc) + * @see tlc2.tool.fp.FPSet#beginChkpt() + */ + @Override + public void beginChkpt() throws IOException { + } + + /* (non-Javadoc) + * @see tlc2.tool.fp.FPSet#commitChkpt() + */ + @Override + public void commitChkpt() throws IOException { + } + + /* (non-Javadoc) + * @see tlc2.tool.fp.FPSet#recover() + */ + @Override + public void recover() throws IOException { + } + + /* (non-Javadoc) + * @see tlc2.tool.fp.FPSet#recoverFP(long) + */ + @Override + public void recoverFP(long fp) throws IOException { + } + + /* (non-Javadoc) + * @see tlc2.tool.fp.FPSet#beginChkpt(java.lang.String) + */ + @Override + public void beginChkpt(String filename) throws IOException { + } + + /* (non-Javadoc) + * @see tlc2.tool.fp.FPSet#commitChkpt(java.lang.String) + */ + @Override + public void commitChkpt(String filename) throws IOException { + } + + /* (non-Javadoc) + * @see tlc2.tool.fp.FPSet#recover(java.lang.String) + */ + @Override + public void recover(String filename) throws IOException { + } +} diff --git a/tlatools/src/tlc2/tool/liveness/DotLivenessStateWriter.java b/tlatools/src/tlc2/tool/liveness/DotLivenessStateWriter.java index 6df00fedd47fba71260f70041a8d7f1d7b0db0f9..2ec361f7206238a9351c67932d651579a0d5f16a 100644 --- a/tlatools/src/tlc2/tool/liveness/DotLivenessStateWriter.java +++ b/tlatools/src/tlc2/tool/liveness/DotLivenessStateWriter.java @@ -30,11 +30,12 @@ import java.io.IOException; import tlc2.tool.TLCState; import tlc2.util.BitVector; import tlc2.util.DotStateWriter; +import tlc2.util.IStateWriter; public class DotLivenessStateWriter extends DotStateWriter implements ILivenessStateWriter { - public DotLivenessStateWriter(String fname) throws IOException { - super(fname.replace(".dot", "_liveness.dot"), ""); + public DotLivenessStateWriter(IStateWriter aStateWriter) throws IOException { + super(aStateWriter.getDumpFileName().replace(".dot", "_liveness.dot"), ""); } /* (non-Javadoc) diff --git a/tlatools/src/tlc2/tool/liveness/LiveCheck.java b/tlatools/src/tlc2/tool/liveness/LiveCheck.java index 773fc5564c3adc2aeb9a5decf21df0a7bcd758f2..342606f47caa504211d1ef21d44ffcae0e4e4212 100644 --- a/tlatools/src/tlc2/tool/liveness/LiveCheck.java +++ b/tlatools/src/tlc2/tool/liveness/LiveCheck.java @@ -22,8 +22,10 @@ import tlc2.tool.TLCState; import tlc2.tool.Tool; import tlc2.util.BitVector; import tlc2.util.FP64; -import tlc2.util.SetOfStates; +import tlc2.util.IStateWriter; import tlc2.util.IStateWriter.Visualization; +import tlc2.util.NoopStateWriter; +import tlc2.util.SetOfStates; import tlc2.util.statistics.DummyBucketStatistics; import tlc2.util.statistics.IBucketStatistics; import util.Assert; @@ -38,14 +40,18 @@ public class LiveCheck implements ILiveCheck { private final ILiveChecker[] checker; public LiveCheck(Tool tool, Action[] acts, String mdir, IBucketStatistics bucketStatistics) throws IOException { - this(tool, acts, Liveness.processLiveness(tool), mdir, bucketStatistics, null); + this(tool, acts, Liveness.processLiveness(tool), mdir, bucketStatistics, new NoopStateWriter()); + } + + public LiveCheck(Tool tool, Action[] acts, String mdir, IBucketStatistics bucketStatistics, IStateWriter stateWriter) throws IOException { + this(tool, acts, Liveness.processLiveness(tool), mdir, bucketStatistics, stateWriter); } - public LiveCheck(Tool tool, Action[] acts, String mdir, IBucketStatistics bucketStatistics, String dumpFile) throws IOException { - this(tool, acts, Liveness.processLiveness(tool), mdir, bucketStatistics, dumpFile); + public LiveCheck(Tool tool, Action[] acts, OrderOfSolution[] solutions, String mdir, IBucketStatistics bucketStatistics) throws IOException { + this(tool, acts, solutions, mdir, bucketStatistics, new NoopLivenessStateWriter()); } - public LiveCheck(Tool tool, Action[] acts, OrderOfSolution[] solutions, String mdir, IBucketStatistics bucketStatistics, String dumpFile) throws IOException { + public LiveCheck(Tool tool, Action[] acts, OrderOfSolution[] solutions, String mdir, IBucketStatistics bucketStatistics, IStateWriter stateWriter) throws IOException { myTool = tool; actions = acts; metadir = mdir; @@ -53,9 +59,9 @@ public class LiveCheck implements ILiveCheck { checker = new ILiveChecker[solutions.length]; for (int soln = 0; soln < solutions.length; soln++) { if (!solutions[soln].hasTableau()) { - checker[soln] = new LiveChecker(solutions[soln], soln, bucketStatistics, dumpFile == null ? new NoopLivenessStateWriter() : new DotLivenessStateWriter(dumpFile)); + checker[soln] = new LiveChecker(solutions[soln], soln, bucketStatistics, stateWriter.isNoop() ? new NoopLivenessStateWriter() : new DotLivenessStateWriter(stateWriter)); } else { - checker[soln] = new TableauLiveChecker(solutions[soln], soln, bucketStatistics, dumpFile == null ? new NoopLivenessStateWriter() : new DotLivenessStateWriter(dumpFile)); + checker[soln] = new TableauLiveChecker(solutions[soln], soln, bucketStatistics, stateWriter.isNoop() ? new NoopLivenessStateWriter() : new DotLivenessStateWriter(stateWriter)); } } } diff --git a/tlatools/src/tlc2/tool/liveness/Liveness.java b/tlatools/src/tlc2/tool/liveness/Liveness.java index 7594bf13633a191cfd6ff35cf46699896b6fde4d..aca58837ac057b393bcdba53032ff3ed805e4aa5 100644 --- a/tlatools/src/tlc2/tool/liveness/Liveness.java +++ b/tlatools/src/tlc2/tool/liveness/Liveness.java @@ -183,8 +183,11 @@ public class Liveness implements ToolGlobals, ASTConstants { // Assert.printStack(e); int level = Spec.getLevel(expr, con); if (level > 2) { - Assert.fail(EC.TLC_LIVE_CANNOT_HANDLE_FORMULA, expr.toString()); - ; + if (e instanceof Assert.TLCRuntimeException) { + Assert.fail(EC.TLC_LIVE_CANNOT_HANDLE_FORMULA, new String[] {expr.toString(), e.getMessage()}); + } else { + Assert.fail(EC.TLC_LIVE_CANNOT_HANDLE_FORMULA, expr.toString()); + } } return astToLive(tool, expr, con, level); } diff --git a/tlatools/src/tlc2/tool/liveness/NoopLivenessStateWriter.java b/tlatools/src/tlc2/tool/liveness/NoopLivenessStateWriter.java index efe82e89af8e9ee099f1517f02cd617ecf066f30..775b55768681d3a62cfeff20c366305c7e7dbc55 100644 --- a/tlatools/src/tlc2/tool/liveness/NoopLivenessStateWriter.java +++ b/tlatools/src/tlc2/tool/liveness/NoopLivenessStateWriter.java @@ -25,6 +25,7 @@ ******************************************************************************/ package tlc2.tool.liveness; +import tlc2.tool.Action; import tlc2.tool.TLCState; import tlc2.util.BitVector; @@ -95,4 +96,25 @@ public class NoopLivenessStateWriter implements ILivenessStateWriter { Visualization visulation) { // noop } + + /* (non-Javadoc) + * @see tlc2.util.IStateWriter#writeState(tlc2.tool.TLCState, tlc2.tool.TLCState, boolean, tlc2.tool.Action) + */ + public void writeState(TLCState state, TLCState successor, boolean successorStateIsNew, Action action) { + // noop + } + + /* (non-Javadoc) + * @see tlc2.util.IStateWriter#getDumpFileName() + */ + public String getDumpFileName() { + return ""; + } + + /* (non-Javadoc) + * @see tlc2.util.IStateWriter#isNoop() + */ + public boolean isNoop() { + return true; + } } diff --git a/tlatools/src/tlc2/util/BufferedRandomAccessFile.java b/tlatools/src/tlc2/util/BufferedRandomAccessFile.java index d768f360902452fb8755da24590df6fdf53fccaa..eaa76c9b50a6fadb0b5003fab0c4414380596144 100644 --- a/tlatools/src/tlc2/util/BufferedRandomAccessFile.java +++ b/tlatools/src/tlc2/util/BufferedRandomAccessFile.java @@ -324,6 +324,13 @@ public final class BufferedRandomAccessFile extends java.io.RandomAccessFile { // Assert.check(this.read(b) == size); return new BigInteger(b); } + + public final int readShortNat() throws IOException { + int res = this.readByte(); + if (res >= 0) return res; + res = (res << 16) | (this.readByte() & 0xff); + return -res; + } public final int readNat() throws IOException { int res = this.readShort(); @@ -388,6 +395,16 @@ public final class BufferedRandomAccessFile extends java.io.RandomAccessFile { // Assert.check(b.length <= size); this.write(b, 0, size); } + + /* Precondition: x is a non-negative short. */ + public final void writeShortNat(int x) throws IOException { + if (x <= 0x7f) { + this.writeByte((short)x); + } + else { + this.writeShort(-x); + } + } /* Precondition: x is a non-negative int. */ public final void writeNat(int x) throws IOException { diff --git a/tlatools/src/tlc2/util/Combinatorics.java b/tlatools/src/tlc2/util/Combinatorics.java index 3b55d8e16faffb1e8925e2042f30691ea27c2fb4..e8f24057a5148c4567d7375871a7a8fbe1f95c25 100644 --- a/tlatools/src/tlc2/util/Combinatorics.java +++ b/tlatools/src/tlc2/util/Combinatorics.java @@ -10,43 +10,43 @@ import util.Assert; public class Combinatorics { public static final int MAXCHOOSENUM = 62; - private static final int CHOOSETABLESIZE = - (MAXCHOOSENUM-3)*(MAXCHOOSENUM-4)/2+MAXCHOOSENUM-3; - private static long[] CHOOSETABLE = new long[CHOOSETABLESIZE]; + public static final int CHOOSETABLESIZE = (MAXCHOOSENUM - 3) * (MAXCHOOSENUM - 4) / 2 + MAXCHOOSENUM - 3; + public static long[] CHOOSETABLE = new long[CHOOSETABLESIZE]; private static long[] SUMCHOOSETABLE = new long[CHOOSETABLESIZE]; public static long choose(int n, int m) { + if (n < 0 || m < 0) { Assert.check(((m >= 0) && (n >= 0) && (n >= m)), EC.TLC_CHOOSE_ARGUMENTS_WRONG, "choose"); - if (m == 0 || m == n) + } + if (m == 0 || m == n) { return (long)1; - else if (m == 1 || m == n-1) + } else if (m == 1 || m == n - 1) { return (long)n; - else { + } else if (n == 0 || m > n) { + // Cannot choose from zero elements or more elements than present. + return 0; + } else { int j = choosePairToInt(n, m); if (j < CHOOSETABLESIZE) { return CHOOSETABLE[j]; } - Assert.fail(EC.TLC_CHOOSE_UPPER_BOUND, String.valueOf(MAXCHOOSENUM)); - return 0; // make compiler happy + return binomial(n, m); // calculate on demand } } - public static long sumChoose(int n, int m) - { + public static long sumChoose(int n, int m) { Assert.check(((m>=0) && (n>=0) && (n>=m)), EC.TLC_CHOOSE_ARGUMENTS_WRONG, "sumChoose"); - if (m == 0) + if (m == 0) { return (long)1; - else if (m == n) + } else if (m == n) { return ((long)1 << n); - else if (m == 1) + } else if (m == 1) { return (long)n; - else if (m == n-1) + } else if (m == n - 1) { return ((long)2 << n) - n; - else - { + } else { int j = choosePairToInt(n,m); - if (j < CHOOSETABLESIZE) - { + if (j < CHOOSETABLESIZE) { return SUMCHOOSETABLE[j]; } Assert.fail(EC.TLC_CHOOSE_UPPER_BOUND, String.valueOf(MAXCHOOSENUM)); @@ -55,7 +55,7 @@ public class Combinatorics { } } - private static int choosePairToInt(int n, int m) { + public static int choosePairToInt(int n, int m) { return ((n-3)*(n-4))/2 + m -2; } @@ -74,8 +74,7 @@ public class Combinatorics { n++; m = 2; sum = 1+n; - } - else + } else m++; } } @@ -122,6 +121,20 @@ public class Combinatorics { } public static BigInteger bigChoose(int n, int m) { + if (n < MAXCHOOSENUM && m < MAXCHOOSENUM) { + return BigInteger.valueOf(choose(n, m)); + } + + BigInteger binomial = BigInteger.ONE; + for (int i = 1, j = n; i <= m; i++, j--) { + final BigInteger bj = BigInteger.valueOf(j); + final BigInteger bi = BigInteger.valueOf(i); + binomial = binomial.multiply(bj).divide(bi); + } + return binomial; + } + + public static BigInteger slowBigChoose(int n, int m) { BigInteger num = fact(n); BigInteger denom = fact(n - m).multiply(fact(m)); @@ -135,8 +148,7 @@ public class Combinatorics { result = BigInt.BigZero; for (int i = 0; i <= m; i++) result = result.add(bigChoose(n, i)); - } - else { + } else { result = BigInt.BigOne; result = result.shiftLeft(n); for (int i = m+1; i <= n; i++) @@ -154,6 +166,51 @@ public class Combinatorics { return new String(sb); } + // https://blog.plover.com/math/choose.html + public static final long binomial(int n, int k) { + if (k > n) { + return 0; + } + if (k > n - k) { + // Optimize to n choose n - k. + k = n - k; + } + + long binomial = 1L; + for (int i = 1, m = n; i <= k; i++, m--) { + binomial = binomial * m / i; + } + return binomial; + } + + public static long[] pascalTableUpTo(final int maxN, final int maxK) { + if (maxN > MAXCHOOSENUM) { + final long[] ppt = new long[((maxN - MAXCHOOSENUM) * (maxK - 1))]; + int idx = 0; + + // Initialize first "row" of extension table from existing triangle. + int i = MAXCHOOSENUM + 1; + for (int j = 2; j <= maxK; j++) { + ppt[idx++] = choose(i, j); + } + // Subsequent rows initialize from previous row. + final int k = maxK - 1; + for (int j = 1; j < (maxN - MAXCHOOSENUM); j++) { + for (int l = 0; l < k; l++) { + if (l == 0) { + ppt[idx] = i++ + ppt[idx - k]; + } else { + ppt[idx] = ppt[idx - k] + ppt[idx - k - 1]; + } + idx++; + } + } + return ppt; + } + return new long[0]; + } + + // SZ Jul 14, 2009: Dead code. not used. // public static void main(String argv[]) { // int i,j; diff --git a/tlatools/src/tlc2/util/DotStateWriter.java b/tlatools/src/tlc2/util/DotStateWriter.java index 92ce992ea0f6dd2d571114253b97b54453a4fa11..14eae03683fd2c40dfec33817787dfeb94169687 100644 --- a/tlatools/src/tlc2/util/DotStateWriter.java +++ b/tlatools/src/tlc2/util/DotStateWriter.java @@ -27,7 +27,12 @@ package tlc2.util; import java.io.IOException; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import tlc2.tool.Action; import tlc2.tool.TLCState; /** @@ -37,15 +42,66 @@ import tlc2.tool.TLCState; */ public class DotStateWriter extends StateWriter { - public DotStateWriter(final String fname) throws IOException { - this(fname, "strict "); - } + // The Graphviz color scheme that is used for state transition edge colors. See + // https://www.graphviz.org/doc/info/colors.html for more details on color schemes. + private static final String dotColorScheme = "paired12"; + + // A mapping of action names to their assigned color ids. Since states are fed + // into a StateWriter incrementally, one at a time, this table is built up over + // time, adding new actions as we find out about them. + private final Map<String, Integer> actionToColors = new HashMap<>(); + + // A mapping from ranks to nodes. + private final Map<Short, Set<Long>> rankToNodes = new HashMap<>(); + + // Determines whether or not transition edges should be colorized in the state + // graph. + private final boolean colorize; + + // Determines whether or not transition edges should be labeled with their + // action names. + private final boolean actionLabels; + + // Used for assigning unique color identifiers to each action type. Incremented + // by 1 every time a new color is assigned to an action. + private Integer colorGen = 1; public DotStateWriter(final String fname, final String strict) throws IOException { + this(fname, strict, false, false); + } + + /** + * @param fname + * @param colorize + * Colorize state transition edges in the DOT state graph. + * @param actionLabels + * Label transition edges in the state graph with the name of the + * associated action. Can potentially add a large amount of visual + * clutter for large graphs with many actions. + * @throws IOException + */ + public DotStateWriter(final String fname, final boolean colorize, final boolean actionLabels) throws IOException { + this(fname, "strict ", colorize, actionLabels); + } + + public DotStateWriter(final String fname, final String strict, final boolean colorize, final boolean actionLabels) throws IOException { super(fname); + this.colorize = colorize; + this.actionLabels = actionLabels; this.writer.append(strict + "digraph DiskGraph {\n"); // strict removes redundant edges // Turned off LR because top to bottom provides better results with GraphViz viewer. // this.writer.append("rankdir=LR;\n"); // Left to right rather than top to bottom + + // Set the color scheme for transition edges if necessary. + if(colorize) { + this.writer.append(String.format("edge [colorscheme=\"%s\"]\n", dotColorScheme)); + } + + // Spread out state nodes a bit more. + this.writer.append("nodesep=0.35;\n"); + + this.writer.append("subgraph cluster_graph {\n"); + this.writer.append("color=\"white\";\n"); // no border. this.writer.flush(); } @@ -60,8 +116,14 @@ public class DotStateWriter extends StateWriter { this.writer.append(states2dot(state)); this.writer.append("\"]"); this.writer.append("\n"); + + maintainRanks(state); } + protected void maintainRanks(final TLCState state) { + rankToNodes.computeIfAbsent(state.level, k -> new HashSet<Long>()).add(state.fingerPrint()); + } + /* (non-Javadoc) * @see tlc2.util.StateWriter#writeState(tlc2.tool.TLCState, tlc2.tool.TLCState, boolean) */ @@ -69,52 +131,154 @@ public class DotStateWriter extends StateWriter { writeState(state, successor, successorStateIsNew, Visualization.DEFAULT); } + public synchronized void writeState(final TLCState state, final TLCState successor, final boolean successorStateIsNew, Action action) + { + writeState(state, successor, null, 0, 0, successorStateIsNew, Visualization.DEFAULT, action); + } + /* (non-Javadoc) * @see tlc2.util.StateWriter#writeState(tlc2.tool.TLCState, tlc2.tool.TLCState, boolean, tlc2.util.IStateWriter.Visualization) */ public synchronized void writeState(TLCState state, TLCState successor, boolean successorStateIsNew, Visualization visualization) { - writeState(state, successor, null, 0, 0, successorStateIsNew, visualization); + writeState(state, successor, null, 0, 0, successorStateIsNew, visualization, null); } /* (non-Javadoc) * @see tlc2.util.StateWriter#writeState(tlc2.tool.TLCState, tlc2.tool.TLCState, tlc2.util.BitVector, int, int, boolean) */ public synchronized void writeState(TLCState state, TLCState successor, BitVector actionChecks, int from, int length, boolean successorStateIsNew) { - writeState(state, successor, actionChecks, from, length, successorStateIsNew, Visualization.DEFAULT); + writeState(state, successor, actionChecks, from, length, successorStateIsNew, Visualization.DEFAULT, null); } /* (non-Javadoc) * @see tlc2.util.StateWriter#writeState(tlc2.tool.TLCState, tlc2.tool.TLCState, java.lang.String, boolean, tlc2.util.IStateWriter.Visualization) */ public synchronized void writeState(TLCState state, TLCState successor, BitVector actionChecks, int from, int length, boolean successorStateIsNew, - Visualization visualization) { + Visualization visualization, Action action) { final String successorsFP = Long.toString(successor.fingerPrint()); - - // Write the transition + + // Write the transition edge. this.writer.append(Long.toString(state.fingerPrint())); this.writer.append(" -> "); this.writer.append(successorsFP); if (visualization == Visualization.STUTTERING) { this.writer.append(" [style=\"dashed\"]"); } - if (length > 0) { // omit if no actions - this.writer.append(" [label=\"" + actionChecks.toString(from, length, 't', 'f') + "\"]"); + + // Add the transition edge label. + if(action!=null) { + String transitionLabel = this.dotTransitionLabel(state, successor, action); + this.writer.append(transitionLabel); } + this.writer.append(";\n"); - + // If the successor is new, print the state's label. Labels are printed // when writeState sees the successor. It does not print the label for // the current state. If it would print the label for the current state, // the init state labels would be printed twice. if (successorStateIsNew) { - // Write the successor's label + // Write the successor's label. this.writer.append(successorsFP); this.writer.append(" [label=\""); this.writer.append(states2dot(successor)); this.writer.append("\"]"); this.writer.append(";\n"); } + + maintainRanks(state); + } + + /** + * Given an action, returns the associated color identifier for it. The color + * identifier is just an integer suitable for use in a GraphViz color scheme. This + * method updates the (action -> color) mapping if this action has not been seen + * before for this DotStateWriter instance. + * + * @param action + * @return the color identifier for the given action + */ + protected Integer getActionColor(final Action action) { + // Return a default color if the given action is null. + if (action == null) { + return 1; + } else { + String actionName = action.getName().toString(); + // If this action has been seen before, retrieve its color. + if (actionToColors.containsKey(actionName)) { + return actionToColors.get(actionName); + } + // If this action has not been seen yet, get the next available color + // and assign it to this action. + else { + this.colorGen++; + actionToColors.put(actionName, this.colorGen); + return this.colorGen; + } + } } + + /** + * Creates a DOT label for an edge representing a state transition. + * + * @param state the current state of the transition + * @param successor the next state of the transition + * @param action the action that induced the transition + * @return the DOT label for the edge + */ + protected String dotTransitionLabel(final TLCState state, final TLCState successor, final Action action) { + // Only colorize edges if specified. Default to black otherwise. + final String color = colorize ? this.getActionColor(action).toString() : "black" ; + + // Only add action label if specified. + final String actionName = actionLabels ? action.getName().toString() : "" ; + + final String labelFmtStr = " [label=\"%s\" color=\"%s\" fontcolor=\"%s\"]"; + return String.format(labelFmtStr, actionName, color, color); + } + + + /** + * Creates a DOT legend that maps actions to their corresponding edge color in the state graph. + * + * @param name the title of the legend + * @param actions the set of action names that will be included in the legend + * @return + */ + protected String dotLegend(final String name, final Set<String> actions) { + final StringBuilder sb = new StringBuilder(); + sb.append(String.format("subgraph %s {", "cluster_legend")); + sb.append("graph[style=bold];"); + sb.append("label = \"Next State Actions\" style=\"solid\"\n"); + sb.append(String.format("node [ labeljust=\"l\" colorscheme=\"%s\" style=filled shape=record ]\n", + dotColorScheme)); + for (String action : actions) { + String str = String.format("%s [label=\"%s\" fillcolor=%d]", action, action, + this.actionToColors.get(action)); + sb.append(str); + sb.append("\n"); + } + sb.append("}"); + return sb.toString(); + } + + /** + * Given a TLC state, generate a string representation suitable for a HTML DOT graph label. + */ + //TODO This cannot handle states with variables such as "active = (0 :> TRUE @@ 1 :> FALSE)". +// protected static String state2html(final TLCState state) { +// final StringBuilder sb = new StringBuilder(); +// final Map<UniqueString, Value> valMap = state.getVals(); +// +// // Generate a string representation of state. +// for (UniqueString key : valMap.keySet()) { +// final String valString = (key.toString() + " = " + valMap.get(key).toString()); +// sb.append(valString); +// // New line between variables. +// sb.append("<br/>"); +// } +// return sb.toString(); +// } protected static String states2dot(final TLCState state) { // Replace "\" with "\\" and """ with "\"". @@ -125,6 +289,19 @@ public class DotStateWriter extends StateWriter { * @see tlc2.util.IStateWriter#close() */ public void close() { + for (final Set<Long> entry : rankToNodes.values()) { + this.writer.append("{rank = same; "); + for (final Long l : entry) { + this.writer.append(l + ";"); + } + this.writer.append("}\n"); + } + this.writer.append("}\n"); // closes the main subgraph. + // We only need the legend if the edges are colored by action and there is more + // than a single action. + if (colorize && this.actionToColors.size() > 1) { + this.writer.append(dotLegend("DotLegend", this.actionToColors.keySet())); + } this.writer.append("}"); super.close(); } diff --git a/tlatools/src/tlc2/util/FP64.java b/tlatools/src/tlc2/util/FP64.java index 87d3a433857ae3ff9fe1db9a68e85a3c441f118e..71a15f1ee523dcc36ee281479cc2623aa57db170 100644 --- a/tlatools/src/tlc2/util/FP64.java +++ b/tlatools/src/tlc2/util/FP64.java @@ -5,6 +5,7 @@ package tlc2.util; import java.io.IOException; import java.io.InputStream; +import java.util.Random; /** * A 64-bit fingerprint is stored in an instance of the type @@ -375,6 +376,21 @@ public class FP64 { public static long getIrredPoly() { return IrredPoly; } + /** + * Initializes {@link FP64#IrredPoly} with a randomly chosen poly from + * {@link FP64#Polys}. + */ + public static void InitRnd() { + Init(new Random().nextInt(Polys.length)); + } + + /** + * Initializes {@link FP64#IrredPoly} the first poly in {@link FP64#Polys}. + */ + public static void Init() { + Init(0); + } + // Initialization code public static void Init(int n) { Init(Polys[n]); diff --git a/tlatools/src/tlc2/util/IStateWriter.java b/tlatools/src/tlc2/util/IStateWriter.java index 1fa797c02a1ad451ae29139d13171b3daa8a6b61..e6b6bed0ff30c26486bfd92e045bd42b0bd63f62 100644 --- a/tlatools/src/tlc2/util/IStateWriter.java +++ b/tlatools/src/tlc2/util/IStateWriter.java @@ -25,6 +25,7 @@ ******************************************************************************/ package tlc2.util; +import tlc2.tool.Action; import tlc2.tool.TLCState; public interface IStateWriter { @@ -48,6 +49,8 @@ public interface IStateWriter { void writeState(TLCState state); void writeState(TLCState state, TLCState successor, boolean successorStateIsNew); + + void writeState(TLCState state, TLCState successor, boolean successorStateIsNew, Action action); void writeState(TLCState state, TLCState successor, boolean successorStateIsNew, Visualization visulation); @@ -56,4 +59,8 @@ public interface IStateWriter { void writeState(TLCState state, TLCState successor, BitVector actionChecks, int from, int length, boolean successorStateIsNew, Visualization visulation); void close(); + + String getDumpFileName(); + + boolean isNoop(); } \ No newline at end of file diff --git a/tlatools/src/tlc2/util/IdThread.java b/tlatools/src/tlc2/util/IdThread.java index 1941cc10a1310b6ae7ec7baf73020d49fe9c0689..700d713e181b749b4736d1d1c266b86eebc77d3a 100644 --- a/tlatools/src/tlc2/util/IdThread.java +++ b/tlatools/src/tlc2/util/IdThread.java @@ -2,12 +2,32 @@ // Portions Copyright (c) 2003 Microsoft Corporation. All rights reserved. package tlc2.util; +import tlc2.tool.TLCState; import tlc2.value.Value; /** An <code>IdThread</code> is a <code>Thread</code> with an integer identifier. */ public class IdThread extends Thread { + private static final ThreadLocal<TLCState> currentState = new ThreadLocal<>(); + + /** + * @return null during the generation of initial states (see + * tlc2.tool.ModelChecker.doInit(boolean) and a TLCState during the + * generation of next-states in tlc2.tool.ModelChecker.doNext(TLCState, + * ObjLongTable, Worker). It corresponds to the predecessor state of the + * next-state currently being generated by the worker thread. + */ + public static final TLCState getCurrentState() { + return currentState.get(); + } + public static final void setCurrentState(final TLCState state) { + currentState.set(state); + } + public static final void resetCurrentState() { + currentState.remove(); + } + private final int id; private Value[] localValues = new Value[4]; diff --git a/tlatools/src/tlc2/util/NoopStateWriter.java b/tlatools/src/tlc2/util/NoopStateWriter.java index bfda81a176326100258f886598aef8a32b254817..4505b16f915c8c326ee4e88abf8051cb02637bff 100644 --- a/tlatools/src/tlc2/util/NoopStateWriter.java +++ b/tlatools/src/tlc2/util/NoopStateWriter.java @@ -25,6 +25,7 @@ ******************************************************************************/ package tlc2.util; +import tlc2.tool.Action; import tlc2.tool.TLCState; public final class NoopStateWriter implements IStateWriter { @@ -71,4 +72,25 @@ public final class NoopStateWriter implements IStateWriter { Visualization visulation) { // noop } + + /* (non-Javadoc) + * @see tlc2.util.IStateWriter#writeState(tlc2.tool.TLCState, tlc2.tool.TLCState, boolean, tlc2.tool.Action) + */ + public void writeState(TLCState state, TLCState successor, boolean successorStateIsNew, Action action) { + // noop + } + + /* (non-Javadoc) + * @see tlc2.util.IStateWriter#isNoop() + */ + public boolean isNoop() { + return true; + } + + /* (non-Javadoc) + * @see tlc2.util.IStateWriter#getDumpFileName() + */ + public String getDumpFileName() { + return ""; + } } diff --git a/tlatools/src/tlc2/util/StateWriter.java b/tlatools/src/tlc2/util/StateWriter.java index b9233d10d0f92ecfcaa4a4162f87bacb066e5277..3682d65e6840d84323cf8fd31bf37076564943bb 100644 --- a/tlatools/src/tlc2/util/StateWriter.java +++ b/tlatools/src/tlc2/util/StateWriter.java @@ -3,6 +3,7 @@ package tlc2.util; import java.io.IOException; import java.io.PrintWriter; +import tlc2.tool.Action; import tlc2.tool.TLCState; import util.FileUtil; @@ -14,15 +15,30 @@ public class StateWriter implements IStateWriter { protected final PrintWriter writer; protected int stateNum; + private String fname; public StateWriter(String fname) throws IOException { - // SZ Feb 24, 2009: stream creation moved + this.fname = fname; this.writer = new PrintWriter(FileUtil.newBFOS(fname)); this.stateNum = 1; } /* (non-Javadoc) + * @see tlc2.util.IStateWriter#getDumpFileName() + */ + public String getDumpFileName() { + return this.fname; + } + + /* (non-Javadoc) + * @see tlc2.util.IStateWriter#isNoop() + */ + public boolean isNoop() { + return false; + } + + /* (non-Javadoc) * @see tlc2.util.IStateWriter#writeState(tlc2.tool.TLCState) */ public synchronized void writeState(TLCState state) @@ -42,6 +58,13 @@ public class StateWriter implements IStateWriter } } + public synchronized void writeState(final TLCState state, final TLCState successor, final boolean successorStateIsNew, Action action) + { + if (successorStateIsNew) { + this.writeState(state); + } + } + /* (non-Javadoc) * @see tlc2.util.IStateWriter#writeState(tlc2.tool.TLCState, tlc2.tool.TLCState, boolean, tlc2.util.IStateWriter.Visualization) */ diff --git a/tlatools/src/tlc2/value/BoolValue.java b/tlatools/src/tlc2/value/BoolValue.java index 77988ab3287e53534610625a574c2991f5c5a416..23337bc6de24aab38e779d8e222cd1d3c21f45f9 100644 --- a/tlatools/src/tlc2/value/BoolValue.java +++ b/tlatools/src/tlc2/value/BoolValue.java @@ -6,7 +6,6 @@ package tlc2.value; -import tlc2.tool.ModelChecker; import tlc2.tool.FingerprintException; import tlc2.util.FP64; import util.Assert; @@ -121,7 +120,7 @@ public class BoolValue extends Value { public final boolean isNormalized() { return true; } - public final void normalize() { /*nop*/ } + public final Value normalize() { /*nop*/ return this; } public final boolean isDefined() { return true; } diff --git a/tlatools/src/tlc2/value/Enumerable.java b/tlatools/src/tlc2/value/Enumerable.java index 6187ac4373983fd5f5e350cc4001024debd69dff..faeb4a6c1c3b93f0f59d070610be56e8ac79852c 100644 --- a/tlatools/src/tlc2/value/Enumerable.java +++ b/tlatools/src/tlc2/value/Enumerable.java @@ -10,7 +10,15 @@ public interface Enumerable { public int size(); public boolean member(Value elem); public ValueEnumeration elements(); + /** + * Returns a {@link ValueEnumeration} which returns k + * {@link Value}s of all {@link Value}s returned by + * {@link Enumerable#elements()}. In other words, it returns + * a randomly chosen subset of all {@link Value} members of + * this {@link Enumerable}. + */ + public ValueEnumeration elements(final int k); + public EnumerableValue getRandomSubset(final int k); public Value isSubsetEq(Value other); - } diff --git a/tlatools/src/tlc2/value/EnumerableValue.java b/tlatools/src/tlc2/value/EnumerableValue.java index 9aa9d7a1643b782587cae8d27f91304d31e63b3f..e158cbf49eb89732d78d34d2966195ca5b533a72 100644 --- a/tlatools/src/tlc2/value/EnumerableValue.java +++ b/tlatools/src/tlc2/value/EnumerableValue.java @@ -27,8 +27,14 @@ package tlc2.value; -import tlc2.tool.ModelChecker; +import java.util.List; +import java.util.Random; + +import tlc2.TLCGlobals; import tlc2.tool.FingerprintException; +import tlc2.tool.ModelChecker; +import tlc2.tool.TLCState; +import tlc2.util.IdThread; public abstract class EnumerableValue extends Value implements Enumerable, ValueConstants { @@ -48,5 +54,217 @@ public abstract class EnumerableValue extends Value implements Enumerable, Value else { throw e; } } } + + @Override + public EnumerableValue getRandomSubset(final int kOutOfN) { + // By default, convert all EVs into SetEnumValue and delegate to its + // getRandomSubset. + return SetEnumValue.convert(this).getRandomSubset(kOutOfN); + } + + public ValueEnumeration elements(final int k) { + // The generic implementation collects all n elements of the actual Enumerable + // into the temporary variable values. The SubSetEnumerator then randomly + // returns up to k elements. + // The underlying assuming here is that the size of EnumerableValue (n) is + // very small and this method is not called as part of the next-state relation. + // If it gets called on larger sets or as part of the next-state relation, + // subclasses can provide a more efficient implementation (e.g. see + // IntervalValue and SetEnumValue which return a more efficient subclass + // of SubsetEnumerator). + final List<Value> values = elements().all(); + return new SubsetEnumerator(k) { + @Override + public Value nextElement() { + if (!hasNext()) { + return null; + } + return values.get(nextIndex()); + } + }; + } + + /* Randomization for sets */ + + private static long randomSeed; + + public static long getRandomSeed() { + return randomSeed; + } + + /** + * Initialize Random with the given seed value. + **/ + public static void setRandom(final long seed) { + randomSeed = seed; + resetRandom(); + } + + /** + * Re-Initialize Random with the recorded seed value. + **/ + public static void resetRandom() { + RANDOMS.remove(); + } + + public static Random getRandom() { + return RANDOMS.get(); + } + + private static final ThreadLocal<Random> RANDOMS = new ThreadLocal<Random>() { + @Override + protected Random initialValue() { + if (TLCGlobals.mainChecker != null && ModelChecker.class.equals(TLCGlobals.mainChecker.getClass())) { + // In order to recreate the error trace in BFS mode - which essentially + // corresponds to rerunning state exploration following a given path - we have + // to recreate the same random values too. Otherwise, TLC will fail to recreate + // the trace because the recreated TLCState does not match the fingerprint in + // the error trace/path. Therefore, we maintain one RNG per IdThread (IWorker) + // which - for the initial states - is seeded with enumFractionSeed and - in the + // scope of next-state - gets seeded with the fingerprint of the predecessor + // state. + return new TLCStateRandom(randomSeed); + } else { + // DFS or Simulation need no special handling because: + // - DFS does not re-create the error trace (just prints the current trace). + // - Simulation mode is intended to allow users to gather statistics on + // behaviors generated with specified probabilities of different transitions. + // (For example, to find the expected time for a message to be delivered with + // retransmission as a function of the probability of message loss). For this, + // it's important that the random choice have no correlation with the state in + // which the choice is made. + return new DefaultRandom(randomSeed); + } + } + + @Override + public Random get() { + // Hook to re-initialize random (no-op for DFS and simulation). + return ((EnumerableValueRandom) super.get()).initialize(); + } + }; + + private static interface EnumerableValueRandom { + public Random initialize(); + } + + @SuppressWarnings("serial") + private static final class DefaultRandom extends Random implements EnumerableValueRandom { + public DefaultRandom(long randomSeed) { + super(randomSeed); + } + + @Override + public final Random initialize() { + // Noop + return this; + } + } + + @SuppressWarnings("serial") + private static final class TLCStateRandom extends Random implements EnumerableValueRandom { + + private TLCState state; + + public TLCStateRandom(long randomSeed) { + super(randomSeed); + } + + private void initializedFor(final TLCState state) { + // XOR the state's fingerprint with the initial randomSeed value. This is done + // so that two identical states (same fingerprint) of two different + // specifications do not produce the same random value. + final long seed = state.fingerPrint() ^ randomSeed; + this.setSeed(seed); + this.state = state; + } + + private boolean isInitializedFor(final TLCState another) { + return state == another; + } + + @Override + public Random initialize() { + final TLCState state = IdThread.getCurrentState(); + // state is null during the generation of initial states and non-null in the + // scope of the next-state relation (however, state can be an initial state). + // Thus, an RNG is seeded with randomSeed during the generation of initial + // states and seeded with randomSeed ^ predecessor's fingerprint during the + // generation of next states. + // Do not re-initialize random for the same TLCState twice to produce two + // distinct values with high probability with a next-state such as: + // Next == x' = RandomElement(0..2) /\ y' = RandomElement(0..2) + // If random was to be re-initialized/re-seeded, RandomElement(0..2) for x' and y' + // would be identical values (also see tlc2.tool.RandomElementXandYTest). + if (state != null && !isInitializedFor(state)) { + initializedFor(state); + } + return this; + } + } + + abstract class SubsetEnumerator implements ValueEnumeration { + + protected final long x; + protected final int a; + protected final int n; + protected final int k; + protected int i; + + public SubsetEnumerator(final int k) { + this(k, size()); + } + + public SubsetEnumerator(final int k, final int n) { + this.n = n; + + // https://en.wikipedia.org/wiki/Linear_congruential_generator + // + // x has to be co-prime to n. Since n might or might not be a prime number + // - it depends on the actual size of the set - we simply set x to + // be a prime number. The prime x has to be larger than n tough, since n is + // bound by Integer.MAX_VALUE, we simply choose the Mersenne prime + // Integer.MAX_VALUE + // for x and accept that we fail if n = Integer.MAX_VALUE. To minimize + // intermediate results and the rounds of mod in nextIndex, we choose 191 if n + // happens to be smaller (very likely). + assert n < Integer.MAX_VALUE; + this.x = n < 191 ? 191L : 1L * Integer.MAX_VALUE; + + // k out of n elements in the range 0 <= k <= n. + if (n > 0) { + this.k = k; + this.a = getRandom().nextInt(n); + } else { + this.k = 0; + this.a = 0; // RANDOM.nextInt(0) causes IllegalArgumentException. + } + } + + public void reset() { + i = 0; + } + + public boolean hasNext() { + return i < k; + } + + /** + * @return A random (uniformly distributed) index in the range [0,n) where n is + * {@link Enumerable#size()}. + */ + public int nextIndex() { + if (n <= 0) { + i++; + return 0; + } + // long x avoids intermediate overflow, final cast to int safe though because of + // mod n. + final int index = (int) (((x * i++) + a) % n); + assert 0 <= index && index < n; + return index; + } + public abstract Value nextElement(); + } } diff --git a/tlatools/src/tlc2/value/FcnLambdaValue.java b/tlatools/src/tlc2/value/FcnLambdaValue.java index 04112012d2c4607529cf121fdab5c91a3c1938bc..3f8d10917352f0b0788782fd40cd1aeb3885fe0e 100644 --- a/tlatools/src/tlc2/value/FcnLambdaValue.java +++ b/tlatools/src/tlc2/value/FcnLambdaValue.java @@ -13,10 +13,9 @@ import java.io.ObjectOutputStream; import tla2sany.semantic.FormalParamNode; import tla2sany.semantic.SemanticNode; import tla2sany.semantic.SymbolNode; -import tlc2.tool.ModelChecker; -import tlc2.tool.FingerprintException; import tlc2.tool.EvalControl; import tlc2.tool.EvalException; +import tlc2.tool.FingerprintException; import tlc2.tool.TLCState; import tlc2.tool.Tool; import tlc2.util.Context; @@ -531,11 +530,12 @@ public class FcnLambdaValue extends Value implements Applicable { } } - public final void normalize() { + public final Value normalize() { try { if (this.fcnRcd != null) { this.fcnRcd.normalize(); } + return this; } catch (RuntimeException | OutOfMemoryError e) { if (hasSource()) { throw FingerprintException.getNewHead(this, e); } diff --git a/tlatools/src/tlc2/value/FcnRcdValue.java b/tlatools/src/tlc2/value/FcnRcdValue.java index 15eafbcdec6e8f5471e6975fdaf47cf434e4ce97..e4922e037bf28630792966df3621f825db601b04 100644 --- a/tlatools/src/tlc2/value/FcnRcdValue.java +++ b/tlatools/src/tlc2/value/FcnRcdValue.java @@ -8,16 +8,15 @@ package tlc2.value; import java.util.Arrays; -import tlc2.tool.ModelChecker; -import tlc2.tool.FingerprintException; import tlc2.tool.EvalControl; +import tlc2.tool.FingerprintException; import tlc2.util.FP64; import util.Assert; public class FcnRcdValue extends Value implements Applicable { - public Value[] domain; - public IntervalValue intv; - public Value[] values; + public final Value[] domain; + public final IntervalValue intv; + public final Value[] values; private boolean isNorm; private int[] indexTbl; // speed up function application @@ -46,6 +45,10 @@ public class FcnRcdValue extends Value implements Applicable { this.indexTbl = fcn.indexTbl; } + public FcnRcdValue(ValueVec elems, Value[] values, boolean isNorm) { + this(elems.toArray(), values, isNorm); + } + public final byte getKind() { return FCNRCDVALUE; } /* We create an index only when the domain is not very small. */ @@ -433,6 +436,18 @@ public class FcnRcdValue extends Value implements Applicable { } } + /** + * Returns the domain of this FunctionRecordValue regardless of its internal + * representation as either Value[] or IntervalValue as Value[]. + */ + public Value[] getDomainAsValues() { + if (this.intv != null) { + return this.intv.asValues(); + } else { + return this.domain; + } + } + public final int size() { try { this.normalize(); @@ -484,7 +499,7 @@ public class FcnRcdValue extends Value implements Applicable { public final boolean isNormalized() { return this.isNorm; } /* This method normalizes (destructively) this function. */ - public final void normalize() { + public final Value normalize() { try { if (!this.isNorm) { @@ -524,7 +539,7 @@ public class FcnRcdValue extends Value implements Applicable { } this.isNorm = true; } - + return this; } catch (RuntimeException | OutOfMemoryError e) { if (hasSource()) { throw FingerprintException.getNewHead(this, e); } diff --git a/tlatools/src/tlc2/value/IntValue.java b/tlatools/src/tlc2/value/IntValue.java index aaf785cf22308717cb9ff42f4f62d40dd75d075e..38bce557fbe80fd09ea5fd3ba6730e03b6a57691 100644 --- a/tlatools/src/tlc2/value/IntValue.java +++ b/tlatools/src/tlc2/value/IntValue.java @@ -6,7 +6,6 @@ package tlc2.value; -import tlc2.tool.ModelChecker; import tlc2.tool.FingerprintException; import tlc2.util.FP64; import util.Assert; @@ -154,7 +153,7 @@ public class IntValue extends Value { public final boolean isNormalized() { return true; } - public final void normalize() { /*nop*/ } + public final Value normalize() { /*nop*/return this; } public final boolean isDefined() { return true; } diff --git a/tlatools/src/tlc2/value/IntervalValue.java b/tlatools/src/tlc2/value/IntervalValue.java index 7342a96f0ef6720121e0a83e7aa1156ef305bda7..fd0de2b18b7b099c15b4919a691d07a5a050ea4d 100644 --- a/tlatools/src/tlc2/value/IntervalValue.java +++ b/tlatools/src/tlc2/value/IntervalValue.java @@ -6,7 +6,6 @@ package tlc2.value; -import tlc2.tool.ModelChecker; import tlc2.tool.FingerprintException; import tlc2.util.FP64; import util.Assert; @@ -106,6 +105,19 @@ implements Enumerable, Reducible { } } + /** + * @return Converts this IntervalValue instance into a Value[]. This can be seen + * as the inverse to the performance optimization that the IntervalValue + * actually is. + */ + final Value[] asValues() { + final Value[] values = new Value[size()]; + for (int i = 0; i < size(); i++) { + values[i] = IntValue.gen(this.low + i); + } + return values; + } + /* Return this - val. */ public final Value diff(Value val) { try { @@ -193,7 +205,7 @@ implements Enumerable, Reducible { public final boolean isNormalized() { return true; } - public final void normalize() { /*nop*/ } + public final Value normalize() { /*nop*/return this; } public final boolean isDefined() { return true; } @@ -246,6 +258,28 @@ implements Enumerable, Reducible { } } + @Override + public EnumerableValue getRandomSubset(final int kOutOfN) { + final ValueVec vec = new ValueVec(kOutOfN); + + final ValueEnumeration ve = elements(kOutOfN); + + Value v = null; + while ((v = ve.nextElement()) != null) { + vec.addElement(v); + } + return new SetEnumValue(vec, false); + } + + public Value elementAt(final int idx) { + if (0 <= idx && idx < size()) { + return IntValue.gen(low + idx); + } + Assert.fail( + "Attempted to retrieve out-of-bounds element from the interval value " + ppr(this.toString()) + "."); + return null; // make compiler happy + } + public final ValueEnumeration elements() { try { return new Enumerator(); @@ -269,5 +303,17 @@ implements Enumerable, Reducible { } } - + + @Override + public ValueEnumeration elements(final int kOutOfN) { + return new EnumerableValue.SubsetEnumerator(kOutOfN) { + @Override + public Value nextElement() { + if (!hasNext()) { + return null; + } + return IntValue.gen(low + nextIndex()); + } + }; + } } diff --git a/tlatools/src/tlc2/value/LazyValue.java b/tlatools/src/tlc2/value/LazyValue.java index 8fe604d9606693dfec1b9816413b9f18e04f9a90..273ca7c510199bfa300e1f0e0e849416f283853a 100644 --- a/tlatools/src/tlc2/value/LazyValue.java +++ b/tlatools/src/tlc2/value/LazyValue.java @@ -192,12 +192,13 @@ public class LazyValue extends Value { } } - public final void normalize() { + public final Value normalize() { try { if (this.val == null || this.val == ValUndef) { Assert.fail("Error(TLC): Attempted to normalize lazy value."); } this.val.normalize(); + return this; } catch (RuntimeException | OutOfMemoryError e) { if (hasSource()) { throw FingerprintException.getNewHead(this, e); } diff --git a/tlatools/src/tlc2/value/MVPerm.java b/tlatools/src/tlc2/value/MVPerm.java index 1f3b3e24ed6754652f2e0cd0821f366864c80701..7b1a4b5438c856f372982db84d53b9f37442bf86 100644 --- a/tlatools/src/tlc2/value/MVPerm.java +++ b/tlatools/src/tlc2/value/MVPerm.java @@ -12,10 +12,10 @@ import util.Assert; import util.Set; public final class MVPerm { - private ModelValue[] elems; + private final ModelValue[] elems; private int count; - public MVPerm() { + private MVPerm() { this.elems = new ModelValue[ModelValue.mvs.length]; this.count = 0; } @@ -49,20 +49,20 @@ public final class MVPerm { return res; } - public final int size() { return this.count; } + private final int size() { return this.count; } - public final ModelValue get(ModelValue k) { + final ModelValue get(ModelValue k) { return this.elems[k.index]; } - public final void put(ModelValue k, ModelValue elem) { + private final void put(ModelValue k, ModelValue elem) { if (!k.equals(elem) && this.elems[k.index] == null) { this.elems[k.index] = elem; this.count++; } } - public final void put(int i, ModelValue elem) { + private final void put(int i, ModelValue elem) { if (this.elems[i] == null && elem != null) { this.elems[i] = elem; this.count++; @@ -89,20 +89,22 @@ public final class MVPerm { return res; } - public static final MVPerm[] permutationSubgroup(ValueEnumeration Enum) { - Set perms = new Set(20); - Vect permVec = new Vect(20); + public static final MVPerm[] permutationSubgroup(final Enumerable enumerable) { + final ValueEnumeration Enum = enumerable.elements(); + final int sz = enumerable.size() - 1; + final Set perms = new Set(sz); + final Vect permVec = new Vect(sz); // Compute the group generators: Value elem; while ((elem = Enum.nextElement()) != null) { - FcnRcdValue fcn = FcnRcdValue.convert(elem); + final FcnRcdValue fcn = FcnRcdValue.convert(elem); if (fcn == null) { Assert.fail("The symmetry operator must specify a set of functions."); } - MVPerm perm = new MVPerm(); + final MVPerm perm = new MVPerm(); for (int i = 0; i < fcn.domain.length; i++) { - Value dval = fcn.domain[i]; - Value rval = fcn.values[i]; + final Value dval = fcn.domain[i]; + final Value rval = fcn.values[i]; if ((dval instanceof ModelValue) && (rval instanceof ModelValue)) { perm.put((ModelValue)dval, (ModelValue)rval); } @@ -115,12 +117,12 @@ public final class MVPerm { } } // Compute the group generated by the generators: - int gsz = permVec.size(); + final int gsz = permVec.size(); int sz0 = 0; while (true) { - int sz1 = permVec.size(); + final int sz1 = permVec.size(); for (int i = 0; i < gsz; i++) { - MVPerm perm1 = (MVPerm)permVec.elementAt(i); + final MVPerm perm1 = (MVPerm)permVec.elementAt(i); for (int j = sz0; j < sz1; j++) { MVPerm perm = perm1.compose((MVPerm)permVec.elementAt(j)); if (perm.size() > 0 && perms.put(perm) == null) { @@ -128,12 +130,12 @@ public final class MVPerm { } } } - if (sz1 == permVec.size()) break; + if (sz1 == permVec.size()) { break; } sz0 = sz1; } // Finally, put all the elements in an array ready for use: - MVPerm[] res = new MVPerm[permVec.size()]; - Enumeration permEnum = permVec.elements(); + final MVPerm[] res = new MVPerm[permVec.size()]; + final Enumeration permEnum = permVec.elements(); for (int i = 0; i < res.length; i++) { res[i] = (MVPerm)permEnum.nextElement(); } diff --git a/tlatools/src/tlc2/value/MethodValue.java b/tlatools/src/tlc2/value/MethodValue.java index 147d8f5173c4ce0a9ec1d907aadb33f8ad47515f..d0b5548006cf6f89c5f4459f3f8eda4a37ea66ac 100644 --- a/tlatools/src/tlc2/value/MethodValue.java +++ b/tlatools/src/tlc2/value/MethodValue.java @@ -6,21 +6,33 @@ package tlc2.value; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import tlc2.output.EC; -import tlc2.tool.ModelChecker; -import tlc2.tool.FingerprintException; +import tlc2.output.MP; import tlc2.tool.EvalException; +import tlc2.tool.FingerprintException; import util.Assert; +import util.Assert.TLCRuntimeException; import util.WrongInvocationException; public class MethodValue extends OpValue implements Applicable { - public Method md; + private final MethodHandle mh; + private final Method md; /* Constructor */ - public MethodValue(Method md) { this.md = md; } + public MethodValue(final Method md) { + this.md = md; + try { + this.mh = MethodHandles.publicLookup().unreflect(md); + } catch (IllegalAccessException e) { + throw new TLCRuntimeException(EC.TLC_MODULE_VALUE_JAVA_METHOD_OVERRIDE, MP.getMessage( + EC.TLC_MODULE_VALUE_JAVA_METHOD_OVERRIDE, new String[] { md.toString(), e.getMessage() })); + } + } public final byte getKind() { return METHODVALUE; } @@ -87,13 +99,15 @@ public class MethodValue extends OpValue implements Applicable { Value res = null; try { - res = (Value)this.md.invoke(null, (Object[]) args); - } catch (Exception e) + res = (Value) this.mh.invokeWithArguments((Object[]) args); + } catch (Throwable e) { if (e instanceof InvocationTargetException) { Throwable targetException = ((InvocationTargetException)e).getTargetException(); throw new EvalException(EC.TLC_MODULE_VALUE_JAVA_METHOD_OVERRIDE, new String[]{this.md.toString(), targetException.getMessage()}); + } else if (e instanceof NullPointerException) { + throw new EvalException(EC.TLC_MODULE_VALUE_JAVA_METHOD_OVERRIDE, new String[]{this.md.toString(), e.getMessage()}); } else { Assert.fail(EC.TLC_MODULE_VALUE_JAVA_METHOD_OVERRIDE, new String[]{this.md.toString(), e.getMessage()}); @@ -176,7 +190,7 @@ public class MethodValue extends OpValue implements Applicable { } } - public final void normalize() { + public final Value normalize() { try { throw new WrongInvocationException("It is a TLC bug: Attempted to normalize an operator."); } diff --git a/tlatools/src/tlc2/value/ModelValue.java b/tlatools/src/tlc2/value/ModelValue.java index 5027b8e2778385e51a8ff35f5c4de9b3e9e958b8..e32a58c1045b197bbc467edfb1d8ff030e3cb7cb 100644 --- a/tlatools/src/tlc2/value/ModelValue.java +++ b/tlatools/src/tlc2/value/ModelValue.java @@ -39,7 +39,6 @@ package tlc2.value; import java.util.Enumeration; import java.util.Hashtable; -import tlc2.tool.ModelChecker; import tlc2.tool.FingerprintException; import tlc2.util.FP64; import util.Assert; @@ -255,7 +254,7 @@ public class ModelValue extends Value { public final boolean isNormalized() { return true; } - public final void normalize() { /*nop*/ } + public final Value normalize() { /*nop*/return this; } public final boolean isDefined() { return true; } diff --git a/tlatools/src/tlc2/value/OpLambdaValue.java b/tlatools/src/tlc2/value/OpLambdaValue.java index e90364ab5660a46789645f1eeec0bab87a00e7a9..da2c12d03b03b62911640ebed1c6df562c3b3315 100644 --- a/tlatools/src/tlc2/value/OpLambdaValue.java +++ b/tlatools/src/tlc2/value/OpLambdaValue.java @@ -8,7 +8,6 @@ package tlc2.value; import tla2sany.semantic.FormalParamNode; import tla2sany.semantic.OpDefNode; -import tlc2.tool.ModelChecker; import tlc2.tool.FingerprintException; import tlc2.tool.TLCState; import tlc2.tool.Tool; @@ -183,7 +182,7 @@ public class OpLambdaValue extends OpValue implements Applicable { } } - public final void normalize() { + public final Value normalize() { try { throw new WrongInvocationException("Should not normalize an operator."); } diff --git a/tlatools/src/tlc2/value/OpRcdValue.java b/tlatools/src/tlc2/value/OpRcdValue.java index fd7d7f6f0eb4b802e7e05694682614e4bee433ff..d06d21670b508ca9cb2f4048c2249a9b77ceb9bc 100644 --- a/tlatools/src/tlc2/value/OpRcdValue.java +++ b/tlatools/src/tlc2/value/OpRcdValue.java @@ -6,7 +6,6 @@ package tlc2.value; -import tlc2.tool.ModelChecker; import tlc2.tool.FingerprintException; import tlc2.util.Vect; import util.Assert; @@ -207,7 +206,7 @@ public class OpRcdValue extends OpValue implements Applicable { } } - public final void normalize() { + public final Value normalize() { try { throw new WrongInvocationException("Should not normalize an operator."); } diff --git a/tlatools/src/tlc2/value/RecordValue.java b/tlatools/src/tlc2/value/RecordValue.java index 1d10c9e6832a16710eb9dd339132d72c6ce7f016..c4cf10f87c41ac944b26f6298012c670f2c854b2 100644 --- a/tlatools/src/tlc2/value/RecordValue.java +++ b/tlatools/src/tlc2/value/RecordValue.java @@ -8,10 +8,9 @@ package tlc2.value; import java.util.Arrays; -import tlc2.tool.ModelChecker; -import tlc2.tool.FingerprintException; import tlc2.output.EC; import tlc2.output.MP; +import tlc2.tool.FingerprintException; import tlc2.util.FP64; import util.Assert; import util.UniqueString; @@ -285,7 +284,7 @@ public class RecordValue extends Value implements Applicable { public final boolean isNormalized() { return this.isNorm; } - public final void normalize() { + public final Value normalize() { try { if (!this.isNorm) { int len = this.names.length; @@ -321,6 +320,7 @@ public class RecordValue extends Value implements Applicable { } this.isNorm = true; } + return this; } catch (RuntimeException | OutOfMemoryError e) { if (hasSource()) { throw FingerprintException.getNewHead(this, e); } diff --git a/tlatools/src/tlc2/value/SetCapValue.java b/tlatools/src/tlc2/value/SetCapValue.java index a54011a541a8fac6bc99a44937e6a5b5a0438597..821cd4f3d22d5b2425572e903575ce111a6143d9 100644 --- a/tlatools/src/tlc2/value/SetCapValue.java +++ b/tlatools/src/tlc2/value/SetCapValue.java @@ -6,7 +6,6 @@ package tlc2.value; -import tlc2.tool.ModelChecker; import tlc2.tool.FingerprintException; import util.Assert; @@ -119,7 +118,7 @@ public class SetCapValue extends EnumerableValue implements Enumerable { } } - public final void normalize() { + public final Value normalize() { try { if (this.capSet == null || this.capSet == DummyEnum) { this.set1.normalize(); @@ -128,6 +127,7 @@ public class SetCapValue extends EnumerableValue implements Enumerable { else { this.capSet.normalize(); } + return this; } catch (RuntimeException | OutOfMemoryError e) { if (hasSource()) { throw FingerprintException.getNewHead(this, e); } diff --git a/tlatools/src/tlc2/value/SetCupValue.java b/tlatools/src/tlc2/value/SetCupValue.java index f2280615128b25cd438c03c3f63ec8d672d553f7..2a69d8c69fd4d6ae5aa90ebf19cca8111b6f7ab5 100644 --- a/tlatools/src/tlc2/value/SetCupValue.java +++ b/tlatools/src/tlc2/value/SetCupValue.java @@ -6,7 +6,6 @@ package tlc2.value; -import tlc2.tool.ModelChecker; import tlc2.tool.FingerprintException; import util.Assert; @@ -115,11 +114,12 @@ public class SetCupValue extends EnumerableValue implements Enumerable { } } - public final void normalize() { + public final Value normalize() { try { if (this.cupSet != null && this.cupSet != DummyEnum) { this.cupSet.normalize(); } + return this; } catch (RuntimeException | OutOfMemoryError e) { if (hasSource()) { throw FingerprintException.getNewHead(this, e); } diff --git a/tlatools/src/tlc2/value/SetDiffValue.java b/tlatools/src/tlc2/value/SetDiffValue.java index 023ac0d325b22623011efb58fbdb72e01ad0c369..4ba3e0758d07b93e82249b13636c0e626900130e 100644 --- a/tlatools/src/tlc2/value/SetDiffValue.java +++ b/tlatools/src/tlc2/value/SetDiffValue.java @@ -6,7 +6,6 @@ package tlc2.value; -import tlc2.tool.ModelChecker; import tlc2.tool.FingerprintException; import util.Assert; @@ -122,7 +121,7 @@ public class SetDiffValue extends EnumerableValue implements Enumerable { } } - public final void normalize() { + public final Value normalize() { try { if (this.diffSet == null || this.diffSet == DummyEnum) { this.set1.normalize(); @@ -131,6 +130,7 @@ public class SetDiffValue extends EnumerableValue implements Enumerable { else { this.diffSet.normalize(); } + return this; } catch (RuntimeException | OutOfMemoryError e) { if (hasSource()) { throw FingerprintException.getNewHead(this, e); } diff --git a/tlatools/src/tlc2/value/SetEnumValue.java b/tlatools/src/tlc2/value/SetEnumValue.java index ef4cb444e935210cc78e9eab95c23d0bb39506d7..601f28a1621a32244a844084cbbfa73d0770ec35 100644 --- a/tlatools/src/tlc2/value/SetEnumValue.java +++ b/tlatools/src/tlc2/value/SetEnumValue.java @@ -6,7 +6,6 @@ package tlc2.value; -import tlc2.tool.ModelChecker; import tlc2.tool.FingerprintException; import tlc2.util.FP64; import util.Assert; @@ -26,6 +25,11 @@ implements Enumerable, Reducible { this.elems = elems; this.isNorm = isNorm; } + + public SetEnumValue() { + this.elems = new ValueVec(0); + this.isNorm = true; + } public final byte getKind() { return SETENUMVALUE; } @@ -196,12 +200,13 @@ implements Enumerable, Reducible { /* This method normalizes (destructively) this set. */ public final boolean isNormalized() { return this.isNorm; } - public final void normalize() { + public final Value normalize() { try { if (!this.isNorm) { this.elems.sort(true); // duplicates eliminated this.isNorm = true; } + return this; } catch (RuntimeException | OutOfMemoryError e) { if (hasSource()) { throw FingerprintException.getNewHead(this, e); } @@ -429,6 +434,13 @@ implements Enumerable, Reducible { // used only for printing the value, it seems that correcting this should // not do any harm. Therefore, LL added the following if statement // on 5 Mar 2012. + // Beware: + // normalize() mutates a SetEnumValue's state. Thus calling toString() + // on a SetEnumValue mutates its state. By convention, toString methods + // generally do not mutate an instance's state (side-effect free) and + // and are thus safe to be called. Failing to adhere to this convention + // can lead to subtle bugs. E.g. think of a programmer who inspects an + // instance with a debugger unconsciously mutating the instance's state. if (!this.isNormalized()) { this.normalize(); } @@ -451,6 +463,12 @@ implements Enumerable, Reducible { } } + public Value randomElement() { + int sz = size(); + int index = (int) Math.floor(getRandom().nextDouble() * sz); + return this.elems.elementAt(index); + } + public final ValueEnumeration elements() { try { return new Enumerator(); @@ -478,4 +496,30 @@ implements Enumerable, Reducible { } } + @Override + public EnumerableValue getRandomSubset(final int kOutOfN) { + final ValueVec vec = new ValueVec(kOutOfN); + + final ValueEnumeration ve = elements(kOutOfN); + + Value v = null; + while ((v = ve.nextElement()) != null) { + vec.addElement(v); + } + return new SetEnumValue(vec, false); + } + + @Override + public ValueEnumeration elements(final int k) { + normalize(); + return new EnumerableValue.SubsetEnumerator(k) { + @Override + public Value nextElement() { + if (!hasNext()) { + return null; + } + return elems.elementAt(nextIndex()); + } + }; + } } diff --git a/tlatools/src/tlc2/value/SetOfFcnsOrRcdsValue.java b/tlatools/src/tlc2/value/SetOfFcnsOrRcdsValue.java new file mode 100644 index 0000000000000000000000000000000000000000..7dd8f63582f2e5295ca5bac68d8ce9620bcbb8ab --- /dev/null +++ b/tlatools/src/tlc2/value/SetOfFcnsOrRcdsValue.java @@ -0,0 +1,129 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.value; + +import java.math.BigInteger; + +public abstract class SetOfFcnsOrRcdsValue extends EnumerableValue { + + @Override + public EnumerableValue getRandomSubset(final int kOutOfN) { + final ValueVec vec = new ValueVec(kOutOfN); + + final ValueEnumeration ve = elements(kOutOfN); + + Value v = null; + while ((v = ve.nextElement()) != null) { + vec.addElement(v); + } + + // Assert no duplicates. For large sets we assume kOutOfN < size() to avoid + // calling size() which then throws an assertion exception anyway. + assert (needBigInteger() ? vec.sort(true).size() == kOutOfN + : vec.sort(true).size() == Math.min(kOutOfN, size())); + + return new SetEnumValue(vec, false); + } + + @Override + public ValueEnumeration elements(final int k) { + if (needBigInteger()) { + return getBigSubsetEnumerator(k); + } else { + return getSubsetEnumerator(k, size()); + } + } + + protected abstract BigIntegerSubsetEnumerator getBigSubsetEnumerator(int k); + + protected abstract SubsetEnumerator getSubsetEnumerator(int k, int n); + + protected abstract boolean needBigInteger(); + + abstract class SubsetEnumerator extends EnumerableValue.SubsetEnumerator { + public SubsetEnumerator(final int k, final int n) { + super(k, n); + } + + @Override + public Value nextElement() { + if (!hasNext()) { + return null; + } + return elementAt(nextIndex()); + } + + protected abstract Value elementAt(int nextIndex); + } + + abstract class BigIntegerSubsetEnumerator implements ValueEnumeration { + + protected final BigInteger x; + protected final BigInteger a; + + protected final int k; + + protected BigInteger sz; + protected int i; + + public BigIntegerSubsetEnumerator(final int k) { + this.k = k; + this.i = 0; + + this.a = BigInteger.valueOf(Math.abs(getRandom().nextLong())); + + // http://primes.utm.edu/lists/2small/0bit.html + // (2^63 - 25) + this.x = BigInteger.valueOf(Long.MAX_VALUE - 24L); + } + + private BigInteger nextIndex() { + // ((x * i) + a) % sz + final BigInteger bi = BigInteger.valueOf(this.i++); + final BigInteger multiply = this.x.multiply(bi); + return multiply.add(this.a).mod(this.sz); + } + + @Override + public void reset() { + this.i = 0; + } + + private boolean hasNext() { + return this.i < this.k; + } + + @Override + public Value nextElement() { + if (!hasNext()) { + return null; + } + return elementAt(nextIndex()); + } + + protected abstract Value elementAt(BigInteger nextIndex); + } +} diff --git a/tlatools/src/tlc2/value/SetOfFcnsValue.java b/tlatools/src/tlc2/value/SetOfFcnsValue.java index 04fac160475032f7edd9c57bd5b7de5e84e2ec05..1f5f00e68de0d72e54780fadf5652c343a55ad3a 100644 --- a/tlatools/src/tlc2/value/SetOfFcnsValue.java +++ b/tlatools/src/tlc2/value/SetOfFcnsValue.java @@ -6,12 +6,13 @@ package tlc2.value; -import tlc2.tool.ModelChecker; -import tlc2.tool.FingerprintException; +import java.math.BigInteger; + import tlc2.TLCGlobals; +import tlc2.tool.FingerprintException; import util.Assert; -public class SetOfFcnsValue extends EnumerableValue implements Enumerable { +public class SetOfFcnsValue extends SetOfFcnsOrRcdsValue implements Enumerable { public Value domain; /* Function domain */ public Value range; /* Function range */ protected SetEnumValue fcnSet; @@ -147,6 +148,20 @@ public class SetOfFcnsValue extends EnumerableValue implements Enumerable { } } + @Override + protected boolean needBigInteger() { + final int rsz = this.range.size(); + final int dsz = this.domain.size(); + long sz = 1; + for (int i = 0; i < dsz; i++) { + sz *= rsz; + if (sz < -2147483648 || sz > 2147483647) { + return true; + } + } + return false; + } + public final boolean isNormalized() { try { if (this.fcnSet == null || this.fcnSet == DummyEnum) { @@ -160,7 +175,7 @@ public class SetOfFcnsValue extends EnumerableValue implements Enumerable { } } - public final void normalize() { + public final Value normalize() { try { if (this.fcnSet == null || this.fcnSet == DummyEnum) { this.domain.normalize(); @@ -169,6 +184,7 @@ public class SetOfFcnsValue extends EnumerableValue implements Enumerable { else { this.fcnSet.normalize(); } + return this; } catch (RuntimeException | OutOfMemoryError e) { if (hasSource()) { throw FingerprintException.getNewHead(this, e); } @@ -342,30 +358,113 @@ public class SetOfFcnsValue extends EnumerableValue implements Enumerable { } } - public final Value nextElement() { - if (this.isDone) return null; - Value[] elems = new Value[this.currentElems.length]; - if (elems.length == 0) { - this.isDone = true; - } - else { - for (int i = 0; i < elems.length; i++) { - elems[i] = this.currentElems[i]; - } - for (int i = elems.length-1; i >= 0; i--) { - this.currentElems[i] = this.enums[i].nextElement(); - if (this.currentElems[i] != null) break; - if (i == 0) { - this.isDone = true; - break; - } - this.enums[i].reset(); - this.currentElems[i] = this.enums[i].nextElement(); - } - } - return new FcnRcdValue(this.dom, elems, true); - } + public final Value nextElement() { + if (this.isDone) { + return null; + } + if (this.currentElems.length == 0) { + this.isDone = true; + return new FcnRcdValue(this.dom, new Value[this.currentElems.length], true); + } else { + // Take and store a snapshot of currentElems as the element to return for + // this invocation of nextElement(). + final Value[] elems = new Value[this.currentElems.length]; + System.arraycopy(this.currentElems, 0, elems, 0, this.currentElems.length); + + // Eagerly generate the next element which is going to be returned the upon next + // invocation of nextElement(). + for (int i = this.currentElems.length - 1; i >= 0; i--) { + this.currentElems[i] = this.enums[i].nextElement(); + if (this.currentElems[i] != null) { + break; + } + if (i == 0) { + this.isDone = true; + break; + } + this.enums[i].reset(); + this.currentElems[i] = this.enums[i].nextElement(); + } + + return new FcnRcdValue(this.dom, elems, true); + } + } } + + @Override + protected tlc2.value.SetOfFcnsOrRcdsValue.SubsetEnumerator getSubsetEnumerator(int k, int n) { + return new SubsetEnumerator(k, n); + } + + class SubsetEnumerator extends SetOfFcnsOrRcdsValue.SubsetEnumerator { + private final SetEnumValue domSet; + private final SetEnumValue rangeSet; + private final int mod; + + SubsetEnumerator(final int k, final int n) { + super(k, n); + domSet = SetEnumValue.convert(domain); + domSet.normalize(); + + rangeSet = SetEnumValue.convert(range); + + mod = range.size(); + } + + @Override + protected Value elementAt(final int idx) { + assert 0 <= idx && idx < size(); + + final Value[] range = new Value[domSet.size()]; + + for (int i = 0; i < domSet.size(); i++) { + final int elementAt = (int) (Math.floor(idx / Math.pow(mod, i)) % mod); + range[range.length - 1 - i] = rangeSet.elems.elementAt(elementAt); + } + + return new FcnRcdValue(domSet.elems, range, true); + } + } + + @Override + protected tlc2.value.SetOfFcnsOrRcdsValue.BigIntegerSubsetEnumerator getBigSubsetEnumerator(int k) { + return new BigIntegerSubsetEnumerator(k); + } + + class BigIntegerSubsetEnumerator extends SetOfFcnsOrRcdsValue.BigIntegerSubsetEnumerator { + + private final SetEnumValue domSet; + private final SetEnumValue rangeSet; + private final BigInteger bMod; + private final int mod; + + public BigIntegerSubsetEnumerator(final int k) { + super(k); + this.domSet = SetEnumValue.convert(domain); + this.domSet.normalize(); + + this.rangeSet = SetEnumValue.convert(range); + this.mod = range.size(); + this.bMod = BigInteger.valueOf(mod); + + this.sz = bMod.pow(domSet.size()); + } + + @Override + protected Value elementAt(final BigInteger idx) { + final Value[] range = new Value[domSet.size()]; + + for (int i = 0; i < domSet.size(); i++) { + final long scale = (long) Math.pow(mod, i); + final BigInteger bScale = BigInteger.valueOf(scale); + // idx2 is the index in the range (0,range.size^domset.size] + final BigInteger idx2 = idx.divide(bScale); + final int elementAt = idx2.mod(bMod).intValueExact(); + range[range.length - 1 - i] = rangeSet.elems.elementAt(elementAt); + } + return new FcnRcdValue(domSet.elems, range, true); + } + } } diff --git a/tlatools/src/tlc2/value/SetOfRcdsValue.java b/tlatools/src/tlc2/value/SetOfRcdsValue.java index c8c9ebfd60a0c00fddc09d50bbc90ed9470f785a..999c474c6034173bb1666bcd2e326a1da024503b 100644 --- a/tlatools/src/tlc2/value/SetOfRcdsValue.java +++ b/tlatools/src/tlc2/value/SetOfRcdsValue.java @@ -6,20 +6,22 @@ package tlc2.value; -import tlc2.tool.ModelChecker; -import tlc2.tool.FingerprintException; +import java.math.BigInteger; + import tlc2.TLCGlobals; import tlc2.output.EC; +import tlc2.tool.FingerprintException; import util.Assert; import util.UniqueString; -public class SetOfRcdsValue extends EnumerableValue implements Enumerable { +public class SetOfRcdsValue extends SetOfFcnsOrRcdsValue implements Enumerable { public UniqueString[] names; // The names of the fields. public Value[] values; // The values of the fields. protected SetEnumValue rcdSet; /* Constructor */ public SetOfRcdsValue(UniqueString[] names, Value[] values, boolean isNorm) { + assert names.length == values.length; // see tlc2.tool.Tool.evalAppl(OpApplNode, Context, TLCState, TLCState, int) case for OPCODE_sor this.names = names; this.values = values; this.rcdSet = null; @@ -156,6 +158,18 @@ public class SetOfRcdsValue extends EnumerableValue implements Enumerable { } } + @Override + protected boolean needBigInteger() { + long sz = 1; + for (int i = 0; i < values.length; i++) { + sz *= values[i].size(); + if (sz < -2147483648 || sz > 2147483647) { + return true; + } + } + return false; + } + public final boolean isNormalized() { try { if (this.rcdSet == null || this.rcdSet == DummyEnum) { @@ -174,7 +188,7 @@ public class SetOfRcdsValue extends EnumerableValue implements Enumerable { } } - public final void normalize() { + public final Value normalize() { try { if (this.rcdSet == null || this.rcdSet == DummyEnum) { for (int i = 0; i < this.names.length; i++) { @@ -184,6 +198,7 @@ public class SetOfRcdsValue extends EnumerableValue implements Enumerable { else { this.rcdSet.normalize(); } + return this; } catch (RuntimeException | OutOfMemoryError e) { if (hasSource()) { throw FingerprintException.getNewHead(this, e); } @@ -409,4 +424,88 @@ public class SetOfRcdsValue extends EnumerableValue implements Enumerable { } + @Override + protected tlc2.value.SetOfFcnsOrRcdsValue.SubsetEnumerator getSubsetEnumerator(int k, int n) { + return new SubsetEnumerator(k, n); + } + + class SubsetEnumerator extends SetOfFcnsOrRcdsValue.SubsetEnumerator { + + private final SetEnumValue[] convert; + private final int[] rescaleBy; + + SubsetEnumerator(final int k, final int n) { + super(k, n); + + convert = new SetEnumValue[values.length]; + rescaleBy = new int[values.length]; + + int numElems = 1; // 1 to avoid div by zero in elementAt + for (int i = values.length - 1; i >= 0; i--) { + convert[i] = SetEnumValue.convert(values[i]); + rescaleBy[i] = numElems; + numElems *= convert[i].elems.size(); + } + } + + protected RecordValue elementAt(final int idx) { + assert 0 <= idx && idx < size(); + + final Value[] val = new Value[names.length]; + for (int i = 0; i < val.length; i++) { + final SetEnumValue sev = convert[i]; + final int mod = sev.elems.size(); + + final int rescaledIdx = (int) Math.floor(idx / rescaleBy[i]); + final int elementAt = rescaledIdx % mod; + + val[i] = sev.elems.elementAt(elementAt); + } + return new RecordValue(names, val, false); + } + } + + @Override + protected BigIntegerSubsetEnumerator getBigSubsetEnumerator(int k) { + return new BigIntegerSubsetEnumerator(k); + } + + class BigIntegerSubsetEnumerator extends SetOfFcnsOrRcdsValue.BigIntegerSubsetEnumerator { + + private final SetEnumValue[] convert; + private final BigInteger[] rescaleBy; + + public BigIntegerSubsetEnumerator(final int k) { + super(k); + + convert = new SetEnumValue[values.length]; + rescaleBy = new BigInteger[values.length]; + + BigInteger numElems = BigInteger.ONE; // 1 to avoid div by zero in elementAt + for (int i = values.length - 1; i >= 0; i--) { + convert[i] = SetEnumValue.convert(values[i]); + rescaleBy[i] = numElems; + numElems = numElems.multiply(BigInteger.valueOf(convert[i].elems.size())); + } + + // The size of the (enumerated) SetOfFcnsOrRcdsValue needs BigInteger. + this.sz = numElems; + } + + @Override + protected Value elementAt(final BigInteger idx) { + final Value[] val = new Value[names.length]; + for (int i = 0; i < val.length; i++) { + final SetEnumValue sev = convert[i]; + final int mod = sev.elems.size(); + + final BigInteger d = idx.divide(rescaleBy[i]); + final BigInteger m = d.mod(BigInteger.valueOf(mod)); + final int elementAt = m.intValueExact(); + + val[i] = sev.elems.elementAt(elementAt); + } + return new RecordValue(names, val, false); + } + } } diff --git a/tlatools/src/tlc2/value/SetOfTuplesValue.java b/tlatools/src/tlc2/value/SetOfTuplesValue.java index 4d6c38f65242ab15e33851c6191f0f46cfd549bd..a7ab439fd8e7f73b3a6a9a15660f36b474d2f2d7 100644 --- a/tlatools/src/tlc2/value/SetOfTuplesValue.java +++ b/tlatools/src/tlc2/value/SetOfTuplesValue.java @@ -6,9 +6,8 @@ package tlc2.value; -import tlc2.tool.ModelChecker; -import tlc2.tool.FingerprintException; import tlc2.TLCGlobals; +import tlc2.tool.FingerprintException; import util.Assert; public class SetOfTuplesValue extends EnumerableValue implements Enumerable { @@ -189,7 +188,7 @@ public class SetOfTuplesValue extends EnumerableValue implements Enumerable { } } - public final void normalize() { + public final Value normalize() { try { if (this.tupleSet == null || this.tupleSet == DummyEnum) { for (int i = 0; i < this.sets.length; i++) { @@ -199,6 +198,7 @@ public class SetOfTuplesValue extends EnumerableValue implements Enumerable { else { this.tupleSet.normalize(); } + return this; } catch (RuntimeException | OutOfMemoryError e) { if (hasSource()) { throw FingerprintException.getNewHead(this, e); } @@ -302,7 +302,7 @@ public class SetOfTuplesValue extends EnumerableValue implements Enumerable { this.sets[0].toString(sb, offset); } for (int i = 1; i < this.sets.length; i++) { - sb.append(" X "); + sb.append(" \\X "); this.sets[i].toString(sb, offset); } if (this.sets.length > 0) { diff --git a/tlatools/src/tlc2/value/SetPredValue.java b/tlatools/src/tlc2/value/SetPredValue.java index 3e153104dae84bd032d08e7b8aff33f3214024a9..832cdebc19a194a2a4d3c36b57230fe9304ce000 100644 --- a/tlatools/src/tlc2/value/SetPredValue.java +++ b/tlatools/src/tlc2/value/SetPredValue.java @@ -12,9 +12,8 @@ import java.io.ObjectOutputStream; import tla2sany.semantic.FormalParamNode; import tla2sany.semantic.SemanticNode; -import tlc2.tool.ModelChecker; -import tlc2.tool.FingerprintException; import tlc2.tool.EvalException; +import tlc2.tool.FingerprintException; import tlc2.tool.TLCState; import tlc2.tool.Tool; import tlc2.util.Context; @@ -206,9 +205,10 @@ public class SetPredValue extends EnumerableValue implements Enumerable { } } - public final void normalize() { + public final Value normalize() { try { this.inVal.normalize(); + return this; } catch (RuntimeException | OutOfMemoryError e) { if (hasSource()) { throw FingerprintException.getNewHead(this, e); } diff --git a/tlatools/src/tlc2/value/StringValue.java b/tlatools/src/tlc2/value/StringValue.java index e637dad783d60409899c8d1fde30d81bd03c019b..a9c07c5b56f7ba2f3e3600020f7bb3e5ad42ca01 100644 --- a/tlatools/src/tlc2/value/StringValue.java +++ b/tlatools/src/tlc2/value/StringValue.java @@ -6,7 +6,6 @@ package tlc2.value; -import tlc2.tool.ModelChecker; import tlc2.tool.FingerprintException; import tlc2.util.FP64; import util.Assert; @@ -129,7 +128,7 @@ public class StringValue extends Value { public final boolean isNormalized() { return true; } - public final void normalize() { /*SKIP*/ } + public final Value normalize() { /*SKIP*/return this; } public final boolean isDefined() { return true; } diff --git a/tlatools/src/tlc2/value/SubsetValue.java b/tlatools/src/tlc2/value/SubsetValue.java index 174b79990dce543e2e1ecc36341453f0bfde3115..3e78e3dde49b0a3ee3112a40056fb680d21e04ae 100644 --- a/tlatools/src/tlc2/value/SubsetValue.java +++ b/tlatools/src/tlc2/value/SubsetValue.java @@ -6,11 +6,17 @@ package tlc2.value; +import java.math.BigDecimal; +import java.math.BigInteger; import java.util.BitSet; +import java.util.Collection; +import java.util.HashSet; +import java.util.Random; +import java.util.TreeMap; -import tlc2.tool.ModelChecker; -import tlc2.tool.FingerprintException; import tlc2.output.EC; +import tlc2.tool.FingerprintException; +import tlc2.util.Combinatorics; import util.Assert; public class SubsetValue extends EnumerableValue implements Enumerable { @@ -153,7 +159,7 @@ public class SubsetValue extends EnumerableValue implements Enumerable { } } - public final void normalize() { + public final Value normalize() { try { if (this.pset == null || this.pset == DummyEnum) { this.set.normalize(); @@ -161,6 +167,7 @@ public class SubsetValue extends EnumerableValue implements Enumerable { else { this.pset.normalize(); } + return this; } catch (RuntimeException | OutOfMemoryError e) { if (hasSource()) { throw FingerprintException.getNewHead(this, e); } @@ -256,7 +263,276 @@ public class SubsetValue extends EnumerableValue implements Enumerable { if (hasSource()) { throw FingerprintException.getNewHead(this, e); } else { throw e; } } - } + } + + public Unrank getUnrank(final int kSubset) { + // Convert outer set only once. + final SetEnumValue convert = SetEnumValue.convert(set); + convert.normalize(); + final ValueVec elems = convert.elems; + + return new Unrank(kSubset, Combinatorics.bigSumChoose(elems.size(), kSubset).longValueExact(), + Combinatorics.pascalTableUpTo(elems.size(), kSubset), elems, kSubset); + } + + public EnumerableValue getRandomSetOfSubsets(final int numOfSubsetsRequested, final int maxLengthOfSubsets) { + // Convert outer set only once. + final SetEnumValue convert = SetEnumValue.convert(set); + convert.normalize(); + final ValueVec elems = convert.elems; + final int size = elems.size(); + + // Calculate the sums of the rows of the Pascal Triangle up to + // maxLengthOfSubsets. + final long[] kss = new long[maxLengthOfSubsets + 1]; + kss[0] = 1L; + // Sum the elems.size()'s row of the Pascal Triangle up to maxLengthOfSubsets. + // This corresponds to Combinatorics.bigSumChoose except that we also keep the + // intermediate results. + BigInteger sum = BigInteger.ONE; // 1 for k=0 + for (int i = 1; i <= maxLengthOfSubsets; i++) { + kss[i] = Combinatorics.bigChoose(size, i).longValueExact(); + sum = sum.add(BigInteger.valueOf(kss[i])); + } + assert sum.equals(Combinatorics.bigSumChoose(size, maxLengthOfSubsets)); + + // Extend existing Pascal Triangle by a table for the k's 2..maxLengthOfSubset + // for all n up to |S| (if needed, otherwise long[0]). + final long[] ppt = Combinatorics.pascalTableUpTo(size, maxLengthOfSubsets); + + final ValueVec vec = new ValueVec(numOfSubsetsRequested); + for (int rank = 0; rank < kss.length; rank++) { + final BigDecimal divide = BigDecimal.valueOf(kss[rank]).divide(new BigDecimal(sum), 32, + BigDecimal.ROUND_HALF_DOWN); + // Small bias towards smaller/shorter k-Subsets because 0 gets rounded up to 1. + final long n = divide.multiply(BigDecimal.valueOf(numOfSubsetsRequested)).max(BigDecimal.ONE).toBigInteger() + .longValueExact(); + + // The last one (kSubsetSizes.length - 1) is generates the outstanding + // number of subsets (will be close to its calculated n anyway). + final RandomUnrank unrank = new RandomUnrank(rank, + rank == kss.length - 1 ? numOfSubsetsRequested - vec.size() : n, ppt, elems, maxLengthOfSubsets, + EnumerableValue.getRandom()); + + Value subset; + while ((subset = unrank.randomSubset()) != null && vec.size() < numOfSubsetsRequested) { + vec.addElement(subset); + } + } + assert vec.size() == numOfSubsetsRequested; + return new SetEnumValue(vec, false); + } + + public class Unrank { + + private final TreeMap<Long, Integer> sums = new TreeMap<>(); + private final long[] partialPascalTable; + private final int maxK; + + private final ValueVec elems; + + private final int k; // rank of k-Subset + + public Unrank(final int k, final long n, final long[] ppt, final ValueVec elems, final int maxK) { + this.k = k; + this.elems = elems; + this.partialPascalTable = ppt; + this.maxK = maxK - 1; + + // Cache the sum of all binomials lt n for 0..elems.size choose k. + int choice = Math.max(k - 1, 0); + sums.put(-1L, choice); // As base for idx = 0 (see lowerEntry below); + long bin = 0L; + while ((bin = memoizedBinomial(choice, k)) < n) { + sums.put(bin, ++choice); + } + } + + public Value subsetAt(long idx) { + // More subsets in this kSubset available. + final ValueVec vec = new ValueVec(k); + + int y = k, choice = sums.lowerEntry(idx).getValue(); + for (; choice >= 0 && k > 0; choice--) { + final long c = memoizedBinomial(choice, y); + if (c <= idx) { + idx -= c; + y--; + vec.addElement(this.elems.elementAt(choice)); + } + } + return new SetEnumValue(vec, false); + } + + protected long memoizedBinomial(final int n, final int k) { + if (k == 0 || k == n) { + return (long) 1; + } else if (k == 1 || k == n - 1) { + return (long) n; + } else if (n == 0 || k > n) { + // Cannot choose from zero elements or more elements than present. + return 0; + } + final int pti = Combinatorics.choosePairToInt(n, k); + if (pti < Combinatorics.CHOOSETABLE.length) { + return Combinatorics.choose(n, k); + } + return partialPascalTable[(n - Combinatorics.MAXCHOOSENUM - 1) * maxK + k - 2]; + } + } + + private class RandomUnrank extends Unrank { + + // Primes taken from: https://primes.utm.edu/lists/2small/0bit.html + // TODO: 9223372036854775783L; // 2^63 - 25 +// private static final long x = 549755813881L; // 2^39 - 7 + private static final long x = 34359738337L; // 2^35 - 31 + + private final long n; + private final long a; + private long i; + + public RandomUnrank(final int k, final long n, final long[] ppt, final ValueVec elems, final int maxK, + final Random random) { + super(k, n, ppt, elems, maxK); + this.n = n; + this.a = Math.abs(random.nextLong()) % n; + } + + public Value randomSubset() { + if (i < n) { + return subsetAt(((x * i++) + a) % n); + } + return null; + } + } + + public EnumerableValue getRandomSetOfSubsets(final int numOfPicks, final double probability) { + final CoinTossingSubsetEnumerator enumerator = new CoinTossingSubsetEnumerator(numOfPicks, probability); + + // Using a set here instead of ValueVec preserves the set invariant (no + // duplicates). The alternative - a ValueVec which gets sorted to remove + // duplicates after the while loops is slower. + final int estimated = (int) (numOfPicks * probability); + final Collection<Value> sets = new HashSet<>(estimated); + Value val; + while ((val = enumerator.nextElement()) != null) { + sets.add(val); + } + + return new SetEnumValue(new ValueVec(sets), false); + } + + /** + * @see SubsetValue#kElements(int) + */ + public final long numberOfKElements(final int k) { + final int size = this.set.size(); + if (k < 0 || size < k || size > 62) { + throw new IllegalArgumentException(String.format("k=%s and n=%s", k, size)); + } + if (k == 0 || k == size) { + return 1; + } + return Combinatorics.choose(size, k); + } + + /** + * [S]^k (sometimes denoted S^[k]) == { t \in SUBSET S : Cardinality(t) = k } + * @param k + * @return + */ + public final ValueEnumeration kElements(final int k) { + if (k < 0 || this.set.size() < k) { + throw new IllegalArgumentException(); + } + if (k == 0) { + return new ValueEnumeration() { + private boolean done = false; + + @Override + public void reset() { + done = false; + } + + @Override + public Value nextElement() { + if (done) { return null; } + done = true; + return new SetEnumValue(); + } + }; + } + + return new KElementEnumerator(k); + } + + public final class KElementEnumerator implements ValueEnumeration { + private final ValueVec elems; + private final int numKSubsetElems; + private final int k; + + private int index; + private int cnt; + + public KElementEnumerator(final int k) { + this.k = k; + + this.numKSubsetElems = (int) numberOfKElements(k); + if (numKSubsetElems < 0) { + throw new IllegalArgumentException("Subset too large."); + } + + final SetEnumValue convert = SetEnumValue.convert(set); + convert.normalize(); + elems = convert.elems; + + reset(); + } + + @Override + public void reset() { + index = (1 << k) - 1; + cnt = 0; + } + + // see "Compute the lexicographically next bit permutation" at + // http://graphics.stanford.edu/~seander/bithacks.html#NextBitPermutation + private int nextIndex() { + final int oldIdx = this.index; + + final int t = (index | (index - 1)) + 1; + this.index = t | ((((t & -t) / (index & -index)) >> 1) - 1); + + return oldIdx; + } + + @Override + public Value nextElement() { + if (cnt >= numKSubsetElems) { + return null; + } + cnt++; + + int bits = nextIndex(); + final ValueVec vals = new ValueVec(Integer.bitCount(bits)); + for (int i = 0; bits > 0 && i < elems.size(); i++) { + // Treat bits as a bitset and add the element of elem at current + // position i if the LSB of bits happens to be set. + if ((bits & 0x1) > 0) { + vals.addElement(elems.elementAt(i)); + } + // ...right-shift zero-fill bits by one afterwards. + bits = bits >>> 1; + } + return new SetEnumValue(vals, false); + } + + public KElementEnumerator sort() { + this.elems.sort(true); + return this; + } + } public final ValueEnumeration elements() { try { @@ -272,10 +548,11 @@ public class SubsetValue extends EnumerableValue implements Enumerable { } final class Enumerator implements ValueEnumeration { - ValueVec elems; + private ValueVec elems; private BitSet descriptor; public Enumerator() { + //WARNING! Mutates the outer instance!? set = SetEnumValue.convert(set); set.normalize(); this.elems = ((SetEnumValue)set).elems; @@ -318,4 +595,105 @@ public class SubsetValue extends EnumerableValue implements Enumerable { } + @Override + public ValueEnumeration elements(final int k) { + final int sz = this.set.size(); + + // Use probabilistic CTSE if size of input set or k are too large. CoinTossing + // can yield duplicates though, thus k means number of picks. + if (sz >= 31 || k > (1 << 16)) { + return new CoinTossingSubsetEnumerator(k); + } + return new SubsetEnumerator(k); + } + + class SubsetEnumerator extends EnumerableValue.SubsetEnumerator { + + private final ValueVec elems; + + SubsetEnumerator(final int k) { + super(k, 1 << set.size()); + final SetEnumValue convert = SetEnumValue.convert(set); + convert.normalize(); + this.elems = convert.elems; + } + + @Override + public Value nextElement() { + if (!hasNext()) { + return null; + } + int bits = nextIndex(); + final ValueVec vals = new ValueVec(Integer.bitCount(bits)); + for (int i = 0; bits > 0 && i < this.elems.size(); i++) { + // Treat bits as a bitset and add the element of this.elem at current + // position i if the LSB of bits happens to be set. + if ((bits & 0x1) > 0) { + vals.addElement(this.elems.elementAt(i)); + } + // ...right-shift zero-fill bits by one afterwards. + bits = bits >>> 1; + } + return new SetEnumValue(vals, false); + } + } + + /* + * LL: I realized that efficiently choosing a random set of k elements in "SUBSET S" + * is simple. Just compute S and randomly choose k elements SS of SUBSET S by + * including each element of S in SS with probability 1/2. This looks to me as + * if it's completely equivalent to enumerating all the elements of SUBSET S and + * choosing a random subset of those elements--except that if we want to choose + * exactly k elements, then we'll have to throw away duplicates. + */ + class CoinTossingSubsetEnumerator implements ValueEnumeration { + + private final ValueVec elems; + private final double probability; + private final int numOfPicks; + private int i; + + public CoinTossingSubsetEnumerator(final int numOfPicks) { + this(numOfPicks, .5d); + } + + public CoinTossingSubsetEnumerator(final int numOfPicks, final double probability) { + this.i = 0; + this.numOfPicks = numOfPicks; + this.probability = probability; + + final SetEnumValue convert = SetEnumValue.convert(set); + convert.normalize(); + this.elems = convert.elems; + } + + // Repeated invocation can yield duplicate elements due to the probabilistic + // nature of CoinTossingSubsetEnumerator. + public Value nextElement() { + if (!hasNext()) { + return null; + } + final ValueVec vals = new ValueVec(elems.size()); + for (int i = 0; i < elems.size(); i++) { + if (EnumerableValue.getRandom().nextDouble() < probability) { + vals.addElement(elems.elementAt(i)); + } + } + this.i++; + return new SetEnumValue(vals, false); + } + + private boolean hasNext() { + return this.i < this.numOfPicks; + } + + @Override + public void reset() { + this.i = 0; + } + + int getNumOfPicks() { + return numOfPicks; + } + } } diff --git a/tlatools/src/tlc2/value/TupleValue.java b/tlatools/src/tlc2/value/TupleValue.java index 9424f81c0f74e96b84f706b836ad005f497ea56b..7137f184247094f45d1cabc5e5737b75290d1448 100644 --- a/tlatools/src/tlc2/value/TupleValue.java +++ b/tlatools/src/tlc2/value/TupleValue.java @@ -7,7 +7,6 @@ package tlc2.value; import tla2sany.semantic.SymbolNode; -import tlc2.tool.ModelChecker; import tlc2.tool.FingerprintException; import tlc2.output.EC; import tlc2.output.MP; @@ -17,7 +16,7 @@ import tlc2.util.FP64; import util.Assert; public class TupleValue extends Value implements Applicable { - public Value[] elems; // the elements of this tuple. + public final Value[] elems; // the elements of this tuple. /* Constructor */ public TupleValue(Value[] elems) { this.elems = elems; } @@ -267,7 +266,7 @@ public class TupleValue extends Value implements Applicable { /* The normalization of the value. */ public final boolean isNormalized() { return true; } - public final void normalize() { /*nop*/ } + public final Value normalize() { /*nop*/return this; } public final boolean isDefined() { try { diff --git a/tlatools/src/tlc2/value/UndefValue.java b/tlatools/src/tlc2/value/UndefValue.java index 4947a6f9ab525b7c38df7c35d738b8f4a96e068a..01fbbc9f837c9dd431e706b071850436ffa5be08 100644 --- a/tlatools/src/tlc2/value/UndefValue.java +++ b/tlatools/src/tlc2/value/UndefValue.java @@ -6,7 +6,6 @@ package tlc2.value; -import tlc2.tool.ModelChecker; import tlc2.tool.FingerprintException; import util.Assert; @@ -102,7 +101,7 @@ public class UndefValue extends Value { public final boolean isNormalized() { return true; } - public final void normalize() { /*nop*/ } + public final Value normalize() { /*nop*/return this; } public final boolean isDefined() { return false; } diff --git a/tlatools/src/tlc2/value/UnionValue.java b/tlatools/src/tlc2/value/UnionValue.java index b203236454d5b48a3ee5517887a4ddd38932d07e..534206c9fda80eb252b251f55a91c1e307e9d104 100644 --- a/tlatools/src/tlc2/value/UnionValue.java +++ b/tlatools/src/tlc2/value/UnionValue.java @@ -6,7 +6,6 @@ package tlc2.value; -import tlc2.tool.ModelChecker; import tlc2.tool.FingerprintException; import util.Assert; @@ -132,11 +131,12 @@ public class UnionValue extends EnumerableValue implements Enumerable { } } - public final void normalize() { + public final Value normalize() { try { if (this.realSet != null && this.realSet != DummyEnum) { this.realSet.normalize(); } + return this; } catch (RuntimeException | OutOfMemoryError e) { if (hasSource()) { throw FingerprintException.getNewHead(this, e); } diff --git a/tlatools/src/tlc2/value/UserValue.java b/tlatools/src/tlc2/value/UserValue.java index 4e9215341462e4de55c1f2834f2c50e3a9e558e6..2c9416413700a70c9449819485367286234445f1 100644 --- a/tlatools/src/tlc2/value/UserValue.java +++ b/tlatools/src/tlc2/value/UserValue.java @@ -6,7 +6,6 @@ package tlc2.value; -import tlc2.tool.ModelChecker; import tlc2.tool.FingerprintException; import util.Assert; @@ -106,7 +105,7 @@ public class UserValue extends Value { /* Nothing to normalize. */ public final boolean isNormalized() { return true; } - public final void normalize() { /*SKIP*/ } + public final Value normalize() { /*SKIP*/return this; } public final boolean isDefined() { return true; } diff --git a/tlatools/src/tlc2/value/Value.java b/tlatools/src/tlc2/value/Value.java index 1d69dfa0105e2885b5fe3378682239432a602920..354211f61216cee3ef2991e84b07ff08aa325298 100644 --- a/tlatools/src/tlc2/value/Value.java +++ b/tlatools/src/tlc2/value/Value.java @@ -9,10 +9,9 @@ package tlc2.value; import java.io.Serializable; import tla2sany.semantic.SemanticNode; -import tlc2.tool.ModelChecker; -import tlc2.tool.FingerprintException; import tlc2.TLCGlobals; import tlc2.pprint.PrettyPrint; +import tlc2.tool.FingerprintException; import tlc2.util.FP64; import util.Assert; @@ -73,7 +72,7 @@ public abstract class Value implements ValueConstants, Serializable { * the value. It is essential for equality comparison. */ public abstract boolean isNormalized(); - public abstract void normalize(); + public abstract Value normalize(); public final boolean isEmpty() { try { @@ -450,4 +449,10 @@ public abstract class Value implements ValueConstants, Serializable { public static String ppr(String s) { return PrettyPrint.mypp(s, 80) ; } + public static String ppr(Value v) { + if (v == null) { + return "null"; + } + return PrettyPrint.mypp(v.toString(), 80) ; + } } diff --git a/tlatools/src/tlc2/value/ValueEnumeration.java b/tlatools/src/tlc2/value/ValueEnumeration.java index efd6dc27e05ccb6f6d3a8df7364553ca69a97bb2..b213f0ecc6b5fe0f1fe5a55d066833a5b4e1f336 100644 --- a/tlatools/src/tlc2/value/ValueEnumeration.java +++ b/tlatools/src/tlc2/value/ValueEnumeration.java @@ -5,6 +5,10 @@ package tlc2.value; +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; + public interface ValueEnumeration { /* Reset allows repeated use of this enumerator. */ public void reset(); @@ -12,4 +16,19 @@ public interface ValueEnumeration { /* Return the next element if there is one. Otherwise return null. */ public Value nextElement(); + default List<Value> all() { + final List<Value> values = new ArrayList<Value>(); + Value elem; + while ((elem = nextElement()) != null) { + values.add(elem); + } + return values; + } + + default void forEach(final Consumer<? super Value> action) { + Value elem; + while ((elem = nextElement()) != null) { + action.accept(elem); + } + } } diff --git a/tlatools/src/tlc2/value/ValueInputStream.java b/tlatools/src/tlc2/value/ValueInputStream.java index 40f00fb926ce10ce7c547e13e607cd1d28e9f844..7a8c91a8f752da2f23a6e18565448b1b0b22e020 100644 --- a/tlatools/src/tlc2/value/ValueInputStream.java +++ b/tlatools/src/tlc2/value/ValueInputStream.java @@ -149,6 +149,10 @@ public final class ValueInputStream implements ValueConstants { } } } + + public final int readShort() throws IOException { + return this.dis.readShort(); + } public final int readInt() throws IOException { return this.dis.readInt(); @@ -169,6 +173,12 @@ public final class ValueInputStream implements ValueConstants { return -res; } + public final short readShortNat() throws IOException { + short res = this.dis.readByte(); + if (res >= 0) return res; + return (short) -((res << 8) | (this.dis.readByte() & 0xFF)); + } + public final long readLongNat() throws IOException { long res = this.dis.readInt(); if (res >= 0) return res; diff --git a/tlatools/src/tlc2/value/ValueOutputStream.java b/tlatools/src/tlc2/value/ValueOutputStream.java index 0b2bdbaa9378f25c2c58004cc29559d96c5113b5..030dcce164627d36c22b192e150a3a47e918d38f 100644 --- a/tlatools/src/tlc2/value/ValueOutputStream.java +++ b/tlatools/src/tlc2/value/ValueOutputStream.java @@ -251,6 +251,10 @@ public final class ValueOutputStream implements ValueConstants { } } + public final void writeShort(short x) throws IOException { + this.dos.writeShort(x); + } + public final void writeInt(int x) throws IOException { this.dos.writeInt(x); } @@ -262,6 +266,16 @@ public final class ValueOutputStream implements ValueConstants { public final void close() throws IOException { this.dos.close(); } + + /* Precondition: x is a non-negative short. */ + public final void writeShortNat(short x) throws IOException { + if (x > 0x7f) { + this.dos.writeShort((short) -x); + } + else { + this.dos.writeByte((byte)x); + } + } /* Precondition: x is a non-negative int. */ public final void writeNat(int x) throws IOException { diff --git a/tlatools/src/tlc2/value/ValueVec.java b/tlatools/src/tlc2/value/ValueVec.java index e2a0dab2889d3929e31a4811453a9720b5ba195d..a5446377b5d19fdf0ab0064af2dc6b877ae124ac 100644 --- a/tlatools/src/tlc2/value/ValueVec.java +++ b/tlatools/src/tlc2/value/ValueVec.java @@ -6,6 +6,7 @@ package tlc2.value; import java.io.Serializable; +import java.util.Collection; import tlc2.TLCGlobals; import util.WrongInvocationException; @@ -32,7 +33,14 @@ public class ValueVec implements Cloneable, Serializable { this.elementData = elems; this.elementCount = elems.length; } - + + public ValueVec(Collection<Value> elems) { + this(elems.size()); + for (Value value : elems) { + addElement(value); + } + } + public final void addElement(Value val) { if (this.elementCount == this.elementData.length) { ensureCapacity(this.elementCount+1); @@ -160,7 +168,7 @@ public class ValueVec implements Cloneable, Serializable { return false; } - public final void sort(boolean noDup) { + public final ValueVec sort(boolean noDup) { int newCount = (this.elementCount == 0) ? 0 : 1; for (int i = 1; i < this.elementCount; i++) { Value elem = this.elementData[i]; @@ -186,6 +194,7 @@ public class ValueVec implements Cloneable, Serializable { } } this.elementCount = newCount; + return this; } public final String toString() { @@ -203,4 +212,10 @@ public class ValueVec implements Cloneable, Serializable { return sb.toString(); } + public Value[] toArray() { + final Value[] copy = new Value[elementCount]; + System.arraycopy(elementData, 0, copy, 0, elementCount); + return copy; + } + } diff --git a/tlatools/src/util/FileUtil.java b/tlatools/src/util/FileUtil.java index a4669b154a528fafa9ecdbb9d84b7fc9e8eeb3f5..c5dfa1164af91cd24b4889c7d65777e1c1367dfb 100644 --- a/tlatools/src/util/FileUtil.java +++ b/tlatools/src/util/FileUtil.java @@ -198,7 +198,7 @@ public class FileUtil } /** - * Atomically replaced the file targetName with the file sourceName. + * Atomically replaces the file targetName with the file sourceName. * @param sourceName * @param targetName * @throws IOException @@ -215,6 +215,11 @@ public class FileUtil * */ public static String makeMetaDir(String specDir, String fromChkpt) + { + return makeMetaDir(new Date(), specDir, fromChkpt); + } + + public static String makeMetaDir(Date date, String specDir, String fromChkpt) { if (fromChkpt != null) { @@ -233,7 +238,7 @@ public class FileUtil } else { sdf = new SimpleDateFormat("yy-MM-dd-HH-mm-ss"); } - metadir += sdf.format(new Date()); + metadir += sdf.format(date); File filedir = new File(metadir); // ensure the non-existence @@ -349,27 +354,18 @@ public class FileUtil * retrieves a new buffered file output stream * @param name * @return + * @throws FileNotFoundException */ - public static OutputStream newBFOS(String name) + public static OutputStream newBFOS(String name) throws FileNotFoundException { - File file = new File(name); - - // LL removed file.exists() test on 10 Nov 2012 because - // it causes an error when TLC called with -dump option - // for a file that doesn't already exist. Also changed - // the error message to something more helpful. - if (file != null /* && file.exists() */) + try { - try - { - FileOutputStream fos = new FileOutputStream(file); - return fos; - } catch (FileNotFoundException e) - { - ToolIO.out.println("Error: Unable to write to file " + name); - } + return new FileOutputStream(new File(name)); + } catch (FileNotFoundException e) + { + ToolIO.out.println("Error: Unable to write to file " + name); + throw e; } - return null; } public static BufferedDataInputStream newBdFIS(boolean useGZIP, File file) throws IOException diff --git a/tlatools/src/util/MailSender.java b/tlatools/src/util/MailSender.java index df6ea98cde3567ebb49e7bbe73cb62e7b21513c5..be5f6bb946ff96bce2df829f61941601d9809f68 100644 --- a/tlatools/src/util/MailSender.java +++ b/tlatools/src/util/MailSender.java @@ -136,6 +136,7 @@ public class MailSender { private static void throttleRetry(final String msg, long minutes) { try { System.err.println(msg); + System.out.println(msg); Thread.sleep(minutes * 60L * 1000L); } catch (InterruptedException e1) { e1.printStackTrace(); @@ -220,7 +221,7 @@ public class MailSender { this.out = new File(tmpdir + File.separator + "MC.out"); ToolIO.out = new LogPrintStream(out); this.err = new File(tmpdir + File.separator + "MC.err"); - ToolIO.err = new LogPrintStream(err); + ToolIO.err = new ErrLogPrintStream(err); } } @@ -308,4 +309,18 @@ public class MailSender { super.println(str); } } + + private static class ErrLogPrintStream extends PrintStream { + public ErrLogPrintStream(File file) throws FileNotFoundException { + super(new FileOutputStream(file)); + } + + /* (non-Javadoc) + * @see java.io.PrintStream#println(java.lang.String) + */ + public void println(String str) { + System.err.println(str); + super.println(str); + } + } } diff --git a/tlatools/src/util/ToolIO.java b/tlatools/src/util/ToolIO.java index 21ab9397b2a172689fe5c2993e9e84194ae3a4c3..5738bcdd9b3734456da29a9c6a44b45808abd0c5 100644 --- a/tlatools/src/util/ToolIO.java +++ b/tlatools/src/util/ToolIO.java @@ -5,6 +5,7 @@ import java.io.PrintStream; import java.util.Iterator; import java.util.LinkedList; import java.util.List; +import java.util.Locale; import tla2sany.semantic.SemanticNode; @@ -87,7 +88,7 @@ public class ToolIO * List of semantic nodes which are used by tools * @see ToolIO#registerSemanticNode() */ - private static List semanticNodes = new LinkedList(); + private static List<SemanticNode> semanticNodes = new LinkedList<>(); /** * The current sequence of messages is messages[0] ... @@ -253,10 +254,10 @@ public class ToolIO */ public static void cleanToolObjects(int toolId) { - Iterator iter = semanticNodes.iterator(); + Iterator<SemanticNode> iter = semanticNodes.iterator(); while(iter.hasNext()) { - SemanticNode node = (SemanticNode) iter.next(); + SemanticNode node = iter.next(); node.setToolObject(toolId, null); } } @@ -266,7 +267,7 @@ public class ToolIO */ public static void unregisterSemanticNodes() { - semanticNodes = new LinkedList(); + semanticNodes = new LinkedList<SemanticNode>(); } } // class ToolIO @@ -282,8 +283,28 @@ class ToolPrintStream extends PrintStream ToolIO.out = this; ToolIO.err = this; } + + /* (non-Javadoc) + * @see java.io.PrintStream#printf(java.lang.String, java.lang.Object[]) + */ + @Override + public PrintStream printf(String format, Object... args) { + // See special logic in println. If super.printf(...) gets used, Toolbox + // functionality breaks. + throw new UnsupportedOperationException("use println instead"); + } + + /* (non-Javadoc) + * @see java.io.PrintStream#printf(java.util.Locale, java.lang.String, java.lang.Object[]) + */ + @Override + public PrintStream printf(Locale l, String format, Object... args) { + // See special logic in println. If super.printf(...) gets used, Toolbox + // functionality breaks. + throw new UnsupportedOperationException("use println instead"); + } - /** + /** * Prints a string in to the ToolIO buffer in a separate line * @param str String to be printed */ diff --git a/tlatools/test-benchmark/ModuleOverwrites.java b/tlatools/test-benchmark/ModuleOverwrites.java new file mode 100644 index 0000000000000000000000000000000000000000..293322daa0e78dd5f4d62fa0750f8305209ccbc1 --- /dev/null +++ b/tlatools/test-benchmark/ModuleOverwrites.java @@ -0,0 +1,36 @@ + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +import tlc2.value.BoolValue; +import tlc2.value.FcnRcdValue; +import tlc2.value.IntValue; +import tlc2.value.Value; + +public class ModuleOverwrites { + + public static Value noDupesOverwrite(final FcnRcdValue frv, final IntValue exclude) { + // LET sub == SelectSeq(t, LAMBDA e: e # emp) + // IN ... + final List<Value> filtered = Arrays.asList(frv.values).stream().filter(e -> e != exclude).collect(Collectors.toList()); + + // IF Len(sub) < 2 THEN TRUE ... + if (filtered.size() < 2) { + return BoolValue.ValTrue; + } + + // ~n^2: + // \A i \in 1..(Len(sub) - 1): + // \A j \in (i+1)..Len(sub): + // abs(sub[i]) # abs(sub[j]) + for (int i = 0; i < filtered.size() - 1; i++) { + for (int j = i + 1; j < filtered.size(); j++) { + if (filtered.get(i) == filtered.get(j)) { + return BoolValue.ValFalse; + } + } + } + return BoolValue.ValTrue; + } +} diff --git a/tlatools/test-benchmark/heapstats.jfc b/tlatools/test-benchmark/heapstats.jfc new file mode 100644 index 0000000000000000000000000000000000000000..5700f60b04b99ac85c9bc2f340746bc6f5bb91de --- /dev/null +++ b/tlatools/test-benchmark/heapstats.jfc @@ -0,0 +1,550 @@ +<?xml version="1.0" encoding="UTF-8"?> +<configuration version="1.0" name="heapstats" description="" provider="Oracle"> + + <producer uri="http://www.oracle.com/hotspot/jvm/" label="Oracle JDK"> + + <control> + + <selection name="gc-level" default="all" label="Garbage Collector"> + <option label="Off" name="off">off</option> + <option label="Normal" name="detailed">normal</option> + <option label="All" name="all">all</option> + </selection> + + <condition name="gc-enabled-normal" true="true" false="false"> + <or> + <test name="gc-level" operator="equal" value="normal"/> + <test name="gc-level" operator="equal" value="all"/> + </or> + </condition> + + <condition name="gc-enabled-all" true="true" false="false"> + <test name="gc-level" operator="equal" value="all"/> + </condition> + + <selection name="compiler-level" default="normal" label="Compiler"> + <option label="Off" name="off">off</option> + <option label="Normal" name="normal">normal</option> + <option label="Detailed" name="detailed">detailed</option> + <option label="All" name="all">all</option> + </selection> + + <condition name="compiler-enabled" true="false" false="true"> + <test name="compiler-level" operator="equal" value="off"/> + </condition> + + <condition name="compiler-enabled-failure" true="true" false="false"> + <or> + <test name="compiler-level" operator="equal" value="detailed"/> + <test name="compiler-level" operator="equal" value="all"/> + </or> + </condition> + + <condition name="compiler-sweeper-threshold" true="0 ms" false="100 ms"> + <test name="compiler-level" operator="equal" value="all"/> + </condition> + + <condition name="compiler-compilation-threshold" true="1000 ms"> + <test name="compiler-level" operator="equal" value="normal"/> + </condition> + + <condition name="compiler-compilation-threshold" true="100 ms"> + <test name="compiler-level" operator="equal" value="detailed"/> + </condition> + + <condition name="compiler-compilation-threshold" true="0 ms"> + <test name="compiler-level" operator="equal" value="all"/> + </condition> + + <condition name="compiler-phase-threshold" true="60 s"> + <test name="compiler-level" operator="equal" value="normal"/> + </condition> + + <condition name="compiler-phase-threshold" true="10 s"> + <test name="compiler-level" operator="equal" value="detailed"/> + </condition> + + <condition name="compiler-phase-threshold" true="0 s"> + <test name="compiler-level" operator="equal" value="all"/> + </condition> + + <selection name="method-sampling-interval" default="maximum" label="Method Sampling"> + <option label="Off" name="off">999 d</option> + <option label="Normal" name="normal">20 ms</option> + <option label="Maximum" name="maximum">10 ms</option> + </selection> + + <condition name="method-sampling-enabled" true="false" false="true"> + <test name="method-sampling-interval" operator="equal" value="999 d"/> + </condition> + + <selection name="thread-dump-interval" default="everySecond" label="Thread Dump"> + <option label="Off" name="off">999 d</option> + <option label="At least Once" name="normal">everyChunk</option> + <option label="Every 60 s" name="everyMinute">60 s</option> + <option label="Every 10 s" name="everyTenSecond">10 s</option> + <option label="Every 1 s" name="everySecond">1 s</option> + </selection> + + <condition name="thread-dump-enabled" true="false" false="true"> + <test name="thread-dump-interval" operator="equal" value="999 d"/> + </condition> + + <selection name="exception-level" default="errors" label="Exceptions"> + <option label="Off" name="off">off</option> + <option label="Errors Only" name="errors">errors</option> + <option label="All Exceptions, including Errors" name="all">all</option> + </selection> + + <condition name="enable-errors" true="true" false="false"> + <or> + <test name="exception-level" operator="equal" value="errors"/> + <test name="exception-level" operator="equal" value="all"/> + </or> + </condition> + + <condition name="enable-exceptions" true="true" false="false"> + <test name="exception-level" operator="equal" value="all"/> + </condition> + + <text name="synchronization-threshold" label="Synchronization Threshold" contentType="timespan" minimum="0 s">10 ms</text> + + <text name="file-io-threshold" label="File I/O Threshold" contentType="timespan" minimum="0 s">10 ms</text> + + <text name="socket-io-threshold" label="Socket I/O Threshold" contentType="timespan" minimum="0 s">10 ms</text> + + <flag name="heap-statistics-enabled" label="Heap Statistics">true</flag> + + <flag name="class-loading-enabled" label="Class Loading">false</flag> + + <flag name="allocation-profiling-enabled" label="Allocation Profiling">true</flag> + + </control> + + <event path="java/statistics/thread_allocation"> + <setting name="enabled">true</setting> + <setting name="period">everyChunk</setting> + </event> + + <event path="java/statistics/class_loading"> + <setting name="enabled">true</setting> + <setting name="period">1000 ms</setting> + </event> + + <event path="java/statistics/threads"> + <setting name="enabled">true</setting> + <setting name="period">1000 ms</setting> + </event> + + <event path="java/thread_start"> + <setting name="enabled">true</setting> + </event> + + <event path="java/thread_end"> + <setting name="enabled">true</setting> + </event> + + <event path="java/thread_sleep"> + <setting name="enabled">true</setting> + <setting name="stackTrace">true</setting> + <setting name="threshold" control="synchronization-threshold">10 ms</setting> + </event> + + <event path="java/thread_park"> + <setting name="enabled">true</setting> + <setting name="stackTrace">true</setting> + <setting name="threshold" control="synchronization-threshold">10 ms</setting> + </event> + + <event path="java/monitor_enter"> + <setting name="enabled">true</setting> + <setting name="stackTrace">true</setting> + <setting name="threshold" control="synchronization-threshold">10 ms</setting> + </event> + + <event path="java/monitor_wait"> + <setting name="enabled">true</setting> + <setting name="stackTrace">true</setting> + <setting name="threshold" control="synchronization-threshold">10 ms</setting> + </event> + + <event path="vm/class/load"> + <setting name="enabled" control="class-loading-enabled">false</setting> + <setting name="stackTrace">true</setting> + <setting name="threshold">0 ms</setting> + </event> + + <event path="vm/class/unload"> + <setting name="enabled" control="class-loading-enabled">false</setting> + </event> + + <event path="vm/info"> + <setting name="enabled">true</setting> + <setting name="period">everyChunk</setting> + </event> + + <event path="vm/initial_system_property"> + <setting name="enabled">true</setting> + <setting name="period">everyChunk</setting> + </event> + + <event path="vm/prof/execution_sample"> + <setting name="enabled" control="method-sampling-enabled">true</setting> + <setting name="period" control="method-sampling-interval">10 ms</setting> + </event> + + <event path="vm/prof/execution_sampling_info"> + <setting name="enabled">false</setting> + <setting name="threshold">1 ms</setting> + </event> + + <event path="vm/runtime/execute_vm_operation"> + <setting name="enabled">true</setting> + <setting name="threshold">10 ms</setting> + </event> + + <event path="vm/runtime/thread_dump"> + <setting name="enabled" control="thread-dump-enabled">true</setting> + <setting name="period" control="thread-dump-interval">1 s</setting> + </event> + + <event path="vm/flag/long"> + <setting name="enabled">true</setting> + <setting name="period">everyChunk</setting> + </event> + + <event path="vm/flag/ulong"> + <setting name="enabled">true</setting> + <setting name="period">everyChunk</setting> + </event> + + <event path="vm/flag/double"> + <setting name="enabled">true</setting> + <setting name="period">everyChunk</setting> + </event> + + <event path="vm/flag/boolean"> + <setting name="enabled">true</setting> + <setting name="period">everyChunk</setting> + </event> + + <event path="vm/flag/string"> + <setting name="enabled">true</setting> + <setting name="period">everyChunk</setting> + </event> + + <event path="vm/flag/long_changed"> + <setting name="enabled">true</setting> + </event> + + <event path="vm/flag/ulong_changed"> + <setting name="enabled">true</setting> + </event> + + <event path="vm/flag/double_changed"> + <setting name="enabled">true</setting> + </event> + + <event path="vm/flag/boolean_changed"> + <setting name="enabled">true</setting> + </event> + + <event path="vm/flag/string_changed"> + <setting name="enabled">true</setting> + </event> + + <event path="vm/gc/detailed/object_count"> + <setting name="enabled" control="heap-statistics-enabled">true</setting> + <setting name="period">everyChunk</setting> + </event> + + <event path="vm/gc/configuration/gc"> + <setting name="enabled" control="gc-enabled-normal">true</setting> + <setting name="period">everyChunk</setting> + </event> + + <event path="vm/gc/configuration/heap"> + <setting name="enabled" control="gc-enabled-normal">true</setting> + <setting name="period">everyChunk</setting> + </event> + + <event path="vm/gc/configuration/young_generation"> + <setting name="enabled" control="gc-enabled-normal">true</setting> + <setting name="period">everyChunk</setting> + </event> + + <event path="vm/gc/configuration/tlab"> + <setting name="enabled" control="gc-enabled-normal">true</setting> + <setting name="period">everyChunk</setting> + </event> + + <event path="vm/gc/configuration/survivor"> + <setting name="enabled" control="gc-enabled-normal">true</setting> + <setting name="period">everyChunk</setting> + </event> + + <event path="vm/gc/detailed/object_count_after_gc"> + <setting name="enabled">false</setting> + </event> + + <event path="vm/gc/heap/summary"> + <setting name="enabled" control="gc-enabled-normal">true</setting> + </event> + + <event path="vm/gc/heap/ps_summary"> + <setting name="enabled" control="gc-enabled-normal">true</setting> + </event> + + <event path="vm/gc/heap/metaspace_summary"> + <setting name="enabled" control="gc-enabled-normal">true</setting> + </event> + + <event path="vm/gc/metaspace/gc_threshold"> + <setting name="enabled" control="gc-enabled-normal">true</setting> + </event> + + <event path="vm/gc/metaspace/allocation_failure"> + <setting name="enabled" control="gc-enabled-normal">true</setting> + <setting name="stackTrace">true</setting> + </event> + + <event path="vm/gc/metaspace/out_of_memory"> + <setting name="enabled" control="gc-enabled-normal">true</setting> + <setting name="stackTrace">true</setting> + </event> + + <event path="vm/gc/metaspace/chunk_free_list_summary"> + <setting name="enabled" control="gc-enabled-normal">true</setting> + </event> + + <event path="vm/gc/collector/garbage_collection"> + <setting name="enabled" control="gc-enabled-normal">true</setting> + <setting name="threshold">0 ms</setting> + </event> + + <event path="vm/gc/collector/parold_garbage_collection"> + <setting name="enabled" control="gc-enabled-normal">true</setting> + <setting name="threshold">0 ms</setting> + </event> + + <event path="vm/gc/collector/young_garbage_collection"> + <setting name="enabled" control="gc-enabled-normal">true</setting> + <setting name="threshold">0 ms</setting> + </event> + + <event path="vm/gc/collector/old_garbage_collection"> + <setting name="enabled" control="gc-enabled-normal">true</setting> + <setting name="threshold">0 ms</setting> + </event> + + <event path="vm/gc/collector/g1_garbage_collection"> + <setting name="enabled" control="gc-enabled-normal">true</setting> + <setting name="threshold">0 ms</setting> + </event> + + <event path="vm/gc/phases/pause"> + <setting name="enabled" control="gc-enabled-normal">true</setting> + <setting name="threshold">0 ms</setting> + </event> + + <event path="vm/gc/phases/pause_level_1"> + <setting name="enabled" control="gc-enabled-normal">true</setting> + <setting name="threshold">0 ms</setting> + </event> + + <event path="vm/gc/phases/pause_level_2"> + <setting name="enabled" control="gc-enabled-normal">true</setting> + <setting name="threshold">0 ms</setting> + </event> + + <event path="vm/gc/phases/pause_level_3"> + <setting name="enabled" control="gc-enabled-all">true</setting> + <setting name="threshold">0 ms</setting> + </event> + + <event path="vm/gc/reference/statistics"> + <setting name="enabled" control="gc-enabled-normal">true</setting> + </event> + + <event path="vm/gc/detailed/promotion_failed"> + <setting name="enabled" control="gc-enabled-normal">true</setting> + </event> + + <event path="vm/gc/detailed/evacuation_failed"> + <setting name="enabled" control="gc-enabled-normal">true</setting> + </event> + + <event path="vm/gc/detailed/evacuation_info"> + <setting name="enabled" control="gc-enabled-normal">true</setting> + </event> + + <event path="vm/gc/detailed/concurrent_mode_failure"> + <setting name="enabled" control="gc-enabled-normal">true</setting> + </event> + + <event path="vm/gc/detailed/allocation_requiring_gc"> + <setting name="enabled" control="gc-enabled-all">true</setting> + <setting name="stackTrace">true</setting> + </event> + + <event path="vm/compiler/config"> + <setting name="enabled" control="compiler-enabled">true</setting> + <setting name="period">everyChunk</setting> + </event> + + <event path="vm/compiler/stats"> + <setting name="enabled" control="compiler-enabled">true</setting> + <setting name="period">1000 ms</setting> + </event> + + <event path="vm/compiler/compilation"> + <setting name="enabled" control="compiler-enabled">true</setting> + <setting name="threshold" control="compiler-compilation-threshold">1000 ms</setting> + </event> + + <event path="vm/compiler/phase"> + <setting name="enabled" control="compiler-enabled">true</setting> + <setting name="threshold" control="compiler-phase-threshold">60 s</setting> + </event> + + <event path="vm/compiler/failure"> + <setting name="enabled" control="compiler-enabled-failure">false</setting> + </event> + + <event path="vm/code_sweeper/config"> + <setting name="enabled" control="compiler-enabled">true</setting> + <setting name="period">everyChunk</setting> + </event> + + <event path="vm/code_sweeper/stats"> + <setting name="enabled" control="compiler-enabled">true</setting> + <setting name="period">everyChunk</setting> + </event> + + <event path="vm/code_sweeper/sweep"> + <setting name="enabled" control="compiler-enabled">true</setting> + <setting name="threshold" control="compiler-sweeper-threshold">100 ms</setting> + </event> + + <event path="vm/code_cache/config"> + <setting name="enabled" control="compiler-enabled">true</setting> + <setting name="period">everyChunk</setting> + </event> + + <event path="vm/code_cache/stats"> + <setting name="enabled" control="compiler-enabled">true</setting> + <setting name="period">everyChunk</setting> + </event> + + <event path="vm/code_cache/full"> + <setting name="enabled" control="compiler-enabled">true</setting> + </event> + + <event path="os/information"> + <setting name="enabled">true</setting> + <setting name="period">everyChunk</setting> + </event> + + <event path="os/processor/cpu_information"> + <setting name="enabled">true</setting> + <setting name="period">everyChunk</setting> + </event> + + <event path="os/processor/context_switch_rate"> + <setting name="enabled" control="compiler-enabled">true</setting> + <setting name="period">10 s</setting> + </event> + + <event path="os/processor/cpu_load"> + <setting name="enabled">true</setting> + <setting name="period">1000 ms</setting> + </event> + + <event path="os/processor/cpu_tsc"> + <setting name="enabled">true</setting> + <setting name="period">everyChunk</setting> + </event> + + <event path="os/system_process"> + <setting name="enabled">true</setting> + <setting name="period">everyChunk</setting> + </event> + + <event path="os/initial_environment_variable"> + <setting name="enabled">true</setting> + <setting name="period">everyChunk</setting> + </event> + + <event path="os/memory/physical_memory"> + <setting name="enabled">true</setting> + <setting name="period">everyChunk</setting> + </event> + + <event path="java/object_alloc_in_new_TLAB"> + <setting name="enabled" control="allocation-profiling-enabled">true</setting> + <setting name="stackTrace">true</setting> + </event> + + <event path="java/object_alloc_outside_TLAB"> + <setting name="enabled" control="allocation-profiling-enabled">true</setting> + <setting name="stackTrace">true</setting> + </event> + + </producer> + + <producer uri="http://www.oracle.com/hotspot/jdk/" label="Oracle JDK"> + + <event path="java/file_read"> + <setting name="enabled">true</setting> + <setting name="stackTrace">true</setting> + <setting name="threshold" control="http://www.oracle.com/hotspot/jvm/file-io-threshold">10 ms</setting> + </event> + + <event path="java/file_write"> + <setting name="enabled">true</setting> + <setting name="stackTrace">true</setting> + <setting name="threshold" control="http://www.oracle.com/hotspot/jvm/file-io-threshold">10 ms</setting> + </event> + + <event path="java/socket_read"> + <setting name="enabled">true</setting> + <setting name="stackTrace">true</setting> + <setting name="threshold" control="http://www.oracle.com/hotspot/jvm/socket-io-threshold">10 ms</setting> + </event> + + <event path="java/socket_write"> + <setting name="enabled">true</setting> + <setting name="stackTrace">true</setting> + <setting name="threshold" control="http://www.oracle.com/hotspot/jvm/socket-io-threshold">10 ms</setting> + </event> + + <event path="java/exception_throw"> + <setting name="enabled" control="http://www.oracle.com/hotspot/jvm/enable-exceptions">false</setting> + <setting name="stackTrace">true</setting> + </event> + + <event path="java/error_throw"> + <setting name="enabled" control="http://www.oracle.com/hotspot/jvm/enable-errors">true</setting> + <setting name="stackTrace">true</setting> + </event> + + <event path="java/statistics/throwables"> + <setting name="enabled">true</setting> + <setting name="period">1000 ms</setting> + </event> + + </producer> + + <producer uri="http://www.oracle.com/hotspot/jfr-info/" label="Oracle JDK"> + + <event path="recordings/recording"> + <setting name="enabled">true</setting> + </event> + + <event path="recordings/recording_setting"> + <setting name="enabled">true</setting> + </event> + + </producer> + +</configuration> diff --git a/tlatools/test-benchmark/tlc2/tool/ModuleOverwrites-1531220029-80dc6de2b.json b/tlatools/test-benchmark/tlc2/tool/ModuleOverwrites-1531220029-80dc6de2b.json new file mode 100644 index 0000000000000000000000000000000000000000..9460d8682ea6f71625e3d2f6b61ea8256c72091a --- /dev/null +++ b/tlatools/test-benchmark/tlc2/tool/ModuleOverwrites-1531220029-80dc6de2b.json @@ -0,0 +1,169 @@ +[ + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.tool.ModuleOverwritesBenchmark.aNoModuleOverwrite", + "mode" : "thrpt", + "threads" : 1, + "forks" : 2, + "jvm" : "/usr/lib/jvm/java-9-oracle/bin/java", + "jvmArgs" : [ + "-Xms8192m", + "-Xmx8192m", + "-Dtlc2.tool.ModuleOverwritesBenchmark.base=/home/markus/src/TLA/tla/tlatools/test-model" + ], + "jdkVersion" : "9.0.4", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "9.0.4+11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 22425.663005813956, + "scoreError" : 5954.899764560438, + "scoreConfidence" : [ + 16470.763241253517, + 28380.562770374396 + ], + "scorePercentiles" : { + "0.0" : 21271.141489690363, + "50.0" : 22502.033943221788, + "90.0" : 23427.442647121898, + "95.0" : 23427.442647121898, + "99.0" : 23427.442647121898, + "99.9" : 23427.442647121898, + "99.99" : 23427.442647121898, + "99.999" : 23427.442647121898, + "99.9999" : 23427.442647121898, + "100.0" : 23427.442647121898 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 21271.141489690363, + 22186.209276647664 + ], + [ + 22817.85860979591, + 23427.442647121898 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.tool.ModuleOverwritesBenchmark.bModuleOverwrite", + "mode" : "thrpt", + "threads" : 1, + "forks" : 2, + "jvm" : "/usr/lib/jvm/java-9-oracle/bin/java", + "jvmArgs" : [ + "-Xms8192m", + "-Xmx8192m", + "-Dtlc2.tool.ModuleOverwritesBenchmark.base=/home/markus/src/TLA/tla/tlatools/test-model" + ], + "jdkVersion" : "9.0.4", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "9.0.4+11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 1142037.5355511934, + "scoreError" : 201257.82920798412, + "scoreConfidence" : [ + 940779.7063432093, + 1343295.3647591774 + ], + "scorePercentiles" : { + "0.0" : 1115758.2755510376, + "50.0" : 1135402.653804632, + "90.0" : 1181586.5590444724, + "95.0" : 1181586.5590444724, + "99.0" : 1181586.5590444724, + "99.9" : 1181586.5590444724, + "99.99" : 1181586.5590444724, + "99.999" : 1181586.5590444724, + "99.9999" : 1181586.5590444724, + "100.0" : 1181586.5590444724 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 1115758.2755510376, + 1181586.5590444724 + ], + [ + 1118561.6168647762, + 1152243.6907444876 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.tool.ModuleOverwritesBenchmark.cModuleOverwriteLinear", + "mode" : "thrpt", + "threads" : 1, + "forks" : 2, + "jvm" : "/usr/lib/jvm/java-9-oracle/bin/java", + "jvmArgs" : [ + "-Xms8192m", + "-Xmx8192m", + "-Dtlc2.tool.ModuleOverwritesBenchmark.base=/home/markus/src/TLA/tla/tlatools/test-model" + ], + "jdkVersion" : "9.0.4", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "9.0.4+11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 3708550.6057697954, + "scoreError" : 824356.4201994061, + "scoreConfidence" : [ + 2884194.185570389, + 4532907.025969202 + ], + "scorePercentiles" : { + "0.0" : 3595787.9785506492, + "50.0" : 3700259.3284566575, + "90.0" : 3837895.787615218, + "95.0" : 3837895.787615218, + "99.0" : 3837895.787615218, + "99.9" : 3837895.787615218, + "99.99" : 3837895.787615218, + "99.999" : 3837895.787615218, + "99.9999" : 3837895.787615218, + "100.0" : 3837895.787615218 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 3798339.118508976, + 3595787.9785506492 + ], + [ + 3602179.538404339, + 3837895.787615218 + ] + ] + }, + "secondaryMetrics" : { + } + } +] + + diff --git a/tlatools/test-benchmark/tlc2/tool/ModuleOverwritesBenchmark.java b/tlatools/test-benchmark/tlc2/tool/ModuleOverwritesBenchmark.java new file mode 100644 index 0000000000000000000000000000000000000000..f5f1a393fc6398149aa7cb59cfdca8b3e67bb858 --- /dev/null +++ b/tlatools/test-benchmark/tlc2/tool/ModuleOverwritesBenchmark.java @@ -0,0 +1,98 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.tool; + +import java.io.File; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; + +import tlc2.value.FcnRcdValue; +import tlc2.value.Value; +import util.SimpleFilenameToStream; +import util.ToolIO; +import util.UniqueString; + +@State(Scope.Benchmark) +public class ModuleOverwritesBenchmark { + + /* + * Run with: java -jar target/benchmarks.jar -wi 2 -i 2 -f2 -rf json -rff + * ModuleOverwritesBenchmark-$(de +%s)-$(git rev-parse --short HEAD).json + * -jvmArgsPrepend "-Xms8192m -Xmx8192m" -jvmArgsAppend + * "-Dtlc2.tool.ModuleOverwritesBenchmark.base=/home/markus/src/TLA/tla/tlatools/test-model tlc2.tool.ModuleOverwritesBenchmark " + */ + + private static final String BASE_PATH = System + .getProperty(ModuleOverwritesBenchmark.class.getName() + ".base"); + + private static final Tool tool; + private static final TLCStateMut state; + + static { + String dir = BASE_PATH + File.separator + "ModuleOverwrites"; + System.err.println(dir); + ToolIO.setUserDir(dir); + + tool = new Tool("", "ModuleOverwrites", "ModuleOverwrites", new SimpleFilenameToStream()); + tool.init(true, null); + + state = (TLCStateMut) tool.getInitStates().elementAt(0); + } + + @Benchmark + public boolean aNoModuleOverwrite() { + shuffleValues(); + return tool.isValid(tool.getInvariants()[0], state); + } + + @Benchmark + public boolean bModuleOverwrite() { + shuffleValues(); + return tool.isValid(tool.getInvariants()[1], state); + } + + @Benchmark + public boolean cModuleOverwriteLinear() { + shuffleValues(); + return tool.isValid(tool.getInvariants()[2], state); + } + + private static final void shuffleValues() { + final FcnRcdValue frv = (FcnRcdValue) state.getVals().get(UniqueString.uniqueStringOf("t")); + + final List<Value> values = Arrays.asList(frv.values); + Collections.shuffle(values); + + for (int i = 0; i < values.size(); i++) { + frv.values[i] = values.get(i); + } + } +} diff --git a/tlatools/test-benchmark/tlc2/util/CombinatoricsBenchmark.java b/tlatools/test-benchmark/tlc2/util/CombinatoricsBenchmark.java new file mode 100644 index 0000000000000000000000000000000000000000..db27ffc507566401a0c1404eac6b725a75850cdb --- /dev/null +++ b/tlatools/test-benchmark/tlc2/util/CombinatoricsBenchmark.java @@ -0,0 +1,76 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.util; + +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; + +@State(Scope.Benchmark) +public class CombinatoricsBenchmark { + + private static List<BigInteger> bincoef; + private static List<BigInteger> slowBincoef; + + static { + bincoef = new ArrayList<BigInteger>(187489); + slowBincoef = new ArrayList<BigInteger>(187489); + } + + @Benchmark + @Warmup(iterations = 3, time = 1) + @Measurement(iterations = 3, time = 1) + @BenchmarkMode(Mode.Throughput) + public List<BigInteger> bigChoose() { + for (int n = Combinatorics.MAXCHOOSENUM + 1; n < Combinatorics.MAXCHOOSENUM << 3; n++) { + for (int k = Combinatorics.MAXCHOOSENUM + 1; k < Combinatorics.MAXCHOOSENUM << 3; k++) { + bincoef.add(Combinatorics.bigChoose(n, k)); + } + } + return bincoef; + } + + @Benchmark + @Warmup(iterations = 3, time = 1) + @Measurement(iterations = 3, time = 1) + @BenchmarkMode(Mode.Throughput) + public List<BigInteger> slowBigChoose() { + for (int n = Combinatorics.MAXCHOOSENUM + 1; n < Combinatorics.MAXCHOOSENUM << 3; n++) { + for (int k = Combinatorics.MAXCHOOSENUM + 1; k < Combinatorics.MAXCHOOSENUM << 3; k++) { + slowBincoef.add(Combinatorics.slowBigChoose(n, k)); + } + } + return slowBincoef; + } +} diff --git a/tlatools/test-benchmark/tlc2/value/IntervalValueBenchmark.java b/tlatools/test-benchmark/tlc2/value/IntervalValueBenchmark.java new file mode 100644 index 0000000000000000000000000000000000000000..c07719467ea42f3bd7119bd21fc67c7fd6113753 --- /dev/null +++ b/tlatools/test-benchmark/tlc2/value/IntervalValueBenchmark.java @@ -0,0 +1,64 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.value; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; + +import tlc2.util.FP64; + +@State(Scope.Benchmark) +public class IntervalValueBenchmark { + + static { + EnumerableValue.setRandom(15041980L); + EnumerableValue.resetRandom(); + + FP64.Init(); + } + + @Param({"16", "18", "20", "22"}) + public int size; + + @Param({"10", "12", "14", "16"}) + public int numOfElements; + + public Enumerable intervalValue; + + @Setup(Level.Invocation) + public void setup() { + intervalValue = (Enumerable) new IntervalValue(1, 1 << size).normalize(); + } + + @Benchmark + public Enumerable randomSubset() { + return intervalValue.getRandomSubset(1 << numOfElements); + } +} diff --git a/tlatools/test-benchmark/tlc2/value/Randomization-1530025487-ebb8802.json b/tlatools/test-benchmark/tlc2/value/Randomization-1530025487-ebb8802.json new file mode 100644 index 0000000000000000000000000000000000000000..d9aaedad0627acc2d8cef1befdcdb0508f6508a8 --- /dev/null +++ b/tlatools/test-benchmark/tlc2/value/Randomization-1530025487-ebb8802.json @@ -0,0 +1,1540 @@ +[ + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.probabilisticN035k16d01", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 9.814265639856911, + "scoreError" : 3.5519226084921507, + "scoreConfidence" : [ + 6.262343031364761, + 13.366188248349061 + ], + "scorePercentiles" : { + "0.0" : 6.753607668439613, + "50.0" : 10.470070397652428, + "90.0" : 12.827941145274211, + "95.0" : 12.858649761728246, + "99.0" : 12.858649761728246, + "99.9" : 12.858649761728246, + "99.99" : 12.858649761728246, + "99.999" : 12.858649761728246, + "99.9999" : 12.858649761728246, + "100.0" : 12.858649761728246 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 12.858649761728246, + 6.911478184305761 + ], + [ + 11.208217963617345, + 12.551563597187895 + ], + [ + 10.767867782062131, + 11.546268236993155 + ], + [ + 7.480349528344792, + 7.892380662647449 + ], + [ + 6.753607668439613, + 10.172273013242725 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.probabilisticN035k16d02", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 2.7932446205666954, + "scoreError" : 0.7212536165365129, + "scoreConfidence" : [ + 2.0719910040301825, + 3.5144982371032083 + ], + "scorePercentiles" : { + "0.0" : 1.9673773629805331, + "50.0" : 3.088890563191904, + "90.0" : 3.201938518939384, + "95.0" : 3.2048232297325607, + "99.0" : 3.2048232297325607, + "99.9" : 3.2048232297325607, + "99.99" : 3.2048232297325607, + "99.999" : 3.2048232297325607, + "99.9999" : 3.2048232297325607, + "100.0" : 3.2048232297325607 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 3.1759761218007947, + 3.1546063327804683 + ], + [ + 3.136413968282235, + 2.5629672227690783 + ], + [ + 1.9673773629805331, + 2.313233836993042 + ], + [ + 3.1541066773395916, + 3.2048232297325607 + ], + [ + 3.0413671581015724, + 2.221574294887079 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.probabilisticN035k80d01", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 28.38809904359423, + "scoreError" : 9.202418157455796, + "scoreConfidence" : [ + 19.185680886138435, + 37.59051720105003 + ], + "scorePercentiles" : { + "0.0" : 19.36331095829827, + "50.0" : 28.60973170258842, + "90.0" : 36.29196537233252, + "95.0" : 36.29504934912339, + "99.0" : 36.29504934912339, + "99.9" : 36.29504934912339, + "99.99" : 36.29504934912339, + "99.999" : 36.29504934912339, + "99.9999" : 36.29504934912339, + "100.0" : 36.29504934912339 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 29.685271545719385, + 24.61858183441453 + ], + [ + 33.0776564207316, + 20.534132532710004 + ], + [ + 24.572440645545356, + 27.53419185945745 + ], + [ + 31.93614570872759, + 19.36331095829827 + ], + [ + 36.26420958121468, + 36.29504934912339 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.probabilisticN035k80d02", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 10.52227709850522, + "scoreError" : 1.6101589911941476, + "scoreConfidence" : [ + 8.912118107311073, + 12.132436089699368 + ], + "scorePercentiles" : { + "0.0" : 8.491378801933548, + "50.0" : 11.247893814845149, + "90.0" : 11.420671041101858, + "95.0" : 11.432291287500947, + "99.0" : 11.432291287500947, + "99.9" : 11.432291287500947, + "99.99" : 11.432291287500947, + "99.999" : 11.432291287500947, + "99.9999" : 11.432291287500947, + "100.0" : 11.432291287500947 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 8.491378801933548, + 9.657996752431464 + ], + [ + 9.574077581775065, + 9.66664321520015 + ], + [ + 11.2822253177283, + 11.31608882351006 + ], + [ + 11.214644306366141, + 11.432291287500947 + ], + [ + 11.281143323324155, + 11.306281575282378 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.probabilisticN060k16d01", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 2.7945558732575426, + "scoreError" : 0.3736130106734233, + "scoreConfidence" : [ + 2.4209428625841194, + 3.168168883930966 + ], + "scorePercentiles" : { + "0.0" : 2.221249810954392, + "50.0" : 2.8431194315606305, + "90.0" : 3.0276341790221912, + "95.0" : 3.0276871486165895, + "99.0" : 3.0276871486165895, + "99.9" : 3.0276871486165895, + "99.99" : 3.0276871486165895, + "99.999" : 3.0276871486165895, + "99.9999" : 3.0276871486165895, + "100.0" : 3.0276871486165895 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 2.8392579355058656, + 3.027157452672608 + ], + [ + 2.571440923836749, + 3.0276871486165895 + ], + [ + 2.221249810954392, + 2.8485126236395106 + ], + [ + 2.846980927615396, + 3.0254151539107506 + ], + [ + 2.7837884068656784, + 2.7540683489578917 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.probabilisticN060k16d02", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 2.645667431385532, + "scoreError" : 0.16743465996444615, + "scoreConfidence" : [ + 2.478232771421086, + 2.8131020913499785 + ], + "scorePercentiles" : { + "0.0" : 2.4741351571772863, + "50.0" : 2.625042773404063, + "90.0" : 2.8393349288272796, + "95.0" : 2.8481004996723, + "99.0" : 2.8481004996723, + "99.9" : 2.8481004996723, + "99.99" : 2.8481004996723, + "99.999" : 2.8481004996723, + "99.9999" : 2.8481004996723, + "100.0" : 2.8481004996723 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 2.5924849093010445, + 2.5767759287385683 + ], + [ + 2.7243545950925228, + 2.760444791222093 + ], + [ + 2.657600637507082, + 2.4741351571772863 + ], + [ + 2.5567216005732463, + 2.5847076500537622 + ], + [ + 2.68134854451742, + 2.8481004996723 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.probabilisticN060k80d01", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 11.298601269411964, + "scoreError" : 0.720388691798619, + "scoreConfidence" : [ + 10.578212577613346, + 12.018989961210583 + ], + "scorePercentiles" : { + "0.0" : 10.287617624566224, + "50.0" : 11.423558384797065, + "90.0" : 11.721178226261209, + "95.0" : 11.729644309762948, + "99.0" : 11.729644309762948, + "99.9" : 11.729644309762948, + "99.99" : 11.729644309762948, + "99.999" : 11.729644309762948, + "99.9999" : 11.729644309762948, + "100.0" : 11.729644309762948 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 11.45647631886964, + 11.644983474745558 + ], + [ + 11.403544772058899, + 11.415097940763632 + ], + [ + 11.729644309762948, + 11.642029824041085 + ], + [ + 10.577135428368546, + 10.287617624566224 + ], + [ + 11.432018828830499, + 11.397464172112608 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.probabilisticN060k80d02", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 8.69862560268995, + "scoreError" : 2.850730402828029, + "scoreConfidence" : [ + 5.84789519986192, + 11.549356005517978 + ], + "scorePercentiles" : { + "0.0" : 5.770652554442691, + "50.0" : 9.55560067282565, + "90.0" : 10.610404276107895, + "95.0" : 10.648561829452847, + "99.0" : 10.648561829452847, + "99.9" : 10.648561829452847, + "99.99" : 10.648561829452847, + "99.999" : 10.648561829452847, + "99.9999" : 10.648561829452847, + "100.0" : 10.648561829452847 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 10.648561829452847, + 10.266986296003333 + ], + [ + 10.212611163875144, + 9.078390005156265 + ], + [ + 10.032811340495034, + 6.596330980326417 + ], + [ + 6.265218422598946, + 10.141051281441365 + ], + [ + 7.973642153107459, + 5.770652554442691 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.probabilisticN100k16d01", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 1.5248786293018326, + "scoreError" : 0.17380994878025358, + "scoreConfidence" : [ + 1.351068680521579, + 1.6986885780820862 + ], + "scorePercentiles" : { + "0.0" : 1.4303491635625107, + "50.0" : 1.4914262953464568, + "90.0" : 1.7974093389527392, + "95.0" : 1.8189693047549174, + "99.0" : 1.8189693047549174, + "99.9" : 1.8189693047549174, + "99.99" : 1.8189693047549174, + "99.999" : 1.8189693047549174, + "99.9999" : 1.8189693047549174, + "100.0" : 1.8189693047549174 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 1.4598484244159358, + 1.4624449978364078 + ], + [ + 1.4303491635625107, + 1.4416282783013532 + ], + [ + 1.4885810066800946, + 1.6033696467331364 + ], + [ + 1.4942715840128191, + 1.5194815860617874 + ], + [ + 1.5298423006593602, + 1.8189693047549174 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.probabilisticN100k16d02", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 1.5171087604788753, + "scoreError" : 0.137741029417015, + "scoreConfidence" : [ + 1.3793677310618604, + 1.6548497898958903 + ], + "scorePercentiles" : { + "0.0" : 1.374140686846801, + "50.0" : 1.5061976180530554, + "90.0" : 1.6719182167808382, + "95.0" : 1.6755564936470366, + "99.0" : 1.6755564936470366, + "99.9" : 1.6755564936470366, + "99.99" : 1.6755564936470366, + "99.999" : 1.6755564936470366, + "99.9999" : 1.6755564936470366, + "100.0" : 1.6755564936470366 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 1.4550262673134087, + 1.4716255018554139 + ], + [ + 1.54464295541126, + 1.4655570993307343 + ], + [ + 1.6391737249850518, + 1.540769734250697 + ], + [ + 1.374140686846801, + 1.4580145430017348 + ], + [ + 1.5465805981466152, + 1.6755564936470366 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.probabilisticN100k80d01", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 5.522708358140621, + "scoreError" : 0.8619263972210056, + "scoreConfidence" : [ + 4.660781960919615, + 6.384634755361627 + ], + "scorePercentiles" : { + "0.0" : 4.557760347176983, + "50.0" : 5.562722302155111, + "90.0" : 6.1258120806090774, + "95.0" : 6.133386755058857, + "99.0" : 6.133386755058857, + "99.9" : 6.133386755058857, + "99.99" : 6.133386755058857, + "99.999" : 6.133386755058857, + "99.9999" : 6.133386755058857, + "100.0" : 6.133386755058857 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 4.557760347176983, + 5.943804937625557 + ], + [ + 4.61878359597353, + 6.054253757090362 + ], + [ + 5.426317144240321, + 5.573249938573027 + ], + [ + 6.057640010561063, + 5.309692429369306 + ], + [ + 6.133386755058857, + 5.552194665737194 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.probabilisticN100k80d02", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 5.2034486056520395, + "scoreError" : 0.8396356557754167, + "scoreConfidence" : [ + 4.363812949876623, + 6.043084261427456 + ], + "scorePercentiles" : { + "0.0" : 4.2453851147076325, + "50.0" : 5.279500987356893, + "90.0" : 5.983987887291637, + "95.0" : 6.010975853830928, + "99.0" : 6.010975853830928, + "99.9" : 6.010975853830928, + "99.99" : 6.010975853830928, + "99.999" : 6.010975853830928, + "99.9999" : 6.010975853830928, + "100.0" : 6.010975853830928 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 5.243868701914112, + 5.741096188438025 + ], + [ + 5.315133272799674, + 5.184673423835484 + ], + [ + 5.546667181331337, + 5.371833327105703 + ], + [ + 5.021845325531628, + 6.010975853830928 + ], + [ + 4.353007667025872, + 4.2453851147076325 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.probabilisticN200k16d01", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 1.339924631382442, + "scoreError" : 0.04479747613250227, + "scoreConfidence" : [ + 1.2951271552499397, + 1.3847221075149443 + ], + "scorePercentiles" : { + "0.0" : 1.2974725063142822, + "50.0" : 1.3317294576636773, + "90.0" : 1.405961752460973, + "95.0" : 1.4112371767231358, + "99.0" : 1.4112371767231358, + "99.9" : 1.4112371767231358, + "99.99" : 1.4112371767231358, + "99.999" : 1.4112371767231358, + "99.9999" : 1.4112371767231358, + "100.0" : 1.4112371767231358 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 1.2974725063142822, + 1.3317783160699779 + ], + [ + 1.330023220063289, + 1.3217067595557936 + ], + [ + 1.3312044039027107, + 1.331680599257377 + ], + [ + 1.345338260664422, + 1.3584829341015097 + ], + [ + 1.3403221371719218, + 1.4112371767231358 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.probabilisticN200k16d02", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 1.2928807628469392, + "scoreError" : 0.09300984990006785, + "scoreConfidence" : [ + 1.1998709129468714, + 1.385890612747007 + ], + "scorePercentiles" : { + "0.0" : 1.23105772545197, + "50.0" : 1.2758400061388142, + "90.0" : 1.4029274412912995, + "95.0" : 1.4031941394477145, + "99.0" : 1.4031941394477145, + "99.9" : 1.4031941394477145, + "99.99" : 1.4031941394477145, + "99.999" : 1.4031941394477145, + "99.9999" : 1.4031941394477145, + "100.0" : 1.4031941394477145 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 1.23105772545197, + 1.2546742096555419 + ], + [ + 1.4031941394477145, + 1.291465109010951 + ], + [ + 1.2563893499415755, + 1.2967143565966486 + ], + [ + 1.2602149032666774, + 1.2927650207517143 + ], + [ + 1.2418056564630344, + 1.4005271578835636 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.probabilisticN200k80d01", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 4.5465162346852726, + "scoreError" : 0.44026456747307174, + "scoreConfidence" : [ + 4.1062516672122005, + 4.986780802158345 + ], + "scorePercentiles" : { + "0.0" : 4.079849518094677, + "50.0" : 4.5407630971316895, + "90.0" : 5.044907925189187, + "95.0" : 5.065693011936493, + "99.0" : 5.065693011936493, + "99.9" : 5.065693011936493, + "99.99" : 5.065693011936493, + "99.999" : 5.065693011936493, + "99.9999" : 5.065693011936493, + "100.0" : 5.065693011936493 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 4.079849518094677, + 4.638800409435509 + ], + [ + 4.204652426820363, + 4.857842144463429 + ], + [ + 4.691995094785729, + 4.415265131211205 + ], + [ + 5.065693011936493, + 4.567625992390603 + ], + [ + 4.429538415841941, + 4.513900201872776 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.probabilisticN200k80d02", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 4.3364906992767995, + "scoreError" : 0.6361600103822059, + "scoreConfidence" : [ + 3.7003306888945935, + 4.972650709659005 + ], + "scorePercentiles" : { + "0.0" : 3.4850481939473967, + "50.0" : 4.4695550132572155, + "90.0" : 4.878136508784269, + "95.0" : 4.8966769796925815, + "99.0" : 4.8966769796925815, + "99.9" : 4.8966769796925815, + "99.99" : 4.8966769796925815, + "99.999" : 4.8966769796925815, + "99.9999" : 4.8966769796925815, + "100.0" : 4.8966769796925815 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 4.8966769796925815, + 4.711272270609456 + ], + [ + 4.1235368739389076, + 4.476218983648658 + ], + [ + 4.644397477491868, + 4.5275343861681225 + ], + [ + 4.462891042865774, + 4.0115585617605545 + ], + [ + 3.4850481939473967, + 4.025772222644671 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.probabilisticN300k16d01", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 1.6148478717291934, + "scoreError" : 0.7446877881103863, + "scoreConfidence" : [ + 0.8701600836188071, + 2.3595356598395796 + ], + "scorePercentiles" : { + "0.0" : 1.1656347467176837, + "50.0" : 1.315218831808714, + "90.0" : 2.2482497486098527, + "95.0" : 2.2518752253276304, + "99.0" : 2.2518752253276304, + "99.9" : 2.2518752253276304, + "99.99" : 2.2518752253276304, + "99.999" : 2.2518752253276304, + "99.9999" : 2.2518752253276304, + "100.0" : 2.2518752253276304 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 1.21743252963011, + 1.1656347467176837 + ], + [ + 1.175409735645137, + 1.2585759163329866 + ], + [ + 1.231843853772198, + 1.3718617472844412 + ], + [ + 2.11681396227486, + 2.14341054215703 + ], + [ + 2.215620458149855, + 2.2518752253276304 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.probabilisticN300k16d02", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 1.8602219960318038, + "scoreError" : 0.39115633236720815, + "scoreConfidence" : [ + 1.4690656636645958, + 2.251378328399012 + ], + "scorePercentiles" : { + "0.0" : 1.4062697603214702, + "50.0" : 1.964762284880499, + "90.0" : 2.0888910844309247, + "95.0" : 2.0920717403135463, + "99.0" : 2.0920717403135463, + "99.9" : 2.0920717403135463, + "99.99" : 2.0920717403135463, + "99.999" : 2.0920717403135463, + "99.9999" : 2.0920717403135463, + "100.0" : 2.0920717403135463 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 1.7989008575828505, + 1.8112093511172844 + ], + [ + 2.0361709586331793, + 2.056975849771783 + ], + [ + 2.060265181487331, + 2.0920717403135463 + ], + [ + 1.4108316913295962, + 1.4062697603214702 + ], + [ + 1.9262588615098382, + 2.00326570825116 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.probabilisticN300k80d01", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 6.55685280713317, + "scoreError" : 1.521062607592989, + "scoreConfidence" : [ + 5.035790199540181, + 8.07791541472616 + ], + "scorePercentiles" : { + "0.0" : 3.722375583789737, + "50.0" : 6.866447622580452, + "90.0" : 7.070923082701012, + "95.0" : 7.07416375512963, + "99.0" : 7.07416375512963, + "99.9" : 7.07416375512963, + "99.99" : 7.07416375512963, + "99.999" : 7.07416375512963, + "99.9999" : 7.07416375512963, + "100.0" : 7.07416375512963 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 6.8806062455577495, + 6.883754498127009 + ], + [ + 7.07416375512963, + 6.641330464691329 + ], + [ + 6.8522889996031555, + 7.007776420526916 + ], + [ + 7.041757030843449, + 6.763664651435106 + ], + [ + 3.722375583789737, + 6.700810421627625 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.probabilisticN300k80d02", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 5.301216427827282, + "scoreError" : 1.1289294375629328, + "scoreConfidence" : [ + 4.172286990264349, + 6.430145865390215 + ], + "scorePercentiles" : { + "0.0" : 3.542477847530514, + "50.0" : 5.271405080419002, + "90.0" : 6.102467200471888, + "95.0" : 6.106821842803865, + "99.0" : 6.106821842803865, + "99.9" : 6.106821842803865, + "99.99" : 6.106821842803865, + "99.999" : 6.106821842803865, + "99.9999" : 6.106821842803865, + "100.0" : 6.106821842803865 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 5.486593720751928, + 6.0632754194840945 + ], + [ + 5.223263080702427, + 3.542477847530514 + ], + [ + 5.018855922335199, + 5.100012670505602 + ], + [ + 6.106821842803865, + 5.319547080135576 + ], + [ + 5.137619833973987, + 6.0136968600496274 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.probabilisticN400k16d01", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 1.5860227730491998, + "scoreError" : 0.30379023334378413, + "scoreConfidence" : [ + 1.2822325397054157, + 1.8898130063929839 + ], + "scorePercentiles" : { + "0.0" : 1.0920813832707281, + "50.0" : 1.5994173400063993, + "90.0" : 1.791811943594711, + "95.0" : 1.7958322769866282, + "99.0" : 1.7958322769866282, + "99.9" : 1.7958322769866282, + "99.99" : 1.7958322769866282, + "99.999" : 1.7958322769866282, + "99.9999" : 1.7958322769866282, + "100.0" : 1.7958322769866282 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 1.0920813832707281, + 1.7958322769866282 + ], + [ + 1.5932804092121582, + 1.7556289430674565 + ], + [ + 1.52308380137161, + 1.715720305433191 + ], + [ + 1.7223091241348114, + 1.5188029344158969 + ], + [ + 1.6055542708006407, + 1.537934281798876 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.probabilisticN400k16d02", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 1.1599289382358806, + "scoreError" : 0.22612698801505537, + "scoreConfidence" : [ + 0.9338019502208252, + 1.386055926250936 + ], + "scorePercentiles" : { + "0.0" : 0.9825177739479852, + "50.0" : 1.077451286867186, + "90.0" : 1.4022996800130283, + "95.0" : 1.410049661563603, + "99.0" : 1.410049661563603, + "99.9" : 1.410049661563603, + "99.99" : 1.410049661563603, + "99.999" : 1.410049661563603, + "99.9999" : 1.410049661563603, + "100.0" : 1.410049661563603 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 1.0763690618814368, + 1.0651796680221743 + ], + [ + 1.070265094440761, + 1.0249632943993892 + ], + [ + 0.9825177739479852, + 1.0785335118529353 + ], + [ + 1.3325498460578566, + 1.410049661563603 + ], + [ + 1.286618213721185, + 1.2722432564714805 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.probabilisticN400k80d01", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 6.027975265926844, + "scoreError" : 0.35112510651249884, + "scoreConfidence" : [ + 5.676850159414345, + 6.379100372439343 + ], + "scorePercentiles" : { + "0.0" : 5.644475565004447, + "50.0" : 6.0550531061834345, + "90.0" : 6.354428372291083, + "95.0" : 6.3564761807971415, + "99.0" : 6.3564761807971415, + "99.9" : 6.3564761807971415, + "99.99" : 6.3564761807971415, + "99.999" : 6.3564761807971415, + "99.9999" : 6.3564761807971415, + "100.0" : 6.3564761807971415 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 5.97900037940529, + 6.335998095736555 + ], + [ + 5.8384965728694365, + 6.025064868648608 + ], + [ + 5.644475565004447, + 6.0918640144917955 + ], + [ + 6.3564761807971415, + 5.7602399161218445 + ], + [ + 6.163095722475063, + 6.08504134371826 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.probabilisticN400k80d02", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 4.627633904221076, + "scoreError" : 0.7331295121689335, + "scoreConfidence" : [ + 3.8945043920521427, + 5.36076341639001 + ], + "scorePercentiles" : { + "0.0" : 3.821230691559164, + "50.0" : 4.559809491822633, + "90.0" : 5.374791544313783, + "95.0" : 5.413207484888207, + "99.0" : 5.413207484888207, + "99.9" : 5.413207484888207, + "99.99" : 5.413207484888207, + "99.999" : 5.413207484888207, + "99.9999" : 5.413207484888207, + "100.0" : 5.413207484888207 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 5.0290480791439665, + 5.016734041159645 + ], + [ + 4.268812624543834, + 4.620526293998292 + ], + [ + 4.499092689646973, + 4.426721770032627 + ], + [ + 4.173392584090863, + 5.007572783147188 + ], + [ + 3.821230691559164, + 5.413207484888207 + ] + ] + }, + "secondaryMetrics" : { + } + } +] + + diff --git a/tlatools/test-benchmark/tlc2/value/Randomization-1530034012-4a34ace.json b/tlatools/test-benchmark/tlc2/value/Randomization-1530034012-4a34ace.json new file mode 100644 index 0000000000000000000000000000000000000000..a156c7da7c271207631634dd5169d6fd2187962f --- /dev/null +++ b/tlatools/test-benchmark/tlc2/value/Randomization-1530034012-4a34ace.json @@ -0,0 +1,1540 @@ +[ + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.probabilisticN035k16d01", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 104.7011087104809, + "scoreError" : 3.7423761914164815, + "scoreConfidence" : [ + 100.95873251906441, + 108.44348490189738 + ], + "scorePercentiles" : { + "0.0" : 100.88954035368401, + "50.0" : 105.882966608304, + "90.0" : 107.34104031428244, + "95.0" : 107.42153923641156, + "99.0" : 107.42153923641156, + "99.9" : 107.42153923641156, + "99.99" : 107.42153923641156, + "99.999" : 107.42153923641156, + "99.9999" : 107.42153923641156, + "100.0" : 107.42153923641156 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 101.44416419113956, + 100.88954035368401 + ], + [ + 106.13510124450892, + 106.0740992343222 + ], + [ + 106.61655001512035, + 107.42153923641156 + ], + [ + 106.02129553873436, + 105.38379400794531 + ], + [ + 101.28036560506887, + 105.74463767787363 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.probabilisticN035k16d02", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 83.24147104170652, + "scoreError" : 4.554176259789341, + "scoreConfidence" : [ + 78.68729478191717, + 87.79564730149586 + ], + "scorePercentiles" : { + "0.0" : 78.55079784872044, + "50.0" : 83.91370138812889, + "90.0" : 86.58980075188902, + "95.0" : 86.64764393677703, + "99.0" : 86.64764393677703, + "99.9" : 86.64764393677703, + "99.99" : 86.64764393677703, + "99.999" : 86.64764393677703, + "99.9999" : 86.64764393677703, + "100.0" : 86.64764393677703 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 78.55079784872044, + 79.51303312164389 + ], + [ + 79.74896736709258, + 82.565057137537 + ], + [ + 83.75757469808822, + 86.06921208789687 + ], + [ + 85.80992118205909, + 86.64764393677703 + ], + [ + 84.06982807816954, + 85.6826749590806 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.probabilisticN035k80d01", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 224.85663488295086, + "scoreError" : 6.028591856716745, + "scoreConfidence" : [ + 218.8280430262341, + 230.88522673966762 + ], + "scorePercentiles" : { + "0.0" : 218.36459658547616, + "50.0" : 226.62847510687035, + "90.0" : 229.33631048633563, + "95.0" : 229.38790988428408, + "99.0" : 229.38790988428408, + "99.9" : 229.38790988428408, + "99.99" : 229.38790988428408, + "99.999" : 229.38790988428408, + "99.9999" : 229.38790988428408, + "100.0" : 229.38790988428408 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 226.63656062437886, + 226.7640288893431 + ], + [ + 219.78519797409433, + 219.94064929540707 + ], + [ + 229.38790988428408, + 228.87191590479955 + ], + [ + 218.36459658547616, + 226.62038958936185 + ], + [ + 225.25506764156407, + 226.94003244079963 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.probabilisticN035k80d02", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 185.97813137612835, + "scoreError" : 19.18711039638145, + "scoreConfidence" : [ + 166.7910209797469, + 205.1652417725098 + ], + "scorePercentiles" : { + "0.0" : 150.78714247391278, + "50.0" : 190.58386393172543, + "90.0" : 192.086769900789, + "95.0" : 192.1063873271388, + "99.0" : 192.1063873271388, + "99.9" : 192.1063873271388, + "99.99" : 192.1063873271388, + "99.999" : 192.1063873271388, + "99.9999" : 192.1063873271388, + "100.0" : 192.1063873271388 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 192.1063873271388, + 191.2646953076457 + ], + [ + 191.9102130636406, + 191.31943951811584 + ], + [ + 191.15971111652445, + 189.79898769959755 + ], + [ + 190.0080167469264, + 189.18588301321768 + ], + [ + 150.78714247391278, + 182.2408374945636 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.probabilisticN060k16d01", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 42.32871200796817, + "scoreError" : 17.81179967979969, + "scoreConfidence" : [ + 24.51691232816848, + 60.14051168776786 + ], + "scorePercentiles" : { + "0.0" : 24.31185136900342, + "50.0" : 44.95980125392232, + "90.0" : 57.23931162819738, + "95.0" : 57.50164238101311, + "99.0" : 57.50164238101311, + "99.9" : 57.50164238101311, + "99.99" : 57.50164238101311, + "99.999" : 57.50164238101311, + "99.9999" : 57.50164238101311, + "100.0" : 57.50164238101311 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 50.88292893960396, + 49.21247544702237 + ], + [ + 54.87833485285576, + 39.086245900476555 + ], + [ + 24.31185136900342, + 29.59827317841755 + ], + [ + 48.24622995596074, + 27.895765503444338 + ], + [ + 41.6733725518839, + 57.50164238101311 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.probabilisticN060k16d02", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 49.43683507637419, + "scoreError" : 8.920714718785595, + "scoreConfidence" : [ + 40.51612035758859, + 58.357549795159784 + ], + "scorePercentiles" : { + "0.0" : 35.51213429538773, + "50.0" : 51.44721321118388, + "90.0" : 53.52767867950377, + "95.0" : 53.54939167959375, + "99.0" : 53.54939167959375, + "99.9" : 53.54939167959375, + "99.99" : 53.54939167959375, + "99.999" : 53.54939167959375, + "99.9999" : 53.54939167959375, + "100.0" : 53.54939167959375 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 50.90779977793198, + 53.54939167959375 + ], + [ + 42.09399366036272, + 50.619658203534115 + ], + [ + 53.332261678693996, + 52.79084790579731 + ], + [ + 51.677694661744894, + 35.51213429538773 + ], + [ + 51.216731760622864, + 52.66783714007247 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.probabilisticN060k80d01", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 93.05935428685841, + "scoreError" : 38.50167771555803, + "scoreConfidence" : [ + 54.55767657130038, + 131.56103200241643 + ], + "scorePercentiles" : { + "0.0" : 57.93386263113723, + "50.0" : 94.70200646800936, + "90.0" : 123.68899208986174, + "95.0" : 124.27879912212194, + "99.0" : 124.27879912212194, + "99.9" : 124.27879912212194, + "99.99" : 124.27879912212194, + "99.999" : 124.27879912212194, + "99.9999" : 124.27879912212194, + "100.0" : 124.27879912212194 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 78.1520920575015, + 124.27879912212194 + ], + [ + 116.16801584966383, + 85.16604351364255 + ], + [ + 57.93386263113723, + 73.94587810450388 + ], + [ + 118.38072879951989, + 104.23796942237615 + ], + [ + 58.02829412796092, + 114.30185924015635 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.probabilisticN060k80d02", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 106.43974868838147, + "scoreError" : 23.394593630033878, + "scoreConfidence" : [ + 83.04515505834759, + 129.83434231841534 + ], + "scorePercentiles" : { + "0.0" : 74.25661377870344, + "50.0" : 114.07122657351444, + "90.0" : 120.05072448321653, + "95.0" : 120.2156072166627, + "99.0" : 120.2156072166627, + "99.9" : 120.2156072166627, + "99.99" : 120.2156072166627, + "99.999" : 120.2156072166627, + "99.9999" : 120.2156072166627, + "100.0" : 120.2156072166627 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 118.5667798822009, + 120.2156072166627 + ], + [ + 117.79734487632652, + 117.82734911263601 + ], + [ + 114.96353532253951, + 90.04572984768308 + ], + [ + 95.661695758385, + 113.17891782448936 + ], + [ + 101.88391326418818, + 74.25661377870344 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.probabilisticN100k16d01", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 21.38813297153077, + "scoreError" : 7.568160681308476, + "scoreConfidence" : [ + 13.819972290222292, + 28.956293652839246 + ], + "scorePercentiles" : { + "0.0" : 13.58606924078156, + "50.0" : 23.914049859153785, + "90.0" : 26.255547300671388, + "95.0" : 26.302995416083153, + "99.0" : 26.302995416083153, + "99.9" : 26.302995416083153, + "99.99" : 26.302995416083153, + "99.999" : 26.302995416083153, + "99.9999" : 26.302995416083153, + "100.0" : 26.302995416083153 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 13.811099062641686, + 17.941382206144834 + ], + [ + 13.58606924078156, + 18.262562513874666 + ], + [ + 25.337148269403375, + 25.828514261965516 + ], + [ + 24.983459026105365, + 26.302995416083153 + ], + [ + 24.38372946115993, + 23.44437025714764 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.probabilisticN100k16d02", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 19.622156265483028, + "scoreError" : 4.987868775642429, + "scoreConfidence" : [ + 14.634287489840599, + 24.610025041125457 + ], + "scorePercentiles" : { + "0.0" : 14.93138023958173, + "50.0" : 20.246976801211183, + "90.0" : 24.27346949430521, + "95.0" : 24.427045698424894, + "99.0" : 24.427045698424894, + "99.9" : 24.427045698424894, + "99.99" : 24.427045698424894, + "99.999" : 24.427045698424894, + "99.9999" : 24.427045698424894, + "100.0" : 24.427045698424894 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 22.89128365722806, + 24.427045698424894 + ], + [ + 19.844680591528572, + 20.649273010893797 + ], + [ + 15.873171889829425, + 18.1962620552237 + ], + [ + 14.93138023958173, + 15.739929179229202 + ], + [ + 21.57751635813752, + 22.091019974753376 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.probabilisticN100k80d01", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 74.26454714978158, + "scoreError" : 15.183553853622525, + "scoreConfidence" : [ + 59.08099329615905, + 89.4481010034041 + ], + "scorePercentiles" : { + "0.0" : 51.674450673992695, + "50.0" : 78.40778804239744, + "90.0" : 81.63045236364282, + "95.0" : 81.6569849685138, + "99.0" : 81.6569849685138, + "99.9" : 81.6569849685138, + "99.99" : 81.6569849685138, + "99.999" : 81.6569849685138, + "99.9999" : 81.6569849685138, + "100.0" : 81.6569849685138 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 80.39172776653989, + 81.6569849685138 + ], + [ + 81.39165891980406, + 81.14393282427004 + ], + [ + 78.82191071568474, + 51.674450673992695 + ], + [ + 76.76071269165135, + 61.78549587027839 + ], + [ + 71.02493169797056, + 77.99366536911016 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.probabilisticN100k80d02", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 60.853839105773126, + "scoreError" : 22.12483509675573, + "scoreConfidence" : [ + 38.729004009017395, + 82.97867420252885 + ], + "scorePercentiles" : { + "0.0" : 38.26110300104155, + "50.0" : 68.39288235960099, + "90.0" : 74.81830147083643, + "95.0" : 74.92553079057613, + "99.0" : 74.92553079057613, + "99.9" : 74.92553079057613, + "99.99" : 74.92553079057613, + "99.999" : 74.92553079057613, + "99.9999" : 74.92553079057613, + "100.0" : 74.92553079057613 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 50.71748836211502, + 48.6232060078198 + ], + [ + 40.686946926075855, + 38.26110300104155 + ], + [ + 66.04801192655289, + 71.26506936711934 + ], + [ + 73.42004429060252, + 70.73775279264909 + ], + [ + 73.85323759317912, + 74.92553079057613 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.probabilisticN200k16d01", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 10.639470911792866, + "scoreError" : 3.088289738509205, + "scoreConfidence" : [ + 7.551181173283661, + 13.727760650302072 + ], + "scorePercentiles" : { + "0.0" : 6.993385262401218, + "50.0" : 10.729512830841635, + "90.0" : 13.677033176490005, + "95.0" : 13.81168335274697, + "99.0" : 13.81168335274697, + "99.9" : 13.81168335274697, + "99.99" : 13.81168335274697, + "99.999" : 13.81168335274697, + "99.9999" : 13.81168335274697, + "100.0" : 13.81168335274697 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 11.409030310947868, + 10.525541923680748 + ], + [ + 8.482542765083899, + 10.631500751171094 + ], + [ + 10.827524910512178, + 8.955246572761785 + ], + [ + 6.993385262401218, + 12.293071678445585 + ], + [ + 12.465181590177318, + 13.81168335274697 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.probabilisticN200k16d02", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 10.456715599876055, + "scoreError" : 1.9028778570206695, + "scoreConfidence" : [ + 8.553837742855386, + 12.359593456896725 + ], + "scorePercentiles" : { + "0.0" : 7.864941352835479, + "50.0" : 10.939755490790464, + "90.0" : 11.714816996362217, + "95.0" : 11.753691593959166, + "99.0" : 11.753691593959166, + "99.9" : 11.753691593959166, + "99.99" : 11.753691593959166, + "99.999" : 11.753691593959166, + "99.9999" : 11.753691593959166, + "100.0" : 11.753691593959166 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 10.952660748060072, + 11.364945617989674 + ], + [ + 10.769860190657486, + 7.864941352835479 + ], + [ + 8.47649876887637, + 10.500627774438772 + ], + [ + 11.753691593959166, + 10.96587977575521 + ], + [ + 10.991199942667485, + 10.926850233520856 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.probabilisticN200k80d01", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 31.969197873061233, + "scoreError" : 1.6677155997623578, + "scoreConfidence" : [ + 30.301482273298877, + 33.63691347282359 + ], + "scorePercentiles" : { + "0.0" : 30.056920293183016, + "50.0" : 32.21477295504585, + "90.0" : 33.33626563901803, + "95.0" : 33.34763314031518, + "99.0" : 33.34763314031518, + "99.9" : 33.34763314031518, + "99.99" : 33.34763314031518, + "99.999" : 33.34763314031518, + "99.9999" : 33.34763314031518, + "100.0" : 33.34763314031518 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 32.419857477883355, + 30.91815408954798 + ], + [ + 32.64844059293107, + 30.056920293183016 + ], + [ + 32.760711407669184, + 32.00968843220835 + ], + [ + 33.34763314031518, + 30.990574339821343 + ], + [ + 31.30604082970921, + 33.23395812734369 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.probabilisticN200k80d02", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 28.20474698855128, + "scoreError" : 3.205925122939175, + "scoreConfidence" : [ + 24.998821865612104, + 31.410672111490452 + ], + "scorePercentiles" : { + "0.0" : 22.814486172933808, + "50.0" : 28.542282298254698, + "90.0" : 30.383993715660303, + "95.0" : 30.416778077286274, + "99.0" : 30.416778077286274, + "99.9" : 30.416778077286274, + "99.99" : 30.416778077286274, + "99.999" : 30.416778077286274, + "99.9999" : 30.416778077286274, + "100.0" : 30.416778077286274 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 27.921304255505774, + 28.829394237761125 + ], + [ + 28.255170358748266, + 27.439633953256468 + ], + [ + 22.814486172933808, + 30.416778077286274 + ], + [ + 29.197701087165743, + 30.088934461026557 + ], + [ + 29.133379644045366, + 27.950687637783403 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.probabilisticN300k16d01", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 8.203667020100887, + "scoreError" : 0.5884166824514152, + "scoreConfidence" : [ + 7.6152503376494725, + 8.792083702552302 + ], + "scorePercentiles" : { + "0.0" : 7.360515269435855, + "50.0" : 8.338306550242326, + "90.0" : 8.592865318321673, + "95.0" : 8.594258152249708, + "99.0" : 8.594258152249708, + "99.9" : 8.594258152249708, + "99.99" : 8.594258152249708, + "99.999" : 8.594258152249708, + "99.9999" : 8.594258152249708, + "100.0" : 8.594258152249708 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 7.898286271236425, + 8.076259860587378 + ], + [ + 8.594258152249708, + 7.360515269435855 + ], + [ + 7.930906266852778, + 8.459445698375168 + ], + [ + 8.395991372547563, + 8.46005576881755 + ], + [ + 8.28062172793709, + 8.580329812969351 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.probabilisticN300k16d02", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 5.763911744882545, + "scoreError" : 1.5043550652048963, + "scoreConfidence" : [ + 4.259556679677649, + 7.268266810087441 + ], + "scorePercentiles" : { + "0.0" : 4.429803153294701, + "50.0" : 5.873212023012337, + "90.0" : 6.966232203393936, + "95.0" : 6.966942875753675, + "99.0" : 6.966942875753675, + "99.9" : 6.966942875753675, + "99.99" : 6.966942875753675, + "99.999" : 6.966942875753675, + "99.9999" : 6.966942875753675, + "100.0" : 6.966942875753675 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 6.9598361521562815, + 5.064587996073755 + ], + [ + 4.946417436382128, + 6.4726554457373355 + ], + [ + 4.575986438005888, + 6.966942875753675 + ], + [ + 5.302652006486136, + 6.476463905397021 + ], + [ + 4.429803153294701, + 6.443772039538537 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.probabilisticN300k80d01", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 18.801957044765565, + "scoreError" : 1.1768612520141342, + "scoreConfidence" : [ + 17.62509579275143, + 19.9788182967797 + ], + "scorePercentiles" : { + "0.0" : 17.140027541125153, + "50.0" : 18.882789178775543, + "90.0" : 19.570854300260155, + "95.0" : 19.571867386585367, + "99.0" : 19.571867386585367, + "99.9" : 19.571867386585367, + "99.99" : 19.571867386585367, + "99.999" : 19.571867386585367, + "99.9999" : 19.571867386585367, + "100.0" : 19.571867386585367 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 19.42278989517915, + 18.714642574717033 + ], + [ + 17.140027541125153, + 18.975405204474427 + ], + [ + 19.571867386585367, + 18.601652618233114 + ], + [ + 19.325002434758275, + 17.916273116173247 + ], + [ + 18.79017315307666, + 19.561736523333238 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.probabilisticN300k80d02", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 14.422596923700885, + "scoreError" : 3.137380248280707, + "scoreConfidence" : [ + 11.285216675420179, + 17.559977171981593 + ], + "scorePercentiles" : { + "0.0" : 11.383432415016602, + "50.0" : 14.75604222776579, + "90.0" : 17.026921267980402, + "95.0" : 17.04323687245957, + "99.0" : 17.04323687245957, + "99.9" : 17.04323687245957, + "99.99" : 17.04323687245957, + "99.999" : 17.04323687245957, + "99.9999" : 17.04323687245957, + "100.0" : 17.04323687245957 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 15.99247577392052, + 15.73714255929863 + ], + [ + 14.611301908761718, + 11.383432415016602 + ], + [ + 17.04323687245957, + 11.547055656321096 + ], + [ + 16.880080827667893, + 12.746244623874427 + ], + [ + 14.90078254676986, + 13.384216052918532 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.probabilisticN400k16d01", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 5.211916463832229, + "scoreError" : 0.2878694029810478, + "scoreConfidence" : [ + 4.924047060851182, + 5.499785866813276 + ], + "scorePercentiles" : { + "0.0" : 4.853473806617481, + "50.0" : 5.1995205258016615, + "90.0" : 5.471484334583664, + "95.0" : 5.474007785023183, + "99.0" : 5.474007785023183, + "99.9" : 5.474007785023183, + "99.99" : 5.474007785023183, + "99.999" : 5.474007785023183, + "99.9999" : 5.474007785023183, + "100.0" : 5.474007785023183 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 5.354418757268614, + 5.194312458985413 + ], + [ + 5.131591504423528, + 5.474007785023183 + ], + [ + 5.448773280627998, + 5.305461276121833 + ], + [ + 4.853473806617481, + 5.20472859261791 + ], + [ + 5.088690394104383, + 5.0637067825319475 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.probabilisticN400k16d02", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 3.629304527595204, + "scoreError" : 1.132757347058442, + "scoreConfidence" : [ + 2.496547180536762, + 4.762061874653646 + ], + "scorePercentiles" : { + "0.0" : 2.915559309920613, + "50.0" : 3.364772640443146, + "90.0" : 4.990571914894521, + "95.0" : 5.0300565133233714, + "99.0" : 5.0300565133233714, + "99.9" : 5.0300565133233714, + "99.99" : 5.0300565133233714, + "99.999" : 5.0300565133233714, + "99.9999" : 5.0300565133233714, + "100.0" : 5.0300565133233714 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 3.3260879136804467, + 3.403457367205845 + ], + [ + 3.2699226571259983, + 4.635210529034868 + ], + [ + 3.6596373110352705, + 2.915559309920613 + ], + [ + 5.0300565133233714, + 4.193119686256376 + ], + [ + 2.92811952830071, + 2.9318744600685447 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.probabilisticN400k80d01", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 11.919790589132187, + "scoreError" : 2.3040130587387164, + "scoreConfidence" : [ + 9.615777530393471, + 14.223803647870904 + ], + "scorePercentiles" : { + "0.0" : 9.277005723195174, + "50.0" : 12.138283342462927, + "90.0" : 13.607971145445818, + "95.0" : 13.623840845084036, + "99.0" : 13.623840845084036, + "99.9" : 13.623840845084036, + "99.99" : 13.623840845084036, + "99.999" : 13.623840845084036, + "99.9999" : 13.623840845084036, + "100.0" : 13.623840845084036 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 12.70028229987442, + 13.465143848701851 + ], + [ + 9.277005723195174, + 11.576284385051434 + ], + [ + 10.71207001794642, + 13.3336465184469 + ], + [ + 12.93772688522609, + 13.623840845084036 + ], + [ + 10.140269780101741, + 11.431635587693814 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.probabilisticN400k80d02", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 2, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 10.814951479430821, + "scoreError" : 1.6082721225126038, + "scoreConfidence" : [ + 9.206679356918217, + 12.423223601943425 + ], + "scorePercentiles" : { + "0.0" : 8.09518224087975, + "50.0" : 11.009162887282663, + "90.0" : 11.986930428051336, + "95.0" : 12.040319596025027, + "99.0" : 12.040319596025027, + "99.9" : 12.040319596025027, + "99.99" : 12.040319596025027, + "99.999" : 12.040319596025027, + "99.9999" : 12.040319596025027, + "100.0" : 12.040319596025027 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 11.409715740306465, + 10.62887792068522 + ], + [ + 11.220771101438357, + 12.040319596025027 + ], + [ + 10.549688373453217, + 8.09518224087975 + ], + [ + 10.797554673126971, + 11.506427916288116 + ], + [ + 11.221808921245392, + 10.679168310859689 + ] + ] + }, + "secondaryMetrics" : { + } + } +] + + diff --git a/tlatools/test-benchmark/tlc2/value/Randomization-1530090015-39e5e3b02.json b/tlatools/test-benchmark/tlc2/value/Randomization-1530090015-39e5e3b02.json new file mode 100644 index 0000000000000000000000000000000000000000..51e87eb6534dffee27aa39b6e1715157afc2df0c --- /dev/null +++ b/tlatools/test-benchmark/tlc2/value/Randomization-1530090015-39e5e3b02.json @@ -0,0 +1,2764 @@ +[ + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.exactN035K08", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 1097.4100006265485, + "scoreError" : 18.746172610480603, + "scoreConfidence" : [ + 1078.6638280160678, + 1116.1561732370292 + ], + "scorePercentiles" : { + "0.0" : 1070.9852942694877, + "50.0" : 1097.1172671563727, + "90.0" : 1117.9515997728565, + "95.0" : 1118.5004689143204, + "99.0" : 1118.5004689143204, + "99.9" : 1118.5004689143204, + "99.99" : 1118.5004689143204, + "99.999" : 1118.5004689143204, + "99.9999" : 1118.5004689143204, + "100.0" : 1118.5004689143204 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 1113.7826718183462, + 1113.2646305679596, + 1114.9188538486044 + ], + [ + 1084.917793753047, + 1084.299986018495, + 1079.464182047453 + ], + [ + 1070.9852942694877, + 1075.1616840185263, + 1078.1363993743855 + ], + [ + 1096.1524577709054, + 1097.1172671563727, + 1099.277463166022 + ], + [ + 1117.585169662422, + 1118.5004689143204, + 1117.5856870118807 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.exactN035K13", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 1034.2552716486327, + "scoreError" : 27.35169469851862, + "scoreConfidence" : [ + 1006.9035769501141, + 1061.6069663471515 + ], + "scorePercentiles" : { + "0.0" : 1005.3538384051334, + "50.0" : 1022.6534180179567, + "90.0" : 1067.0820977406106, + "95.0" : 1068.458879600175, + "99.0" : 1068.458879600175, + "99.9" : 1068.458879600175, + "99.99" : 1068.458879600175, + "99.999" : 1068.458879600175, + "99.9999" : 1068.458879600175, + "100.0" : 1068.458879600175 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 1066.1642431675677, + 1063.3273758617393, + 1068.458879600175 + ], + [ + 1062.2765573564798, + 1061.573347389188, + 1061.5603793273897 + ], + [ + 1010.1720467924506, + 1015.693698660016, + 1005.3538384051334 + ], + [ + 1015.2201321834501, + 1025.303876739694, + 1022.6534180179567 + ], + [ + 1015.886233836108, + 1007.6578509270264, + 1012.5271964651157 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.exactN035K208", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 502.66124243720077, + "scoreError" : 10.614974423466029, + "scoreConfidence" : [ + 492.04626801373473, + 513.2762168606668 + ], + "scorePercentiles" : { + "0.0" : 489.5148473340847, + "50.0" : 500.4178505896733, + "90.0" : 518.1309761542769, + "95.0" : 520.3806131370512, + "99.0" : 520.3806131370512, + "99.9" : 520.3806131370512, + "99.99" : 520.3806131370512, + "99.999" : 520.3806131370512, + "99.9999" : 520.3806131370512, + "100.0" : 520.3806131370512 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 510.77485406637885, + 505.81162738513854, + 509.07757893513616 + ], + [ + 493.85353690685673, + 504.07730401905195, + 500.4178505896733 + ], + [ + 493.85940376784185, + 489.5148473340847, + 493.74139475743834 + ], + [ + 516.6312181657607, + 515.8472703403316, + 520.3806131370512 + ], + [ + 495.2043172055357, + 493.9980281156843, + 496.7287918320494 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.exactN035K213", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 462.0258729311534, + "scoreError" : 7.877473468365682, + "scoreConfidence" : [ + 454.1483994627877, + 469.9033463995191 + ], + "scorePercentiles" : { + "0.0" : 449.2511741938684, + "50.0" : 460.48813319259403, + "90.0" : 474.1827113566221, + "95.0" : 476.19767792691187, + "99.0" : 476.19767792691187, + "99.9" : 476.19767792691187, + "99.99" : 476.19767792691187, + "99.999" : 476.19767792691187, + "99.9999" : 476.19767792691187, + "100.0" : 476.19767792691187 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 464.9046948760132, + 458.8498608215445, + 460.6953931107954 + ], + [ + 460.48813319259403, + 449.2511741938684, + 459.6366661583392 + ], + [ + 472.8394003097623, + 470.8250313809336, + 476.19767792691187 + ], + [ + 456.7541738807125, + 453.99886375051915, + 456.1469952817119 + ], + [ + 466.8236790826741, + 458.0855305153289, + 464.89081948559203 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.exactN060K08", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 1076.5566631329848, + "scoreError" : 22.991060050267603, + "scoreConfidence" : [ + 1053.5656030827172, + 1099.5477231832524 + ], + "scorePercentiles" : { + "0.0" : 1045.0955162635062, + "50.0" : 1075.3019088738981, + "90.0" : 1113.2633951944288, + "95.0" : 1113.6691955910264, + "99.0" : 1113.6691955910264, + "99.9" : 1113.6691955910264, + "99.99" : 1113.6691955910264, + "99.999" : 1113.6691955910264, + "99.9999" : 1113.6691955910264, + "100.0" : 1113.6691955910264 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 1112.992861596697, + 1113.6691955910264, + 1111.3041072898486 + ], + [ + 1045.0955162635062, + 1051.3772405221043, + 1048.4291300952746 + ], + [ + 1076.000070587678, + 1076.0625748128045, + 1071.5587553529267 + ], + [ + 1071.6859312258673, + 1068.3009730999265, + 1071.4440678427177 + ], + [ + 1075.3019088738981, + 1077.0246306759236, + 1078.1029831645724 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.exactN060K208", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 496.1030631646705, + "scoreError" : 3.512699094351389, + "scoreConfidence" : [ + 492.59036407031914, + 499.6157622590219 + ], + "scorePercentiles" : { + "0.0" : 491.43330033311906, + "50.0" : 494.94021411353697, + "90.0" : 501.88168312327156, + "95.0" : 502.1685014930431, + "99.0" : 502.1685014930431, + "99.9" : 502.1685014930431, + "99.99" : 502.1685014930431, + "99.999" : 502.1685014930431, + "99.9999" : 502.1685014930431, + "100.0" : 502.1685014930431 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 494.622303651207, + 495.90058307689736, + 492.580756602375 + ], + [ + 494.1116037743665, + 495.01071450868614, + 494.94021411353697 + ], + [ + 501.69047087675716, + 494.5425609152021, + 494.7138223319291 + ], + [ + 497.9790836860548, + 493.42693781498247, + 502.1685014930431 + ], + [ + 497.5099091980131, + 500.915185093889, + 491.43330033311906 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.exactN100K08", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 1006.1274789066429, + "scoreError" : 8.632240073484734, + "scoreConfidence" : [ + 997.4952388331582, + 1014.7597189801276 + ], + "scorePercentiles" : { + "0.0" : 994.5489507073092, + "50.0" : 1008.2208529988354, + "90.0" : 1016.7314568936902, + "95.0" : 1017.9323197373135, + "99.0" : 1017.9323197373135, + "99.9" : 1017.9323197373135, + "99.99" : 1017.9323197373135, + "99.999" : 1017.9323197373135, + "99.9999" : 1017.9323197373135, + "100.0" : 1017.9323197373135 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 1011.4325473447026, + 1012.3943441117173, + 1012.0558392628138 + ], + [ + 999.2841855514707, + 994.5489507073092, + 996.9796561999148 + ], + [ + 997.8109211825629, + 999.1303362912394, + 995.8581509199988 + ], + [ + 1008.7552140583837, + 1006.7978351857138, + 1008.2208529988354 + ], + [ + 1015.930881664608, + 1017.9323197373135, + 1014.7801483830583 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.exactN100K10", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 970.6587710396896, + "scoreError" : 16.366794132058363, + "scoreConfidence" : [ + 954.2919769076312, + 987.0255651717479 + ], + "scorePercentiles" : { + "0.0" : 952.0599711325602, + "50.0" : 975.4598238934245, + "90.0" : 993.2203947074937, + "95.0" : 993.9927256858603, + "99.0" : 993.9927256858603, + "99.9" : 993.9927256858603, + "99.99" : 993.9927256858603, + "99.999" : 993.9927256858603, + "99.9999" : 993.9927256858603, + "100.0" : 993.9927256858603 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 978.8544718524862, + 975.9496048189004, + 976.2882003954288 + ], + [ + 955.7626937786133, + 953.4614389039157, + 952.0599711325602 + ], + [ + 989.752017782688, + 993.9927256858603, + 992.7055073885828 + ], + [ + 975.4598238934245, + 974.8941100428519, + 977.6110691282292 + ], + [ + 952.6560927866482, + 953.5554874785408, + 956.8783505266105 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.exactN100K208", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 471.55749301741713, + "scoreError" : 18.06646722720142, + "scoreConfidence" : [ + 453.4910257902157, + 489.62396024461856 + ], + "scorePercentiles" : { + "0.0" : 444.2461877774847, + "50.0" : 478.64697777245993, + "90.0" : 488.6964600347632, + "95.0" : 489.07127104849866, + "99.0" : 489.07127104849866, + "99.9" : 489.07127104849866, + "99.99" : 489.07127104849866, + "99.999" : 489.07127104849866, + "99.9999" : 489.07127104849866, + "100.0" : 489.07127104849866 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 462.6847861327774, + 461.33662119031106, + 461.9008743593246 + ], + [ + 485.7371925332991, + 487.93614870638663, + 487.1728144213904 + ], + [ + 478.7600319803987, + 478.64697777245993, + 475.73798730951023 + ], + [ + 444.4951556999079, + 444.99416499519276, + 444.2461877774847 + ], + [ + 488.4465860256062, + 489.07127104849866, + 482.19559530870873 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.exactN100K210", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 463.27979318017736, + "scoreError" : 2.738923148411572, + "scoreConfidence" : [ + 460.5408700317658, + 466.01871632858894 + ], + "scorePercentiles" : { + "0.0" : 455.0503335926937, + "50.0" : 463.59813051170687, + "90.0" : 465.5939719156776, + "95.0" : 465.6217761333669, + "99.0" : 465.6217761333669, + "99.9" : 465.6217761333669, + "99.99" : 465.6217761333669, + "99.999" : 465.6217761333669, + "99.9999" : 465.6217761333669, + "100.0" : 465.6217761333669 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 462.9965879231482, + 464.76841742491064, + 464.03749327877694 + ], + [ + 464.54349294814807, + 464.7117517675539, + 463.3785963327552 + ], + [ + 463.59813051170687, + 461.82233064366426, + 463.4625924577529 + ], + [ + 461.94882832573154, + 462.7852470345038, + 455.0503335926937 + ], + [ + 464.8958835573962, + 465.6217761333669, + 465.57543577055145 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.exactN200K10", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 989.5388634227542, + "scoreError" : 14.134596639039657, + "scoreConfidence" : [ + 975.4042667837145, + 1003.6734600617938 + ], + "scorePercentiles" : { + "0.0" : 961.1299197289487, + "50.0" : 994.9023644719024, + "90.0" : 1001.4687219332199, + "95.0" : 1002.1899328794412, + "99.0" : 1002.1899328794412, + "99.9" : 1002.1899328794412, + "99.99" : 1002.1899328794412, + "99.999" : 1002.1899328794412, + "99.9999" : 1002.1899328794412, + "100.0" : 1002.1899328794412 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 1002.1899328794412, + 1000.987914635739, + 999.3257493472246 + ], + [ + 994.0756147113772, + 992.0096401293727, + 983.5593316535548 + ], + [ + 969.9189180491841, + 961.1299197289487, + 965.7159429222877 + ], + [ + 997.4301681073473, + 997.2109925387504, + 993.5771423426628 + ], + [ + 996.0496049913994, + 994.9023644719024, + 994.9997148321199 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.exactN200K210", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 446.7645512891926, + "scoreError" : 5.442536243476984, + "scoreConfidence" : [ + 441.3220150457156, + 452.20708753266956 + ], + "scorePercentiles" : { + "0.0" : 439.7788610749823, + "50.0" : 444.6941886476842, + "90.0" : 454.3681767298469, + "95.0" : 455.1577951726488, + "99.0" : 455.1577951726488, + "99.9" : 455.1577951726488, + "99.99" : 455.1577951726488, + "99.999" : 455.1577951726488, + "99.9999" : 455.1577951726488, + "100.0" : 455.1577951726488 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 442.536439675751, + 442.1295516755243, + 443.61230124071636 + ], + [ + 441.93263323460167, + 443.15368820445184, + 439.7788610749823 + ], + [ + 451.37913040998745, + 453.119744620769, + 455.1577951726488 + ], + [ + 445.3849374919964, + 443.67885909223224, + 444.6941886476842 + ], + [ + 449.5295117305883, + 453.8417644346456, + 451.5388626313101 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.exactN300K09", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 954.5732192493725, + "scoreError" : 5.551621199499133, + "scoreConfidence" : [ + 949.0215980498734, + 960.1248404488716 + ], + "scorePercentiles" : { + "0.0" : 945.3720405703026, + "50.0" : 953.6524108444851, + "90.0" : 962.1200566980764, + "95.0" : 962.5669852462835, + "99.0" : 962.5669852462835, + "99.9" : 962.5669852462835, + "99.99" : 962.5669852462835, + "99.999" : 962.5669852462835, + "99.9999" : 962.5669852462835, + "100.0" : 962.5669852462835 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 954.1688926211596, + 945.3720405703026, + 950.2428738759257 + ], + [ + 962.5669852462835, + 957.7397409724297, + 961.2017714264199 + ], + [ + 953.6524108444851, + 947.3565151947821, + 951.9325767720046 + ], + [ + 952.9053707672446, + 952.9197918501438, + 951.4168492777303 + ], + [ + 955.5011769209501, + 961.822104332605, + 959.7991880681216 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.exactN300K209", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 450.89503297404093, + "scoreError" : 12.138825735933237, + "scoreConfidence" : [ + 438.7562072381077, + 463.03385870997414 + ], + "scorePercentiles" : { + "0.0" : 435.72432879783145, + "50.0" : 454.37173618852, + "90.0" : 462.3558539284659, + "95.0" : 462.8919887974014, + "99.0" : 462.8919887974014, + "99.9" : 462.8919887974014, + "99.99" : 462.8919887974014, + "99.999" : 462.8919887974014, + "99.9999" : 462.8919887974014, + "100.0" : 462.8919887974014 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 462.8919887974014, + 461.99843068250885, + 460.4487856098874 + ], + [ + 436.09229699373617, + 435.73679679316433, + 435.72432879783145 + ], + [ + 457.9076168075443, + 454.37173618852, + 453.84531942745616 + ], + [ + 461.18430422993384, + 461.55135982783224, + 461.21794818436797 + ], + [ + 439.49132061780773, + 436.9753218138549, + 443.98793983876783 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.exactN400K09", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 983.4090697829313, + "scoreError" : 20.353875245485536, + "scoreConfidence" : [ + 963.0551945374458, + 1003.7629450284168 + ], + "scorePercentiles" : { + "0.0" : 961.3544835692653, + "50.0" : 986.8900359941699, + "90.0" : 1014.0635900707392, + "95.0" : 1015.3218017992034, + "99.0" : 1015.3218017992034, + "99.9" : 1015.3218017992034, + "99.99" : 1015.3218017992034, + "99.999" : 1015.3218017992034, + "99.9999" : 1015.3218017992034, + "100.0" : 1015.3218017992034 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 1013.2247822517631, + 1008.5224693030892, + 1015.3218017992034 + ], + [ + 963.6600003262133, + 961.3544835692653, + 964.2604725503714 + ], + [ + 964.255848325267, + 963.6935738628946, + 965.7504960556753 + ], + [ + 982.4583162785699, + 986.8900359941699, + 990.323392540617 + ], + [ + 987.3693459858683, + 991.2407062635492, + 992.8103216374556 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.exactN400K209", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 451.1764672222263, + "scoreError" : 2.545263432265774, + "scoreConfidence" : [ + 448.6312037899605, + 453.72173065449203 + ], + "scorePercentiles" : { + "0.0" : 446.6593536735987, + "50.0" : 452.20506456629676, + "90.0" : 453.91965046617594, + "95.0" : 454.35371900812015, + "99.0" : 454.35371900812015, + "99.9" : 454.35371900812015, + "99.99" : 454.35371900812015, + "99.999" : 454.35371900812015, + "99.9999" : 454.35371900812015, + "100.0" : 454.35371900812015 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 450.57287995912594, + 446.6593536735987, + 447.7813070872143 + ], + [ + 453.2936817739289, + 454.35371900812015, + 452.64494170279477 + ], + [ + 453.63027143821313, + 453.2989723622714, + 452.2870188343068 + ], + [ + 450.5136392458904, + 452.76369198433946, + 452.20506456629676 + ], + [ + 450.47627812762016, + 449.13553895483466, + 448.03064961483847 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.probabilisticN035k16d01", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 111.79662970943086, + "scoreError" : 0.7890127048293907, + "scoreConfidence" : [ + 111.00761700460147, + 112.58564241426025 + ], + "scorePercentiles" : { + "0.0" : 110.81792123675102, + "50.0" : 111.63634201501539, + "90.0" : 113.06924508737265, + "95.0" : 113.08224436332766, + "99.0" : 113.08224436332766, + "99.9" : 113.08224436332766, + "99.99" : 113.08224436332766, + "99.999" : 113.08224436332766, + "99.9999" : 113.08224436332766, + "100.0" : 113.08224436332766 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 111.29903017089258, + 111.42436747681585, + 111.63634201501539 + ], + [ + 111.00989580513003, + 110.93670869534073, + 110.81792123675102 + ], + [ + 111.52833563609899, + 112.1591021102084, + 111.1764979636141 + ], + [ + 112.36085370900122, + 112.05007826200827, + 111.78819153003603 + ], + [ + 113.06057890340264, + 112.61929776381965, + 113.08224436332766 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.probabilisticN035k16d02", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 89.7182022702618, + "scoreError" : 2.172963251231951, + "scoreConfidence" : [ + 87.54523901902985, + 91.89116552149375 + ], + "scorePercentiles" : { + "0.0" : 85.84200393117202, + "50.0" : 90.27090741911687, + "90.0" : 92.3810979004838, + "95.0" : 93.11756140139963, + "99.0" : 93.11756140139963, + "99.9" : 93.11756140139963, + "99.99" : 93.11756140139963, + "99.999" : 93.11756140139963, + "99.9999" : 93.11756140139963, + "100.0" : 93.11756140139963 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 85.84200393117202, + 89.1807854408291, + 90.27090741911687 + ], + [ + 87.3556755615599, + 88.79771050809072, + 88.51046955362463 + ], + [ + 91.55413764147796, + 91.89012223320658, + 93.11756140139963 + ], + [ + 86.51916283413281, + 90.98701469226555, + 90.52543821910433 + ], + [ + 90.98478201115844, + 89.75155479071478, + 90.48570781607357 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.probabilisticN035k80d01", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 202.3949374176122, + "scoreError" : 76.820246452902, + "scoreConfidence" : [ + 125.5746909647102, + 279.2151838705142 + ], + "scorePercentiles" : { + "0.0" : 62.533078280440755, + "50.0" : 236.98298162260488, + "90.0" : 238.04756155357592, + "95.0" : 238.44544251126433, + "99.0" : 238.44544251126433, + "99.9" : 238.44544251126433, + "99.99" : 238.44544251126433, + "99.999" : 238.44544251126433, + "99.9999" : 238.44544251126433, + "100.0" : 238.44544251126433 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 65.28482459982169, + 62.533078280440755, + 62.86501075965584 + ], + [ + 236.34452072668992, + 237.04304386424084, + 237.24788684662477 + ], + [ + 237.14014300559694, + 236.98298162260488, + 236.96093410427136 + ], + [ + 237.29981291785649, + 237.78230758178364, + 238.44544251126433 + ], + [ + 236.06974469885435, + 237.18346967861726, + 236.74086006585983 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.probabilisticN035k80d02", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 168.757445724798, + "scoreError" : 59.96352310536157, + "scoreConfidence" : [ + 108.79392261943644, + 228.72096883015956 + ], + "scorePercentiles" : { + "0.0" : 59.64677121868498, + "50.0" : 198.8785907076378, + "90.0" : 200.62793021114447, + "95.0" : 201.44893232158273, + "99.0" : 201.44893232158273, + "99.9" : 201.44893232158273, + "99.99" : 201.44893232158273, + "99.999" : 201.44893232158273, + "99.9999" : 201.44893232158273, + "100.0" : 201.44893232158273 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 199.59465968359842, + 198.8785907076378, + 201.44893232158273 + ], + [ + 185.05094006181417, + 181.90098450811843, + 184.69705621029397 + ], + [ + 198.1725657833017, + 199.40604617925544, + 200.0805954708523 + ], + [ + 200.07847647167017, + 199.12662121145598, + 199.65956416851796 + ], + [ + 61.03111129545997, + 62.58877057972579, + 59.64677121868498 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.probabilisticN060k16d01", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 41.88173804156052, + "scoreError" : 21.641052708911293, + "scoreConfidence" : [ + 20.240685332649225, + 63.52279075047181 + ], + "scorePercentiles" : { + "0.0" : 17.314578239882202, + "50.0" : 53.43711652682356, + "90.0" : 60.884092184012786, + "95.0" : 61.260559842110936, + "99.0" : 61.260559842110936, + "99.9" : 61.260559842110936, + "99.99" : 61.260559842110936, + "99.999" : 61.260559842110936, + "99.9999" : 61.260559842110936, + "100.0" : 61.260559842110936 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 59.33104684307764, + 59.53181275631804, + 53.43711652682356 + ], + [ + 17.80064132900073, + 18.55071640995103, + 18.58120889565767 + ], + [ + 58.03999543510948, + 53.4100942386382, + 58.052406438944026 + ], + [ + 17.85164062383314, + 18.333252045960474, + 17.314578239882202 + ], + [ + 60.63311374528069, + 56.097887252819845, + 61.260559842110936 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.probabilisticN060k16d02", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 36.56665003083814, + "scoreError" : 18.66373381114973, + "scoreConfidence" : [ + 17.90291621968841, + 55.23038384198787 + ], + "scorePercentiles" : { + "0.0" : 15.056264334102831, + "50.0" : 48.329605821660785, + "90.0" : 53.08653654903394, + "95.0" : 54.25752497444918, + "99.0" : 54.25752497444918, + "99.9" : 54.25752497444918, + "99.99" : 54.25752497444918, + "99.999" : 54.25752497444918, + "99.9999" : 54.25752497444918, + "100.0" : 54.25752497444918 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 52.30587759875711, + 50.89740808812191, + 48.490769953699825 + ], + [ + 16.81083935546008, + 15.564007832258609, + 16.39521871779643 + ], + [ + 16.733797362232355, + 15.516230446715122, + 15.056264334102831 + ], + [ + 50.11015442617881, + 48.329605821660785, + 48.684902971532644 + ], + [ + 47.545755585789614, + 54.25752497444918, + 51.80139299381688 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.probabilisticN060k80d01", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 78.2768276326478, + "scoreError" : 54.24124305658098, + "scoreConfidence" : [ + 24.035584576066817, + 132.51807068922878 + ], + "scorePercentiles" : { + "0.0" : 37.250187654772, + "50.0" : 38.96014368934481, + "90.0" : 139.48222343003533, + "95.0" : 140.34307206731017, + "99.0" : 140.34307206731017, + "99.9" : 140.34307206731017, + "99.99" : 140.34307206731017, + "99.999" : 140.34307206731017, + "99.9999" : 140.34307206731017, + "100.0" : 140.34307206731017 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 138.22101883517513, + 138.90832433851875, + 140.34307206731017 + ], + [ + 38.96014368934481, + 38.924566981836946, + 39.00455037162455 + ], + [ + 37.59438997098785, + 38.523063640560814, + 38.392137576295916 + ], + [ + 37.76841497596615, + 37.250187654772, + 37.936969239249734 + ], + [ + 136.21572250509894, + 137.9734908501482, + 138.13636179282656 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.probabilisticN060k80d02", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 124.03155340277755, + "scoreError" : 1.7041628682686132, + "scoreConfidence" : [ + 122.32739053450894, + 125.73571627104616 + ], + "scorePercentiles" : { + "0.0" : 121.03892315668844, + "50.0" : 123.98575598368575, + "90.0" : 126.25927433354428, + "95.0" : 127.84501521488984, + "99.0" : 127.84501521488984, + "99.9" : 127.84501521488984, + "99.99" : 127.84501521488984, + "99.999" : 127.84501521488984, + "99.9999" : 127.84501521488984, + "100.0" : 127.84501521488984 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 121.03892315668844, + 123.34968751497817, + 124.61003817070844 + ], + [ + 121.64343181005583, + 122.66636174264978, + 123.61521861057459 + ], + [ + 124.82761951845447, + 127.84501521488984, + 125.14647894863876 + ], + [ + 123.82364098353128, + 123.98575598368575, + 125.20211374598057 + ], + [ + 123.9664162877595, + 124.33974867593705, + 124.4128506771307 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.probabilisticN100k16d01", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 17.21948547671312, + "scoreError" : 9.768385836056055, + "scoreConfidence" : [ + 7.451099640657066, + 26.987871312769176 + ], + "scorePercentiles" : { + "0.0" : 9.531255528831748, + "50.0" : 10.471563319670624, + "90.0" : 28.820521988121587, + "95.0" : 29.828117035381403, + "99.0" : 29.828117035381403, + "99.9" : 29.828117035381403, + "99.99" : 29.828117035381403, + "99.999" : 29.828117035381403, + "99.9999" : 29.828117035381403, + "100.0" : 29.828117035381403 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 10.483362539127844, + 9.531255528831748, + 10.094349529554583 + ], + [ + 27.621117396416544, + 29.828117035381403, + 27.994409180320012 + ], + [ + 10.471563319670624, + 10.1331220370504, + 10.318472291948353 + ], + [ + 9.595252849157111, + 9.769539562772682, + 9.869845681337562 + ], + [ + 27.205193467975715, + 27.227889774537143, + 28.148791956615042 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.probabilisticN100k16d02", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 18.464359867970856, + "scoreError" : 8.311327421577667, + "scoreConfidence" : [ + 10.153032446393189, + 26.77568728954852 + ], + "scorePercentiles" : { + "0.0" : 8.229146693738992, + "50.0" : 22.49167287956409, + "90.0" : 25.804821887916685, + "95.0" : 25.829650222260966, + "99.0" : 25.829650222260966, + "99.9" : 25.829650222260966, + "99.99" : 25.829650222260966, + "99.999" : 25.829650222260966, + "99.9999" : 25.829650222260966, + "100.0" : 25.829650222260966 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 9.527894173773607, + 9.818854530996784, + 9.154779599286208 + ], + [ + 25.654878365292156, + 24.834351265024267, + 24.59512253294589 + ], + [ + 22.156172311251122, + 25.788269665020497, + 25.360154295341367 + ], + [ + 9.595702277507995, + 8.229146693738992, + 9.828474154678585 + ], + [ + 22.49167287956409, + 24.100275052880303, + 25.829650222260966 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.probabilisticN100k80d01", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 72.49527604120003, + "scoreError" : 28.035411213750177, + "scoreConfidence" : [ + 44.45986482744985, + 100.53068725495021 + ], + "scorePercentiles" : { + "0.0" : 21.47265569784971, + "50.0" : 84.75581903533245, + "90.0" : 86.00899397831984, + "95.0" : 86.22436713282667, + "99.0" : 86.22436713282667, + "99.9" : 86.22436713282667, + "99.99" : 86.22436713282667, + "99.999" : 86.22436713282667, + "99.9999" : 86.22436713282667, + "100.0" : 86.22436713282667 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 86.22436713282667, + 84.75581903533245, + 85.7171555039946 + ], + [ + 85.26646896110239, + 84.6158681141584, + 84.5742491024965 + ], + [ + 21.47265569784971, + 22.16855145680661, + 21.906505925320847 + ], + [ + 85.72688693918556, + 85.86541187531529, + 85.72165739057459 + ], + [ + 82.97022991080364, + 85.83572145510848, + 84.60759211712481 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.probabilisticN100k80d02", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 75.76316076457995, + "scoreError" : 1.08734402016124, + "scoreConfidence" : [ + 74.67581674441871, + 76.85050478474119 + ], + "scorePercentiles" : { + "0.0" : 74.6818791597644, + "50.0" : 75.48095324431024, + "90.0" : 77.58887233782316, + "95.0" : 77.83464678924264, + "99.0" : 77.83464678924264, + "99.9" : 77.83464678924264, + "99.99" : 77.83464678924264, + "99.999" : 77.83464678924264, + "99.9999" : 77.83464678924264, + "100.0" : 77.83464678924264 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 75.48095324431024, + 77.09733152820617, + 75.17226414701386 + ], + [ + 75.31666545428482, + 77.4250227035435, + 77.83464678924264 + ], + [ + 74.6818791597644, + 75.11506337121622, + 74.77331452668341 + ], + [ + 75.4896030608472, + 75.8044221987372, + 76.70930150903817 + ], + [ + 74.81801152854665, + 74.9970337339526, + 75.7318985133122 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.probabilisticN200k16d01", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 13.476450163931311, + "scoreError" : 1.2896892083531966, + "scoreConfidence" : [ + 12.186760955578114, + 14.766139372284508 + ], + "scorePercentiles" : { + "0.0" : 11.671607189080921, + "50.0" : 13.469265986649162, + "90.0" : 15.118259520342173, + "95.0" : 15.163268753626065, + "99.0" : 15.163268753626065, + "99.9" : 15.163268753626065, + "99.99" : 15.163268753626065, + "99.999" : 15.163268753626065, + "99.9999" : 15.163268753626065, + "100.0" : 15.163268753626065 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 12.058133062196317, + 15.163268753626065, + 13.960561231856634 + ], + [ + 13.469265986649162, + 11.671607189080921, + 14.865003799454195 + ], + [ + 14.064668471493432, + 13.87572764864681, + 15.088253364819579 + ], + [ + 13.346198109882147, + 12.974736022371665, + 11.874707898705099 + ], + [ + 12.066633708048501, + 14.81302882386872, + 12.85495838827039 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.probabilisticN200k16d02", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 8.792444933870911, + "scoreError" : 3.804202494942238, + "scoreConfidence" : [ + 4.988242438928673, + 12.59664742881315 + ], + "scorePercentiles" : { + "0.0" : 4.149665279641244, + "50.0" : 10.400189052702512, + "90.0" : 12.909168961085117, + "95.0" : 13.298437179178826, + "99.0" : 13.298437179178826, + "99.9" : 13.298437179178826, + "99.99" : 13.298437179178826, + "99.999" : 13.298437179178826, + "99.9999" : 13.298437179178826, + "100.0" : 13.298437179178826 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 10.997988780122506, + 12.649656815689308, + 10.9454950321249 + ], + [ + 11.912332925901623, + 10.922879908100002, + 10.400189052702512 + ], + [ + 5.078954968203786, + 4.995431022633059, + 4.759604131263156 + ], + [ + 12.264762086331977, + 10.292533184425917, + 13.298437179178826 + ], + [ + 4.149665279641244, + 4.158323207461708, + 5.060420434283126 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.probabilisticN200k80d01", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 33.37684670457286, + "scoreError" : 1.1565852491337936, + "scoreConfidence" : [ + 32.22026145543907, + 34.53343195370665 + ], + "scorePercentiles" : { + "0.0" : 31.472270538496055, + "50.0" : 33.10015327046203, + "90.0" : 35.2133249446947, + "95.0" : 35.863345731220264, + "99.0" : 35.863345731220264, + "99.9" : 35.863345731220264, + "99.99" : 35.863345731220264, + "99.999" : 35.863345731220264, + "99.9999" : 35.863345731220264, + "100.0" : 35.863345731220264 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 33.10015327046203, + 32.89648344373738, + 33.39307641332626 + ], + [ + 32.867732424665064, + 32.68752414839513, + 34.38295008974919 + ], + [ + 32.74220812187432, + 32.84528659957435, + 33.70332732200391 + ], + [ + 32.280178487772815, + 33.52977072059713, + 35.863345731220264 + ], + [ + 31.472270538496055, + 34.779977753677656, + 34.10841550304143 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.probabilisticN200k80d02", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 30.151335851401438, + "scoreError" : 1.378331339199239, + "scoreConfidence" : [ + 28.7730045122022, + 31.529667190600676 + ], + "scorePercentiles" : { + "0.0" : 27.54284438702816, + "50.0" : 30.65998212492608, + "90.0" : 31.717771399770445, + "95.0" : 31.923578454605742, + "99.0" : 31.923578454605742, + "99.9" : 31.923578454605742, + "99.99" : 31.923578454605742, + "99.999" : 31.923578454605742, + "99.9999" : 31.923578454605742, + "100.0" : 31.923578454605742 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 29.596739267682036, + 30.941198236266363, + 31.011414237193954 + ], + [ + 30.65998212492608, + 28.831923022843988, + 31.580566696546914 + ], + [ + 27.54284438702816, + 31.105304347233353, + 31.923578454605742 + ], + [ + 30.77385159749443, + 31.16622091259212, + 30.311370773497615 + ], + [ + 28.27503088694388, + 28.95587964045146, + 29.594133185715393 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.probabilisticN300k16d01", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 7.61875429536946, + "scoreError" : 2.4566164405898365, + "scoreConfidence" : [ + 5.162137854779623, + 10.075370735959297 + ], + "scorePercentiles" : { + "0.0" : 3.144677802002079, + "50.0" : 8.745904272573547, + "90.0" : 8.89636638544586, + "95.0" : 8.903701335626923, + "99.0" : 8.903701335626923, + "99.9" : 8.903701335626923, + "99.99" : 8.903701335626923, + "99.999" : 8.903701335626923, + "99.9999" : 8.903701335626923, + "100.0" : 8.903701335626923 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 8.503088573991551, + 8.773988239024698, + 8.76367514142568 + ], + [ + 8.600631378190974, + 8.745904272573547, + 8.76158497674196 + ], + [ + 3.1969390106546505, + 3.144677802002079, + 3.2170094933240767 + ], + [ + 8.891476418658485, + 8.720486419629784, + 8.418913150443379 + ], + [ + 8.863072431677601, + 8.776165786576518, + 8.903701335626923 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.probabilisticN300k16d02", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 6.365052802025193, + "scoreError" : 1.930732054854557, + "scoreConfidence" : [ + 4.434320747170636, + 8.29578485687975 + ], + "scorePercentiles" : { + "0.0" : 2.7971553338224524, + "50.0" : 7.135663135428521, + "90.0" : 7.683754720951823, + "95.0" : 7.7332392258994584, + "99.0" : 7.7332392258994584, + "99.9" : 7.7332392258994584, + "99.99" : 7.7332392258994584, + "99.999" : 7.7332392258994584, + "99.9999" : 7.7332392258994584, + "100.0" : 7.7332392258994584 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 2.9216825985770014, + 3.040284362761938, + 2.7971553338224524 + ], + [ + 7.341871035609219, + 6.498861914849152, + 6.985421065283115 + ], + [ + 7.135663135428521, + 7.27932326531456, + 7.650765050986733 + ], + [ + 7.145284940127866, + 7.3495945036029475, + 7.1173658579880925 + ], + [ + 7.7332392258994584, + 7.103607107321174, + 7.375672632805673 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.probabilisticN300k80d01", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 14.785894114222918, + "scoreError" : 7.075300736265591, + "scoreConfidence" : [ + 7.710593377957327, + 21.86119485048851 + ], + "scorePercentiles" : { + "0.0" : 6.6238101234689175, + "50.0" : 18.63405522824858, + "90.0" : 22.137903119219704, + "95.0" : 23.443478066734833, + "99.0" : 23.443478066734833, + "99.9" : 23.443478066734833, + "99.99" : 23.443478066734833, + "99.999" : 23.443478066734833, + "99.9999" : 23.443478066734833, + "100.0" : 23.443478066734833 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 20.81463482193428, + 21.26751982087628, + 18.63405522824858 + ], + [ + 6.6238101234689175, + 6.75658101722185, + 7.051271053910943 + ], + [ + 19.0767889149469, + 19.13286549864879, + 20.00862757999917 + ], + [ + 8.333342952466932, + 6.795686318602955, + 7.148169626132261 + ], + [ + 17.922511600530722, + 23.443478066734833, + 18.77906908962039 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.probabilisticN300k80d02", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 15.069645555892203, + "scoreError" : 4.995764307788415, + "scoreConfidence" : [ + 10.073881248103788, + 20.065409863680618 + ], + "scorePercentiles" : { + "0.0" : 6.525438308782814, + "50.0" : 15.836747387967138, + "90.0" : 19.861826612604133, + "95.0" : 21.353181774527926, + "99.0" : 21.353181774527926, + "99.9" : 21.353181774527926, + "99.99" : 21.353181774527926, + "99.999" : 21.353181774527926, + "99.9999" : 21.353181774527926, + "100.0" : 21.353181774527926 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 18.4972820712625, + 15.836747387967138, + 14.398722570118466 + ], + [ + 18.19260235832646, + 18.867589837988273, + 21.353181774527926 + ], + [ + 15.637367010115758, + 15.44904856502463, + 17.03452840674345 + ], + [ + 14.766921479727264, + 18.15860626837125, + 17.654420461003873 + ], + [ + 6.681110290356621, + 6.525438308782814, + 6.991116548066628 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.probabilisticN400k16d01", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 5.9353103682546475, + "scoreError" : 0.5290397619836832, + "scoreConfidence" : [ + 5.406270606270964, + 6.464350130238331 + ], + "scorePercentiles" : { + "0.0" : 4.878922326878594, + "50.0" : 6.054419632488941, + "90.0" : 6.527640940958293, + "95.0" : 6.597539744033696, + "99.0" : 6.597539744033696, + "99.9" : 6.597539744033696, + "99.99" : 6.597539744033696, + "99.999" : 6.597539744033696, + "99.9999" : 6.597539744033696, + "100.0" : 6.597539744033696 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 6.054419632488941, + 6.4116396040170525, + 5.328226475687357 + ], + [ + 6.144454845608136, + 6.481041738908025, + 6.004152066541914 + ], + [ + 4.878922326878594, + 6.3474334083378565, + 6.2586295143444 + ], + [ + 5.515362412224871, + 5.55586134418077, + 6.14224253754926 + ], + [ + 5.903052458531737, + 5.406677414487111, + 6.597539744033696 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.probabilisticN400k16d02", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 4.673432502837802, + "scoreError" : 1.552878455432352, + "scoreConfidence" : [ + 3.1205540474054496, + 6.226310958270154 + ], + "scorePercentiles" : { + "0.0" : 2.181545141685607, + "50.0" : 5.214889853823411, + "90.0" : 6.017274704916607, + "95.0" : 6.1166478430723, + "99.0" : 6.1166478430723, + "99.9" : 6.1166478430723, + "99.99" : 6.1166478430723, + "99.999" : 6.1166478430723, + "99.9999" : 6.1166478430723, + "100.0" : 6.1166478430723 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 5.856509945420771, + 5.737826324730627, + 5.771332586433917 + ], + [ + 2.181545141685607, + 2.229206724090047, + 2.3084518606427173 + ], + [ + 5.951025946146145, + 5.214889853823411, + 5.886929566087091 + ], + [ + 4.427686276216721, + 3.8137970569954778, + 4.275272285428256 + ], + [ + 6.1166478430723, + 4.422922211435889, + 5.907443920358064 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.probabilisticN400k80d01", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 14.191716644777708, + "scoreError" : 1.1430000694377032, + "scoreConfidence" : [ + 13.048716575340006, + 15.33471671421541 + ], + "scorePercentiles" : { + "0.0" : 11.917408845733258, + "50.0" : 13.958179722702921, + "90.0" : 15.837807319547421, + "95.0" : 17.105871806738772, + "99.0" : 17.105871806738772, + "99.9" : 17.105871806738772, + "99.99" : 17.105871806738772, + "99.999" : 17.105871806738772, + "99.9999" : 17.105871806738772, + "100.0" : 17.105871806738772 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 14.992430994753187, + 14.017956171834632, + 13.770044082590667 + ], + [ + 14.736605508795641, + 14.292851076013473, + 13.791605869593202 + ], + [ + 14.608433896935244, + 17.105871806738772, + 13.643092918848009 + ], + [ + 14.530654082597914, + 13.85593344020735, + 13.958179722702921 + ], + [ + 11.917408845733258, + 13.822748519920893, + 13.83193273440047 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetValueBenchmark.probabilisticN400k80d02", + "mode" : "thrpt", + "threads" : 32, + "forks" : 5, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 2, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "primaryMetric" : { + "score" : 11.445924020087164, + "scoreError" : 0.7562865417460121, + "scoreConfidence" : [ + 10.689637478341151, + 12.202210561833176 + ], + "scorePercentiles" : { + "0.0" : 10.115188136208515, + "50.0" : 11.625739262267807, + "90.0" : 12.254490517068911, + "95.0" : 12.274847040996331, + "99.0" : 12.274847040996331, + "99.9" : 12.274847040996331, + "99.99" : 12.274847040996331, + "99.999" : 12.274847040996331, + "99.9999" : 12.274847040996331, + "100.0" : 12.274847040996331 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 11.041682048939798, + 10.72140891631031, + 11.713493275401389 + ], + [ + 12.274847040996331, + 11.99574212912567, + 11.424147706282449 + ], + [ + 12.227950081408531, + 12.15024855716867, + 10.115188136208515 + ], + [ + 11.625739262267807, + 12.240919501117297, + 11.246913457541167 + ], + [ + 10.355403568190786, + 10.814855595486414, + 11.740321024862308 + ] + ] + }, + "secondaryMetrics" : { + } + } +] + + diff --git a/tlatools/test-benchmark/tlc2/value/Randomization-1530276206-f9351808e.json b/tlatools/test-benchmark/tlc2/value/Randomization-1530276206-f9351808e.json new file mode 100644 index 0000000000000000000000000000000000000000..620024cfc1c2b143d7f3f404519e535020256760 --- /dev/null +++ b/tlatools/test-benchmark/tlc2/value/Randomization-1530276206-f9351808e.json @@ -0,0 +1,5480 @@ +[ + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.IntervalValueBenchmark.randomSubset", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "10", + "size" : "16" + }, + "primaryMetric" : { + "score" : 49640.96317575774, + "scoreError" : 5313.823551389228, + "scoreConfidence" : [ + 44327.13962436851, + 54954.786727146966 + ], + "scorePercentiles" : { + "0.0" : 45299.63022275939, + "50.0" : 51707.01294679341, + "90.0" : 51792.0525170781, + "95.0" : 51792.0525170781, + "99.0" : 51792.0525170781, + "99.9" : 51792.0525170781, + "99.99" : 51792.0525170781, + "99.999" : 51792.0525170781, + "99.9999" : 51792.0525170781, + "100.0" : 51792.0525170781 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 45530.88567814011, + 51764.47020165688, + 51757.65739578748 + ], + [ + 45446.34432145206, + 51792.0525170781, + 51766.0839096055 + ], + [ + 45299.63022275939, + 51707.01294679341, + 51704.53138854678 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.IntervalValueBenchmark.randomSubset", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "10", + "size" : "18" + }, + "primaryMetric" : { + "score" : 50092.47797235212, + "scoreError" : 5392.976153483466, + "scoreConfidence" : [ + 44699.50181886865, + 55485.45412583559 + ], + "scorePercentiles" : { + "0.0" : 45806.15583093199, + "50.0" : 52212.23315720261, + "90.0" : 52291.239598679516, + "95.0" : 52291.239598679516, + "99.0" : 52291.239598679516, + "99.9" : 52291.239598679516, + "99.99" : 52291.239598679516, + "99.999" : 52291.239598679516, + "99.9999" : 52291.239598679516, + "100.0" : 52291.239598679516 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 45818.19205297116, + 52231.680868925316, + 52221.134396231224 + ], + [ + 45806.15583093199, + 52291.239598679516, + 52237.194933707266 + ], + [ + 45816.40300074469, + 52212.23315720261, + 52198.06791177533 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.IntervalValueBenchmark.randomSubset", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "10", + "size" : "20" + }, + "primaryMetric" : { + "score" : 49990.28972514267, + "scoreError" : 5502.797921246911, + "scoreConfidence" : [ + 44487.491803895755, + 55493.087646389584 + ], + "scorePercentiles" : { + "0.0" : 45511.00241759965, + "50.0" : 52126.89606655572, + "90.0" : 52233.40400921543, + "95.0" : 52233.40400921543, + "99.0" : 52233.40400921543, + "99.9" : 52233.40400921543, + "99.99" : 52233.40400921543, + "99.999" : 52233.40400921543, + "99.9999" : 52233.40400921543, + "100.0" : 52233.40400921543 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 45511.00241759965, + 52233.40400921543, + 52205.53649296292 + ], + [ + 45667.504109107984, + 52124.212991879795, + 52126.89606655572 + ], + [ + 45696.077246698456, + 52170.13722017491, + 52177.83697208921 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.IntervalValueBenchmark.randomSubset", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "10", + "size" : "22" + }, + "primaryMetric" : { + "score" : 50193.049249178745, + "scoreError" : 5503.959207285861, + "scoreConfidence" : [ + 44689.09004189288, + 55697.00845646461 + ], + "scorePercentiles" : { + "0.0" : 45643.817888990605, + "50.0" : 52301.39674013717, + "90.0" : 52462.18236414704, + "95.0" : 52462.18236414704, + "99.0" : 52462.18236414704, + "99.9" : 52462.18236414704, + "99.99" : 52462.18236414704, + "99.999" : 52462.18236414704, + "99.9999" : 52462.18236414704, + "100.0" : 52462.18236414704 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 45892.976137266036, + 52462.18236414704, + 52453.20770855828 + ], + [ + 45643.817888990605, + 52291.433577618795, + 52301.39674013717 + ], + [ + 45947.118771708076, + 52390.05153155216, + 52355.258522630495 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.IntervalValueBenchmark.randomSubset", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "12", + "size" : "16" + }, + "primaryMetric" : { + "score" : 12388.472482181454, + "scoreError" : 1310.6534167783188, + "scoreConfidence" : [ + 11077.819065403135, + 13699.125898959774 + ], + "scorePercentiles" : { + "0.0" : 11285.266335573237, + "50.0" : 12834.514397250188, + "90.0" : 13044.637481341451, + "95.0" : 13044.637481341451, + "99.0" : 13044.637481341451, + "99.9" : 13044.637481341451, + "99.99" : 13044.637481341451, + "99.999" : 13044.637481341451, + "99.9999" : 13044.637481341451, + "100.0" : 13044.637481341451 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 11285.266335573237, + 12834.514397250188, + 12829.567077442836 + ], + [ + 11314.962513672499, + 12837.195838018031, + 12834.883987297198 + ], + [ + 11470.809031188168, + 13044.41567784948, + 13044.637481341451 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.IntervalValueBenchmark.randomSubset", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "12", + "size" : "18" + }, + "primaryMetric" : { + "score" : 12613.63279333138, + "scoreError" : 1320.2113558877807, + "scoreConfidence" : [ + 11293.4214374436, + 13933.844149219161 + ], + "scorePercentiles" : { + "0.0" : 11558.576256589442, + "50.0" : 13136.284044044995, + "90.0" : 13145.815445587406, + "95.0" : 13145.815445587406, + "99.0" : 13145.815445587406, + "99.9" : 13145.815445587406, + "99.99" : 13145.815445587406, + "99.999" : 13145.815445587406, + "99.9999" : 13145.815445587406, + "100.0" : 13145.815445587406 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 11562.562122602727, + 13121.216969485053, + 13142.682578357562 + ], + [ + 11577.397173511414, + 13136.564495516533, + 13145.815445587406 + ], + [ + 11558.576256589442, + 13136.284044044995, + 13141.596054287289 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.IntervalValueBenchmark.randomSubset", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "12", + "size" : "20" + }, + "primaryMetric" : { + "score" : 12767.277008962783, + "scoreError" : 1350.7430977066049, + "scoreConfidence" : [ + 11416.533911256178, + 14118.020106669388 + ], + "scorePercentiles" : { + "0.0" : 11673.125520204727, + "50.0" : 13293.226993436885, + "90.0" : 13322.824248316305, + "95.0" : 13322.824248316305, + "99.0" : 13322.824248316305, + "99.9" : 13322.824248316305, + "99.99" : 13322.824248316305, + "99.999" : 13322.824248316305, + "99.9999" : 13322.824248316305, + "100.0" : 13322.824248316305 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 11682.42453794474, + 13322.824248316305, + 13305.14901056783 + ], + [ + 11731.931211941232, + 13310.804851354042, + 13298.118294577689 + ], + [ + 11673.125520204727, + 13293.226993436885, + 13287.888412321618 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.IntervalValueBenchmark.randomSubset", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "12", + "size" : "22" + }, + "primaryMetric" : { + "score" : 12782.30988288717, + "scoreError" : 1349.2729930773378, + "scoreConfidence" : [ + 11433.036889809831, + 14131.582875964508 + ], + "scorePercentiles" : { + "0.0" : 11696.55425677517, + "50.0" : 13306.127044938077, + "90.0" : 13329.692162687668, + "95.0" : 13329.692162687668, + "99.0" : 13329.692162687668, + "99.9" : 13329.692162687668, + "99.99" : 13329.692162687668, + "99.999" : 13329.692162687668, + "99.9999" : 13329.692162687668, + "100.0" : 13329.692162687668 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 11708.654623917859, + 13323.82703106391, + 13314.724906111427 + ], + [ + 11730.355758753562, + 13329.692162687668, + 13326.110985122861 + ], + [ + 11696.55425677517, + 13304.742176614005, + 13306.127044938077 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.IntervalValueBenchmark.randomSubset", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "14", + "size" : "16" + }, + "primaryMetric" : { + "score" : 3093.1495929008024, + "scoreError" : 346.74835334135383, + "scoreConfidence" : [ + 2746.4012395594486, + 3439.897946242156 + ], + "scorePercentiles" : { + "0.0" : 2811.640231155538, + "50.0" : 3196.7520849762427, + "90.0" : 3250.545388604313, + "95.0" : 3250.545388604313, + "99.0" : 3250.545388604313, + "99.9" : 3250.545388604313, + "99.99" : 3250.545388604313, + "99.999" : 3250.545388604313, + "99.9999" : 3250.545388604313, + "100.0" : 3250.545388604313 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 2826.116998686077, + 3250.545388604313, + 3247.768020740325 + ], + [ + 2820.5627690430083, + 3196.28472878314, + 3196.7520849762427 + ], + [ + 2811.640231155538, + 3244.312320960192, + 3244.3637931583835 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.IntervalValueBenchmark.randomSubset", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "14", + "size" : "18" + }, + "primaryMetric" : { + "score" : 3122.0276611038216, + "scoreError" : 348.9807966037056, + "scoreConfidence" : [ + 2773.046864500116, + 3471.008457707527 + ], + "scorePercentiles" : { + "0.0" : 2843.861197248272, + "50.0" : 3225.4945702961986, + "90.0" : 3280.0974416640975, + "95.0" : 3280.0974416640975, + "99.0" : 3280.0974416640975, + "99.9" : 3280.0974416640975, + "99.99" : 3280.0974416640975, + "99.999" : 3280.0974416640975, + "99.9999" : 3280.0974416640975, + "100.0" : 3280.0974416640975 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 2843.861197248272, + 3225.4945702961986, + 3224.285841135945 + ], + [ + 2851.2312950983455, + 3280.0974416640975, + 3279.2880277145277 + ], + [ + 2844.767137452957, + 3275.2140152716156, + 3274.009424052435 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.IntervalValueBenchmark.randomSubset", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "14", + "size" : "20" + }, + "primaryMetric" : { + "score" : 3128.182505713841, + "scoreError" : 352.70588064925437, + "scoreConfidence" : [ + 2775.476625064586, + 3480.8883863630954 + ], + "scorePercentiles" : { + "0.0" : 2847.3938357080215, + "50.0" : 3266.4757342822227, + "90.0" : 3270.3027372924234, + "95.0" : 3270.3027372924234, + "99.0" : 3270.3027372924234, + "99.9" : 3270.3027372924234, + "99.99" : 3270.3027372924234, + "99.999" : 3270.3027372924234, + "99.9999" : 3270.3027372924234, + "100.0" : 3270.3027372924234 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 2849.4282134610653, + 3268.9208437052844, + 3268.7159804614453 + ], + [ + 2848.1879022834896, + 3268.6771978438255, + 3270.3027372924234 + ], + [ + 2847.3938357080215, + 3266.4757342822227, + 3265.5401063867894 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.IntervalValueBenchmark.randomSubset", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "14", + "size" : "22" + }, + "primaryMetric" : { + "score" : 3153.7636821728956, + "scoreError" : 348.28080992188865, + "scoreConfidence" : [ + 2805.482872251007, + 3502.0444920947843 + ], + "scorePercentiles" : { + "0.0" : 2872.890876914191, + "50.0" : 3291.3750004584786, + "90.0" : 3293.583354708205, + "95.0" : 3293.583354708205, + "99.0" : 3293.583354708205, + "99.9" : 3293.583354708205, + "99.99" : 3293.583354708205, + "99.999" : 3293.583354708205, + "99.9999" : 3293.583354708205, + "100.0" : 3293.583354708205 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 2881.1285187344015, + 3293.447094293651, + 3293.583354708205 + ], + [ + 2878.301292488309, + 3291.590790172244, + 3291.8708447988733 + ], + [ + 2872.890876914191, + 3289.685366987708, + 3291.3750004584786 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.IntervalValueBenchmark.randomSubset", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "16", + "size" : "16" + }, + "primaryMetric" : { + "score" : 754.1516892747499, + "scoreError" : 79.62590658677267, + "scoreConfidence" : [ + 674.5257826879772, + 833.7775958615225 + ], + "scorePercentiles" : { + "0.0" : 689.815108835357, + "50.0" : 785.5121091682423, + "90.0" : 786.1593997389693, + "95.0" : 786.1593997389693, + "99.0" : 786.1593997389693, + "99.9" : 786.1593997389693, + "99.99" : 786.1593997389693, + "99.999" : 786.1593997389693, + "99.9999" : 786.1593997389693, + "100.0" : 786.1593997389693 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 689.815108835357, + 785.5741258481343, + 785.7560041624466 + ], + [ + 691.9066761852858, + 785.3832547314797, + 785.5121091682423 + ], + [ + 691.2113743557514, + 786.0471504470823, + 786.1593997389693 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.IntervalValueBenchmark.randomSubset", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "16", + "size" : "18" + }, + "primaryMetric" : { + "score" : 755.2970915553086, + "scoreError" : 80.71289326564478, + "scoreConfidence" : [ + 674.5841982896638, + 836.0099848209534 + ], + "scorePercentiles" : { + "0.0" : 689.3261645820087, + "50.0" : 787.1481893418177, + "90.0" : 787.4757133907947, + "95.0" : 787.4757133907947, + "99.0" : 787.4757133907947, + "99.9" : 787.4757133907947, + "99.99" : 787.4757133907947, + "99.999" : 787.4757133907947, + "99.9999" : 787.4757133907947, + "100.0" : 787.4757133907947 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 692.9483094744046, + 787.3657829481007, + 787.4757133907947 + ], + [ + 689.3261645820087, + 787.3677945014489, + 787.4191934017078 + ], + [ + 691.5283032251681, + 787.094373132326, + 787.1481893418177 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.IntervalValueBenchmark.randomSubset", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "16", + "size" : "20" + }, + "primaryMetric" : { + "score" : 762.6279992742304, + "scoreError" : 80.34724687095452, + "scoreConfidence" : [ + 682.2807524032759, + 842.975246145185 + ], + "scorePercentiles" : { + "0.0" : 697.3980478833844, + "50.0" : 794.3445633019713, + "90.0" : 795.0085959260741, + "95.0" : 795.0085959260741, + "99.0" : 795.0085959260741, + "99.9" : 795.0085959260741, + "99.99" : 795.0085959260741, + "99.999" : 795.0085959260741, + "99.9999" : 795.0085959260741, + "100.0" : 795.0085959260741 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 698.4229637307766, + 794.3445633019713, + 793.9489816526121 + ], + [ + 700.8456003388544, + 794.5945236436294, + 794.4315156786275 + ], + [ + 697.3980478833844, + 795.0085959260741, + 794.6572013121432 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.IntervalValueBenchmark.randomSubset", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "16", + "size" : "22" + }, + "primaryMetric" : { + "score" : 764.3750602448353, + "scoreError" : 80.68894396184207, + "scoreConfidence" : [ + 683.6861162829932, + 845.0640042066773 + ], + "scorePercentiles" : { + "0.0" : 699.7014110614892, + "50.0" : 796.2602155288497, + "90.0" : 796.5952973580177, + "95.0" : 796.5952973580177, + "99.0" : 796.5952973580177, + "99.9" : 796.5952973580177, + "99.99" : 796.5952973580177, + "99.999" : 796.5952973580177, + "99.9999" : 796.5952973580177, + "100.0" : 796.5952973580177 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 701.0430727080461, + 796.5131224765947, + 796.2602155288497 + ], + [ + 699.7014110614892, + 796.5952973580177, + 796.4591521020396 + ], + [ + 700.3195823264297, + 796.4214650040959, + 796.0622236379558 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SetEnumValueBenchmark.randomSubset", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "10", + "size" : "16" + }, + "primaryMetric" : { + "score" : 49502.210903830506, + "scoreError" : 2180.6384847775116, + "scoreConfidence" : [ + 47321.572419052995, + 51682.84938860802 + ], + "scorePercentiles" : { + "0.0" : 47655.33428821115, + "50.0" : 50230.826123322026, + "90.0" : 50501.60093043969, + "95.0" : 50501.60093043969, + "99.0" : 50501.60093043969, + "99.9" : 50501.60093043969, + "99.99" : 50501.60093043969, + "99.999" : 50501.60093043969, + "99.9999" : 50501.60093043969, + "100.0" : 50501.60093043969 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 50391.905166447745, + 47844.68146107775, + 50442.44941352523 + ], + [ + 50478.94781912993, + 47841.85382307288, + 50501.60093043969 + ], + [ + 50132.29910924824, + 47655.33428821115, + 50230.826123322026 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SetEnumValueBenchmark.randomSubset", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "10", + "size" : "18" + }, + "primaryMetric" : { + "score" : 43388.646770714564, + "scoreError" : 1824.0070133783458, + "scoreConfidence" : [ + 41564.63975733622, + 45212.65378409291 + ], + "scorePercentiles" : { + "0.0" : 41908.68208838806, + "50.0" : 44109.81981657809, + "90.0" : 44426.17983992118, + "95.0" : 44426.17983992118, + "99.0" : 44426.17983992118, + "99.9" : 44426.17983992118, + "99.99" : 44426.17983992118, + "99.999" : 44426.17983992118, + "99.9999" : 44426.17983992118, + "100.0" : 44426.17983992118 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 42959.98334772449, + 41908.68208838806, + 44426.17983992118 + ], + [ + 44146.3158770916, + 41945.847090831056, + 44231.11069648557 + ], + [ + 44109.81981657809, + 42362.86628906258, + 44407.0158903484 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SetEnumValueBenchmark.randomSubset", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "12", + "size" : "16" + }, + "primaryMetric" : { + "score" : 13073.928567644358, + "scoreError" : 455.0289758555767, + "scoreConfidence" : [ + 12618.89959178878, + 13528.957543499935 + ], + "scorePercentiles" : { + "0.0" : 12698.65628972352, + "50.0" : 13248.105996963992, + "90.0" : 13266.864886797623, + "95.0" : 13266.864886797623, + "99.0" : 13266.864886797623, + "99.9" : 13266.864886797623, + "99.99" : 13266.864886797623, + "99.999" : 13266.864886797623, + "99.9999" : 13266.864886797623, + "100.0" : 13266.864886797623 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 13249.94147626679, + 12718.420804415366, + 13246.593618380437 + ], + [ + 13264.846389306727, + 12698.65628972352, + 13266.864886797623 + ], + [ + 13248.105996963992, + 12722.25928141193, + 13249.668365532834 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SetEnumValueBenchmark.randomSubset", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "12", + "size" : "18" + }, + "primaryMetric" : { + "score" : 12501.577464061656, + "scoreError" : 444.6915074792037, + "scoreConfidence" : [ + 12056.885956582453, + 12946.26897154086 + ], + "scorePercentiles" : { + "0.0" : 12037.42229550993, + "50.0" : 12638.508815275294, + "90.0" : 12718.100722495303, + "95.0" : 12718.100722495303, + "99.0" : 12718.100722495303, + "99.9" : 12718.100722495303, + "99.99" : 12718.100722495303, + "99.999" : 12718.100722495303, + "99.9999" : 12718.100722495303, + "100.0" : 12718.100722495303 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 12718.100722495303, + 12228.434844498648, + 12710.659628481108 + ], + [ + 12689.742493400452, + 12224.186682821746, + 12716.142434180676 + ], + [ + 12550.999259891745, + 12037.42229550993, + 12638.508815275294 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SetEnumValueBenchmark.randomSubset", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "14", + "size" : "16" + }, + "primaryMetric" : { + "score" : 3284.772083671136, + "scoreError" : 81.60408630341242, + "scoreConfidence" : [ + 3203.1679973677237, + 3366.3761699745482 + ], + "scorePercentiles" : { + "0.0" : 3189.1372114368223, + "50.0" : 3277.284569032633, + "90.0" : 3329.641950984068, + "95.0" : 3329.641950984068, + "99.0" : 3329.641950984068, + "99.9" : 3329.641950984068, + "99.99" : 3329.641950984068, + "99.999" : 3329.641950984068, + "99.9999" : 3329.641950984068, + "100.0" : 3329.641950984068 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 3327.848346895691, + 3275.004005396584, + 3255.6325331662183 + ], + [ + 3329.641950984068, + 3277.284569032633, + 3251.9750289858857 + ], + [ + 3327.825256708278, + 3328.599850434049, + 3189.1372114368223 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SetEnumValueBenchmark.randomSubset", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "14", + "size" : "18" + }, + "primaryMetric" : { + "score" : 3230.6479624325852, + "scoreError" : 94.90664496969116, + "scoreConfidence" : [ + 3135.741317462894, + 3325.5546074022764 + ], + "scorePercentiles" : { + "0.0" : 3153.754348280746, + "50.0" : 3267.453613803697, + "90.0" : 3273.684632912715, + "95.0" : 3273.684632912715, + "99.0" : 3273.684632912715, + "99.9" : 3273.684632912715, + "99.99" : 3273.684632912715, + "99.999" : 3273.684632912715, + "99.9999" : 3273.684632912715, + "100.0" : 3273.684632912715 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 3273.684632912715, + 3153.754348280746, + 3267.453613803697 + ], + [ + 3258.1025910932767, + 3156.428497056323, + 3271.285152033579 + ], + [ + 3267.8386497664164, + 3156.5328019876342, + 3270.7513749588757 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SetEnumValueBenchmark.randomSubset", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "16", + "size" : "16" + }, + "primaryMetric" : { + "score" : 823.4316998112048, + "scoreError" : 25.939794171726785, + "scoreConfidence" : [ + 797.491905639478, + 849.3714939829316 + ], + "scorePercentiles" : { + "0.0" : 802.397710235852, + "50.0" : 833.5045147381396, + "90.0" : 834.2711558096636, + "95.0" : 834.2711558096636, + "99.0" : 834.2711558096636, + "99.9" : 834.2711558096636, + "99.99" : 834.2711558096636, + "99.999" : 834.2711558096636, + "99.9999" : 834.2711558096636, + "100.0" : 834.2711558096636 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 833.3595645394191, + 833.7893620355246, + 803.4402352532005 + ], + [ + 833.5045147381396, + 833.6484430823392, + 802.7288730250546 + ], + [ + 833.7454395816497, + 834.2711558096636, + 802.397710235852 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SetEnumValueBenchmark.randomSubset", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "16", + "size" : "18" + }, + "primaryMetric" : { + "score" : 809.6322316499339, + "scoreError" : 16.253938423035617, + "scoreConfidence" : [ + 793.3782932268983, + 825.8861700729695 + ], + "scorePercentiles" : { + "0.0" : 796.0190033616673, + "50.0" : 811.8755776600925, + "90.0" : 819.4075214305818, + "95.0" : 819.4075214305818, + "99.0" : 819.4075214305818, + "99.9" : 819.4075214305818, + "99.99" : 819.4075214305818, + "99.999" : 819.4075214305818, + "99.9999" : 819.4075214305818, + "100.0" : 819.4075214305818 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 818.5031196447524, + 798.4081991109515, + 810.7415320198564 + ], + [ + 819.4075214305818, + 797.8467244104413, + 811.8755776600925 + ], + [ + 819.2693405867176, + 796.0190033616673, + 814.619066624345 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SetOfFcnsBenchmark.randomSubset", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "10", + "sizeS" : "8", + "sizeT" : "16" + }, + "primaryMetric" : { + "score" : 647.1867941761544, + "scoreError" : 3.7818910980181824, + "scoreConfidence" : [ + 643.4049030781363, + 650.9686852741726 + ], + "scorePercentiles" : { + "0.0" : 644.213016835251, + "50.0" : 647.9407506823107, + "90.0" : 649.5076908495989, + "95.0" : 649.5076908495989, + "99.0" : 649.5076908495989, + "99.9" : 649.5076908495989, + "99.99" : 649.5076908495989, + "99.999" : 649.5076908495989, + "99.9999" : 649.5076908495989, + "100.0" : 649.5076908495989 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 647.9407506823107, + 647.9116977621215, + 648.0067141135914 + ], + [ + 644.3013790717916, + 644.213016835251, + 644.3666218206417 + ], + [ + 649.2607806796373, + 649.1724957704467, + 649.5076908495989 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SetOfFcnsBenchmark.randomSubset", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "10", + "sizeS" : "16", + "sizeT" : "16" + }, + "primaryMetric" : { + "score" : 221.44655051938983, + "scoreError" : 13.909079062854891, + "scoreConfidence" : [ + 207.53747145653494, + 235.35562958224472 + ], + "scorePercentiles" : { + "0.0" : 204.8240311023435, + "50.0" : 224.0518031742482, + "90.0" : 228.35683319745365, + "95.0" : 228.35683319745365, + "99.0" : 228.35683319745365, + "99.9" : 228.35683319745365, + "99.99" : 228.35683319745365, + "99.999" : 228.35683319745365, + "99.9999" : 228.35683319745365, + "100.0" : 228.35683319745365 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 204.8240311023435, + 224.0518031742482, + 224.01327724454094 + ], + [ + 213.56829048978287, + 227.33864065781717, + 227.26232787518387 + ], + [ + 215.4858636393008, + 228.11788729383744, + 228.35683319745365 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SetOfFcnsBenchmark.randomSubset", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "10", + "sizeS" : "16", + "sizeT" : "32" + }, + "primaryMetric" : { + "score" : 222.37137540024008, + "scoreError" : 5.559984450616226, + "scoreConfidence" : [ + 216.81139094962387, + 227.9313598508563 + ], + "scorePercentiles" : { + "0.0" : 216.58675683600657, + "50.0" : 222.70165156756354, + "90.0" : 226.16307043469672, + "95.0" : 226.16307043469672, + "99.0" : 226.16307043469672, + "99.9" : 226.16307043469672, + "99.99" : 226.16307043469672, + "99.999" : 226.16307043469672, + "99.9999" : 226.16307043469672, + "100.0" : 226.16307043469672 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 216.58675683600657, + 224.1371309829792, + 224.10075995959227 + ], + [ + 220.35363962879737, + 226.1492340225272, + 226.16307043469672 + ], + [ + 218.4864923788299, + 222.66364279116806, + 222.70165156756354 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SetOfFcnsBenchmark.randomSubset", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "10", + "sizeS" : "46", + "sizeT" : "46" + }, + "primaryMetric" : { + "score" : 75.72740097592362, + "scoreError" : 3.4132048806359965, + "scoreConfidence" : [ + 72.31419609528761, + 79.14060585655962 + ], + "scorePercentiles" : { + "0.0" : 72.72645314188827, + "50.0" : 76.95022373203598, + "90.0" : 77.27206641844197, + "95.0" : 77.27206641844197, + "99.0" : 77.27206641844197, + "99.9" : 77.27206641844197, + "99.99" : 77.27206641844197, + "99.999" : 77.27206641844197, + "99.9999" : 77.27206641844197, + "100.0" : 77.27206641844197 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 72.94548866083792, + 76.9410767018892, + 76.98245623710076 + ], + [ + 73.43212452775425, + 76.95022373203598, + 77.03967211843509 + ], + [ + 72.72645314188827, + 77.27206641844197, + 77.25704724492914 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SetOfFcnsBenchmark.randomSubset", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "12", + "sizeS" : "8", + "sizeT" : "16" + }, + "primaryMetric" : { + "score" : 161.53980160918428, + "scoreError" : 1.870134697144832, + "scoreConfidence" : [ + 159.66966691203945, + 163.40993630632912 + ], + "scorePercentiles" : { + "0.0" : 159.03524580466686, + "50.0" : 161.70340128551297, + "90.0" : 162.49031781942435, + "95.0" : 162.49031781942435, + "99.0" : 162.49031781942435, + "99.9" : 162.49031781942435, + "99.99" : 162.49031781942435, + "99.999" : 162.49031781942435, + "99.9999" : 162.49031781942435, + "100.0" : 162.49031781942435 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 162.07445600022487, + 160.57583425222728, + 159.03524580466686 + ], + [ + 161.70340128551297, + 161.68507671480938, + 161.50123217365086 + ], + [ + 162.49031781942435, + 162.38764340457288, + 162.40500702756916 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SetOfFcnsBenchmark.randomSubset", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "12", + "sizeS" : "16", + "sizeT" : "16" + }, + "primaryMetric" : { + "score" : 53.46499347299082, + "scoreError" : 5.867414373810976, + "scoreConfidence" : [ + 47.597579099179846, + 59.33240784680179 + ], + "scorePercentiles" : { + "0.0" : 45.94204023414223, + "50.0" : 53.479703035485905, + "90.0" : 56.75676236356654, + "95.0" : 56.75676236356654, + "99.0" : 56.75676236356654, + "99.9" : 56.75676236356654, + "99.99" : 56.75676236356654, + "99.999" : 56.75676236356654, + "99.9999" : 56.75676236356654, + "100.0" : 56.75676236356654 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 45.94204023414223, + 53.36608236984878, + 53.34870923323005 + ], + [ + 53.479703035485905, + 56.75676236356654, + 56.74956202778669 + ], + [ + 50.30251209236314, + 55.63350741616807, + 55.60606248432599 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SetOfFcnsBenchmark.randomSubset", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "12", + "sizeS" : "16", + "sizeT" : "32" + }, + "primaryMetric" : { + "score" : 51.8439407388088, + "scoreError" : 4.484671845858238, + "scoreConfidence" : [ + 47.35926889295056, + 56.328612584667034 + ], + "scorePercentiles" : { + "0.0" : 47.27989289225459, + "50.0" : 53.492635674195995, + "90.0" : 53.757214799388535, + "95.0" : 53.757214799388535, + "99.0" : 53.757214799388535, + "99.9" : 53.757214799388535, + "99.99" : 53.757214799388535, + "99.999" : 53.757214799388535, + "99.9999" : 53.757214799388535, + "100.0" : 53.757214799388535 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 47.27989289225459, + 53.74038598329412, + 53.757214799388535 + ], + [ + 49.09660954034463, + 53.492635674195995, + 53.4736155993692 + ], + [ + 48.6573067020978, + 53.55710707161856, + 53.54069838671571 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SetOfFcnsBenchmark.randomSubset", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "12", + "sizeS" : "46", + "sizeT" : "46" + }, + "primaryMetric" : { + "score" : 18.90725915615425, + "scoreError" : 0.7804465567066122, + "scoreConfidence" : [ + 18.12681259944764, + 19.68770571286086 + ], + "scorePercentiles" : { + "0.0" : 18.083064307930712, + "50.0" : 19.14917876700788, + "90.0" : 19.249811875079445, + "95.0" : 19.249811875079445, + "99.0" : 19.249811875079445, + "99.9" : 19.249811875079445, + "99.99" : 19.249811875079445, + "99.999" : 19.249811875079445, + "99.9999" : 19.249811875079445, + "100.0" : 19.249811875079445 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 18.411711432236366, + 19.248074461825105, + 19.249811875079445 + ], + [ + 18.083064307930712, + 19.144228606307806, + 19.14917876700788 + ], + [ + 18.415538642092212, + 19.23014612115009, + 19.233578191758667 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SetOfFcnsBenchmark.randomSubset", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "14", + "sizeS" : "8", + "sizeT" : "16" + }, + "primaryMetric" : { + "score" : 39.624521240283165, + "scoreError" : 1.0488684170365838, + "scoreConfidence" : [ + 38.57565282324658, + 40.67338965731975 + ], + "scorePercentiles" : { + "0.0" : 39.125842021507026, + "50.0" : 39.28708732835848, + "90.0" : 40.46096128601025, + "95.0" : 40.46096128601025, + "99.0" : 40.46096128601025, + "99.9" : 40.46096128601025, + "99.99" : 40.46096128601025, + "99.999" : 40.46096128601025, + "99.9999" : 40.46096128601025, + "100.0" : 40.46096128601025 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 39.28708732835848, + 39.257636656375865, + 39.33546447082681 + ], + [ + 40.46096128601025, + 40.45441613380897, + 40.43723948355265 + ], + [ + 39.125842021507026, + 39.13170218795689, + 39.13034159415156 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SetOfFcnsBenchmark.randomSubset", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "14", + "sizeS" : "16", + "sizeT" : "16" + }, + "primaryMetric" : { + "score" : 13.274726190126739, + "scoreError" : 1.3039809195863328, + "scoreConfidence" : [ + 11.970745270540405, + 14.578707109713072 + ], + "scorePercentiles" : { + "0.0" : 11.624137750149469, + "50.0" : 13.414896159016187, + "90.0" : 13.918947078802928, + "95.0" : 13.918947078802928, + "99.0" : 13.918947078802928, + "99.9" : 13.918947078802928, + "99.99" : 13.918947078802928, + "99.999" : 13.918947078802928, + "99.9999" : 13.918947078802928, + "100.0" : 13.918947078802928 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 11.624137750149469, + 13.405266857198068, + 13.414896159016187 + ], + [ + 12.854352745998838, + 13.914432007900592, + 13.918947078802928 + ], + [ + 12.6445060460198, + 13.830851172745358, + 13.86514589330942 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SetOfFcnsBenchmark.randomSubset", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "14", + "sizeS" : "16", + "sizeT" : "32" + }, + "primaryMetric" : { + "score" : 13.461700151375673, + "scoreError" : 0.8943109617012777, + "scoreConfidence" : [ + 12.567389189674396, + 14.356011113076951 + ], + "scorePercentiles" : { + "0.0" : 12.216580937652516, + "50.0" : 13.474822827150453, + "90.0" : 13.885334874438747, + "95.0" : 13.885334874438747, + "99.0" : 13.885334874438747, + "99.9" : 13.885334874438747, + "99.99" : 13.885334874438747, + "99.999" : 13.885334874438747, + "99.9999" : 13.885334874438747, + "100.0" : 13.885334874438747 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 13.474822827150453, + 13.885334874438747, + 13.880361830891577 + ], + [ + 12.216580937652516, + 13.34324755612668, + 13.333659592726146 + ], + [ + 13.312995951652352, + 13.855167548603434, + 13.85313024313915 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SetOfFcnsBenchmark.randomSubset", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "14", + "sizeS" : "46", + "sizeT" : "46" + }, + "primaryMetric" : { + "score" : 4.785473823060737, + "scoreError" : 0.09157201524952041, + "scoreConfidence" : [ + 4.693901807811217, + 4.8770458383102575 + ], + "scorePercentiles" : { + "0.0" : 4.680392565751563, + "50.0" : 4.814195849833611, + "90.0" : 4.826405956632901, + "95.0" : 4.826405956632901, + "99.0" : 4.826405956632901, + "99.9" : 4.826405956632901, + "99.99" : 4.826405956632901, + "99.999" : 4.826405956632901, + "99.9999" : 4.826405956632901, + "100.0" : 4.826405956632901 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 4.825325890186347, + 4.826405956632901, + 4.824177954164531 + ], + [ + 4.7068701547087, + 4.816073932095836, + 4.814195849833611 + ], + [ + 4.680392565751563, + 4.788402722758373, + 4.787419381414775 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SetOfFcnsBenchmark.randomSubset", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "16", + "sizeS" : "8", + "sizeT" : "16" + }, + "primaryMetric" : { + "score" : 9.89982000722811, + "scoreError" : 0.33280867548870424, + "scoreConfidence" : [ + 9.567011331739405, + 10.232628682716815 + ], + "scorePercentiles" : { + "0.0" : 9.734914127138898, + "50.0" : 9.791439108813481, + "90.0" : 10.16822709776698, + "95.0" : 10.16822709776698, + "99.0" : 10.16822709776698, + "99.9" : 10.16822709776698, + "99.99" : 10.16822709776698, + "99.999" : 10.16822709776698, + "99.9999" : 10.16822709776698, + "100.0" : 10.16822709776698 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 9.734914127138898, + 9.7470755601293, + 9.758007599891789 + ], + [ + 9.784627853561423, + 9.791439108813481, + 9.79476878246331 + ], + [ + 10.163168560261175, + 10.156151375026647, + 10.16822709776698 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SetOfFcnsBenchmark.randomSubset", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "16", + "sizeS" : "16", + "sizeT" : "16" + }, + "primaryMetric" : { + "score" : 3.46851120656168, + "scoreError" : 0.15187211446914156, + "scoreConfidence" : [ + 3.3166390920925384, + 3.620383321030822 + ], + "scorePercentiles" : { + "0.0" : 3.3073638224575204, + "50.0" : 3.493397740973071, + "90.0" : 3.565974969542478, + "95.0" : 3.565974969542478, + "99.0" : 3.565974969542478, + "99.9" : 3.565974969542478, + "99.99" : 3.565974969542478, + "99.999" : 3.565974969542478, + "99.9999" : 3.565974969542478, + "100.0" : 3.565974969542478 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 3.347335173684363, + 3.4981533045812223, + 3.493397740973071 + ], + [ + 3.538081938209828, + 3.565974969542478, + 3.559943009691145 + ], + [ + 3.3073638224575204, + 3.4566397768670205, + 3.4497111230484716 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SetOfFcnsBenchmark.randomSubset", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "16", + "sizeS" : "16", + "sizeT" : "32" + }, + "primaryMetric" : { + "score" : 3.320243517610311, + "scoreError" : 0.2033555773696232, + "scoreConfidence" : [ + 3.1168879402406877, + 3.5235990949799345 + ], + "scorePercentiles" : { + "0.0" : 3.128674595620351, + "50.0" : 3.320454421215615, + "90.0" : 3.4454338235067277, + "95.0" : 3.4454338235067277, + "99.0" : 3.4454338235067277, + "99.9" : 3.4454338235067277, + "99.99" : 3.4454338235067277, + "99.999" : 3.4454338235067277, + "99.9999" : 3.4454338235067277, + "100.0" : 3.4454338235067277 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 3.136340117029289, + 3.320454421215615, + 3.3238979868107763 + ], + [ + 3.444734865360478, + 3.444531840232602, + 3.4454338235067277 + ], + [ + 3.128674595620351, + 3.3184243644982026, + 3.3196996442187574 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SetOfFcnsBenchmark.randomSubset", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "16", + "sizeS" : "46", + "sizeT" : "46" + }, + "primaryMetric" : { + "score" : 1.2002835531139824, + "scoreError" : 0.00981363481252792, + "scoreConfidence" : [ + 1.1904699183014544, + 1.2100971879265103 + ], + "scorePercentiles" : { + "0.0" : 1.1888399240420688, + "50.0" : 1.201983800331197, + "90.0" : 1.2066745006827952, + "95.0" : 1.2066745006827952, + "99.0" : 1.2066745006827952, + "99.9" : 1.2066745006827952, + "99.99" : 1.2066745006827952, + "99.999" : 1.2066745006827952, + "99.9999" : 1.2066745006827952, + "100.0" : 1.2066745006827952 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 1.2041308148128782, + 1.201983800331197, + 1.1958477616169232 + ], + [ + 1.2063945371173965, + 1.2008293589671861, + 1.1888399240420688 + ], + [ + 1.2066745006827952, + 1.202267767625606, + 1.1955835128297898 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetBenchmark.randomSetOfSubsets", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "10", + "size" : "32" + }, + "primaryMetric" : { + "score" : 940.8855661086935, + "scoreError" : 3.4223536604405456, + "scoreConfidence" : [ + 937.463212448253, + 944.3079197691341 + ], + "scorePercentiles" : { + "0.0" : 937.7496835501817, + "50.0" : 941.8177828251877, + "90.0" : 942.7714879849624, + "95.0" : 942.7714879849624, + "99.0" : 942.7714879849624, + "99.9" : 942.7714879849624, + "99.99" : 942.7714879849624, + "99.999" : 942.7714879849624, + "99.9999" : 942.7714879849624, + "100.0" : 942.7714879849624 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 941.7459055359798, + 937.7496835501817, + 941.8177828251877 + ], + [ + 942.5585323480059, + 938.2784667462907, + 942.1225315535781 + ], + [ + 942.2929621202793, + 938.6327423137767, + 942.7714879849624 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetBenchmark.randomSetOfSubsets", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "10", + "size" : "64" + }, + "primaryMetric" : { + "score" : 488.3817704649295, + "scoreError" : 0.9632956295974225, + "scoreConfidence" : [ + 487.41847483533206, + 489.34506609452694 + ], + "scorePercentiles" : { + "0.0" : 487.5965761315435, + "50.0" : 488.38102095368896, + "90.0" : 489.3325381106533, + "95.0" : 489.3325381106533, + "99.0" : 489.3325381106533, + "99.9" : 489.3325381106533, + "99.99" : 489.3325381106533, + "99.999" : 489.3325381106533, + "99.9999" : 489.3325381106533, + "100.0" : 489.3325381106533 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 489.3325381106533, + 488.25101439577145, + 488.452599571124 + ], + [ + 488.9109274511842, + 487.812757100369, + 487.5965761315435 + ], + [ + 488.83932517783984, + 488.38102095368896, + 487.85917529219154 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetBenchmark.randomSetOfSubsets", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "10", + "size" : "128" + }, + "primaryMetric" : { + "score" : 242.61365637195175, + "scoreError" : 1.9134005293665914, + "scoreConfidence" : [ + 240.70025584258516, + 244.52705690131833 + ], + "scorePercentiles" : { + "0.0" : 241.26479708971638, + "50.0" : 242.34398252470044, + "90.0" : 244.24675229669347, + "95.0" : 244.24675229669347, + "99.0" : 244.24675229669347, + "99.9" : 244.24675229669347, + "99.99" : 244.24675229669347, + "99.999" : 244.24675229669347, + "99.9999" : 244.24675229669347, + "100.0" : 244.24675229669347 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 241.4397517030553, + 244.01334660280847, + 242.34398252470044 + ], + [ + 241.26479708971638, + 243.7866250915524, + 242.12992466789876 + ], + [ + 241.68321929043304, + 244.24675229669347, + 242.61450808070728 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetBenchmark.randomSetOfSubsets", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "10", + "size" : "256" + }, + "primaryMetric" : { + "score" : 120.85955941053479, + "scoreError" : 3.7280365091521346, + "scoreConfidence" : [ + 117.13152290138265, + 124.58759591968692 + ], + "scorePercentiles" : { + "0.0" : 116.6453650373679, + "50.0" : 120.06786377622636, + "90.0" : 122.98037514837691, + "95.0" : 122.98037514837691, + "99.0" : 122.98037514837691, + "99.9" : 122.98037514837691, + "99.99" : 122.98037514837691, + "99.999" : 122.98037514837691, + "99.9999" : 122.98037514837691, + "100.0" : 122.98037514837691 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 119.52903855196647, + 122.9665550276074, + 122.93574806155075 + ], + [ + 119.69657382921002, + 122.98037514837691, + 122.8541072830955 + ], + [ + 116.6453650373679, + 120.06040797941165, + 120.06786377622636 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetBenchmark.randomSetOfSubsets", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "12", + "size" : "32" + }, + "primaryMetric" : { + "score" : 236.15568531499392, + "scoreError" : 0.9343184697856747, + "scoreConfidence" : [ + 235.22136684520825, + 237.09000378477958 + ], + "scorePercentiles" : { + "0.0" : 235.18235796901774, + "50.0" : 236.27009630502064, + "90.0" : 236.71074512210538, + "95.0" : 236.71074512210538, + "99.0" : 236.71074512210538, + "99.9" : 236.71074512210538, + "99.99" : 236.71074512210538, + "99.999" : 236.71074512210538, + "99.9999" : 236.71074512210538, + "100.0" : 236.71074512210538 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 236.69176980161902, + 235.72484818055145, + 236.71074512210538 + ], + [ + 236.5139670958129, + 235.52594275864817, + 236.60991270130964 + ], + [ + 236.27009630502064, + 235.18235796901774, + 236.17152790086047 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetBenchmark.randomSetOfSubsets", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "12", + "size" : "64" + }, + "primaryMetric" : { + "score" : 120.86574418461974, + "scoreError" : 0.5189869088755038, + "scoreConfidence" : [ + 120.34675727574424, + 121.38473109349525 + ], + "scorePercentiles" : { + "0.0" : 120.43954658603056, + "50.0" : 121.00004093431384, + "90.0" : 121.18853293499319, + "95.0" : 121.18853293499319, + "99.0" : 121.18853293499319, + "99.9" : 121.18853293499319, + "99.99" : 121.18853293499319, + "99.999" : 121.18853293499319, + "99.9999" : 121.18853293499319, + "100.0" : 121.18853293499319 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 120.4515814273751, + 120.43954658603056, + 120.51591497018322 + ], + [ + 121.11987061106079, + 121.03536572279732, + 120.91070696956106 + ], + [ + 121.18853293499319, + 121.13013750526268, + 121.00004093431384 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetBenchmark.randomSetOfSubsets", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "12", + "size" : "128" + }, + "primaryMetric" : { + "score" : 59.50769061781115, + "scoreError" : 2.491321344548971, + "scoreConfidence" : [ + 57.01636927326218, + 61.99901196236012 + ], + "scorePercentiles" : { + "0.0" : 55.55904745390125, + "50.0" : 59.99867807312548, + "90.0" : 60.12785914176523, + "95.0" : 60.12785914176523, + "99.0" : 60.12785914176523, + "99.9" : 60.12785914176523, + "99.99" : 60.12785914176523, + "99.999" : 60.12785914176523, + "99.9999" : 60.12785914176523, + "100.0" : 60.12785914176523 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 59.95975139329583, + 59.99867807312548, + 55.55904745390125 + ], + [ + 59.9533037865786, + 59.86773438632764, + 60.034152404427 + ], + [ + 60.062748602814544, + 60.00594031806476, + 60.12785914176523 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetBenchmark.randomSetOfSubsets", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "12", + "size" : "256" + }, + "primaryMetric" : { + "score" : 30.035431778783398, + "scoreError" : 0.7720115667275985, + "scoreConfidence" : [ + 29.2634202120558, + 30.807443345510997 + ], + "scorePercentiles" : { + "0.0" : 29.36866906331322, + "50.0" : 30.259863504658576, + "90.0" : 30.38089095732961, + "95.0" : 30.38089095732961, + "99.0" : 30.38089095732961, + "99.9" : 30.38089095732961, + "99.99" : 30.38089095732961, + "99.999" : 30.38089095732961, + "99.9999" : 30.38089095732961, + "100.0" : 30.38089095732961 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 29.36866906331322, + 30.257560790621415, + 30.259863504658576 + ], + [ + 29.524440119872914, + 30.377688781433207, + 30.378318426064762 + ], + [ + 29.393690138840228, + 30.377764226916675, + 30.38089095732961 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetBenchmark.randomSetOfSubsets", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "14", + "size" : "32" + }, + "primaryMetric" : { + "score" : 57.78449169282468, + "scoreError" : 0.25174915581279583, + "scoreConfidence" : [ + 57.532742537011885, + 58.036240848637476 + ], + "scorePercentiles" : { + "0.0" : 57.514251611175986, + "50.0" : 57.76518675310032, + "90.0" : 57.942565521247296, + "95.0" : 57.942565521247296, + "99.0" : 57.942565521247296, + "99.9" : 57.942565521247296, + "99.99" : 57.942565521247296, + "99.999" : 57.942565521247296, + "99.9999" : 57.942565521247296, + "100.0" : 57.942565521247296 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 57.76518675310032, + 57.514251611175986, + 57.74584132456393 + ], + [ + 57.92848099338778, + 57.693013889485805, + 57.942565521247296 + ], + [ + 57.89925314595382, + 57.64918655421162, + 57.92264544229567 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetBenchmark.randomSetOfSubsets", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "14", + "size" : "64" + }, + "primaryMetric" : { + "score" : 29.651491243464402, + "scoreError" : 0.12291674794846726, + "scoreConfidence" : [ + 29.528574495515937, + 29.77440799141287 + ], + "scorePercentiles" : { + "0.0" : 29.564685568469237, + "50.0" : 29.628667539981386, + "90.0" : 29.750422375906208, + "95.0" : 29.750422375906208, + "99.0" : 29.750422375906208, + "99.9" : 29.750422375906208, + "99.99" : 29.750422375906208, + "99.999" : 29.750422375906208, + "99.9999" : 29.750422375906208, + "100.0" : 29.750422375906208 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 29.564685568469237, + 29.571865226878806, + 29.583432053296068 + ], + [ + 29.712168387905113, + 29.750422375906208, + 29.628667539981386 + ], + [ + 29.70578937525705, + 29.72982764429422, + 29.61656301919153 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetBenchmark.randomSetOfSubsets", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "14", + "size" : "128" + }, + "primaryMetric" : { + "score" : 14.966346077321589, + "scoreError" : 0.14083917460810721, + "scoreConfidence" : [ + 14.825506902713482, + 15.107185251929696 + ], + "scorePercentiles" : { + "0.0" : 14.870153350883559, + "50.0" : 14.965133247853384, + "90.0" : 15.071977759947723, + "95.0" : 15.071977759947723, + "99.0" : 15.071977759947723, + "99.9" : 15.071977759947723, + "99.99" : 15.071977759947723, + "99.999" : 15.071977759947723, + "99.9999" : 15.071977759947723, + "100.0" : 15.071977759947723 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 14.872909128391527, + 15.07088173326791, + 14.966466458528696 + ], + [ + 14.876996820055009, + 15.054670031738755, + 14.947926165227734 + ], + [ + 14.870153350883559, + 15.071977759947723, + 14.965133247853384 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetBenchmark.randomSetOfSubsets", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "14", + "size" : "256" + }, + "primaryMetric" : { + "score" : 7.4929123396556365, + "scoreError" : 0.17711661607330295, + "scoreConfidence" : [ + 7.315795723582333, + 7.67002895572894 + ], + "scorePercentiles" : { + "0.0" : 7.344177741488789, + "50.0" : 7.560633453264906, + "90.0" : 7.5680383531645585, + "95.0" : 7.5680383531645585, + "99.0" : 7.5680383531645585, + "99.9" : 7.5680383531645585, + "99.99" : 7.5680383531645585, + "99.999" : 7.5680383531645585, + "99.9999" : 7.5680383531645585, + "100.0" : 7.5680383531645585 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 7.352927179314497, + 7.5680383531645585, + 7.568031280437031 + ], + [ + 7.344177741488789, + 7.558938968199607, + 7.561108925864961 + ], + [ + 7.360537627959725, + 7.560633453264906, + 7.561817527206654 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetBenchmark.randomSetOfSubsets", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "16", + "size" : "32" + }, + "primaryMetric" : { + "score" : 14.12707487278992, + "scoreError" : 0.0705701121612911, + "scoreConfidence" : [ + 14.056504760628629, + 14.197644984951213 + ], + "scorePercentiles" : { + "0.0" : 14.045219248776148, + "50.0" : 14.12659745374599, + "90.0" : 14.174116369702018, + "95.0" : 14.174116369702018, + "99.0" : 14.174116369702018, + "99.9" : 14.174116369702018, + "99.99" : 14.174116369702018, + "99.999" : 14.174116369702018, + "99.9999" : 14.174116369702018, + "100.0" : 14.174116369702018 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 14.12659745374599, + 14.045219248776148, + 14.118116581295373 + ], + [ + 14.160373672620183, + 14.094305865194697, + 14.159211580439047 + ], + [ + 14.174116369702018, + 14.102596604618341, + 14.163136478717492 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetBenchmark.randomSetOfSubsets", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "16", + "size" : "64" + }, + "primaryMetric" : { + "score" : 7.266381680744571, + "scoreError" : 0.0314834507050696, + "scoreConfidence" : [ + 7.2348982300395015, + 7.29786513144964 + ], + "scorePercentiles" : { + "0.0" : 7.242444363446909, + "50.0" : 7.267648124694403, + "90.0" : 7.288481059319786, + "95.0" : 7.288481059319786, + "99.0" : 7.288481059319786, + "99.9" : 7.288481059319786, + "99.99" : 7.288481059319786, + "99.999" : 7.288481059319786, + "99.9999" : 7.288481059319786, + "100.0" : 7.288481059319786 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 7.267648124694403, + 7.285342164764824, + 7.242444363446909 + ], + [ + 7.255021652408882, + 7.285224559232886, + 7.24294226646453 + ], + [ + 7.278377968993735, + 7.288481059319786, + 7.2519529673751855 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetBenchmark.randomSetOfSubsets", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "16", + "size" : "128" + }, + "primaryMetric" : { + "score" : 3.6497554428776358, + "scoreError" : 0.03841688365133788, + "scoreConfidence" : [ + 3.611338559226298, + 3.6881723265289734 + ], + "scorePercentiles" : { + "0.0" : 3.6183155091861385, + "50.0" : 3.648096864564528, + "90.0" : 3.6841018017113205, + "95.0" : 3.6841018017113205, + "99.0" : 3.6841018017113205, + "99.9" : 3.6841018017113205, + "99.99" : 3.6841018017113205, + "99.999" : 3.6841018017113205, + "99.9999" : 3.6841018017113205, + "100.0" : 3.6841018017113205 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 3.634059338089468, + 3.6788480653647095, + 3.648096864564528 + ], + [ + 3.6183155091861385, + 3.6691475217581515, + 3.632623610621194 + ], + [ + 3.6340565733165495, + 3.6841018017113205, + 3.6485497012866586 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetBenchmark.randomSetOfSubsets", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "16", + "size" : "256" + }, + "primaryMetric" : { + "score" : 1.8523095561784801, + "scoreError" : 0.030323853785498622, + "scoreConfidence" : [ + 1.8219857023929815, + 1.8826334099639788 + ], + "scorePercentiles" : { + "0.0" : 1.8239117503947395, + "50.0" : 1.8621334722675167, + "90.0" : 1.8673452589640651, + "95.0" : 1.8673452589640651, + "99.0" : 1.8673452589640651, + "99.9" : 1.8673452589640651, + "99.99" : 1.8673452589640651, + "99.999" : 1.8673452589640651, + "99.9999" : 1.8673452589640651, + "100.0" : 1.8673452589640651 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 1.8375132948596045, + 1.8673452589640651, + 1.8606371045545045 + ], + [ + 1.8253859071644025, + 1.8650899516618138, + 1.8663739030912672 + ], + [ + 1.8239117503947395, + 1.8621334722675167, + 1.8623953626484073 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetBenchmark.randomSetOfSubsets", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "20", + "size" : "32" + }, + "primaryMetric" : { + "score" : 0.815405606395385, + "scoreError" : 0.007376600213618425, + "scoreConfidence" : [ + 0.8080290061817665, + 0.8227822066090034 + ], + "scorePercentiles" : { + "0.0" : 0.8100211392269732, + "50.0" : 0.8157161091242544, + "90.0" : 0.8222992984714158, + "95.0" : 0.8222992984714158, + "99.0" : 0.8222992984714158, + "99.9" : 0.8222992984714158, + "99.99" : 0.8222992984714158, + "99.999" : 0.8222992984714158, + "99.9999" : 0.8222992984714158, + "100.0" : 0.8222992984714158 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 0.8117869388228873, + 0.8145968267194525, + 0.8102262997624171 + ], + [ + 0.8100211392269732, + 0.8157161091242544, + 0.8162979185742621 + ], + [ + 0.8163625083929198, + 0.8213434184638821, + 0.8222992984714158 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetBenchmark.randomSetOfSubsets", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "20", + "size" : "64" + }, + "primaryMetric" : { + "score" : 0.40328804844292354, + "scoreError" : 0.0028630303370206483, + "scoreConfidence" : [ + 0.4004250181059029, + 0.40615107877994416 + ], + "scorePercentiles" : { + "0.0" : 0.40163443030059487, + "50.0" : 0.40217276377360556, + "90.0" : 0.4061534001859155, + "95.0" : 0.4061534001859155, + "99.0" : 0.4061534001859155, + "99.9" : 0.4061534001859155, + "99.99" : 0.4061534001859155, + "99.999" : 0.4061534001859155, + "99.9999" : 0.4061534001859155, + "100.0" : 0.4061534001859155 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 0.40476771290873986, + 0.4037297178244125, + 0.4061534001859155 + ], + [ + 0.40215063632598, + 0.40163443030059487, + 0.4051522304851012 + ], + [ + 0.4021542415673392, + 0.4016773026146231, + 0.40217276377360556 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetBenchmark.randomSetOfSubsets", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "20", + "size" : "128" + }, + "primaryMetric" : { + "score" : 0.21530835237739487, + "scoreError" : 0.00316882904311516, + "scoreConfidence" : [ + 0.2121395233342797, + 0.21847718142051004 + ], + "scorePercentiles" : { + "0.0" : 0.213179245449477, + "50.0" : 0.21498614336373545, + "90.0" : 0.21804435382366047, + "95.0" : 0.21804435382366047, + "99.0" : 0.21804435382366047, + "99.9" : 0.21804435382366047, + "99.99" : 0.21804435382366047, + "99.999" : 0.21804435382366047, + "99.9999" : 0.21804435382366047, + "100.0" : 0.21804435382366047 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 0.21361651479341479, + 0.21804435382366047, + 0.2153415105318766 + ], + [ + 0.213179245449477, + 0.21728117821674925, + 0.21455915572280176 + ], + [ + 0.21326258869209858, + 0.21750448080274012, + 0.21498614336373545 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetBenchmark.randomSetOfSubsets", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "20", + "size" : "256" + }, + "primaryMetric" : { + "score" : 0.11238928761614583, + "scoreError" : 0.001728818027193669, + "scoreConfidence" : [ + 0.11066046958895216, + 0.1141181056433395 + ], + "scorePercentiles" : { + "0.0" : 0.11096554243148343, + "50.0" : 0.11236778839587218, + "90.0" : 0.11371225952719105, + "95.0" : 0.11371225952719105, + "99.0" : 0.11371225952719105, + "99.9" : 0.11371225952719105, + "99.99" : 0.11371225952719105, + "99.999" : 0.11371225952719105, + "99.9999" : 0.11371225952719105, + "100.0" : 0.11371225952719105 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 0.11096554243148343, + 0.11331316219066813, + 0.11236778839587218 + ], + [ + 0.11132446045043788, + 0.11371225952719105, + 0.11260766904717413 + ], + [ + 0.11141079827926309, + 0.11366691638640296, + 0.11213499183681985 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetBenchmark.randomSetOfSubsets", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "24", + "size" : "32" + }, + "primaryMetric" : { + "score" : 0.04910733411972115, + "scoreError" : 9.919993036906951E-4, + "scoreConfidence" : [ + 0.048115334816030454, + 0.05009933342341185 + ], + "scorePercentiles" : { + "0.0" : 0.04785069270165027, + "50.0" : 0.04920083794793364, + "90.0" : 0.04974845748136814, + "95.0" : 0.04974845748136814, + "99.0" : 0.04974845748136814, + "99.9" : 0.04974845748136814, + "99.99" : 0.04974845748136814, + "99.999" : 0.04974845748136814, + "99.9999" : 0.04974845748136814, + "100.0" : 0.04974845748136814 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 0.04920083794793364, + 0.049013302202522674, + 0.04863697352455684 + ], + [ + 0.049574854456079974, + 0.04942860585264381, + 0.04974845748136814 + ], + [ + 0.04956659261874403, + 0.04785069270165027, + 0.04894569029199095 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetBenchmark.randomSetOfSubsets", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "24", + "size" : "64" + }, + "primaryMetric" : { + "score" : 0.021996942226223695, + "scoreError" : 0.001223011827842711, + "scoreConfidence" : [ + 0.020773930398380984, + 0.023219954054066405 + ], + "scorePercentiles" : { + "0.0" : 0.021206605100633595, + "50.0" : 0.022204038901540282, + "90.0" : 0.02285143457296508, + "95.0" : 0.02285143457296508, + "99.0" : 0.02285143457296508, + "99.9" : 0.02285143457296508, + "99.99" : 0.02285143457296508, + "99.999" : 0.02285143457296508, + "99.9999" : 0.02285143457296508, + "100.0" : 0.02285143457296508 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 0.02285143457296508, + 0.021271412124217133, + 0.0222529103969887 + ], + [ + 0.02277063641256935, + 0.021206605100633595, + 0.021370956424092393 + ], + [ + 0.02281475408024271, + 0.021229732022763986, + 0.022204038901540282 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetBenchmark.randomSetOfSubsetsExact", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "10", + "size" : "32" + }, + "primaryMetric" : { + "score" : 6386.565795976956, + "scoreError" : 792.1663122224614, + "scoreConfidence" : [ + 5594.399483754494, + 7178.732108199418 + ], + "scorePercentiles" : { + "0.0" : 5713.694702288845, + "50.0" : 6655.358764129061, + "90.0" : 6745.727252434273, + "95.0" : 6745.727252434273, + "99.0" : 6745.727252434273, + "99.9" : 6745.727252434273, + "99.99" : 6745.727252434273, + "99.999" : 6745.727252434273, + "99.9999" : 6745.727252434273, + "100.0" : 6745.727252434273 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 6699.219916941565, + 5768.823450309422, + 6703.286814783046 + ], + [ + 6741.156445050042, + 5797.684182713598, + 6745.727252434273 + ], + [ + 6655.358764129061, + 5713.694702288845, + 6654.140635142748 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetBenchmark.randomSetOfSubsetsExact", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "10", + "size" : "64" + }, + "primaryMetric" : { + "score" : 5751.799729776909, + "scoreError" : 703.7751119214772, + "scoreConfidence" : [ + 5048.024617855432, + 6455.574841698386 + ], + "scorePercentiles" : { + "0.0" : 5188.826682026075, + "50.0" : 6027.003718632205, + "90.0" : 6041.565670269849, + "95.0" : 6041.565670269849, + "99.0" : 6041.565670269849, + "99.9" : 6041.565670269849, + "99.99" : 6041.565670269849, + "99.999" : 6041.565670269849, + "99.9999" : 6041.565670269849, + "100.0" : 6041.565670269849 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 6035.290118817631, + 5197.995356856098, + 6041.565670269849 + ], + [ + 6027.6365465635, + 5188.826682026075, + 6026.93874641699 + ], + [ + 6027.448315558002, + 5193.4924128518305, + 6027.003718632205 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetBenchmark.randomSetOfSubsetsExact", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "10", + "size" : "128" + }, + "primaryMetric" : { + "score" : 5396.41858036665, + "scoreError" : 692.4767567843886, + "scoreConfidence" : [ + 4703.941823582261, + 6088.895337151038 + ], + "scorePercentiles" : { + "0.0" : 4717.085732529054, + "50.0" : 5449.325363271581, + "90.0" : 5804.387234518538, + "95.0" : 5804.387234518538, + "99.0" : 5804.387234518538, + "99.9" : 5804.387234518538, + "99.99" : 5804.387234518538, + "99.999" : 5804.387234518538, + "99.9999" : 5804.387234518538, + "100.0" : 5804.387234518538 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 5710.726353968836, + 4936.6454282045515, + 5710.563537849235 + ], + [ + 5443.704529230653, + 4717.085732529054, + 5449.325363271581 + ], + [ + 5795.56767079827, + 4999.761372929123, + 5804.387234518538 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetBenchmark.randomSetOfSubsetsExact", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "10", + "size" : "256" + }, + "primaryMetric" : { + "score" : 5338.528833690778, + "scoreError" : 642.6865323262485, + "scoreConfidence" : [ + 4695.84230136453, + 5981.215366017026 + ], + "scorePercentiles" : { + "0.0" : 4816.211036391922, + "50.0" : 5592.290362015759, + "90.0" : 5598.237388965811, + "95.0" : 5598.237388965811, + "99.0" : 5598.237388965811, + "99.9" : 5598.237388965811, + "99.99" : 5598.237388965811, + "99.999" : 5598.237388965811, + "99.9999" : 5598.237388965811, + "100.0" : 5598.237388965811 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 5589.214694677729, + 4836.893728784345, + 5593.741175525523 + ], + [ + 5592.290362015759, + 4832.858876227758, + 5594.915771067337 + ], + [ + 5592.396469560819, + 4816.211036391922, + 5598.237388965811 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetBenchmark.randomSetOfSubsetsExact", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "12", + "size" : "32" + }, + "primaryMetric" : { + "score" : 1445.2994799478993, + "scoreError" : 175.00246806454027, + "scoreConfidence" : [ + 1270.2970118833591, + 1620.3019480124394 + ], + "scorePercentiles" : { + "0.0" : 1304.453222626917, + "50.0" : 1512.8888905018887, + "90.0" : 1517.6364934622381, + "95.0" : 1517.6364934622381, + "99.0" : 1517.6364934622381, + "99.9" : 1517.6364934622381, + "99.99" : 1517.6364934622381, + "99.999" : 1517.6364934622381, + "99.9999" : 1517.6364934622381, + "100.0" : 1517.6364934622381 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 1512.8548350143578, + 1513.0402455594708, + 1304.453222626917 + ], + [ + 1512.8888905018887, + 1515.3646737654515, + 1305.1104620235824 + ], + [ + 1516.482476628759, + 1517.6364934622381, + 1309.8640199484262 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetBenchmark.randomSetOfSubsetsExact", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "12", + "size" : "64" + }, + "primaryMetric" : { + "score" : 1315.0872776573538, + "scoreError" : 159.24200916012424, + "scoreConfidence" : [ + 1155.8452684972294, + 1474.329286817478 + ], + "scorePercentiles" : { + "0.0" : 1177.8433003668486, + "50.0" : 1366.6742876812843, + "90.0" : 1385.2593526169985, + "95.0" : 1385.2593526169985, + "99.0" : 1385.2593526169985, + "99.9" : 1385.2593526169985, + "99.99" : 1385.2593526169985, + "99.999" : 1385.2593526169985, + "99.9999" : 1385.2593526169985, + "100.0" : 1385.2593526169985 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 1382.8361977329685, + 1382.6820468439241, + 1195.6796392562026 + ], + [ + 1365.612489963466, + 1366.6742876812843, + 1177.8433003668486 + ], + [ + 1384.8586134304985, + 1385.2593526169985, + 1194.3395710239927 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetBenchmark.randomSetOfSubsetsExact", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "12", + "size" : "128" + }, + "primaryMetric" : { + "score" : 1283.678005805807, + "scoreError" : 157.03079680154033, + "scoreConfidence" : [ + 1126.6472090042666, + 1440.7088026073475 + ], + "scorePercentiles" : { + "0.0" : 1153.4418641546772, + "50.0" : 1343.8744918106247, + "90.0" : 1347.442856430225, + "95.0" : 1347.442856430225, + "99.0" : 1347.442856430225, + "99.9" : 1347.442856430225, + "99.99" : 1347.442856430225, + "99.999" : 1347.442856430225, + "99.9999" : 1347.442856430225, + "100.0" : 1347.442856430225 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 1346.9373529042812, + 1347.442856430225, + 1164.7204691032007 + ], + [ + 1343.8744918106247, + 1342.9954214911315, + 1153.4418641546772 + ], + [ + 1347.0783197578448, + 1347.303553607001, + 1159.3077229932755 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetBenchmark.randomSetOfSubsetsExact", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "12", + "size" : "256" + }, + "primaryMetric" : { + "score" : 1269.9493588394673, + "scoreError" : 152.09842493843254, + "scoreConfidence" : [ + 1117.8509339010348, + 1422.0477837779 + ], + "scorePercentiles" : { + "0.0" : 1147.258945682416, + "50.0" : 1326.3094960282574, + "90.0" : 1333.9773182234367, + "95.0" : 1333.9773182234367, + "99.0" : 1333.9773182234367, + "99.9" : 1333.9773182234367, + "99.99" : 1333.9773182234367, + "99.999" : 1333.9773182234367, + "99.9999" : 1333.9773182234367, + "100.0" : 1333.9773182234367 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 1330.937017988604, + 1331.781013712139, + 1151.3025128066724 + ], + [ + 1325.092552687089, + 1326.3094960282574, + 1147.258945682416 + ], + [ + 1333.430930831772, + 1333.9773182234367, + 1149.4544415948185 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetBenchmark.randomSetOfSubsetsExact", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "14", + "size" : "32" + }, + "primaryMetric" : { + "score" : 331.4211691811984, + "scoreError" : 39.72591885175523, + "scoreConfidence" : [ + 291.6952503294432, + 371.14708803295366 + ], + "scorePercentiles" : { + "0.0" : 299.70654954457757, + "50.0" : 346.81718517560597, + "90.0" : 347.5654842338588, + "95.0" : 347.5654842338588, + "99.0" : 347.5654842338588, + "99.9" : 347.5654842338588, + "99.99" : 347.5654842338588, + "99.999" : 347.5654842338588, + "99.9999" : 347.5654842338588, + "100.0" : 347.5654842338588 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 347.5654842338588, + 347.3078636522035, + 299.70654954457757 + ], + [ + 346.81718517560597, + 347.5600492130343, + 300.24013083607304 + ], + [ + 347.02901204498386, + 346.8002041858344, + 299.7640437446145 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetBenchmark.randomSetOfSubsetsExact", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "14", + "size" : "64" + }, + "primaryMetric" : { + "score" : 311.3392998224587, + "scoreError" : 8.092880027858497, + "scoreConfidence" : [ + 303.24641979460023, + 319.4321798503172 + ], + "scorePercentiles" : { + "0.0" : 303.864281154577, + "50.0" : 313.53343870279156, + "90.0" : 315.28847407610476, + "95.0" : 315.28847407610476, + "99.0" : 315.28847407610476, + "99.9" : 315.28847407610476, + "99.99" : 315.28847407610476, + "99.999" : 315.28847407610476, + "99.9999" : 315.28847407610476, + "100.0" : 315.28847407610476 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 313.53343870279156, + 313.52494012757575, + 306.9042783090912 + ], + [ + 314.64847282876036, + 314.63972158920654, + 304.42205790234715 + ], + [ + 315.228033711674, + 315.28847407610476, + 303.864281154577 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetBenchmark.randomSetOfSubsetsExact", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "14", + "size" : "128" + }, + "primaryMetric" : { + "score" : 302.2836732171543, + "scoreError" : 4.149706655572463, + "scoreConfidence" : [ + 298.1339665615818, + 306.43337987272673 + ], + "scorePercentiles" : { + "0.0" : 299.0505978738112, + "50.0" : 303.12956903610376, + "90.0" : 304.64899373895605, + "95.0" : 304.64899373895605, + "99.0" : 304.64899373895605, + "99.9" : 304.64899373895605, + "99.99" : 304.64899373895605, + "99.999" : 304.64899373895605, + "99.9999" : 304.64899373895605, + "100.0" : 304.64899373895605 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 299.10203001349043, + 299.0505978738112, + 299.15578250184234 + ], + [ + 303.1047767742677, + 303.12956903610376, + 303.1836065480273 + ], + [ + 304.64899373895605, + 304.54986000188603, + 304.62784246600364 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetBenchmark.randomSetOfSubsetsExact", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "14", + "size" : "256" + }, + "primaryMetric" : { + "score" : 300.95692329813187, + "scoreError" : 3.927290388673294, + "scoreConfidence" : [ + 297.0296329094586, + 304.88421368680514 + ], + "scorePercentiles" : { + "0.0" : 297.82178632724117, + "50.0" : 302.460585005198, + "90.0" : 302.6934983893305, + "95.0" : 302.6934983893305, + "99.0" : 302.6934983893305, + "99.9" : 302.6934983893305, + "99.99" : 302.6934983893305, + "99.999" : 302.6934983893305, + "99.9999" : 302.6934983893305, + "100.0" : 302.6934983893305 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 302.667066530584, + 302.6934983893305, + 302.6823762496941 + ], + [ + 302.460585005198, + 302.08539343860014, + 302.47158139038163 + ], + [ + 297.86992487307157, + 297.82178632724117, + 297.8600974790862 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetBenchmark.randomSetOfSubsetsExact", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "16", + "size" : "32" + }, + "primaryMetric" : { + "score" : 74.50878265101892, + "scoreError" : 1.5659955259011837, + "scoreConfidence" : [ + 72.94278712511773, + 76.0747781769201 + ], + "scorePercentiles" : { + "0.0" : 73.18420589697276, + "50.0" : 75.0801265833059, + "90.0" : 75.19920151231858, + "95.0" : 75.19920151231858, + "99.0" : 75.19920151231858, + "99.9" : 75.19920151231858, + "99.99" : 75.19920151231858, + "99.999" : 75.19920151231858, + "99.9999" : 75.19920151231858, + "100.0" : 75.19920151231858 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 75.07250433493931, + 75.0801265833059, + 75.08953871319032 + ], + [ + 73.18420589697276, + 73.30250562624731, + 73.31900441517166 + ], + [ + 75.19920151231858, + 75.15335166079, + 75.17860511623435 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetBenchmark.randomSetOfSubsetsExact", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "16", + "size" : "64" + }, + "primaryMetric" : { + "score" : 75.52429503392334, + "scoreError" : 0.5517480024585578, + "scoreConfidence" : [ + 74.97254703146479, + 76.07604303638189 + ], + "scorePercentiles" : { + "0.0" : 75.19908655669559, + "50.0" : 75.44663150488897, + "90.0" : 75.9517135006675, + "95.0" : 75.9517135006675, + "99.0" : 75.9517135006675, + "99.9" : 75.9517135006675, + "99.99" : 75.9517135006675, + "99.999" : 75.9517135006675, + "99.9999" : 75.9517135006675, + "100.0" : 75.9517135006675 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 75.35367838336924, + 75.4596740558918, + 75.44663150488897 + ], + [ + 75.93801711229243, + 75.93950246123045, + 75.9517135006675 + ], + [ + 75.19908655669559, + 75.21442172604338, + 75.21593000423054 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetBenchmark.randomSetOfSubsetsExact", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "16", + "size" : "128" + }, + "primaryMetric" : { + "score" : 67.47125972839588, + "scoreError" : 0.9761457967212661, + "scoreConfidence" : [ + 66.49511393167461, + 68.44740552511715 + ], + "scorePercentiles" : { + "0.0" : 66.9589801118839, + "50.0" : 67.17805812799128, + "90.0" : 68.25316810917784, + "95.0" : 68.25316810917784, + "99.0" : 68.25316810917784, + "99.9" : 68.25316810917784, + "99.99" : 68.25316810917784, + "99.999" : 68.25316810917784, + "99.9999" : 68.25316810917784, + "100.0" : 68.25316810917784 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 68.23832315328102, + 68.22025948080903, + 68.25316810917784 + ], + [ + 67.20470000773832, + 67.17224019849884, + 67.17805812799128 + ], + [ + 66.99686263071861, + 66.9589801118839, + 67.01874573546412 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetBenchmark.randomSetOfSubsetsExact", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "16", + "size" : "256" + }, + "primaryMetric" : { + "score" : 67.32137339767219, + "scoreError" : 0.6819868243441913, + "scoreConfidence" : [ + 66.639386573328, + 68.00336022201638 + ], + "scorePercentiles" : { + "0.0" : 66.89781446847066, + "50.0" : 67.22587345785756, + "90.0" : 67.83559662001014, + "95.0" : 67.83559662001014, + "99.0" : 67.83559662001014, + "99.9" : 67.83559662001014, + "99.99" : 67.83559662001014, + "99.999" : 67.83559662001014, + "99.9999" : 67.83559662001014, + "100.0" : 67.83559662001014 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 67.83559662001014, + 67.8322057260434, + 67.82536987354793 + ], + [ + 67.23765444299026, + 67.20703272536338, + 67.22587345785756 + ], + [ + 66.91126212224623, + 66.89781446847066, + 66.9195511425202 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetBenchmark.randomSetOfSubsetsExact", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "20", + "size" : "32" + }, + "primaryMetric" : { + "score" : 3.9488767206617124, + "scoreError" : 0.01271426348096421, + "scoreConfidence" : [ + 3.9361624571807483, + 3.9615909841426764 + ], + "scorePercentiles" : { + "0.0" : 3.9395433532608974, + "50.0" : 3.9479157994483596, + "90.0" : 3.961011353696486, + "95.0" : 3.961011353696486, + "99.0" : 3.961011353696486, + "99.9" : 3.961011353696486, + "99.99" : 3.961011353696486, + "99.999" : 3.961011353696486, + "99.9999" : 3.961011353696486, + "100.0" : 3.961011353696486 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 3.9474670664367095, + 3.9407630752460774, + 3.941580998321083 + ], + [ + 3.951314216557007, + 3.9479157994483596, + 3.9395433532608974 + ], + [ + 3.961011353696486, + 3.9580669899343075, + 3.9522276330544845 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetBenchmark.randomSetOfSubsetsExact", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "20", + "size" : "64" + }, + "primaryMetric" : { + "score" : 3.712183075627399, + "scoreError" : 0.004411977283529826, + "scoreConfidence" : [ + 3.707771098343869, + 3.716595052910929 + ], + "scorePercentiles" : { + "0.0" : 3.7088991397404043, + "50.0" : 3.71197990044313, + "90.0" : 3.716693076529153, + "95.0" : 3.716693076529153, + "99.0" : 3.716693076529153, + "99.9" : 3.716693076529153, + "99.99" : 3.716693076529153, + "99.999" : 3.716693076529153, + "99.9999" : 3.716693076529153, + "100.0" : 3.716693076529153 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 3.712300697056719, + 3.7088991397404043, + 3.712866800949536 + ], + [ + 3.7156716434094634, + 3.709451487937914, + 3.7103748198468636 + ], + [ + 3.716693076529153, + 3.711410114733411, + 3.71197990044313 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetBenchmark.randomSetOfSubsetsExact", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "20", + "size" : "128" + }, + "primaryMetric" : { + "score" : 3.6510588192982802, + "scoreError" : 0.010158835052119179, + "scoreConfidence" : [ + 3.640899984246161, + 3.6612176543503994 + ], + "scorePercentiles" : { + "0.0" : 3.6417932096613206, + "50.0" : 3.652773141901331, + "90.0" : 3.659304341428677, + "95.0" : 3.659304341428677, + "99.0" : 3.659304341428677, + "99.9" : 3.659304341428677, + "99.99" : 3.659304341428677, + "99.999" : 3.659304341428677, + "99.9999" : 3.659304341428677, + "100.0" : 3.659304341428677 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 3.6417932096613206, + 3.6484140187033773, + 3.6427744353372957 + ], + [ + 3.6490259698619028, + 3.656541227931445, + 3.6532776508863405 + ], + [ + 3.652773141901331, + 3.659304341428677, + 3.65562537797283 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetBenchmark.randomSetOfSubsetsExact", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "20", + "size" : "256" + }, + "primaryMetric" : { + "score" : 3.585564475367141, + "scoreError" : 0.05905549153815459, + "scoreConfidence" : [ + 3.5265089838289865, + 3.6446199669052954 + ], + "scorePercentiles" : { + "0.0" : 3.533524149742564, + "50.0" : 3.6065639777483764, + "90.0" : 3.6158764022769976, + "95.0" : 3.6158764022769976, + "99.0" : 3.6158764022769976, + "99.9" : 3.6158764022769976, + "99.99" : 3.6158764022769976, + "99.999" : 3.6158764022769976, + "99.9999" : 3.6158764022769976, + "100.0" : 3.6158764022769976 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 3.6065639777483764, + 3.6045966516377965, + 3.6119839861983194 + ], + [ + 3.6071137983733683, + 3.6067334754515645, + 3.6158764022769976 + ], + [ + 3.5447209034309646, + 3.5389669334443195, + 3.533524149742564 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetBenchmark.randomSetOfSubsetsExact", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "24", + "size" : "32" + }, + "primaryMetric" : { + "score" : 0.20908264283795241, + "scoreError" : 0.005521587867919933, + "scoreConfidence" : [ + 0.2035610549700325, + 0.21460423070587234 + ], + "scorePercentiles" : { + "0.0" : 0.20496353683409937, + "50.0" : 0.20922435885392085, + "90.0" : 0.21325690252957974, + "95.0" : 0.21325690252957974, + "99.0" : 0.21325690252957974, + "99.9" : 0.21325690252957974, + "99.99" : 0.21325690252957974, + "99.999" : 0.21325690252957974, + "99.9999" : 0.21325690252957974, + "100.0" : 0.21325690252957974 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 0.20542256226005204, + 0.21325690252957974, + 0.20935781859286504 + ], + [ + 0.20496353683409937, + 0.21256935316767595, + 0.2086984266652402 + ], + [ + 0.20550737583398893, + 0.21274345080414955, + 0.20922435885392085 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.21", + "benchmark" : "tlc2.value.SubsetBenchmark.randomSetOfSubsetsExact", + "mode" : "thrpt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-8-oracle/jre/bin/java", + "jvmArgs" : [ + "-Xms32768m", + "-Xmx32768m" + ], + "jdkVersion" : "1.8.0_171", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.171-b11", + "warmupIterations" : 3, + "warmupTime" : "10 s", + "warmupBatchSize" : 1, + "measurementIterations" : 3, + "measurementTime" : "10 s", + "measurementBatchSize" : 1, + "params" : { + "numOfElements" : "24", + "size" : "64" + }, + "primaryMetric" : { + "score" : 0.1974683037696797, + "scoreError" : 0.010640093913706952, + "scoreConfidence" : [ + 0.18682820985597273, + 0.20810839768338665 + ], + "scorePercentiles" : { + "0.0" : 0.19000299496590883, + "50.0" : 0.19685709664617682, + "90.0" : 0.20514302078860988, + "95.0" : 0.20514302078860988, + "99.0" : 0.20514302078860988, + "99.9" : 0.20514302078860988, + "99.99" : 0.20514302078860988, + "99.999" : 0.20514302078860988, + "99.9999" : 0.20514302078860988, + "100.0" : 0.20514302078860988 + }, + "scoreUnit" : "ops/s", + "rawData" : [ + [ + 0.2050238255850441, + 0.19685709664617682, + 0.19055863675929088 + ], + [ + 0.20514302078860988, + 0.19650966439452058, + 0.19000299496590883 + ], + [ + 0.20504185082390858, + 0.19712856235839904, + 0.19094908160525834 + ] + ] + }, + "secondaryMetrics" : { + } + } +] + + diff --git a/tlatools/test-benchmark/tlc2/value/RandomizationBenchmark.java b/tlatools/test-benchmark/tlc2/value/RandomizationBenchmark.java new file mode 100644 index 0000000000000000000000000000000000000000..e26006915c068281ceeb529b3d1db3abe59577c0 --- /dev/null +++ b/tlatools/test-benchmark/tlc2/value/RandomizationBenchmark.java @@ -0,0 +1,515 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.value; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; + +import tlc2.TLCGlobals; +import tlc2.util.FP64; + +@State(Scope.Benchmark) +public class RandomizationBenchmark { + + private static final Enumerable enum016; + private static final Enumerable enum032; + private static final Enumerable enum064; + private static final Enumerable enum128; + private static final Enumerable enum256; + private static final Enumerable enum512; + private static final Enumerable enum1024; + private static final Enumerable enum2048; + private static final Enumerable enum4096; + private static final Enumerable enum8192; + private static final Enumerable enum16384; + private static final Enumerable enum32768; + private static final Enumerable enumTLCBound; + + private static final Enumerable interval16; + private static final Enumerable interval20; + private static final Enumerable interval24; + private static final Enumerable interval28; + private static final Enumerable interval31; + + private static final int twoPow12 = (int) (Math.pow(2, 12) - 1); + private static final int twoPow08 = (int) (Math.pow(2, 8) - 1); + private static final int twoPow16 = (int) (Math.pow(2, 16) - 1); + private static final Enumerable fcns008x008; // 2^24 + private static final Enumerable fcns011x011; // ~2^31 + private static final Enumerable fcns016x008; + private static final Enumerable fcns016x016; // ~2^65 + private static final Enumerable fcns032x016; + private static final Enumerable fcns032x032; // ~2^150 + private static final Enumerable fcns048x048; // ~2^268 + + private static final SubsetValue subset2pow24; // 2^24 + private static final SubsetValue subset2pow31; // ~2^31 + private static final SubsetValue subset2pow65; // ~2^65 + private static final SubsetValue subset2pow150; // ~2^150 + private static final SubsetValue subset2pow268; // ~2^268 + + private static ValueVec getValues(int from, int to) { + final ValueVec vec = new ValueVec(to - from); + for (int i = from; i <= to; i++) { + vec.addElement(IntValue.gen(i)); + } + return vec; + } + + static { + EnumerableValue.setRandom(15041980L); + EnumerableValue.resetRandom(); + + FP64.Init(); + + enum016 = new SetEnumValue(getValues(1, 16), true); + enum032 = new SetEnumValue(getValues(1, 32), true); + enum064 = new SetEnumValue(getValues(1, 64), true); + enum128 = new SetEnumValue(getValues(1, 128), true); + enum256 = new SetEnumValue(getValues(1, 256), true); + enum512 = new SetEnumValue(getValues(1, 512), true); + enum1024 = new SetEnumValue(getValues(1, 1024), true); + enum2048 = new SetEnumValue(getValues(1, 2048), true); + enum4096 = new SetEnumValue(getValues(1, 4096), true); + enum8192 = new SetEnumValue(getValues(1, 8192), true); + enum16384 = new SetEnumValue(getValues(1, 16384), true); + enum32768 = new SetEnumValue(getValues(1, 32768), true); + enumTLCBound = new SetEnumValue(getValues(1, TLCGlobals.setBound), true); + + interval16 = new IntervalValue(0, 2 << 16); + interval20 = new IntervalValue(0, 2 << 20); + interval24 = new IntervalValue(0, 2 << 24); + interval28 = new IntervalValue(0, 2 << 28); + interval31 = new IntervalValue(0, Integer.MAX_VALUE); // maximum possible value for internal ValueVec + + fcns008x008 = new SetOfFcnsValue(new SetEnumValue(getValues(1, 8), true), + new SetEnumValue(getValues(1, 8), true)); + fcns011x011 = new SetOfFcnsValue(new SetEnumValue(getValues(1, 11), true), + new SetEnumValue(getValues(1, 11), true)); + fcns016x008 = new SetOfFcnsValue(new SetEnumValue(getValues(1, 16), true), + new SetEnumValue(getValues(1, 8), true)); + fcns016x016 = new SetOfFcnsValue(new SetEnumValue(getValues(1, 16), true), + new SetEnumValue(getValues(1, 16), true)); + fcns032x016 = new SetOfFcnsValue(new SetEnumValue(getValues(1, 32), true), + new SetEnumValue(getValues(1, 16), true)); + fcns032x032 = new SetOfFcnsValue(new SetEnumValue(getValues(1, 32), true), + new SetEnumValue(getValues(1, 32), true)); + fcns048x048 = new SetOfFcnsValue(new SetEnumValue(getValues(1, 48), true), + new SetEnumValue(getValues(1, 48), true)); + + subset2pow24 = new SubsetValue(new IntervalValue(1, 24)); + subset2pow31 = new SubsetValue(new IntervalValue(1, 31)); + subset2pow65 = new SubsetValue(new IntervalValue(1, 65)); + subset2pow150 = new SubsetValue(new IntervalValue(1, 150)); + subset2pow268 = new SubsetValue(new IntervalValue(1, 268)); + } + + /* exact */ + + @Benchmark + public EnumerableValue randomSetOfSubsetExact024k008() { + return subset2pow24.getRandomSetOfSubsets(twoPow08, 10); + } + + @Benchmark + public EnumerableValue randomSetOfSubsetExact024k012() { + return subset2pow24.getRandomSetOfSubsets(twoPow12, 10); + } + + @Benchmark + public EnumerableValue randomSetOfSubsetExact024k016() { + return subset2pow24.getRandomSetOfSubsets(twoPow16, 10); + } + + @Benchmark + public EnumerableValue randomSetOfSubsetExact031k008() { + return subset2pow31.getRandomSetOfSubsets(twoPow08, 10); + } + + @Benchmark + public EnumerableValue randomSetOfSubsetExact031k012() { + return subset2pow31.getRandomSetOfSubsets(twoPow12, 10); + } + + @Benchmark + public EnumerableValue randomSetOfSubsetExact031k016() { + return subset2pow31.getRandomSetOfSubsets(twoPow16, 10); + } + + @Benchmark + public EnumerableValue randomSetOfSubsetExact65k008() { + return subset2pow65.getRandomSetOfSubsets(twoPow08, 10); + } + + @Benchmark + public EnumerableValue randomSetOfSubsetExact065k012() { + return subset2pow65.getRandomSetOfSubsets(twoPow12, 10); + } + + @Benchmark + public EnumerableValue randomSetOfSubsetExact065k016() { + return subset2pow65.getRandomSetOfSubsets(twoPow16, 10); + } + + @Benchmark + public EnumerableValue randomSetOfSubsetExact150k008() { + return subset2pow150.getRandomSetOfSubsets(twoPow08, 10); + } + + @Benchmark + public EnumerableValue randomSetOfSubsetExact150k012() { + return subset2pow150.getRandomSetOfSubsets(twoPow12, 10); + } + + @Benchmark + public EnumerableValue randomSetOfSubsetExact150k016() { + return subset2pow150.getRandomSetOfSubsets(twoPow16, 10); + } + + @Benchmark + public EnumerableValue randomSetOfSubsetExact268k008() { + return subset2pow268.getRandomSetOfSubsets(twoPow08, 10); + } + + @Benchmark + public EnumerableValue randomSetOfSubsetExact268k012() { + return subset2pow268.getRandomSetOfSubsets(twoPow12, 10); + } + + @Benchmark + public EnumerableValue randomSetOfSubsetExact268k016() { + return subset2pow268.getRandomSetOfSubsets(twoPow16, 10); + } + + /* probabilistic */ + + @Benchmark + public EnumerableValue randomSetOfSubset024k008() { + return subset2pow24.getRandomSetOfSubsets(twoPow08, .1d); + } + + @Benchmark + public EnumerableValue randomSetOfSubset024k012() { + return subset2pow24.getRandomSetOfSubsets(twoPow12, .1d); + } + + @Benchmark + public EnumerableValue randomSetOfSubset024k016() { + return subset2pow24.getRandomSetOfSubsets(twoPow16, .1d); + } + + @Benchmark + public EnumerableValue randomSetOfSubset031k008() { + return subset2pow31.getRandomSetOfSubsets(twoPow08, .1d); + } + + @Benchmark + public EnumerableValue randomSetOfSubset031k012() { + return subset2pow31.getRandomSetOfSubsets(twoPow12, .1d); + } + + @Benchmark + public EnumerableValue randomSetOfSubset031k016() { + return subset2pow31.getRandomSetOfSubsets(twoPow16, .1d); + } + + @Benchmark + public EnumerableValue randomSetOfSubset065k008() { + return subset2pow65.getRandomSetOfSubsets(twoPow08, .1d); + } + + @Benchmark + public EnumerableValue randomSetOfSubset065k012() { + return subset2pow65.getRandomSetOfSubsets(twoPow12, .1d); + } + + @Benchmark + public EnumerableValue randomSetOfSubset065k016() { + return subset2pow65.getRandomSetOfSubsets(twoPow16, .1d); + } + + @Benchmark + public EnumerableValue randomSetOfSubset150k008() { + return subset2pow150.getRandomSetOfSubsets(twoPow08, .1d); + } + + @Benchmark + public EnumerableValue randomSetOfSubset150k012() { + return subset2pow150.getRandomSetOfSubsets(twoPow12, .1d); + } + + @Benchmark + public EnumerableValue randomSetOfSubset150k016() { + return subset2pow150.getRandomSetOfSubsets(twoPow16, .1d); + } + + @Benchmark + public EnumerableValue randomSetOfSubset268k008() { + return subset2pow268.getRandomSetOfSubsets(twoPow08, .1d); + } + + @Benchmark + public EnumerableValue randomSetOfSubset268k012() { + return subset2pow268.getRandomSetOfSubsets(twoPow12, .1d); + } + + @Benchmark + public EnumerableValue randomSetOfSubset268k016() { + return subset2pow268.getRandomSetOfSubsets(twoPow16, .1d); + } + + /* IntervalValue */ + + @Benchmark + public EnumerableValue randomInterval016setBound() { + return interval16.getRandomSubset(TLCGlobals.setBound); + } + + @Benchmark + public EnumerableValue randomInterval020setBound() { + return interval20.getRandomSubset(TLCGlobals.setBound); + } + + @Benchmark + public EnumerableValue randomInterval024setBound() { + return interval24.getRandomSubset(TLCGlobals.setBound); + } + + @Benchmark + public EnumerableValue randomInterval028setBound() { + return interval28.getRandomSubset(TLCGlobals.setBound); + } + + @Benchmark + public EnumerableValue randomInterval031setBound() { + return interval31.getRandomSubset(TLCGlobals.setBound); + } + + @Benchmark + public EnumerableValue randomIntervalt016all() { + return interval16.getRandomSubset(interval16.size() - 1); + } + + @Benchmark + public EnumerableValue randomInterval020all() { + return interval20.getRandomSubset(interval20.size() - 1); + } + + @Benchmark + public EnumerableValue randomInterval024all() { + return interval24.getRandomSubset(interval24.size() - 1); + } + + @Benchmark + public EnumerableValue randomIntervalt016half() { + return interval16.getRandomSubset(interval16.size() / 2); + } + + @Benchmark + public EnumerableValue randomInterval020half() { + return interval20.getRandomSubset(interval20.size() / 2); + } + + @Benchmark + public EnumerableValue randomInterval024half() { + return interval24.getRandomSubset(interval24.size() / 2); + } + + /* SetEnumValue */ + + @Benchmark + public EnumerableValue randomSubset016() { + return enum016.getRandomSubset(enum016.size() - 1); + } + + @Benchmark + public EnumerableValue randomSubset032() { + return enum032.getRandomSubset(enum032.size() - 1); + } + + @Benchmark + public EnumerableValue randomSubset064() { + return enum064.getRandomSubset(enum064.size() - 1); + } + + @Benchmark + public EnumerableValue randomSubset128() { + return enum128.getRandomSubset(enum128.size() - 1); + } + + @Benchmark + public EnumerableValue randomSubset256() { + return enum256.getRandomSubset(enum256.size() - 1); + } + + @Benchmark + public EnumerableValue randomSubset512() { + return enum512.getRandomSubset(enum512.size() - 1); + } + + @Benchmark + public EnumerableValue randomSubset1024() { + return enum1024.getRandomSubset(enum1024.size() - 1); + } + + @Benchmark + public EnumerableValue randomSubset2048() { + return enum2048.getRandomSubset(enum2048.size() - 1); + } + + @Benchmark + public EnumerableValue randomSubset4096() { + return enum4096.getRandomSubset(enum4096.size() - 1); + } + + @Benchmark + public EnumerableValue randomSubset8192() { + return enum8192.getRandomSubset(enum8192.size() - 1); + } + + @Benchmark + public EnumerableValue randomSubset16384() { + return enum16384.getRandomSubset(enum16384.size() - 1); + } + + @Benchmark + public EnumerableValue randomSubset32768() { + return enum32768.getRandomSubset(enum32768.size() - 1); + } + + @Benchmark + public EnumerableValue randomSubsetTLCBound() { + return enumTLCBound.getRandomSubset(enumTLCBound.size() - 1); + } + + /* randomSubset with SetOfFcns */ + + @Benchmark + public EnumerableValue randomSubsetFcns008x008p16() { + return fcns008x008.getRandomSubset(twoPow16); + } + + @Benchmark + public EnumerableValue randomSubsetFcns008x008p08() { + return fcns008x008.getRandomSubset(twoPow08); + } + + @Benchmark + public EnumerableValue randomSubsetFcns008x008p12() { + return fcns008x008.getRandomSubset(twoPow12); + } + + @Benchmark + public EnumerableValue randomSubsetFcns011x011p16() { + return fcns008x008.getRandomSubset(twoPow16); + } + + @Benchmark + public EnumerableValue randomSubsetFcns011x011p08() { + return fcns011x011.getRandomSubset(twoPow08); + } + + @Benchmark + public EnumerableValue randomSubsetFcns011x011p12() { + return fcns011x011.getRandomSubset(twoPow12); + } + + @Benchmark + public EnumerableValue randomSubsetFcns016x008p16() { + return fcns011x011.getRandomSubset(twoPow16); + } + + @Benchmark + public EnumerableValue randomSubsetFcns016x008p08() { + return fcns016x008.getRandomSubset(twoPow08); + } + + @Benchmark + public EnumerableValue randomSubsetFcns016x008p12() { + return fcns016x008.getRandomSubset(twoPow12); + } + + @Benchmark + public EnumerableValue randomSubsetFcns016x016p16() { + return fcns016x016.getRandomSubset(twoPow16); + } + + @Benchmark + public EnumerableValue randomSubsetFcns016x016p08() { + return fcns016x016.getRandomSubset(twoPow08); + } + + @Benchmark + public EnumerableValue randomSubsetFcns016x016p12() { + return fcns016x016.getRandomSubset(twoPow12); + } + + @Benchmark + public EnumerableValue randomSubsetFcns032x016p16() { + return fcns032x016.getRandomSubset(twoPow16); + } + + @Benchmark + public EnumerableValue randomSubsetFcns032x016p08() { + return fcns032x016.getRandomSubset(twoPow08); + } + + @Benchmark + public EnumerableValue randomSubsetFcns032x016p12() { + return fcns032x016.getRandomSubset(twoPow12); + } + + @Benchmark + public EnumerableValue randomSubsetFcns032x032p16() { + return fcns032x032.getRandomSubset(twoPow16); + } + + @Benchmark + public EnumerableValue randomSubsetFcns032x032p08() { + return fcns032x032.getRandomSubset(twoPow08); + } + + @Benchmark + public EnumerableValue randomSubsetFcns032x032p12() { + return fcns032x032.getRandomSubset(twoPow12); + } + + @Benchmark + public EnumerableValue randomSubsetFcns048x048p16() { + return fcns048x048.getRandomSubset(twoPow16); + } + + @Benchmark + public EnumerableValue randomSubsetFcns048x048p08() { + return fcns048x048.getRandomSubset(twoPow08); + } + + @Benchmark + public EnumerableValue randomSubsetFcns048x048p12() { + return fcns048x048.getRandomSubset(twoPow12); + } +} diff --git a/tlatools/test-benchmark/tlc2/value/SetEnumValueBenchmark.java b/tlatools/test-benchmark/tlc2/value/SetEnumValueBenchmark.java new file mode 100644 index 0000000000000000000000000000000000000000..91707427532edde57d05ddbb1993a2ae2fece837 --- /dev/null +++ b/tlatools/test-benchmark/tlc2/value/SetEnumValueBenchmark.java @@ -0,0 +1,72 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.value; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; + +import tlc2.util.FP64; + +@State(Scope.Benchmark) +public class SetEnumValueBenchmark { + + static { + EnumerableValue.setRandom(15041980L); + EnumerableValue.resetRandom(); + + FP64.Init(); + } + + private static ValueVec getValues(int from, int to) { + final ValueVec vec = new ValueVec(to - from); + for (int i = from; i <= to; i++) { + vec.addElement(IntValue.gen(i)); + } + return vec; + } + + @Param({"10", "12", "14", "16"}) + public int numOfElements; + + @Param({"16", "18", "20", "22"}) + public int size; + + public Enumerable setEnumValue; + + @Setup(Level.Invocation) + public void setup() { + setEnumValue = (Enumerable) new SetEnumValue(getValues(1, 1 << size), false).normalize(); + } + + @Benchmark + public EnumerableValue randomSubset() { + return setEnumValue.getRandomSubset(1 << numOfElements); + } +} diff --git a/tlatools/test-benchmark/tlc2/value/SetOfFcnsBenchmark.java b/tlatools/test-benchmark/tlc2/value/SetOfFcnsBenchmark.java new file mode 100644 index 0000000000000000000000000000000000000000..4e558e0501100679f955518b77a6257729bcfb47 --- /dev/null +++ b/tlatools/test-benchmark/tlc2/value/SetOfFcnsBenchmark.java @@ -0,0 +1,83 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.value; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; + +import tlc2.util.FP64; + +@State(Scope.Benchmark) +public class SetOfFcnsBenchmark { + + static { + EnumerableValue.setRandom(15041980L); + EnumerableValue.resetRandom(); + + FP64.Init(); + } + + @Param({"10", "12", "14", "16"}) + public int numOfElements; + + @Param({"16", "32", "46"}) + public int sizeT; + + @Param({"8", "16", "46"}) + public int sizeS; + + // 08x16 ~= 2^32 = 4294967296 + // 16x16 = 2^64 = 10^19 + // 16x32 ~= 2^128 ~= 10^38 + // 46x46 ~= 2^256 ~= 10^77 + + public Enumerable setOfFcns; + + @Setup(Level.Invocation) + public void setup() { + if ((sizeS == 8 && sizeT == 16) + || (sizeS == 16 && sizeT == 16) + || (sizeS == 16 && sizeT == 32) + || (sizeS == 46 && sizeT == 46)) { + final Value domain = new IntervalValue(1, sizeS); + final Value range = new IntervalValue(1, sizeT); + setOfFcns = (Enumerable) new SetOfFcnsValue(domain, range).normalize(); + } else { + // This appears to be the only way to skip permutations from the parameter space + // sizeS X sizeT X numOfElements. + System.exit(0); + } + } + + @Benchmark + public EnumerableValue randomSubset() { + return setOfFcns.getRandomSubset(1 << numOfElements); + } +} diff --git a/tlatools/test-benchmark/tlc2/value/SubsetBenchmark.java b/tlatools/test-benchmark/tlc2/value/SubsetBenchmark.java new file mode 100644 index 0000000000000000000000000000000000000000..63e05bff52979d853dfbd55c3f11839ba6262313 --- /dev/null +++ b/tlatools/test-benchmark/tlc2/value/SubsetBenchmark.java @@ -0,0 +1,76 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.value; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; + +import tlc2.util.FP64; + +@State(Scope.Benchmark) +public class SubsetBenchmark { + + static { + EnumerableValue.setRandom(15041980L); + EnumerableValue.resetRandom(); + + FP64.Init(); + } + + @Param({"10", "12", "14", "16", "20", "24"}) + public int numOfElements; + + @Param({"32", "64", "128", "256"}) + public int size; + + public SubsetValue subset; + + @Setup(Level.Invocation) + public void setup() { + if (size < 128 || (size >= 128 && numOfElements <= 20)) { + subset = (SubsetValue) new SubsetValue(new IntervalValue(1, size)).normalize(); + } else { + // This appears to be the only way to skip permutations from the parameter space + // size X numOfElements. These permutations will go OOM or reach GC overhad + // limit anyway. + System.exit(0); + } + } + + @Benchmark + public EnumerableValue randomSetOfSubsets() { + return subset.getRandomSetOfSubsets(1 << numOfElements, .1d); + } + + @Benchmark + public EnumerableValue randomSetOfSubsetsExact() { + return subset.getRandomSetOfSubsets(1 << numOfElements, 10); + } +} diff --git a/tlatools/test-benchmark/tlc2/value/SubsetValueBenchmark.java b/tlatools/test-benchmark/tlc2/value/SubsetValueBenchmark.java new file mode 100644 index 0000000000000000000000000000000000000000..10edca6895059679cf198737359346e9140f8eda --- /dev/null +++ b/tlatools/test-benchmark/tlc2/value/SubsetValueBenchmark.java @@ -0,0 +1,311 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.value; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; + +import tlc2.util.FP64; + +@State(Scope.Benchmark) +public class SubsetValueBenchmark { + + private static final SubsetValue subset35; + private static final SubsetValue subset60; + private static final SubsetValue subset100; + private static final SubsetValue subset200; + private static final SubsetValue subset300; + private static final SubsetValue subset400; + + private static final int k = 80000; + private static final double d = 0.1d; + private static final int k2 = 160000; + private static final double d2 = 0.2d; + + static { + EnumerableValue.setRandom(15041980L); + EnumerableValue.resetRandom(); + + FP64.Init(); + + subset35 = new SubsetValue(new IntervalValue(1, 35)); + subset35.normalize(); + subset60 = new SubsetValue(new IntervalValue(1, 60)); + subset60.normalize(); + subset100 = new SubsetValue(new IntervalValue(1, 100)); + subset100.normalize(); + subset200 = new SubsetValue(new IntervalValue(1, 200)); + subset200.normalize(); + subset300 = new SubsetValue(new IntervalValue(1, 300)); + subset300.normalize(); + subset400 = new SubsetValue(new IntervalValue(1, 400)); + subset400.normalize(); + } + + @Benchmark + public EnumerableValue probabilisticN035k80d01() { + // ~49k subsets + return subset35.getRandomSetOfSubsets(k, d); + } + + @Benchmark + public EnumerableValue probabilisticN060k80d01() { + // ~76500 subsets + return subset60.getRandomSetOfSubsets(k, d); + } + + @Benchmark + public EnumerableValue probabilisticN100k80d01() { + // ~79900 + return subset100.getRandomSetOfSubsets(k, d); + } + + @Benchmark + public EnumerableValue probabilisticN200k80d01() { + // ~80k + return subset200.getRandomSetOfSubsets(k, d); + } + + @Benchmark + public EnumerableValue probabilisticN300k80d01() { + // ~80k + return subset300.getRandomSetOfSubsets(k, d); + } + + @Benchmark + public EnumerableValue probabilisticN400k80d01() { + // ~80k + return subset400.getRandomSetOfSubsets(k, d); + } + + @Benchmark + public EnumerableValue probabilisticN035k16d01() { + // ~73500 + return subset35.getRandomSetOfSubsets(k2, d); + } + + @Benchmark + public EnumerableValue probabilisticN060k16d01() { + // ~150k + return subset60.getRandomSetOfSubsets(k2, d); + } + + @Benchmark + public EnumerableValue probabilisticN100k16d01() { + // ~160k + return subset100.getRandomSetOfSubsets(k2, d); + } + + @Benchmark + public EnumerableValue probabilisticN200k16d01() { + // 160k + return subset200.getRandomSetOfSubsets(k2, d); + } + + @Benchmark + public EnumerableValue probabilisticN300k16d01() { + // 160k + return subset300.getRandomSetOfSubsets(k2, d); + } + + @Benchmark + public EnumerableValue probabilisticN400k16d01() { + // 160k + return subset400.getRandomSetOfSubsets(k2, d); + } + + /* d2 */ + + @Benchmark + public EnumerableValue probabilisticN035k80d02() { + // ~77600 + return subset35.getRandomSetOfSubsets(k, d2); + } + + @Benchmark + public EnumerableValue probabilisticN060k80d02() { + // 80k + return subset60.getRandomSetOfSubsets(k, d2); + } + + @Benchmark + public EnumerableValue probabilisticN100k80d02() { + // 80k + return subset100.getRandomSetOfSubsets(k, d2); + } + + @Benchmark + public EnumerableValue probabilisticN200k80d02() { + // 80k + return subset200.getRandomSetOfSubsets(k, d2); + } + + @Benchmark + public EnumerableValue probabilisticN300k80d02() { + // 80k + return subset300.getRandomSetOfSubsets(k, d2); + } + + @Benchmark + public EnumerableValue probabilisticN400k80d02() { + // 80k + return subset400.getRandomSetOfSubsets(k, d2); + } + + @Benchmark + public EnumerableValue probabilisticN035k16d02() { + // ~15200 + return subset35.getRandomSetOfSubsets(k2, d2); + } + + @Benchmark + public EnumerableValue probabilisticN060k16d02() { + // 160k + return subset60.getRandomSetOfSubsets(k2, d2); + } + + @Benchmark + public EnumerableValue probabilisticN100k16d02() { + // 160k + return subset100.getRandomSetOfSubsets(k2, d2); + } + + @Benchmark + public EnumerableValue probabilisticN200k16d02() { + // 160k + return subset200.getRandomSetOfSubsets(k2, d2); + } + + @Benchmark + public EnumerableValue probabilisticN300k16d02() { + // 160k + return subset300.getRandomSetOfSubsets(k2, d2); + } + + @Benchmark + public EnumerableValue probabilisticN400k16d02() { + // 160k + return subset400.getRandomSetOfSubsets(k2, d2); + } + + /* Exact getRandomSetOfSubsets */ + + @Benchmark + public EnumerableValue exactN035K08() { + return subset35.getRandomSetOfSubsets(k, 8); + } + + @Benchmark + public EnumerableValue exactN035K13() { + return subset35.getRandomSetOfSubsets(k, 13); + } + + @Benchmark + public EnumerableValue exactN060K08() { + return subset60.getRandomSetOfSubsets(k, 8); + } + + @Benchmark + public EnumerableValue exactN100K08() { + return subset100.getRandomSetOfSubsets(k, 8); + } + + @Benchmark + public EnumerableValue exactN100K10() { + return subset100.getRandomSetOfSubsets(k, 10); + } + + @Benchmark + public EnumerableValue exactN200K10() { + return subset200.getRandomSetOfSubsets(k, 10); + } + + @Benchmark + public EnumerableValue exactN300K09() { + return subset300.getRandomSetOfSubsets(k, 9); + } + + @Benchmark + public EnumerableValue exactN400K09() { + return subset400.getRandomSetOfSubsets(k, 9); + } + + /* k2 */ + + @Benchmark + public EnumerableValue exactN035K208() { + return subset35.getRandomSetOfSubsets(k2, 8); + } + + @Benchmark + public EnumerableValue exactN035K213() { + return subset35.getRandomSetOfSubsets(k2, 13); + } + + @Benchmark + public EnumerableValue exactN060K208() { + return subset60.getRandomSetOfSubsets(k2, 8); + } + + @Benchmark + public EnumerableValue exactN100K208() { + return subset100.getRandomSetOfSubsets(k2, 8); + } + + @Benchmark + public EnumerableValue exactN100K210() { + return subset100.getRandomSetOfSubsets(k2, 10); + } + + @Benchmark + public EnumerableValue exactN200K210() { + return subset200.getRandomSetOfSubsets(k2, 10); + } + + @Benchmark + public EnumerableValue exactN300K209() { + return subset300.getRandomSetOfSubsets(k2, 9); + } + + @Benchmark + public EnumerableValue exactN400K209() { + return subset400.getRandomSetOfSubsets(k2, 9); + } +} + +/* + * Mode.Throughput: Calculate number of operations in a time unit. (Higher score + * better) Mode.AverageTime: Calculate an average running time. (Lower score + * better) Mode.SampleTime: Calculate how long does it take for a method to run + * (including percentiles). Mode.SingleShotTime: Just run a method once (useful + * for cold-testing mode). Or more than once if you have specified a batch size + * for your iterations (see @Measurement annotation below) – in this case JMH + * will calculate the batch running time (total time for all invocations in a + * batch). Any set of these modes You can specify any set of these modes – the + * test will be run several times (depending on number of requested modes). + * Mode.All: All these modes one after another. + */ \ No newline at end of file diff --git a/tlatools/test-model/.gitattributes b/tlatools/test-model/.gitattributes new file mode 100644 index 0000000000000000000000000000000000000000..fcadb2cf97913f58a2523f535336e725c6b59d1f --- /dev/null +++ b/tlatools/test-model/.gitattributes @@ -0,0 +1 @@ +* text eol=lf diff --git a/tlatools/test-model/.gitignore b/tlatools/test-model/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..2f100884b03c579eea1de3e29a003ea94ac86545 --- /dev/null +++ b/tlatools/test-model/.gitignore @@ -0,0 +1,2 @@ +/CallGotoTest.old +/CallGotoUnlabeledTest.old diff --git a/tlatools/test-model/AssignmentNext.cfg b/tlatools/test-model/AssignmentNext.cfg index bc224b9def594b0819de3f0b45ede63ea8213c7b..c8cffbe64c3dcc8bce148218f2e7b66a7537f573 100644 --- a/tlatools/test-model/AssignmentNext.cfg +++ b/tlatools/test-model/AssignmentNext.cfg @@ -1,2 +1,4 @@ SPECIFICATION Spec +INVARIANT +Inv \ No newline at end of file diff --git a/tlatools/test-model/AssignmentNext.tla b/tlatools/test-model/AssignmentNext.tla index 94574a5ebf9567f6050a745894ab80eac1a569b6..75450d5ab5cfd5bb62dde3346e63959f5ecd0690 100644 --- a/tlatools/test-model/AssignmentNext.tla +++ b/tlatools/test-model/AssignmentNext.tla @@ -4,6 +4,7 @@ VARIABLE s Next(var) == \E val \in 0..1: (var' = val /\ var' > 0) -Spec == s = "" /\ [][Next(s)]_s +Spec == s = 23 /\ [][Next(s)]_s +Inv == s # 0 ============================================================================= diff --git a/tlatools/test-model/BagsTest.cfg b/tlatools/test-model/BagsTest.cfg new file mode 100644 index 0000000000000000000000000000000000000000..c03e566aa685ca74cda77763f103772eca0b2097 --- /dev/null +++ b/tlatools/test-model/BagsTest.cfg @@ -0,0 +1,4 @@ +SPECIFICATION +Spec +CONSTANT +C = C \ No newline at end of file diff --git a/tlatools/test-model/BagsTest.tla b/tlatools/test-model/BagsTest.tla new file mode 100644 index 0000000000000000000000000000000000000000..05dd61b84d5f28d64767b0da9a2b81c84c0ad831 --- /dev/null +++ b/tlatools/test-model/BagsTest.tla @@ -0,0 +1,199 @@ +---------------------------- MODULE BagsTest ---------------------------- +EXTENDS Bags, TLC, Integers + +CONSTANT C + +strings == {"a","b","c","d","e","f","g","h","i","j","k","l","m","n","o"} + +s == {"a","b","c"} + +a == <<>> +b == <<1,2,3>> +c == <<2,3,4>> +d == <<1,1,1>> +e == 1 :> 1 +f == 2 :> 1 +g == [x \in {1,2,3} |-> x * x] +h == [a |-> 3, b |-> 2, c |-> 1] + +ASSUME(EmptyBag = <<>>) + +\* IsABag +ASSUME(IsABag(a)) +ASSUME(IsABag(b)) +ASSUME(IsABag(c)) +ASSUME(IsABag(d)) +ASSUME(IsABag(e)) +ASSUME(IsABag(f)) +ASSUME(IsABag(g)) +ASSUME(IsABag(h)) + +ASSUME(IsABag(SetToBag({}))) + +t == <<0>> +u == 2 :> -1 +v == <<1,0>> +w == <<0,1>> +x == <<0,0,0>> +y == <<-1,-2,-3>> +z == <<"a","b","c">> + +ASSUME(~IsABag(t)) +ASSUME(~IsABag(u)) +ASSUME(~IsABag(v)) +ASSUME(~IsABag(w)) +ASSUME(~IsABag(x)) +ASSUME(~IsABag(y)) +ASSUME(~IsABag(z)) \* With the standard module TLC fails with "Cannot decide if element "a" is element of Nat" + +ASSUME(\A bool \in BOOLEAN : ~IsABag(bool)) +ASSUME(~IsABag(C)) + +\* BagCardinality +ASSUME(BagCardinality(a) = 0) +ASSUME(BagCardinality(b) = 6) +ASSUME(BagCardinality(c) = 9) +ASSUME(BagCardinality(d) = 3) +ASSUME(BagCardinality(e) = 1) +ASSUME(BagCardinality(f) = 1) +ASSUME(BagCardinality(g) = (1*1+2*2+3*3)) +ASSUME(BagCardinality(h) = 6) + +ASSUME(BagCardinality(<<1>>) = 1) +ASSUME(BagCardinality(<<1,3>>) = 4) + +\* BagIn +ASSUME(\A elem \in 1..10: ~BagIn(elem, a)) +ASSUME(\A elem \in 1..3: BagIn(elem, b)) +ASSUME(\A elem \in 4..10: ~BagIn(elem, b)) +ASSUME(\A dom \in DOMAIN c: BagIn(dom, c)) +ASSUME(\A dom \in DOMAIN d: BagIn(dom, d)) +ASSUME(\A dom \in DOMAIN e: BagIn(dom, e)) +ASSUME(\A dom \in DOMAIN f: BagIn(dom, f)) +ASSUME(\A dom \in DOMAIN f: BagIn(dom, f)) +ASSUME(\A dom \in DOMAIN g: BagIn(dom, g)) +ASSUME(\A dom \in DOMAIN h: BagIn(dom, h)) +ASSUME(\A str \in (strings \ DOMAIN h): ~BagIn(str, h)) +ASSUME(\A elem \in s : BagIn(elem, SetToBag(s))) + + +\* SetToBag and BagToSet +Codomain(fun) == {fun[i] : i \in DOMAIN fun} +ASSUME(SetToBag(s) = [elem \in s |-> 1]) +ASSUME(DOMAIN SetToBag(s) = s) +ASSUME(Codomain(SetToBag(s)) = {1}) +ASSUME(BagToSet(SetToBag(s)) = s) + +ASSUME(BagToSet(a) = {}) +ASSUME(BagToSet(b) = DOMAIN b) +ASSUME(BagToSet(c) = DOMAIN c) +ASSUME(BagToSet(d) = DOMAIN d) +ASSUME(BagToSet(e) = {1}) +ASSUME(BagToSet(f) = {2}) +ASSUME(BagToSet(g) = DOMAIN g) +ASSUME(BagToSet(h) = s) + + +\* CopiesIn +ASSUME(\A str \in strings: CopiesIn(str, a) = 0) + +ASSUME(\A dom \in DOMAIN b: CopiesIn(dom, b) = b[dom]) +ASSUME(\A elem \in 5..10: CopiesIn(elem, b) = 0) +ASSUME(\A dom \in DOMAIN c: CopiesIn(dom, c) = c[dom]) +ASSUME(\A elem \in 5..10: CopiesIn(elem, c) = 0) +ASSUME(\A dom \in DOMAIN d: CopiesIn(dom, d) = d[dom]) +ASSUME(\A elem \in 5..10: CopiesIn(elem, d) = 0) + +ASSUME(CopiesIn(1, e) = 1) +ASSUME(CopiesIn(2, f) = 1) +ASSUME(CopiesIn(1, f) = 0) +ASSUME(CopiesIn(1, 1 :> 0) = 0) +ASSUME(CopiesIn(2, 2 :> -1) = -1) + +ASSUME(\A dom \in DOMAIN g: CopiesIn(dom, g) = dom * dom) + +ASSUME(CopiesIn("a", h) = 3) +ASSUME(CopiesIn("b", h) = 2) +ASSUME(CopiesIn("c", h) = 1) +ASSUME(\A str \in (strings \ DOMAIN h): CopiesIn(str, h) = 0) + +ASSUME(\A aelem \in s: CopiesIn(aelem, [elem \in s |-> 42]) = 42) +ASSUME(\A aelem \in s: CopiesIn(aelem, [elem \in s |-> 0]) = 0) + + +\* (+) +ASSUME(EmptyBag (+) EmptyBag = EmptyBag) +ASSUME(a (+) a = a) +ASSUME(b (+) b = <<2,4,6>>) +ASSUME(b (+) EmptyBag = b) +ASSUME(c (+) c = <<4,6,8>>) +ASSUME(d (+) d = <<2,2,2>>) +ASSUME(e (+) e = <<2>>) +ASSUME(b (+) c = c (+) b) +ASSUME(b (+) c = <<3,5,7>>) +ASSUME(h (+) h = [a |-> 6, b |-> 4, c |-> 2]) +ASSUME([c |-> 3, d |-> 2, e |-> 1] (+) h = [a |-> 3, b |-> 2, c |-> 4, d |-> 2, e |-> 1]) + + +\* (-) +ASSUME(a (-) a = a) +ASSUME(b (-) b = EmptyBag) +ASSUME(b (-) EmptyBag = b) +ASSUME(c (-) c = EmptyBag) +ASSUME(d (-) d = EmptyBag) +ASSUME(e (-) e = EmptyBag) +ASSUME(b (-) c = b (-) c) +ASSUME(b (-) c = EmptyBag) +ASSUME(c (-) b = <<1,1,1>>) +ASSUME([c |-> 3, d |-> 2, e |-> 1] (-) h = [c |-> 2, d |-> 2, e |-> 1]) +ASSUME((1:>1) (-) EmptyBag = <<1>>) + + +\* BagUnion +ASSUME(BagUnion({a,a}) = a) +ASSUME(BagUnion({b,b}) = b) +ASSUME(BagUnion({c,c}) = c) +ASSUME(BagUnion({d,d}) = d) +ASSUME(BagUnion({e,e}) = e) +ASSUME(BagUnion({f,f}) = f) +ASSUME(BagUnion({g,g}) = g) +ASSUME(BagUnion({h,h}) = h) +ASSUME(BagUnion({h,h,[c |-> 3, d |-> 2, e |-> 1]}) = h (+) [c |-> 3, d |-> 2, e |-> 1]) +ASSUME(BagUnion({a,b,c,d}) = <<4,6,8>>) +ASSUME(BagUnion({EmptyBag, EmptyBag}) = <<>>) +ASSUME(BagUnion({[a |-> 3, b |-> 2, c |-> 1],[c |-> 3, d |-> 2, e |-> 1]}) = [a |-> 3, b |-> 2, c |-> 4, d |-> 2, e |-> 1]) +ASSUME(BagUnion({1 :> 2, 2 :> 2, 3 :> 3}) = (1 :> 2) (+) (2 :> 2) (+) (3 :> 3)) +ASSUME(BagUnion({<<>>, <<1,1,1>>, <<1,2,3,4>>}) = (1:>2 @@ 2:>3 @@ 3:>4 @@ 4:>4)) + + +\* \sqsubseteq +ASSUME((a \sqsubseteq a) = TRUE) +ASSUME((a \sqsubseteq b) = TRUE) +ASSUME((a \sqsubseteq c) = TRUE) +ASSUME((a \sqsubseteq d) = TRUE) +ASSUME((b \sqsubseteq b) = TRUE) +ASSUME((c \sqsubseteq c) = TRUE) +ASSUME((h \sqsubseteq [a |-> 3]) = FALSE) +ASSUME((h \sqsubseteq [a |-> 3, b |-> 2]) = FALSE) +ASSUME(([a |-> 3] \sqsubseteq h) = TRUE) +ASSUME(([a |-> 3, b |-> 2] \sqsubseteq h) = TRUE) +ASSUME(([a |-> 3, c |-> 1] \sqsubseteq h) = TRUE) +ASSUME(([b |-> 2, c |-> 1] \sqsubseteq h) = TRUE) +ASSUME((h \sqsubseteq h) = TRUE) + + +\* BagOfAll +ASSUME(BagOfAll(LAMBDA elem : elem, a) = a) +ASSUME(BagOfAll(LAMBDA elem : TRUE, a) = a) +ASSUME(BagOfAll(LAMBDA elem : elem, h) = h) +ASSUME(BagOfAll(LAMBDA elem : TRUE, h) = TRUE :> 6) +ASSUME(BagOfAll(LAMBDA elem : IF elem = "a" THEN "b" ELSE elem, [a |-> 3, b |-> 2, c |-> 1]) = [b |-> 5, c |-> 1]) + + +\* SubBag +\* Module overwrite does not overwrite SubBag + +\* A dummy spec to make TLC run model checking as required by BagsTest.java. +Spec == [][TRUE]_<<>> + +============================================================================= diff --git a/tlatools/test-model/Bug156/FindOp.tla b/tlatools/test-model/Bug156/FindOp.tla index 565d6a4166ec9be74f15724a037f9d77c2f84aeb..04f2226f73061387a7dff9a1088478688237375a 100644 --- a/tlatools/test-model/Bug156/FindOp.tla +++ b/tlatools/test-model/Bug156/FindOp.tla @@ -1,2474 +1,2474 @@ -Known Bugs: -- The operator may not be found if you click on a space inside its name, as in - "Bar (x) ! y" - -Known Features: -- Detects the ">" and "<" in " <3> " as operators. - -- If at a label that is also the name of an operator, then that operator - will be found. - -- An operator appearing inside a comment or a string will be found. - -------------------------------- MODULE FindOpWithoutPrint ------------------------------- -EXTENDS Integers, Sequences, TLC ------------------------------------------------------------------------------ -(***************************************************************************) -(* Operations for doing things in Java coordinates. *) -(***************************************************************************) -JavaSeq(seq) == [i \in 0 .. (Len(seq)-1) |-> seq[i+1]] - \* Turns a TLA sequence into a Java array. - -JavaSubseq(seq, b, e) == [i \in 0 .. (e-1-b) |-> seq[i+b]] - \* Corresponds to Java's Subseq String method. - -JavaLen(seq) == IF DOMAIN seq = {} - THEN 0 - ELSE 1 + - CHOOSE i \in DOMAIN seq : \A j \in DOMAIN seq : i >= j - \* Corresponds to Java's seq.size() for strings or seq.len for - \* arrays. - -JavaIndex(jarray, elt, fromPos) == - \* For jarray a Java array, it equals the smallest i >= fromPos such that - \* jarray[i] = elt, or -1 if there is no such i - LET Found(i) == jarray[i] = elt - lastIdx == JavaLen(jarray) - 1 - IN IF \E i \in fromPos .. lastIdx : Found(i) - THEN CHOOSE i \in fromPos .. lastIdx : /\ Found(i) - /\ \A j \in fromPos .. (i-1): ~Found(j) - ELSE -1 - -JavaSeqSeq(seq) == [i \in 0 .. (Len(seq)-1) |-> JavaSeq(seq[i+1])] - \* Converts a TLA sequence of TLA sequences to the corresponding - \* array of Java arrays - -JavaAppend(seq, elt) == LET len == JavaLen(seq) - IN [i \in 0..len |-> IF i = len THEN elt ELSE seq[i]] - \* Appends an element to the end of a Java sequence. - -JavaConcatenate(seq1, seq2) == LET len1 == JavaLen(seq1) - len2 == JavaLen(seq2) - IN [i \in 0..(len1 + len2-1) |-> - IF i < len1 THEN seq1[i] - ELSE seq2[i-len1]] - \* Concatenates two Java arrays - -IsJavaArray(array, S) == array \in [0..(JavaLen(array)-1) -> S] - \* True iff array is a Java array of elements of "type" S - -\* NullJavaArray == (-1 :> {}) ------------------------------------------------------------------------------ -(***************************************************************************) -(* The input. *) -(***************************************************************************) - -(***************************************************************************) -(* The contents of the current line of the module. *) -(***************************************************************************) -lineInput == JavaSeq(<< "f", "(" , "b", ")", \* " ", "!", " ", "a", "!" , " ", "g" , \* , " ", " ", " ", "(", "[", "x", "]", ")", " ", -\* "(", "e", ")", " ", -\* "<", "3", "4", ">", "a", "." -" " - >>) - - -(***************************************************************************) -(* The current position (in Java coordinates) of the cursor in the module. *) -(***************************************************************************) -currentPosition == 1 \* 7 ------------------------------------------------------------------------------ -Padding == JavaSeq(<<";", ";", ";", ";", ";", ";", ";", ";", ";", ";">>) - \* In an implementation ";" is replaced by an untypable character - - -GoingLeft == FALSE - \* TRUE would mean that we continue searching for the symbol to the left if - \* find that we're inside a subexpression selector. - -XSymbols == JavaSeqSeq(<< <<"(", "\\", "X", ")">> >>) - \* These are the Operators that contain "X". - \* Note that "\\X" is a TeXSymbol, not an Operator. - -Operators == JavaSeqSeq(<< -\* "-+->", "<=>", "...", "::=", "(+)", "(-)", "(.)", "(/)", "(\\X)", -\* "--", "**", "++", "<:", "<=", "<", ">=", "..", "||", "[]", "<>", -\* "/\\", "\\/", "//", "/", "/=", "~>", "=>", "=<", "=|", "^^", "##", -\* "|-", "|=", "&&", "$$", "??", "%%", "@@", "!!", ":>", ":=", "~", "=", -\* "#", "^", "-", "*", ">", "<", "+", "|", "&", "$", "%", "\\" -<< "(", "+", ")" >>, -<< "-", "+", "-", ">" >>, -<< "<", "=", ">" >>, -<< ".", ".", "." >>, -<< ":", ":", "=" >>, -<< "(", "-", ")" >>, -<< "(", ".", ")" >>, -<< "(", "/", ")" >>, -<< "(", "\\", "X", ")" >>, -<< "-", "-" >>, -<< "*", "*" >>, -<< "+", "+" >>, -<< "<", ":" >>, -<< "<", "=" >>, -<< "<", " " >>, -<< ">", "=" >>, -<< ".", "." >>, -<< "|", "|" >>, -<< "[", "]" >>, -<< "<", ">" >>, -<< "/", "\\" >>, -<< "\\", "/" >>, -<< "/", "/" >>, -<< "/", "=" >>, -<< "~", ">" >>, -<< "=", ">" >>, -<< "=", "<" >>, -<< "=", "|" >>, -<< "^", "^" >>, -<< "#", "#" >>, -<< "|", "-" >>, -<< "|", "=" >>, -<< "&", "&" >>, -<< "$", "$" >>, -<< "?", "?" >>, -<< "%", "%" >>, -<< "@", "@" >>, -<< "!", "!" >>, -<< ":", ">" >>, -<< ":", "=" >>, -<<"^", "+">>, -<<"^", "*">>, -<<"^", "#">>, -<<"~">>, -<<"=">>, -<<"#">>, -<<"^">>, -<<"-">>, -<<"*">>, -<<">">>, -<<"<">>, -<<"+">>, -<<"|">>, -<<"&">>, -<<"$">>, -<<"%">>, -<<"\\">>, -<<"'">> ->>) - -NonOperators == JavaSeqSeq( << -<<"=", "=">>, -<<"-", "-", "-">>, -<<"-", ">">>, -<<"<", "-">>, -<<"*", "*", "*">>, -<<"<", "<">>, -<<">", ">">> ->> ) - -\* ParenOperators == JavaSeqSeq( << -\* << "(", "+", ")" >>, -\* << "(", "-", ")" >>, -\* << "(", ".", ")" >>, -\* << "(", "/", ")" >>, -\* << "(", "\\", "X", ")" >> -\* >> ) - -TeXSymbols == JavaSeqSeq(<< -\* "\\neg", "\\lnot", "\\approx", -\* "\\asymp", "\\bigcirc", "\\bullet", "\\cap", "\\cdot", "\\circ", -\* "\\cong", "\\cup", "\\div", "\\doteq", "\\equiv", "\\geq", "\\gg", -\* "\\in", "\\intersect", "\\union", "\\land", "\\leq", "\\ll", "\\lor", -\* "\\mod", "\\o", "\\odot", "\\ominus", "\\oplus", "\\oslash", -\* "\\otimes", "\\prec", "\\preceq", "\\propto", "\\sim", "\\simeq", -\* "\\sqcap", "\\sqcup", "\\sqsubset", "\\sqsupset", "\\sqsubseteq", -\* "\\sqsupseteq", "\\star", "\\subset", "\\subseteq", "\\succ", -\* "\\succeq", "\\supset", "\\supseteq", "\\uplus", "\\wr", "\\notin", -\* "\\times", "\\X" -<<"\\", "n", "e", "g">>, -<<"\\", "l", "n", "o", "t">>, -<<"\\", "a", "p", "p", "r", "o", "x">>, -<<"\\", "a", "s", "y", "m", "p">>, -<<"\\", "b", "i", "g", "c", "i", "r", "c">>, -<<"\\", "b", "u", "l", "l", "e", "t">>, -<<"\\", "c", "a", "p">>, -<<"\\", "c", "d", "o", "t">>, -<<"\\", "c", "i", "r", "c">>, -<<"\\", "c", "o", "n", "g">>, -<<"\\", "c", "u", "p">>, -<<"\\", "d", "i", "v">>, -<<"\\", "d", "o", "t", "e", "q">>, -<<"\\", "e", "q", "u", "i", "v">>, -<<"\\", "g", "e", "q">>, -<<"\\", "g", "g">>, -<<"\\", "i", "n", "t", "e", "r", "s", "e", "c", "t">>, -<<"\\", "u", "n", "i", "o", "n">>, -<<"\\", "l", "a", "n", "d">>, -<<"\\", "l", "e", "q">>, -<<"\\", "l", "l">>, -<<"\\", "l", "o", "r">>, -<<"\\", "m", "o", "d">>, -<<"\\", "o", "d", "o", "t">>, -<<"\\", "o", "m", "i", "n", "u", "s">>, -<<"\\", "o", "p", "l", "u", "s">>, -<<"\\", "o", "s", "l", "a", "s", "h">>, -<<"\\", "o", "t", "i", "m", "e", "s">>, -<<"\\", "p", "r", "e", "c">>, -<<"\\", "p", "r", "e", "c", "e", "q", "">>, -<<"\\", "p", "r", "o", "p", "t", "o">>, -<<"\\", "s", "i", "m">>, -<<"\\", "s", "i", "m", "e", "q">>, -<<"\\", "s", "q", "c", "a", "p">>, -<<"\\", "s", "q", "c", "u", "p">>, -<<"\\", "s", "q", "s", "u", "b", "s", "e", "t">>, -<<"\\", "s", "q", "s", "u", "p", "s", "e", "t">>, -<<"\\", "s", "q", "s", "u", "b", "s", "e", "t", "e", "q">>, -<<"\\", "s", "q", "s", "u", "p", "s", "e", "t", "e", "q">>, -<<"\\", "s", "t", "a", "r">>, -<<"\\", "s", "u", "b", "s", "e", "t", "">>, -<<"\\", "s", "u", "b", "s", "e", "t", "e", "q">>, -<<"\\", "s", "u", "c", "c">>, -<<"\\", "s", "u", "c", "c", "e", "q">>, -<<"\\", "s", "u", "p", "s", "e", "t", "">>, -<<"\\", "s", "u", "p", "s", "e", "t", "e", "q">>, -<<"\\", "u", "p", "l", "u", "s">>, -<<"\\", "w", "r">>, -<<"\\", "n", "o", "t", "i", "n">>, -<<"\\", "t", "i", "m", "e", "s">>, -<<"\\", "o">>, -<<"\\", "i", "n">>, -<<"\\", "X">> ->>) - -IsNumber(seq) == /\ \A i \in DOMAIN seq : - seq[i] \in {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"} - /\ (DOMAIN seq) # {} -IdChar == {"a", "b", "c", "d", "e", "f", "g", "h", "i", "n", (* ... *) "X", "Y", "Z", - "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "_"} - -RightDelimiters == JavaSeqSeq(<< <<")">>, <<"]">>, <<"}">>, <<">", ">">> >>) -LeftDelimiters == JavaSeqSeq(<< <<"(">>, <<"[">>, <<"{">>, <<"<", "<">> >>) ------------------------------------------------------------------------------ -TokenSpec == [token : STRING, leftPos : Nat, rightPos : Nat] -NullTokenSpec == [null |-> "null"] -(**************************************************************************** - ---algorithm FindOp { -variables - line = JavaConcatenate (Padding, JavaConcatenate(lineInput, Padding)); - foundTokenSpecs = << >> ; - \* Array records of form [token |-> string of a token, - \* leftPos |-> location in line of left of token, - \* rightPos |-> location in line of just to the - \* right of token] - lastToken = FALSE; \* true if there can be no tokens to right of first - \* one found - notLastToken = FALSE; \* true if we found a "!" to the right of the - \* first token found. - curPos = currentPosition + JavaLen(Padding) ; - returnVal; \* Use for returning values from a procedure call. - tempVar1 ; - tempVar2 ; - tempVar3 ; - -define -{ - FixOrigin(tokarray) == - [i \in DOMAIN tokarray |-> - [token |->tokarray[i].token, rightPos |-> tokarray[i].rightPos - JavaLen(Padding), - leftPos |-> tokarray[i].leftPos - JavaLen(Padding)]] - -}; - -macro vreturn(val) -{ returnVal := val; - return; -} - -\* Returns the TokenSpec for the token in the array tokArray of -\* Java strings (Java array of 1-character strings) in the line -\* containing the character at position pos, or NullTokenSpec -\* if there is none. -procedure findTokenIn(pos, tokArray) - variables i ; tokIdx ; - { i := 0; - while (i < JavaLen(tokArray)) - { tokIdx := JavaIndex(tokArray[i], line[pos], 0); - while (tokIdx # -1) - { with (ftlft = pos - tokIdx, - ftrt = pos - tokIdx + JavaLen(tokArray[i])) - { if (tokArray[i] = JavaSubseq(line, ftlft, ftrt)) - { vreturn([token |-> tokArray[i], - leftPos |-> ftlft, rightPos |-> ftrt]) - }; - }; - tokIdx := JavaIndex(tokArray[i], line[pos], tokIdx+1); - }; - i := i+1; - }; - vreturn(NullTokenSpec); - } - - -\* Returns the TokenSpec of the largest token containing digits, -\* letters, and "_" characters containing position pos. Returns -\* NullTokenSpec if that would be an empty token. -procedure findMaximalIdCharSeq(pos) - variables token = << >>; left = pos; rt = pos; - { \* token := << >>; - \* left := pos; - while (line[left-1] \in IdChar) - { left := left-1; - }; - while (line[rt] \in IdChar) - { rt := rt+1 - }; - if (left = rt) - { vreturn(NullTokenSpec) } - else - { vreturn([token |-> JavaSubseq(line, left, rt), - leftPos |-> left, rightPos |-> rt]) - } - } - -\* Returns the position of the left paren matching a ")" at pos-1. -\* If there is none, it returns -1. -procedure findMatchingLeftParen(pos) -{ if (line[pos-1] # ")") {vreturn(pos)}; - call findMatchingLeftInner(pos, 0); - return; - } - -procedure findMatchingLeftInner(pos, delim) - variables ipos = pos; jdelim; delimLen; -{ delimLen := JavaLen(LeftDelimiters[delim]); - ipos := pos - delimLen; - while (JavaSubseq(line, ipos-delimLen, ipos) # LeftDelimiters[delim]) - { if (line[ipos-1] = ";") {vreturn(-1)}; - ipos := ipos-1; - jdelim := 0; - while (jdelim < JavaLen(LeftDelimiters)) - { if (JavaSubseq(line, ipos-delimLen, ipos) = RightDelimiters[jdelim]) - { call findMatchingLeftInner(ipos, jdelim); - ipos := returnVal; - if (ipos < 0) { vreturn(-1)}; - jdelim := 99 ; \* exit while loop - }; - jdelim := jdelim+1; - } - }; - vreturn(ipos-delimLen); - } - -\* Returns the position of the right paren matching a "(" at position pos. -\* If there is none, it returns -1. -procedure findMatchingRightParen(pos) -{ if (line[pos] # "(") {vreturn(pos)}; - call findMatchingRightInner(pos, 0); - return; - } - -procedure findMatchingRightInner(pos, delim) - variables ipos = pos; jdelim; delimLen; -{ delimLen := JavaLen(RightDelimiters[delim]); - ipos := pos + delimLen; - while (JavaSubseq(line, ipos, ipos+delimLen) # RightDelimiters[delim]) - { if (line[ipos] = ";") {vreturn(-1)}; - ipos := ipos+1; - jdelim := 0; - while (jdelim < JavaLen(RightDelimiters)) - { if (JavaSubseq(line, ipos, ipos+delimLen) = LeftDelimiters[jdelim]) - { call findMatchingRightInner(ipos, jdelim); - ipos := returnVal; - if (ipos < 0) { vreturn(-1)}; - jdelim := 99 ; \* exit while loop - }; - jdelim := jdelim+1; - } - }; - vreturn(ipos+delimLen); - } - -\* Assumes that leftTok and rightTok are two TokenSpecs, -\* possibly NullTokenSpecs, separated by a ">". Checks -\* if they form a step name. If so, it returns the -\* TokenSpec for that step name; otherwise it returns -\* NullTokenSpec. -procedure checkIfStepName(leftTok, rightTok) -{ if (leftTok = NullTokenSpec \/ rightTok = NullTokenSpec) - { vreturn(NullTokenSpec) }; - if ( /\ IsNumber(leftTok.token) - /\ line[leftTok.leftPos-1] = "<" - /\ line[leftTok.leftPos-2] # "<" ) - { vreturn( [token |-> JavaSubseq(line, - leftTok.leftPos-1, - rightTok.rightPos), - leftPos |-> leftTok.leftPos-1, - rightPos |-> rightTok.rightPos] ) - }; - else { vreturn(NullTokenSpec) }; -} -procedure skipLeftOverSpaces() -{ while (line[curPos-1] = " ") { curPos := curPos - 1; }; - return; -} - -procedure skipRightOverSpaces() -{ while (line[curPos] = " ") { curPos := curPos+1; }; - return; -} - -\* Returns a TokenSpec array of possible tokens to be selected -\* when the cursor is at position curPos of line. It -\* returns a zero-length array if there are none. -\* -\* Known Bug: This will not work right in some cases when curPos -\* are spaces inside a name, as in -\* -\* Foo (x, y)!bar -\* ^ -procedure findTokenSpecs() -variables currentToken; left; rt; notDone; foundBangToken; -temp1; temp2; temp3; -{ \* Try to find the current TokenSpec and put it in foundTokenSpecs, - \* leaving curPos to the left of that token. If the token is a - \* step name, we can return that single TokenSpec as the spec. - \* If it is an unnamed step, or if it is not a possible identifier - \* or operator symbol, we return << >> (a zero-length array). - - \* First, we must check if we may be inside a string of form (" ")^* "!" (" ")^* - \* and, if so, move to its left, setting notLastToken to TRUE - if (line[curPos] = " ") - { call skipLeftOverSpaces() ; - if (line[curPos-1] = "!" /\ line[curPos-2] # "!") - { notLastToken := TRUE; - curPos := curPos - 1; - call skipLeftOverSpaces(); - } - } - else if (line[curPos] = "!" /\ line[curPos-1] # "!" /\ line[curPos+1] # "!") - { notLastToken := TRUE; - call skipLeftOverSpaces() - }; - - \* If we're to the right of a ")", we could be inside something like - \* - \* Foo(42) ! bar - \* ^ - \* so we set notLastToken true and move to the left of the parentesized string. - if ( /\ \/ notLastToken - \/ line[curPos] = " " - /\ line[curPos-1] = ")") - { notLastToken := TRUE; - call findMatchingLeftParen(curPos); - if (returnVal < 0) {vreturn(<< >>)}; - curPos := returnVal; - call skipLeftOverSpaces(); - }; - \* If notLastToken is true, then we should be just to the right - \* of the token we are expecting to find to the left of the "!" or the - \* parenthesized expression. - \* Otherwise, if we're not at an IdChar or at an operator, then - \* let's try one character to the left. - \* Note: this happens to work if we're right before "<4>7" or "\in" - \* because both "<" and "\\" are operators. - - if (notLastToken) { curPos := curPos - 1; }; - else - { if (line[curPos] \notin IdChar) - { call findTokenIn(curPos, Operators); - if ( returnVal = NullTokenSpec ) - { curPos := curPos - 1 - } - } - - } ; -\* \* Following code replaced by preceding "else" clause -\* -\* \* If we didn't move left and we're at a "(" or "." that's not the beginning -\* \* of an operator, let's move left 1. -\* if (~ notLastToken /\ line[curPos] = "(") -\* { call findTokenIn(curPos, ParenOperators); -\* if (returnVal = NullTokenSpec) { curPos := curPos - 1 } -\* } -\* else if ( /\ ~ notLastToken -\* /\ line[curPos] = "." -\* /\ line[curPos+1] # "." -\* /\ line[curPos-1] # "." ) -\* { curPos := curPos - 1 }; -\* -\* \* If we're at a space (which means we haven't found a "!" or moved left -\* \* over a parenthesized string), then try as if the cursor were -\* \* one character to the left. -\* if (line[curPos] = " ") { curPos := curPos - 1}; - - if (line[curPos] \in IdChar) - { \* Check if we're at an "X" that is inside an "\X" or "\X". - \* Note: this works because there are no TeXSymbols besides - if (line[curPos] = "X") { call findTokenIn(curPos, XSymbols); } - else {returnVal := NullTokenSpec} ; - if (returnVal # NullTokenSpec) - { foundTokenSpecs := JavaSeq(<<returnVal>>); - curPos := returnVal.leftPos; - lastToken := TRUE; - } - else - { call findMaximalIdCharSeq(curPos); - currentToken := returnVal; - \* Check if token is part of step name. If it is, we set - \* First, see if currentToken could be the token after the "<...>". - if ( line[currentToken.leftPos-1] = ">" ) - { call findMaximalIdCharSeq(currentToken.leftPos - 1); - call checkIfStepName(returnVal, currentToken); - if (returnVal # NullTokenSpec) - { foundTokenSpecs := JavaSeq(<<returnVal>>); - vreturn(FixOrigin(foundTokenSpecs)); - } - }; - \* Next see if it's the token to the left of the ">" - if (line[currentToken.rightPos] = ">" ) - { call findMaximalIdCharSeq(currentToken.rightPos+1); - call checkIfStepName(currentToken, returnVal); - if (returnVal # NullTokenSpec) - { foundTokenSpecs := JavaSeq(<<returnVal>>); - vreturn(FixOrigin(foundTokenSpecs)); - } - }; - - \* Next, check if it's a number, and abort if it is. - if (IsNumber(currentToken.token)) - { vreturn(<< >>) - }; - - \* Next, check if the token appears as "\\"token, in - \* which case we adjust currentTok - left := currentToken.leftPos ; - rt := currentToken.rightPos ; - if ( /\ line[left-1] = "\\" - /\ line[left-2] # "\\" - /\ \E ii \in DOMAIN TeXSymbols : - JavaSubseq(line, left-1, rt) = TeXSymbols[ii] ) - { lastToken := TRUE; - currentToken.leftPos := left - 1 || - currentToken.token := JavaSubseq(line, left-1, rt); - }; - foundTokenSpecs := - JavaSeq( << currentToken >>); - curPos := left; - } - } - else - { call findTokenIn(curPos, Operators); - currentToken := returnVal; - if (currentToken = NullTokenSpec) - { vreturn(<< >>); - }; - call findTokenIn(curPos, NonOperators); - if (returnVal # NullTokenSpec) - { vreturn(<< >>); - }; - - \* Need to check if beginning or end of level specifier - \* of step number. - if ( currentToken.token = JavaSeq(<< "<" >>) ) - { call findMaximalIdCharSeq(currentToken.rightPos); - temp1 := returnVal; - if (/\ temp1 # NullTokenSpec - /\ line[temp1.rightPos] = ">") - { call findMaximalIdCharSeq(temp1.rightPos + 1); - temp2 := returnVal; - call checkIfStepName(temp1, temp2); - if (returnVal # NullTokenSpec) - { foundTokenSpecs := JavaSeq(<<returnVal>>); - vreturn(FixOrigin(foundTokenSpecs)); - } - } - } - else if (currentToken.token = JavaSeq(<< ">" >>)) - { call findMaximalIdCharSeq(currentToken.leftPos); - temp1 := returnVal; - call findMaximalIdCharSeq(currentToken.rightPos); - temp2 := returnVal; - call checkIfStepName(temp1, temp2); - if (returnVal # NullTokenSpec) - { foundTokenSpecs := JavaSeq(<<returnVal>>); - vreturn(FixOrigin(foundTokenSpecs)); - } - }; - - \* We check for the case of a "\\" starting a TeX token. - if (currentToken.token = JavaSeq(<<"\\">>)) - { call findMaximalIdCharSeq(currentToken.rightPos); - if ( /\ returnVal # NullTokenSpec - /\ \E ii \in DOMAIN TeXSymbols : - JavaSubseq(line, - currentToken.leftPos, - returnVal.rightPos) = TeXSymbols[ii] ) - { currentToken.rightPos := returnVal.rightPos || - currentToken.token := JavaSubseq(line, - currentToken.leftPos, - returnVal.rightPos) - } - }; - - foundTokenSpecs := JavaSeq(<<currentToken>>); - curPos := currentToken.leftPos; - lastToken := TRUE; - }; - - assert JavaLen(foundTokenSpecs) = 1; - -\*print <<"1", foundTokenSpecs[0]>>; - \** We have now found the base token. We now look to find extenders - \* to the left of the form idtoken "!". These must be part of the - \* name, so we prepend them to foundTokenSpecs[0]. - curPos := foundTokenSpecs[0].leftPos; - notDone := TRUE; - while (notDone) - { call skipLeftOverSpaces(); - if (curPos < 0 \/ line[curPos-1] = ";") - { notDone := FALSE; } - else - { if (line[curPos-1] = "!" /\ (line[curPos-2] # "!")) - { curPos := curPos - 1; - call skipLeftOverSpaces(); - call findMatchingLeftParen(curPos); - curPos := returnVal; - if (curPos < 0) { notDone := FALSE } - else - { call skipLeftOverSpaces(); - call findMaximalIdCharSeq(curPos); - currentToken := returnVal ; - if ( \/ currentToken = NullTokenSpec - \/ IsNumber(currentToken.token) ) - { notDone := FALSE } - else - { curPos := currentToken.leftPos; - foundTokenSpecs[0] := - [token |-> JavaConcatenate( - JavaAppend(currentToken.token, "!"), - foundTokenSpecs[0].token), - leftPos |-> curPos, - rightPos |-> foundTokenSpecs[0].rightPos]; - } - } - } - else {notDone := FALSE;} - }; - - }; - - assert foundTokenSpecs # << >> ; - - if (lastToken = TRUE) {vreturn(FixOrigin(foundTokenSpecs))}; - -\* print <<"2", foundTokenSpecs[0]>>; - - curPos := foundTokenSpecs[0].rightPos; - foundBangToken := FALSE; - notDone := TRUE; - while (notDone) - { call skipRightOverSpaces(); - call findMatchingRightParen(curPos); - curPos := returnVal; - if (curPos < 0) {notDone := FALSE} - else - { call skipRightOverSpaces(); - if (line[curPos] # "!" \/ line[curPos+1] = "!") - { notDone := FALSE } - else - { curPos := curPos + 1; - call skipRightOverSpaces(); - call findMaximalIdCharSeq(curPos); - currentToken := returnVal ; - if ( \/ currentToken = NullTokenSpec - \/ IsNumber(currentToken.token) ) - { notDone := FALSE } - else - { foundBangToken := TRUE; - foundTokenSpecs := - JavaConcatenate( - JavaSeq( - << [token |-> - JavaConcatenate(JavaAppend(foundTokenSpecs[0].token, - "!"), - currentToken.token), - leftPos |-> foundTokenSpecs[0].leftPos, - rightPos |-> currentToken.rightPos] - >> ) , - foundTokenSpecs); - curPos := currentToken.rightPos; - } - } - } - }; - - if (notLastToken /\ ~ foundBangToken) { vreturn (<< >>) }; - - vreturn(FixOrigin(foundTokenSpecs)); -} \* end findTokenSpecs - -\* Main Body: -{ curPos := JavaLen(Padding); - tempVar1 := (-1 :> ""); - tempVar2 := JavaLen(Padding); -\*curPos := 15; -\*call findTokenSpecs(); -\*print returnVal; -\* print line; - while (tempVar2 < JavaLen(lineInput) + JavaLen(Padding)) - { \* print <<"curPos: ", tempVar2>>; - curPos := tempVar2; - foundTokenSpecs := << >> ; - lastToken := FALSE; - notLastToken := FALSE; - call findTokenSpecs(); -\* if (tempVar2 >= 0 + JavaLen(Padding)) -\* { print "done with run" ; -\* assert FALSE -\* }; -\* if (returnVal = tempVar1) -\* { print "same" \* ,"lastToken: ", lastToken, ", notLastToken: ", notLastToken>> -\* } -\* else -\* { print returnVal; - \* print <<"lastToken: ", lastToken, ", notLastToken: ", notLastToken>>; -\* }; - tempVar1 := returnVal; - tempVar2 := tempVar2 + 1; - }; - print "goodby world"; - -} \* end Main Body -} \* End algorithm - -*****************************************************************************************) -\* BEGIN TRANSLATION -\* Procedure variable left of procedure findMaximalIdCharSeq at line 317 col 28 changed to left_ -\* Procedure variable rt of procedure findMaximalIdCharSeq at line 317 col 40 changed to rt_ -\* Procedure variable ipos of procedure findMatchingLeftInner at line 343 col 12 changed to ipos_ -\* Procedure variable jdelim of procedure findMatchingLeftInner at line 343 col 24 changed to jdelim_ -\* Procedure variable delimLen of procedure findMatchingLeftInner at line 343 col 32 changed to delimLen_ -\* Parameter pos of procedure findTokenIn at line 292 col 23 changed to pos_ -\* Parameter pos of procedure findMaximalIdCharSeq at line 316 col 32 changed to pos_f -\* Parameter pos of procedure findMatchingLeftParen at line 336 col 33 changed to pos_fi -\* Parameter pos of procedure findMatchingLeftInner at line 342 col 33 changed to pos_fin -\* Parameter delim of procedure findMatchingLeftInner at line 342 col 38 changed to delim_ -\* Parameter pos of procedure findMatchingRightParen at line 365 col 34 changed to pos_find -CONSTANT defaultInitValue +Known Bugs: +- The operator may not be found if you click on a space inside its name, as in + "Bar (x) ! y" + +Known Features: +- Detects the ">" and "<" in " <3> " as operators. + +- If at a label that is also the name of an operator, then that operator + will be found. + +- An operator appearing inside a comment or a string will be found. + +------------------------------- MODULE FindOpWithoutPrint ------------------------------- +EXTENDS Integers, Sequences, TLC +----------------------------------------------------------------------------- +(***************************************************************************) +(* Operations for doing things in Java coordinates. *) +(***************************************************************************) +JavaSeq(seq) == [i \in 0 .. (Len(seq)-1) |-> seq[i+1]] + \* Turns a TLA sequence into a Java array. + +JavaSubseq(seq, b, e) == [i \in 0 .. (e-1-b) |-> seq[i+b]] + \* Corresponds to Java's Subseq String method. + +JavaLen(seq) == IF DOMAIN seq = {} + THEN 0 + ELSE 1 + + CHOOSE i \in DOMAIN seq : \A j \in DOMAIN seq : i >= j + \* Corresponds to Java's seq.size() for strings or seq.len for + \* arrays. + +JavaIndex(jarray, elt, fromPos) == + \* For jarray a Java array, it equals the smallest i >= fromPos such that + \* jarray[i] = elt, or -1 if there is no such i + LET Found(i) == jarray[i] = elt + lastIdx == JavaLen(jarray) - 1 + IN IF \E i \in fromPos .. lastIdx : Found(i) + THEN CHOOSE i \in fromPos .. lastIdx : /\ Found(i) + /\ \A j \in fromPos .. (i-1): ~Found(j) + ELSE -1 + +JavaSeqSeq(seq) == [i \in 0 .. (Len(seq)-1) |-> JavaSeq(seq[i+1])] + \* Converts a TLA sequence of TLA sequences to the corresponding + \* array of Java arrays + +JavaAppend(seq, elt) == LET len == JavaLen(seq) + IN [i \in 0..len |-> IF i = len THEN elt ELSE seq[i]] + \* Appends an element to the end of a Java sequence. + +JavaConcatenate(seq1, seq2) == LET len1 == JavaLen(seq1) + len2 == JavaLen(seq2) + IN [i \in 0..(len1 + len2-1) |-> + IF i < len1 THEN seq1[i] + ELSE seq2[i-len1]] + \* Concatenates two Java arrays + +IsJavaArray(array, S) == array \in [0..(JavaLen(array)-1) -> S] + \* True iff array is a Java array of elements of "type" S + +\* NullJavaArray == (-1 :> {}) +----------------------------------------------------------------------------- +(***************************************************************************) +(* The input. *) +(***************************************************************************) + +(***************************************************************************) +(* The contents of the current line of the module. *) +(***************************************************************************) +lineInput == JavaSeq(<< "f", "(" , "b", ")", \* " ", "!", " ", "a", "!" , " ", "g" , \* , " ", " ", " ", "(", "[", "x", "]", ")", " ", +\* "(", "e", ")", " ", +\* "<", "3", "4", ">", "a", "." +" " + >>) + + +(***************************************************************************) +(* The current position (in Java coordinates) of the cursor in the module. *) +(***************************************************************************) +currentPosition == 1 \* 7 +----------------------------------------------------------------------------- +Padding == JavaSeq(<<";", ";", ";", ";", ";", ";", ";", ";", ";", ";">>) + \* In an implementation ";" is replaced by an untypable character + + +GoingLeft == FALSE + \* TRUE would mean that we continue searching for the symbol to the left if + \* find that we're inside a subexpression selector. + +XSymbols == JavaSeqSeq(<< <<"(", "\\", "X", ")">> >>) + \* These are the Operators that contain "X". + \* Note that "\\X" is a TeXSymbol, not an Operator. + +Operators == JavaSeqSeq(<< +\* "-+->", "<=>", "...", "::=", "(+)", "(-)", "(.)", "(/)", "(\\X)", +\* "--", "**", "++", "<:", "<=", "<", ">=", "..", "||", "[]", "<>", +\* "/\\", "\\/", "//", "/", "/=", "~>", "=>", "=<", "=|", "^^", "##", +\* "|-", "|=", "&&", "$$", "??", "%%", "@@", "!!", ":>", ":=", "~", "=", +\* "#", "^", "-", "*", ">", "<", "+", "|", "&", "$", "%", "\\" +<< "(", "+", ")" >>, +<< "-", "+", "-", ">" >>, +<< "<", "=", ">" >>, +<< ".", ".", "." >>, +<< ":", ":", "=" >>, +<< "(", "-", ")" >>, +<< "(", ".", ")" >>, +<< "(", "/", ")" >>, +<< "(", "\\", "X", ")" >>, +<< "-", "-" >>, +<< "*", "*" >>, +<< "+", "+" >>, +<< "<", ":" >>, +<< "<", "=" >>, +<< "<", " " >>, +<< ">", "=" >>, +<< ".", "." >>, +<< "|", "|" >>, +<< "[", "]" >>, +<< "<", ">" >>, +<< "/", "\\" >>, +<< "\\", "/" >>, +<< "/", "/" >>, +<< "/", "=" >>, +<< "~", ">" >>, +<< "=", ">" >>, +<< "=", "<" >>, +<< "=", "|" >>, +<< "^", "^" >>, +<< "#", "#" >>, +<< "|", "-" >>, +<< "|", "=" >>, +<< "&", "&" >>, +<< "$", "$" >>, +<< "?", "?" >>, +<< "%", "%" >>, +<< "@", "@" >>, +<< "!", "!" >>, +<< ":", ">" >>, +<< ":", "=" >>, +<<"^", "+">>, +<<"^", "*">>, +<<"^", "#">>, +<<"~">>, +<<"=">>, +<<"#">>, +<<"^">>, +<<"-">>, +<<"*">>, +<<">">>, +<<"<">>, +<<"+">>, +<<"|">>, +<<"&">>, +<<"$">>, +<<"%">>, +<<"\\">>, +<<"'">> +>>) + +NonOperators == JavaSeqSeq( << +<<"=", "=">>, +<<"-", "-", "-">>, +<<"-", ">">>, +<<"<", "-">>, +<<"*", "*", "*">>, +<<"<", "<">>, +<<">", ">">> +>> ) + +\* ParenOperators == JavaSeqSeq( << +\* << "(", "+", ")" >>, +\* << "(", "-", ")" >>, +\* << "(", ".", ")" >>, +\* << "(", "/", ")" >>, +\* << "(", "\\", "X", ")" >> +\* >> ) + +TeXSymbols == JavaSeqSeq(<< +\* "\\neg", "\\lnot", "\\approx", +\* "\\asymp", "\\bigcirc", "\\bullet", "\\cap", "\\cdot", "\\circ", +\* "\\cong", "\\cup", "\\div", "\\doteq", "\\equiv", "\\geq", "\\gg", +\* "\\in", "\\intersect", "\\union", "\\land", "\\leq", "\\ll", "\\lor", +\* "\\mod", "\\o", "\\odot", "\\ominus", "\\oplus", "\\oslash", +\* "\\otimes", "\\prec", "\\preceq", "\\propto", "\\sim", "\\simeq", +\* "\\sqcap", "\\sqcup", "\\sqsubset", "\\sqsupset", "\\sqsubseteq", +\* "\\sqsupseteq", "\\star", "\\subset", "\\subseteq", "\\succ", +\* "\\succeq", "\\supset", "\\supseteq", "\\uplus", "\\wr", "\\notin", +\* "\\times", "\\X" +<<"\\", "n", "e", "g">>, +<<"\\", "l", "n", "o", "t">>, +<<"\\", "a", "p", "p", "r", "o", "x">>, +<<"\\", "a", "s", "y", "m", "p">>, +<<"\\", "b", "i", "g", "c", "i", "r", "c">>, +<<"\\", "b", "u", "l", "l", "e", "t">>, +<<"\\", "c", "a", "p">>, +<<"\\", "c", "d", "o", "t">>, +<<"\\", "c", "i", "r", "c">>, +<<"\\", "c", "o", "n", "g">>, +<<"\\", "c", "u", "p">>, +<<"\\", "d", "i", "v">>, +<<"\\", "d", "o", "t", "e", "q">>, +<<"\\", "e", "q", "u", "i", "v">>, +<<"\\", "g", "e", "q">>, +<<"\\", "g", "g">>, +<<"\\", "i", "n", "t", "e", "r", "s", "e", "c", "t">>, +<<"\\", "u", "n", "i", "o", "n">>, +<<"\\", "l", "a", "n", "d">>, +<<"\\", "l", "e", "q">>, +<<"\\", "l", "l">>, +<<"\\", "l", "o", "r">>, +<<"\\", "m", "o", "d">>, +<<"\\", "o", "d", "o", "t">>, +<<"\\", "o", "m", "i", "n", "u", "s">>, +<<"\\", "o", "p", "l", "u", "s">>, +<<"\\", "o", "s", "l", "a", "s", "h">>, +<<"\\", "o", "t", "i", "m", "e", "s">>, +<<"\\", "p", "r", "e", "c">>, +<<"\\", "p", "r", "e", "c", "e", "q", "">>, +<<"\\", "p", "r", "o", "p", "t", "o">>, +<<"\\", "s", "i", "m">>, +<<"\\", "s", "i", "m", "e", "q">>, +<<"\\", "s", "q", "c", "a", "p">>, +<<"\\", "s", "q", "c", "u", "p">>, +<<"\\", "s", "q", "s", "u", "b", "s", "e", "t">>, +<<"\\", "s", "q", "s", "u", "p", "s", "e", "t">>, +<<"\\", "s", "q", "s", "u", "b", "s", "e", "t", "e", "q">>, +<<"\\", "s", "q", "s", "u", "p", "s", "e", "t", "e", "q">>, +<<"\\", "s", "t", "a", "r">>, +<<"\\", "s", "u", "b", "s", "e", "t", "">>, +<<"\\", "s", "u", "b", "s", "e", "t", "e", "q">>, +<<"\\", "s", "u", "c", "c">>, +<<"\\", "s", "u", "c", "c", "e", "q">>, +<<"\\", "s", "u", "p", "s", "e", "t", "">>, +<<"\\", "s", "u", "p", "s", "e", "t", "e", "q">>, +<<"\\", "u", "p", "l", "u", "s">>, +<<"\\", "w", "r">>, +<<"\\", "n", "o", "t", "i", "n">>, +<<"\\", "t", "i", "m", "e", "s">>, +<<"\\", "o">>, +<<"\\", "i", "n">>, +<<"\\", "X">> +>>) + +IsNumber(seq) == /\ \A i \in DOMAIN seq : + seq[i] \in {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"} + /\ (DOMAIN seq) # {} +IdChar == {"a", "b", "c", "d", "e", "f", "g", "h", "i", "n", (* ... *) "X", "Y", "Z", + "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "_"} + +RightDelimiters == JavaSeqSeq(<< <<")">>, <<"]">>, <<"}">>, <<">", ">">> >>) +LeftDelimiters == JavaSeqSeq(<< <<"(">>, <<"[">>, <<"{">>, <<"<", "<">> >>) +----------------------------------------------------------------------------- +TokenSpec == [token : STRING, leftPos : Nat, rightPos : Nat] +NullTokenSpec == [null |-> "null"] +(**************************************************************************** + +--algorithm FindOp { +variables + line = JavaConcatenate (Padding, JavaConcatenate(lineInput, Padding)); + foundTokenSpecs = << >> ; + \* Array records of form [token |-> string of a token, + \* leftPos |-> location in line of left of token, + \* rightPos |-> location in line of just to the + \* right of token] + lastToken = FALSE; \* true if there can be no tokens to right of first + \* one found + notLastToken = FALSE; \* true if we found a "!" to the right of the + \* first token found. + curPos = currentPosition + JavaLen(Padding) ; + returnVal; \* Use for returning values from a procedure call. + tempVar1 ; + tempVar2 ; + tempVar3 ; + +define +{ + FixOrigin(tokarray) == + [i \in DOMAIN tokarray |-> + [token |->tokarray[i].token, rightPos |-> tokarray[i].rightPos - JavaLen(Padding), + leftPos |-> tokarray[i].leftPos - JavaLen(Padding)]] + +}; + +macro vreturn(val) +{ returnVal := val; + return; +} + +\* Returns the TokenSpec for the token in the array tokArray of +\* Java strings (Java array of 1-character strings) in the line +\* containing the character at position pos, or NullTokenSpec +\* if there is none. +procedure findTokenIn(pos, tokArray) + variables i ; tokIdx ; + { i := 0; + while (i < JavaLen(tokArray)) + { tokIdx := JavaIndex(tokArray[i], line[pos], 0); + while (tokIdx # -1) + { with (ftlft = pos - tokIdx, + ftrt = pos - tokIdx + JavaLen(tokArray[i])) + { if (tokArray[i] = JavaSubseq(line, ftlft, ftrt)) + { vreturn([token |-> tokArray[i], + leftPos |-> ftlft, rightPos |-> ftrt]) + }; + }; + tokIdx := JavaIndex(tokArray[i], line[pos], tokIdx+1); + }; + i := i+1; + }; + vreturn(NullTokenSpec); + } + + +\* Returns the TokenSpec of the largest token containing digits, +\* letters, and "_" characters containing position pos. Returns +\* NullTokenSpec if that would be an empty token. +procedure findMaximalIdCharSeq(pos) + variables token = << >>; left = pos; rt = pos; + { \* token := << >>; + \* left := pos; + while (line[left-1] \in IdChar) + { left := left-1; + }; + while (line[rt] \in IdChar) + { rt := rt+1 + }; + if (left = rt) + { vreturn(NullTokenSpec) } + else + { vreturn([token |-> JavaSubseq(line, left, rt), + leftPos |-> left, rightPos |-> rt]) + } + } + +\* Returns the position of the left paren matching a ")" at pos-1. +\* If there is none, it returns -1. +procedure findMatchingLeftParen(pos) +{ if (line[pos-1] # ")") {vreturn(pos)}; + call findMatchingLeftInner(pos, 0); + return; + } + +procedure findMatchingLeftInner(pos, delim) + variables ipos = pos; jdelim; delimLen; +{ delimLen := JavaLen(LeftDelimiters[delim]); + ipos := pos - delimLen; + while (JavaSubseq(line, ipos-delimLen, ipos) # LeftDelimiters[delim]) + { if (line[ipos-1] = ";") {vreturn(-1)}; + ipos := ipos-1; + jdelim := 0; + while (jdelim < JavaLen(LeftDelimiters)) + { if (JavaSubseq(line, ipos-delimLen, ipos) = RightDelimiters[jdelim]) + { call findMatchingLeftInner(ipos, jdelim); + ipos := returnVal; + if (ipos < 0) { vreturn(-1)}; + jdelim := 99 ; \* exit while loop + }; + jdelim := jdelim+1; + } + }; + vreturn(ipos-delimLen); + } + +\* Returns the position of the right paren matching a "(" at position pos. +\* If there is none, it returns -1. +procedure findMatchingRightParen(pos) +{ if (line[pos] # "(") {vreturn(pos)}; + call findMatchingRightInner(pos, 0); + return; + } + +procedure findMatchingRightInner(pos, delim) + variables ipos = pos; jdelim; delimLen; +{ delimLen := JavaLen(RightDelimiters[delim]); + ipos := pos + delimLen; + while (JavaSubseq(line, ipos, ipos+delimLen) # RightDelimiters[delim]) + { if (line[ipos] = ";") {vreturn(-1)}; + ipos := ipos+1; + jdelim := 0; + while (jdelim < JavaLen(RightDelimiters)) + { if (JavaSubseq(line, ipos, ipos+delimLen) = LeftDelimiters[jdelim]) + { call findMatchingRightInner(ipos, jdelim); + ipos := returnVal; + if (ipos < 0) { vreturn(-1)}; + jdelim := 99 ; \* exit while loop + }; + jdelim := jdelim+1; + } + }; + vreturn(ipos+delimLen); + } + +\* Assumes that leftTok and rightTok are two TokenSpecs, +\* possibly NullTokenSpecs, separated by a ">". Checks +\* if they form a step name. If so, it returns the +\* TokenSpec for that step name; otherwise it returns +\* NullTokenSpec. +procedure checkIfStepName(leftTok, rightTok) +{ if (leftTok = NullTokenSpec \/ rightTok = NullTokenSpec) + { vreturn(NullTokenSpec) }; + if ( /\ IsNumber(leftTok.token) + /\ line[leftTok.leftPos-1] = "<" + /\ line[leftTok.leftPos-2] # "<" ) + { vreturn( [token |-> JavaSubseq(line, + leftTok.leftPos-1, + rightTok.rightPos), + leftPos |-> leftTok.leftPos-1, + rightPos |-> rightTok.rightPos] ) + }; + else { vreturn(NullTokenSpec) }; +} +procedure skipLeftOverSpaces() +{ while (line[curPos-1] = " ") { curPos := curPos - 1; }; + return; +} + +procedure skipRightOverSpaces() +{ while (line[curPos] = " ") { curPos := curPos+1; }; + return; +} + +\* Returns a TokenSpec array of possible tokens to be selected +\* when the cursor is at position curPos of line. It +\* returns a zero-length array if there are none. +\* +\* Known Bug: This will not work right in some cases when curPos +\* are spaces inside a name, as in +\* +\* Foo (x, y)!bar +\* ^ +procedure findTokenSpecs() +variables currentToken; left; rt; notDone; foundBangToken; +temp1; temp2; temp3; +{ \* Try to find the current TokenSpec and put it in foundTokenSpecs, + \* leaving curPos to the left of that token. If the token is a + \* step name, we can return that single TokenSpec as the spec. + \* If it is an unnamed step, or if it is not a possible identifier + \* or operator symbol, we return << >> (a zero-length array). + + \* First, we must check if we may be inside a string of form (" ")^* "!" (" ")^* + \* and, if so, move to its left, setting notLastToken to TRUE + if (line[curPos] = " ") + { call skipLeftOverSpaces() ; + if (line[curPos-1] = "!" /\ line[curPos-2] # "!") + { notLastToken := TRUE; + curPos := curPos - 1; + call skipLeftOverSpaces(); + } + } + else if (line[curPos] = "!" /\ line[curPos-1] # "!" /\ line[curPos+1] # "!") + { notLastToken := TRUE; + call skipLeftOverSpaces() + }; + + \* If we're to the right of a ")", we could be inside something like + \* + \* Foo(42) ! bar + \* ^ + \* so we set notLastToken true and move to the left of the parentesized string. + if ( /\ \/ notLastToken + \/ line[curPos] = " " + /\ line[curPos-1] = ")") + { notLastToken := TRUE; + call findMatchingLeftParen(curPos); + if (returnVal < 0) {vreturn(<< >>)}; + curPos := returnVal; + call skipLeftOverSpaces(); + }; + \* If notLastToken is true, then we should be just to the right + \* of the token we are expecting to find to the left of the "!" or the + \* parenthesized expression. + \* Otherwise, if we're not at an IdChar or at an operator, then + \* let's try one character to the left. + \* Note: this happens to work if we're right before "<4>7" or "\in" + \* because both "<" and "\\" are operators. + + if (notLastToken) { curPos := curPos - 1; }; + else + { if (line[curPos] \notin IdChar) + { call findTokenIn(curPos, Operators); + if ( returnVal = NullTokenSpec ) + { curPos := curPos - 1 + } + } + + } ; +\* \* Following code replaced by preceding "else" clause +\* +\* \* If we didn't move left and we're at a "(" or "." that's not the beginning +\* \* of an operator, let's move left 1. +\* if (~ notLastToken /\ line[curPos] = "(") +\* { call findTokenIn(curPos, ParenOperators); +\* if (returnVal = NullTokenSpec) { curPos := curPos - 1 } +\* } +\* else if ( /\ ~ notLastToken +\* /\ line[curPos] = "." +\* /\ line[curPos+1] # "." +\* /\ line[curPos-1] # "." ) +\* { curPos := curPos - 1 }; +\* +\* \* If we're at a space (which means we haven't found a "!" or moved left +\* \* over a parenthesized string), then try as if the cursor were +\* \* one character to the left. +\* if (line[curPos] = " ") { curPos := curPos - 1}; + + if (line[curPos] \in IdChar) + { \* Check if we're at an "X" that is inside an "\X" or "\X". + \* Note: this works because there are no TeXSymbols besides + if (line[curPos] = "X") { call findTokenIn(curPos, XSymbols); } + else {returnVal := NullTokenSpec} ; + if (returnVal # NullTokenSpec) + { foundTokenSpecs := JavaSeq(<<returnVal>>); + curPos := returnVal.leftPos; + lastToken := TRUE; + } + else + { call findMaximalIdCharSeq(curPos); + currentToken := returnVal; + \* Check if token is part of step name. If it is, we set + \* First, see if currentToken could be the token after the "<...>". + if ( line[currentToken.leftPos-1] = ">" ) + { call findMaximalIdCharSeq(currentToken.leftPos - 1); + call checkIfStepName(returnVal, currentToken); + if (returnVal # NullTokenSpec) + { foundTokenSpecs := JavaSeq(<<returnVal>>); + vreturn(FixOrigin(foundTokenSpecs)); + } + }; + \* Next see if it's the token to the left of the ">" + if (line[currentToken.rightPos] = ">" ) + { call findMaximalIdCharSeq(currentToken.rightPos+1); + call checkIfStepName(currentToken, returnVal); + if (returnVal # NullTokenSpec) + { foundTokenSpecs := JavaSeq(<<returnVal>>); + vreturn(FixOrigin(foundTokenSpecs)); + } + }; + + \* Next, check if it's a number, and abort if it is. + if (IsNumber(currentToken.token)) + { vreturn(<< >>) + }; + + \* Next, check if the token appears as "\\"token, in + \* which case we adjust currentTok + left := currentToken.leftPos ; + rt := currentToken.rightPos ; + if ( /\ line[left-1] = "\\" + /\ line[left-2] # "\\" + /\ \E ii \in DOMAIN TeXSymbols : + JavaSubseq(line, left-1, rt) = TeXSymbols[ii] ) + { lastToken := TRUE; + currentToken.leftPos := left - 1 || + currentToken.token := JavaSubseq(line, left-1, rt); + }; + foundTokenSpecs := + JavaSeq( << currentToken >>); + curPos := left; + } + } + else + { call findTokenIn(curPos, Operators); + currentToken := returnVal; + if (currentToken = NullTokenSpec) + { vreturn(<< >>); + }; + call findTokenIn(curPos, NonOperators); + if (returnVal # NullTokenSpec) + { vreturn(<< >>); + }; + + \* Need to check if beginning or end of level specifier + \* of step number. + if ( currentToken.token = JavaSeq(<< "<" >>) ) + { call findMaximalIdCharSeq(currentToken.rightPos); + temp1 := returnVal; + if (/\ temp1 # NullTokenSpec + /\ line[temp1.rightPos] = ">") + { call findMaximalIdCharSeq(temp1.rightPos + 1); + temp2 := returnVal; + call checkIfStepName(temp1, temp2); + if (returnVal # NullTokenSpec) + { foundTokenSpecs := JavaSeq(<<returnVal>>); + vreturn(FixOrigin(foundTokenSpecs)); + } + } + } + else if (currentToken.token = JavaSeq(<< ">" >>)) + { call findMaximalIdCharSeq(currentToken.leftPos); + temp1 := returnVal; + call findMaximalIdCharSeq(currentToken.rightPos); + temp2 := returnVal; + call checkIfStepName(temp1, temp2); + if (returnVal # NullTokenSpec) + { foundTokenSpecs := JavaSeq(<<returnVal>>); + vreturn(FixOrigin(foundTokenSpecs)); + } + }; + + \* We check for the case of a "\\" starting a TeX token. + if (currentToken.token = JavaSeq(<<"\\">>)) + { call findMaximalIdCharSeq(currentToken.rightPos); + if ( /\ returnVal # NullTokenSpec + /\ \E ii \in DOMAIN TeXSymbols : + JavaSubseq(line, + currentToken.leftPos, + returnVal.rightPos) = TeXSymbols[ii] ) + { currentToken.rightPos := returnVal.rightPos || + currentToken.token := JavaSubseq(line, + currentToken.leftPos, + returnVal.rightPos) + } + }; + + foundTokenSpecs := JavaSeq(<<currentToken>>); + curPos := currentToken.leftPos; + lastToken := TRUE; + }; + + assert JavaLen(foundTokenSpecs) = 1; + +\*print <<"1", foundTokenSpecs[0]>>; + \** We have now found the base token. We now look to find extenders + \* to the left of the form idtoken "!". These must be part of the + \* name, so we prepend them to foundTokenSpecs[0]. + curPos := foundTokenSpecs[0].leftPos; + notDone := TRUE; + while (notDone) + { call skipLeftOverSpaces(); + if (curPos < 0 \/ line[curPos-1] = ";") + { notDone := FALSE; } + else + { if (line[curPos-1] = "!" /\ (line[curPos-2] # "!")) + { curPos := curPos - 1; + call skipLeftOverSpaces(); + call findMatchingLeftParen(curPos); + curPos := returnVal; + if (curPos < 0) { notDone := FALSE } + else + { call skipLeftOverSpaces(); + call findMaximalIdCharSeq(curPos); + currentToken := returnVal ; + if ( \/ currentToken = NullTokenSpec + \/ IsNumber(currentToken.token) ) + { notDone := FALSE } + else + { curPos := currentToken.leftPos; + foundTokenSpecs[0] := + [token |-> JavaConcatenate( + JavaAppend(currentToken.token, "!"), + foundTokenSpecs[0].token), + leftPos |-> curPos, + rightPos |-> foundTokenSpecs[0].rightPos]; + } + } + } + else {notDone := FALSE;} + }; + + }; + + assert foundTokenSpecs # << >> ; + + if (lastToken = TRUE) {vreturn(FixOrigin(foundTokenSpecs))}; + +\* print <<"2", foundTokenSpecs[0]>>; + + curPos := foundTokenSpecs[0].rightPos; + foundBangToken := FALSE; + notDone := TRUE; + while (notDone) + { call skipRightOverSpaces(); + call findMatchingRightParen(curPos); + curPos := returnVal; + if (curPos < 0) {notDone := FALSE} + else + { call skipRightOverSpaces(); + if (line[curPos] # "!" \/ line[curPos+1] = "!") + { notDone := FALSE } + else + { curPos := curPos + 1; + call skipRightOverSpaces(); + call findMaximalIdCharSeq(curPos); + currentToken := returnVal ; + if ( \/ currentToken = NullTokenSpec + \/ IsNumber(currentToken.token) ) + { notDone := FALSE } + else + { foundBangToken := TRUE; + foundTokenSpecs := + JavaConcatenate( + JavaSeq( + << [token |-> + JavaConcatenate(JavaAppend(foundTokenSpecs[0].token, + "!"), + currentToken.token), + leftPos |-> foundTokenSpecs[0].leftPos, + rightPos |-> currentToken.rightPos] + >> ) , + foundTokenSpecs); + curPos := currentToken.rightPos; + } + } + } + }; + + if (notLastToken /\ ~ foundBangToken) { vreturn (<< >>) }; + + vreturn(FixOrigin(foundTokenSpecs)); +} \* end findTokenSpecs + +\* Main Body: +{ curPos := JavaLen(Padding); + tempVar1 := (-1 :> ""); + tempVar2 := JavaLen(Padding); +\*curPos := 15; +\*call findTokenSpecs(); +\*print returnVal; +\* print line; + while (tempVar2 < JavaLen(lineInput) + JavaLen(Padding)) + { \* print <<"curPos: ", tempVar2>>; + curPos := tempVar2; + foundTokenSpecs := << >> ; + lastToken := FALSE; + notLastToken := FALSE; + call findTokenSpecs(); +\* if (tempVar2 >= 0 + JavaLen(Padding)) +\* { print "done with run" ; +\* assert FALSE +\* }; +\* if (returnVal = tempVar1) +\* { print "same" \* ,"lastToken: ", lastToken, ", notLastToken: ", notLastToken>> +\* } +\* else +\* { print returnVal; + \* print <<"lastToken: ", lastToken, ", notLastToken: ", notLastToken>>; +\* }; + tempVar1 := returnVal; + tempVar2 := tempVar2 + 1; + }; + print "goodby world"; + +} \* end Main Body +} \* End algorithm + +*****************************************************************************************) +\* BEGIN TRANSLATION +\* Procedure variable left of procedure findMaximalIdCharSeq at line 317 col 28 changed to left_ +\* Procedure variable rt of procedure findMaximalIdCharSeq at line 317 col 40 changed to rt_ +\* Procedure variable ipos of procedure findMatchingLeftInner at line 343 col 12 changed to ipos_ +\* Procedure variable jdelim of procedure findMatchingLeftInner at line 343 col 24 changed to jdelim_ +\* Procedure variable delimLen of procedure findMatchingLeftInner at line 343 col 32 changed to delimLen_ +\* Parameter pos of procedure findTokenIn at line 292 col 23 changed to pos_ +\* Parameter pos of procedure findMaximalIdCharSeq at line 316 col 32 changed to pos_f +\* Parameter pos of procedure findMatchingLeftParen at line 336 col 33 changed to pos_fi +\* Parameter pos of procedure findMatchingLeftInner at line 342 col 33 changed to pos_fin +\* Parameter delim of procedure findMatchingLeftInner at line 342 col 38 changed to delim_ +\* Parameter pos of procedure findMatchingRightParen at line 365 col 34 changed to pos_find +CONSTANT defaultInitValue VARIABLES line, foundTokenSpecs, lastToken, notLastToken, curPos, returnVal, - tempVar1, tempVar2, tempVar3, pc, stack - -(* define statement *) -FixOrigin(tokarray) == -[i \in DOMAIN tokarray |-> - [token |->tokarray[i].token, rightPos |-> tokarray[i].rightPos - JavaLen(Padding), - leftPos |-> tokarray[i].leftPos - JavaLen(Padding)]] - + tempVar1, tempVar2, tempVar3, pc, stack + +(* define statement *) +FixOrigin(tokarray) == +[i \in DOMAIN tokarray |-> + [token |->tokarray[i].token, rightPos |-> tokarray[i].rightPos - JavaLen(Padding), + leftPos |-> tokarray[i].leftPos - JavaLen(Padding)]] + VARIABLES pos_, tokArray, i, tokIdx, pos_f, token, left_, rt_, pos_fi, pos_fin, delim_, ipos_, jdelim_, delimLen_, pos_find, pos, delim, ipos, jdelim, delimLen, leftTok, rightTok, currentToken, left, rt, - notDone, foundBangToken, temp1, temp2, temp3 - + notDone, foundBangToken, temp1, temp2, temp3 + vars == << line, foundTokenSpecs, lastToken, notLastToken, curPos, returnVal, tempVar1, tempVar2, tempVar3, pc, stack, pos_, tokArray, i, tokIdx, pos_f, token, left_, rt_, pos_fi, pos_fin, delim_, ipos_, jdelim_, delimLen_, pos_find, pos, delim, ipos, jdelim, delimLen, leftTok, rightTok, currentToken, left, rt, notDone, foundBangToken, temp1, - temp2, temp3 >> - -Init == (* Global variables *) - /\ line = JavaConcatenate (Padding, JavaConcatenate(lineInput, Padding)) - /\ foundTokenSpecs = << >> - /\ lastToken = FALSE - /\ notLastToken = FALSE - /\ curPos = currentPosition + JavaLen(Padding) - /\ returnVal = defaultInitValue - /\ tempVar1 = defaultInitValue - /\ tempVar2 = defaultInitValue - /\ tempVar3 = defaultInitValue - (* Procedure findTokenIn *) - /\ pos_ = defaultInitValue - /\ tokArray = defaultInitValue - /\ i = defaultInitValue - /\ tokIdx = defaultInitValue - (* Procedure findMaximalIdCharSeq *) - /\ pos_f = defaultInitValue - /\ token = << >> - /\ left_ = pos_f - /\ rt_ = pos_f - (* Procedure findMatchingLeftParen *) - /\ pos_fi = defaultInitValue - (* Procedure findMatchingLeftInner *) - /\ pos_fin = defaultInitValue - /\ delim_ = defaultInitValue - /\ ipos_ = pos_fin - /\ jdelim_ = defaultInitValue - /\ delimLen_ = defaultInitValue - (* Procedure findMatchingRightParen *) - /\ pos_find = defaultInitValue - (* Procedure findMatchingRightInner *) - /\ pos = defaultInitValue - /\ delim = defaultInitValue - /\ ipos = pos - /\ jdelim = defaultInitValue - /\ delimLen = defaultInitValue - (* Procedure checkIfStepName *) - /\ leftTok = defaultInitValue - /\ rightTok = defaultInitValue - (* Procedure findTokenSpecs *) - /\ currentToken = defaultInitValue - /\ left = defaultInitValue - /\ rt = defaultInitValue - /\ notDone = defaultInitValue - /\ foundBangToken = defaultInitValue - /\ temp1 = defaultInitValue - /\ temp2 = defaultInitValue - /\ temp3 = defaultInitValue - /\ stack = << >> - /\ pc = "Lbl_77" - -Lbl_1 == /\ pc = "Lbl_1" - /\ i' = 0 - /\ pc' = "Lbl_2" - /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, - curPos, returnVal, tempVar1, tempVar2, tempVar3, - stack, pos_, tokArray, tokIdx, pos_f, token, left_, - rt_, pos_fi, pos_fin, delim_, ipos_, jdelim_, - delimLen_, pos_find, pos, delim, ipos, jdelim, - delimLen, leftTok, rightTok, currentToken, left, rt, - notDone, foundBangToken, temp1, temp2, temp3 >> - -Lbl_2 == /\ pc = "Lbl_2" - /\ IF i < JavaLen(tokArray) - THEN /\ tokIdx' = JavaIndex(tokArray[i], line[pos_], 0) - /\ pc' = "Lbl_3" - /\ UNCHANGED << returnVal, stack, pos_, tokArray, i >> - ELSE /\ returnVal' = NullTokenSpec - /\ pc' = Head(stack).pc - /\ i' = Head(stack).i - /\ tokIdx' = Head(stack).tokIdx - /\ pos_' = Head(stack).pos_ - /\ tokArray' = Head(stack).tokArray - /\ stack' = Tail(stack) - /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, - curPos, tempVar1, tempVar2, tempVar3, pos_f, token, - left_, rt_, pos_fi, pos_fin, delim_, ipos_, jdelim_, - delimLen_, pos_find, pos, delim, ipos, jdelim, - delimLen, leftTok, rightTok, currentToken, left, rt, - notDone, foundBangToken, temp1, temp2, temp3 >> - -Lbl_3 == /\ pc = "Lbl_3" - /\ IF tokIdx # -1 - THEN /\ LET ftlft == pos_ - tokIdx IN - LET ftrt == pos_ - tokIdx + JavaLen(tokArray[i]) IN - IF tokArray[i] = JavaSubseq(line, ftlft, ftrt) - THEN /\ returnVal' = [token |-> tokArray[i], - leftPos |-> ftlft, rightPos |-> ftrt] - /\ pc' = Head(stack).pc - /\ i' = Head(stack).i - /\ tokIdx' = Head(stack).tokIdx - /\ pos_' = Head(stack).pos_ - /\ tokArray' = Head(stack).tokArray - /\ stack' = Tail(stack) - ELSE /\ pc' = "Lbl_4" - /\ UNCHANGED << returnVal, stack, pos_, - tokArray, i, tokIdx >> - ELSE /\ i' = i+1 - /\ pc' = "Lbl_2" - /\ UNCHANGED << returnVal, stack, pos_, tokArray, tokIdx >> - /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, - curPos, tempVar1, tempVar2, tempVar3, pos_f, token, - left_, rt_, pos_fi, pos_fin, delim_, ipos_, jdelim_, - delimLen_, pos_find, pos, delim, ipos, jdelim, - delimLen, leftTok, rightTok, currentToken, left, rt, - notDone, foundBangToken, temp1, temp2, temp3 >> - -Lbl_4 == /\ pc = "Lbl_4" - /\ tokIdx' = JavaIndex(tokArray[i], line[pos_], tokIdx+1) - /\ pc' = "Lbl_3" - /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, - curPos, returnVal, tempVar1, tempVar2, tempVar3, - stack, pos_, tokArray, i, pos_f, token, left_, rt_, - pos_fi, pos_fin, delim_, ipos_, jdelim_, delimLen_, - pos_find, pos, delim, ipos, jdelim, delimLen, leftTok, - rightTok, currentToken, left, rt, notDone, - foundBangToken, temp1, temp2, temp3 >> - -findTokenIn == Lbl_1 \/ Lbl_2 \/ Lbl_3 \/ Lbl_4 - -Lbl_5 == /\ pc = "Lbl_5" - /\ IF line[left_-1] \in IdChar - THEN /\ left_' = left_-1 - /\ pc' = "Lbl_5" - ELSE /\ pc' = "Lbl_6" - /\ left_' = left_ - /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, - curPos, returnVal, tempVar1, tempVar2, tempVar3, - stack, pos_, tokArray, i, tokIdx, pos_f, token, rt_, - pos_fi, pos_fin, delim_, ipos_, jdelim_, delimLen_, - pos_find, pos, delim, ipos, jdelim, delimLen, leftTok, - rightTok, currentToken, left, rt, notDone, - foundBangToken, temp1, temp2, temp3 >> - -Lbl_6 == /\ pc = "Lbl_6" - /\ IF line[rt_] \in IdChar - THEN /\ rt_' = rt_+1 - /\ pc' = "Lbl_6" - /\ UNCHANGED << returnVal, stack, pos_f, token, left_ >> - ELSE /\ IF left_ = rt_ - THEN /\ returnVal' = NullTokenSpec - /\ pc' = Head(stack).pc - /\ token' = Head(stack).token - /\ left_' = Head(stack).left_ - /\ rt_' = Head(stack).rt_ - /\ pos_f' = Head(stack).pos_f - /\ stack' = Tail(stack) - ELSE /\ returnVal' = [token |-> JavaSubseq(line, left_, rt_), - leftPos |-> left_, rightPos |-> rt_] - /\ pc' = Head(stack).pc - /\ token' = Head(stack).token - /\ left_' = Head(stack).left_ - /\ rt_' = Head(stack).rt_ - /\ pos_f' = Head(stack).pos_f - /\ stack' = Tail(stack) - /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, - curPos, tempVar1, tempVar2, tempVar3, pos_, tokArray, - i, tokIdx, pos_fi, pos_fin, delim_, ipos_, jdelim_, - delimLen_, pos_find, pos, delim, ipos, jdelim, - delimLen, leftTok, rightTok, currentToken, left, rt, - notDone, foundBangToken, temp1, temp2, temp3 >> - -findMaximalIdCharSeq == Lbl_5 \/ Lbl_6 - -Lbl_7 == /\ pc = "Lbl_7" - /\ IF line[pos_fi-1] # ")" - THEN /\ returnVal' = pos_fi - /\ pc' = Head(stack).pc - /\ pos_fi' = Head(stack).pos_fi - /\ stack' = Tail(stack) - ELSE /\ pc' = "Lbl_8" - /\ UNCHANGED << returnVal, stack, pos_fi >> - /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, - curPos, tempVar1, tempVar2, tempVar3, pos_, tokArray, - i, tokIdx, pos_f, token, left_, rt_, pos_fin, delim_, - ipos_, jdelim_, delimLen_, pos_find, pos, delim, ipos, - jdelim, delimLen, leftTok, rightTok, currentToken, - left, rt, notDone, foundBangToken, temp1, temp2, - temp3 >> - -Lbl_8 == /\ pc = "Lbl_8" - /\ /\ delim_' = 0 - /\ pos_fin' = pos_fi - /\ stack' = << [ procedure |-> "findMatchingLeftInner", - pc |-> Head(stack).pc, - ipos_ |-> ipos_, - jdelim_ |-> jdelim_, - delimLen_ |-> delimLen_, - pos_fin |-> pos_fin, - delim_ |-> delim_ ] >> - \o Tail(stack) - /\ ipos_' = pos_fin' - /\ jdelim_' = defaultInitValue - /\ delimLen_' = defaultInitValue - /\ pc' = "Lbl_9" - /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, - curPos, returnVal, tempVar1, tempVar2, tempVar3, pos_, - tokArray, i, tokIdx, pos_f, token, left_, rt_, pos_fi, - pos_find, pos, delim, ipos, jdelim, delimLen, leftTok, - rightTok, currentToken, left, rt, notDone, - foundBangToken, temp1, temp2, temp3 >> - -findMatchingLeftParen == Lbl_7 \/ Lbl_8 - -Lbl_9 == /\ pc = "Lbl_9" - /\ delimLen_' = JavaLen(LeftDelimiters[delim_]) - /\ ipos_' = pos_fin - delimLen_' - /\ pc' = "Lbl_10" - /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, - curPos, returnVal, tempVar1, tempVar2, tempVar3, - stack, pos_, tokArray, i, tokIdx, pos_f, token, left_, - rt_, pos_fi, pos_fin, delim_, jdelim_, pos_find, pos, - delim, ipos, jdelim, delimLen, leftTok, rightTok, - currentToken, left, rt, notDone, foundBangToken, - temp1, temp2, temp3 >> - -Lbl_10 == /\ pc = "Lbl_10" - /\ IF JavaSubseq(line, ipos_-delimLen_, ipos_) # LeftDelimiters[delim_] - THEN /\ IF line[ipos_-1] = ";" - THEN /\ returnVal' = -1 - /\ pc' = Head(stack).pc - /\ ipos_' = Head(stack).ipos_ - /\ jdelim_' = Head(stack).jdelim_ - /\ delimLen_' = Head(stack).delimLen_ - /\ pos_fin' = Head(stack).pos_fin - /\ delim_' = Head(stack).delim_ - /\ stack' = Tail(stack) - ELSE /\ pc' = "Lbl_11" - /\ UNCHANGED << returnVal, stack, pos_fin, - delim_, ipos_, jdelim_, - delimLen_ >> - ELSE /\ returnVal' = ipos_-delimLen_ - /\ pc' = Head(stack).pc - /\ ipos_' = Head(stack).ipos_ - /\ jdelim_' = Head(stack).jdelim_ - /\ delimLen_' = Head(stack).delimLen_ - /\ pos_fin' = Head(stack).pos_fin - /\ delim_' = Head(stack).delim_ - /\ stack' = Tail(stack) - /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, - curPos, tempVar1, tempVar2, tempVar3, pos_, tokArray, - i, tokIdx, pos_f, token, left_, rt_, pos_fi, - pos_find, pos, delim, ipos, jdelim, delimLen, - leftTok, rightTok, currentToken, left, rt, notDone, - foundBangToken, temp1, temp2, temp3 >> - -Lbl_11 == /\ pc = "Lbl_11" - /\ ipos_' = ipos_-1 - /\ jdelim_' = 0 - /\ pc' = "Lbl_12" - /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, - curPos, returnVal, tempVar1, tempVar2, tempVar3, - stack, pos_, tokArray, i, tokIdx, pos_f, token, - left_, rt_, pos_fi, pos_fin, delim_, delimLen_, - pos_find, pos, delim, ipos, jdelim, delimLen, - leftTok, rightTok, currentToken, left, rt, notDone, - foundBangToken, temp1, temp2, temp3 >> - -Lbl_12 == /\ pc = "Lbl_12" - /\ IF jdelim_ < JavaLen(LeftDelimiters) - THEN /\ IF JavaSubseq(line, ipos_-delimLen_, ipos_) = RightDelimiters[jdelim_] - THEN /\ /\ delim_' = jdelim_ - /\ pos_fin' = ipos_ - /\ stack' = << [ procedure |-> "findMatchingLeftInner", - pc |-> "Lbl_13", - ipos_ |-> ipos_, - jdelim_ |-> jdelim_, - delimLen_ |-> delimLen_, - pos_fin |-> pos_fin, - delim_ |-> delim_ ] >> - \o stack - /\ ipos_' = pos_fin' - /\ jdelim_' = defaultInitValue - /\ delimLen_' = defaultInitValue - /\ pc' = "Lbl_9" - ELSE /\ pc' = "Lbl_16" - /\ UNCHANGED << stack, pos_fin, delim_, ipos_, - jdelim_, delimLen_ >> - ELSE /\ pc' = "Lbl_10" - /\ UNCHANGED << stack, pos_fin, delim_, ipos_, jdelim_, - delimLen_ >> - /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, - curPos, returnVal, tempVar1, tempVar2, tempVar3, - pos_, tokArray, i, tokIdx, pos_f, token, left_, rt_, - pos_fi, pos_find, pos, delim, ipos, jdelim, delimLen, - leftTok, rightTok, currentToken, left, rt, notDone, - foundBangToken, temp1, temp2, temp3 >> - -Lbl_16 == /\ pc = "Lbl_16" - /\ jdelim_' = jdelim_+1 - /\ pc' = "Lbl_12" - /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, - curPos, returnVal, tempVar1, tempVar2, tempVar3, - stack, pos_, tokArray, i, tokIdx, pos_f, token, - left_, rt_, pos_fi, pos_fin, delim_, ipos_, - delimLen_, pos_find, pos, delim, ipos, jdelim, - delimLen, leftTok, rightTok, currentToken, left, rt, - notDone, foundBangToken, temp1, temp2, temp3 >> - -Lbl_13 == /\ pc = "Lbl_13" - /\ ipos_' = returnVal - /\ IF ipos_' < 0 - THEN /\ returnVal' = -1 - /\ pc' = "Lbl_14" - ELSE /\ pc' = "Lbl_15" - /\ UNCHANGED returnVal - /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, - curPos, tempVar1, tempVar2, tempVar3, stack, pos_, - tokArray, i, tokIdx, pos_f, token, left_, rt_, - pos_fi, pos_fin, delim_, jdelim_, delimLen_, - pos_find, pos, delim, ipos, jdelim, delimLen, - leftTok, rightTok, currentToken, left, rt, notDone, - foundBangToken, temp1, temp2, temp3 >> - -Lbl_14 == /\ pc = "Lbl_14" - /\ pc' = Head(stack).pc - /\ ipos_' = Head(stack).ipos_ - /\ jdelim_' = Head(stack).jdelim_ - /\ delimLen_' = Head(stack).delimLen_ - /\ pos_fin' = Head(stack).pos_fin - /\ delim_' = Head(stack).delim_ - /\ stack' = Tail(stack) - /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, - curPos, returnVal, tempVar1, tempVar2, tempVar3, - pos_, tokArray, i, tokIdx, pos_f, token, left_, rt_, - pos_fi, pos_find, pos, delim, ipos, jdelim, delimLen, - leftTok, rightTok, currentToken, left, rt, notDone, - foundBangToken, temp1, temp2, temp3 >> - -Lbl_15 == /\ pc = "Lbl_15" - /\ jdelim_' = 99 - /\ pc' = "Lbl_16" - /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, - curPos, returnVal, tempVar1, tempVar2, tempVar3, - stack, pos_, tokArray, i, tokIdx, pos_f, token, - left_, rt_, pos_fi, pos_fin, delim_, ipos_, - delimLen_, pos_find, pos, delim, ipos, jdelim, - delimLen, leftTok, rightTok, currentToken, left, rt, - notDone, foundBangToken, temp1, temp2, temp3 >> - -findMatchingLeftInner == Lbl_9 \/ Lbl_10 \/ Lbl_11 \/ Lbl_12 \/ Lbl_16 - \/ Lbl_13 \/ Lbl_14 \/ Lbl_15 - -Lbl_17 == /\ pc = "Lbl_17" - /\ IF line[pos_find] # "(" - THEN /\ returnVal' = pos_find - /\ pc' = Head(stack).pc - /\ pos_find' = Head(stack).pos_find - /\ stack' = Tail(stack) - ELSE /\ pc' = "Lbl_18" - /\ UNCHANGED << returnVal, stack, pos_find >> - /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, - curPos, tempVar1, tempVar2, tempVar3, pos_, tokArray, - i, tokIdx, pos_f, token, left_, rt_, pos_fi, pos_fin, - delim_, ipos_, jdelim_, delimLen_, pos, delim, ipos, - jdelim, delimLen, leftTok, rightTok, currentToken, - left, rt, notDone, foundBangToken, temp1, temp2, - temp3 >> - -Lbl_18 == /\ pc = "Lbl_18" - /\ /\ delim' = 0 - /\ pos' = pos_find - /\ stack' = << [ procedure |-> "findMatchingRightInner", - pc |-> Head(stack).pc, - ipos |-> ipos, - jdelim |-> jdelim, - delimLen |-> delimLen, - pos |-> pos, - delim |-> delim ] >> - \o Tail(stack) - /\ ipos' = pos' - /\ jdelim' = defaultInitValue - /\ delimLen' = defaultInitValue - /\ pc' = "Lbl_19" - /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, - curPos, returnVal, tempVar1, tempVar2, tempVar3, - pos_, tokArray, i, tokIdx, pos_f, token, left_, rt_, - pos_fi, pos_fin, delim_, ipos_, jdelim_, delimLen_, - pos_find, leftTok, rightTok, currentToken, left, rt, - notDone, foundBangToken, temp1, temp2, temp3 >> - -findMatchingRightParen == Lbl_17 \/ Lbl_18 - -Lbl_19 == /\ pc = "Lbl_19" - /\ delimLen' = JavaLen(RightDelimiters[delim]) - /\ ipos' = pos + delimLen' - /\ pc' = "Lbl_20" - /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, - curPos, returnVal, tempVar1, tempVar2, tempVar3, - stack, pos_, tokArray, i, tokIdx, pos_f, token, - left_, rt_, pos_fi, pos_fin, delim_, ipos_, jdelim_, - delimLen_, pos_find, pos, delim, jdelim, leftTok, - rightTok, currentToken, left, rt, notDone, - foundBangToken, temp1, temp2, temp3 >> - -Lbl_20 == /\ pc = "Lbl_20" - /\ IF JavaSubseq(line, ipos, ipos+delimLen) # RightDelimiters[delim] - THEN /\ IF line[ipos] = ";" - THEN /\ returnVal' = -1 - /\ pc' = Head(stack).pc - /\ ipos' = Head(stack).ipos - /\ jdelim' = Head(stack).jdelim - /\ delimLen' = Head(stack).delimLen - /\ pos' = Head(stack).pos - /\ delim' = Head(stack).delim - /\ stack' = Tail(stack) - ELSE /\ pc' = "Lbl_21" - /\ UNCHANGED << returnVal, stack, pos, delim, - ipos, jdelim, delimLen >> - ELSE /\ returnVal' = ipos+delimLen - /\ pc' = Head(stack).pc - /\ ipos' = Head(stack).ipos - /\ jdelim' = Head(stack).jdelim - /\ delimLen' = Head(stack).delimLen - /\ pos' = Head(stack).pos - /\ delim' = Head(stack).delim - /\ stack' = Tail(stack) - /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, - curPos, tempVar1, tempVar2, tempVar3, pos_, tokArray, - i, tokIdx, pos_f, token, left_, rt_, pos_fi, pos_fin, - delim_, ipos_, jdelim_, delimLen_, pos_find, leftTok, - rightTok, currentToken, left, rt, notDone, - foundBangToken, temp1, temp2, temp3 >> - -Lbl_21 == /\ pc = "Lbl_21" - /\ ipos' = ipos+1 - /\ jdelim' = 0 - /\ pc' = "Lbl_22" - /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, - curPos, returnVal, tempVar1, tempVar2, tempVar3, - stack, pos_, tokArray, i, tokIdx, pos_f, token, - left_, rt_, pos_fi, pos_fin, delim_, ipos_, jdelim_, - delimLen_, pos_find, pos, delim, delimLen, leftTok, - rightTok, currentToken, left, rt, notDone, - foundBangToken, temp1, temp2, temp3 >> - -Lbl_22 == /\ pc = "Lbl_22" - /\ IF jdelim < JavaLen(RightDelimiters) - THEN /\ IF JavaSubseq(line, ipos, ipos+delimLen) = LeftDelimiters[jdelim] - THEN /\ /\ delim' = jdelim - /\ pos' = ipos - /\ stack' = << [ procedure |-> "findMatchingRightInner", - pc |-> "Lbl_23", - ipos |-> ipos, - jdelim |-> jdelim, - delimLen |-> delimLen, - pos |-> pos, - delim |-> delim ] >> - \o stack - /\ ipos' = pos' - /\ jdelim' = defaultInitValue - /\ delimLen' = defaultInitValue - /\ pc' = "Lbl_19" - ELSE /\ pc' = "Lbl_26" - /\ UNCHANGED << stack, pos, delim, ipos, - jdelim, delimLen >> - ELSE /\ pc' = "Lbl_20" - /\ UNCHANGED << stack, pos, delim, ipos, jdelim, delimLen >> - /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, - curPos, returnVal, tempVar1, tempVar2, tempVar3, - pos_, tokArray, i, tokIdx, pos_f, token, left_, rt_, - pos_fi, pos_fin, delim_, ipos_, jdelim_, delimLen_, - pos_find, leftTok, rightTok, currentToken, left, rt, - notDone, foundBangToken, temp1, temp2, temp3 >> - -Lbl_26 == /\ pc = "Lbl_26" - /\ jdelim' = jdelim+1 - /\ pc' = "Lbl_22" - /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, - curPos, returnVal, tempVar1, tempVar2, tempVar3, - stack, pos_, tokArray, i, tokIdx, pos_f, token, - left_, rt_, pos_fi, pos_fin, delim_, ipos_, jdelim_, - delimLen_, pos_find, pos, delim, ipos, delimLen, - leftTok, rightTok, currentToken, left, rt, notDone, - foundBangToken, temp1, temp2, temp3 >> - -Lbl_23 == /\ pc = "Lbl_23" - /\ ipos' = returnVal - /\ IF ipos' < 0 - THEN /\ returnVal' = -1 - /\ pc' = "Lbl_24" - ELSE /\ pc' = "Lbl_25" - /\ UNCHANGED returnVal - /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, - curPos, tempVar1, tempVar2, tempVar3, stack, pos_, - tokArray, i, tokIdx, pos_f, token, left_, rt_, - pos_fi, pos_fin, delim_, ipos_, jdelim_, delimLen_, - pos_find, pos, delim, jdelim, delimLen, leftTok, - rightTok, currentToken, left, rt, notDone, - foundBangToken, temp1, temp2, temp3 >> - -Lbl_24 == /\ pc = "Lbl_24" - /\ pc' = Head(stack).pc - /\ ipos' = Head(stack).ipos - /\ jdelim' = Head(stack).jdelim - /\ delimLen' = Head(stack).delimLen - /\ pos' = Head(stack).pos - /\ delim' = Head(stack).delim - /\ stack' = Tail(stack) - /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, - curPos, returnVal, tempVar1, tempVar2, tempVar3, - pos_, tokArray, i, tokIdx, pos_f, token, left_, rt_, - pos_fi, pos_fin, delim_, ipos_, jdelim_, delimLen_, - pos_find, leftTok, rightTok, currentToken, left, rt, - notDone, foundBangToken, temp1, temp2, temp3 >> - -Lbl_25 == /\ pc = "Lbl_25" - /\ jdelim' = 99 - /\ pc' = "Lbl_26" - /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, - curPos, returnVal, tempVar1, tempVar2, tempVar3, - stack, pos_, tokArray, i, tokIdx, pos_f, token, - left_, rt_, pos_fi, pos_fin, delim_, ipos_, jdelim_, - delimLen_, pos_find, pos, delim, ipos, delimLen, - leftTok, rightTok, currentToken, left, rt, notDone, - foundBangToken, temp1, temp2, temp3 >> - -findMatchingRightInner == Lbl_19 \/ Lbl_20 \/ Lbl_21 \/ Lbl_22 \/ Lbl_26 - \/ Lbl_23 \/ Lbl_24 \/ Lbl_25 - -Lbl_27 == /\ pc = "Lbl_27" - /\ IF leftTok = NullTokenSpec \/ rightTok = NullTokenSpec - THEN /\ returnVal' = NullTokenSpec - /\ pc' = Head(stack).pc - /\ leftTok' = Head(stack).leftTok - /\ rightTok' = Head(stack).rightTok - /\ stack' = Tail(stack) - ELSE /\ pc' = "Lbl_28" - /\ UNCHANGED << returnVal, stack, leftTok, rightTok >> - /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, - curPos, tempVar1, tempVar2, tempVar3, pos_, tokArray, - i, tokIdx, pos_f, token, left_, rt_, pos_fi, pos_fin, - delim_, ipos_, jdelim_, delimLen_, pos_find, pos, - delim, ipos, jdelim, delimLen, currentToken, left, - rt, notDone, foundBangToken, temp1, temp2, temp3 >> - -Lbl_28 == /\ pc = "Lbl_28" - /\ IF /\ IsNumber(leftTok.token) - /\ line[leftTok.leftPos-1] = "<" - /\ line[leftTok.leftPos-2] # "<" - THEN /\ returnVal' = [token |-> JavaSubseq(line, - leftTok.leftPos-1, - rightTok.rightPos), - leftPos |-> leftTok.leftPos-1, - rightPos |-> rightTok.rightPos] - /\ pc' = Head(stack).pc - /\ leftTok' = Head(stack).leftTok - /\ rightTok' = Head(stack).rightTok - /\ stack' = Tail(stack) - ELSE /\ returnVal' = NullTokenSpec - /\ pc' = Head(stack).pc - /\ leftTok' = Head(stack).leftTok - /\ rightTok' = Head(stack).rightTok - /\ stack' = Tail(stack) - /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, - curPos, tempVar1, tempVar2, tempVar3, pos_, tokArray, - i, tokIdx, pos_f, token, left_, rt_, pos_fi, pos_fin, - delim_, ipos_, jdelim_, delimLen_, pos_find, pos, - delim, ipos, jdelim, delimLen, currentToken, left, - rt, notDone, foundBangToken, temp1, temp2, temp3 >> - -checkIfStepName == Lbl_27 \/ Lbl_28 - -Lbl_29 == /\ pc = "Lbl_29" - /\ IF line[curPos-1] = " " - THEN /\ curPos' = curPos - 1 - /\ pc' = "Lbl_29" - /\ stack' = stack - ELSE /\ pc' = Head(stack).pc - /\ stack' = Tail(stack) - /\ UNCHANGED curPos - /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, - returnVal, tempVar1, tempVar2, tempVar3, pos_, - tokArray, i, tokIdx, pos_f, token, left_, rt_, - pos_fi, pos_fin, delim_, ipos_, jdelim_, delimLen_, - pos_find, pos, delim, ipos, jdelim, delimLen, - leftTok, rightTok, currentToken, left, rt, notDone, - foundBangToken, temp1, temp2, temp3 >> - -skipLeftOverSpaces == Lbl_29 - -Lbl_30 == /\ pc = "Lbl_30" - /\ IF line[curPos] = " " - THEN /\ curPos' = curPos+1 - /\ pc' = "Lbl_30" - /\ stack' = stack - ELSE /\ pc' = Head(stack).pc - /\ stack' = Tail(stack) - /\ UNCHANGED curPos - /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, - returnVal, tempVar1, tempVar2, tempVar3, pos_, - tokArray, i, tokIdx, pos_f, token, left_, rt_, - pos_fi, pos_fin, delim_, ipos_, jdelim_, delimLen_, - pos_find, pos, delim, ipos, jdelim, delimLen, - leftTok, rightTok, currentToken, left, rt, notDone, - foundBangToken, temp1, temp2, temp3 >> - -skipRightOverSpaces == Lbl_30 - -Lbl_31 == /\ pc = "Lbl_31" - /\ IF line[curPos] = " " - THEN /\ stack' = << [ procedure |-> "skipLeftOverSpaces", - pc |-> "Lbl_32" ] >> - \o stack - /\ pc' = "Lbl_29" - /\ UNCHANGED notLastToken - ELSE /\ IF line[curPos] = "!" /\ line[curPos-1] # "!" /\ line[curPos+1] # "!" - THEN /\ notLastToken' = TRUE - /\ stack' = << [ procedure |-> "skipLeftOverSpaces", - pc |-> "Lbl_33" ] >> - \o stack - /\ pc' = "Lbl_29" - ELSE /\ pc' = "Lbl_33" - /\ UNCHANGED << notLastToken, stack >> - /\ UNCHANGED << line, foundTokenSpecs, lastToken, curPos, returnVal, - tempVar1, tempVar2, tempVar3, pos_, tokArray, i, - tokIdx, pos_f, token, left_, rt_, pos_fi, pos_fin, - delim_, ipos_, jdelim_, delimLen_, pos_find, pos, - delim, ipos, jdelim, delimLen, leftTok, rightTok, - currentToken, left, rt, notDone, foundBangToken, - temp1, temp2, temp3 >> - -Lbl_32 == /\ pc = "Lbl_32" - /\ IF line[curPos-1] = "!" /\ line[curPos-2] # "!" - THEN /\ notLastToken' = TRUE - /\ curPos' = curPos - 1 - /\ stack' = << [ procedure |-> "skipLeftOverSpaces", - pc |-> "Lbl_33" ] >> - \o stack - /\ pc' = "Lbl_29" - ELSE /\ pc' = "Lbl_33" - /\ UNCHANGED << notLastToken, curPos, stack >> - /\ UNCHANGED << line, foundTokenSpecs, lastToken, returnVal, - tempVar1, tempVar2, tempVar3, pos_, tokArray, i, - tokIdx, pos_f, token, left_, rt_, pos_fi, pos_fin, - delim_, ipos_, jdelim_, delimLen_, pos_find, pos, - delim, ipos, jdelim, delimLen, leftTok, rightTok, - currentToken, left, rt, notDone, foundBangToken, - temp1, temp2, temp3 >> - -Lbl_33 == /\ pc = "Lbl_33" - /\ IF /\ \/ notLastToken - \/ line[curPos] = " " - /\ line[curPos-1] = ")" - THEN /\ notLastToken' = TRUE - /\ /\ pos_fi' = curPos - /\ stack' = << [ procedure |-> "findMatchingLeftParen", - pc |-> "Lbl_34", - pos_fi |-> pos_fi ] >> - \o stack - /\ pc' = "Lbl_7" - ELSE /\ pc' = "Lbl_36" - /\ UNCHANGED << notLastToken, stack, pos_fi >> - /\ UNCHANGED << line, foundTokenSpecs, lastToken, curPos, returnVal, - tempVar1, tempVar2, tempVar3, pos_, tokArray, i, - tokIdx, pos_f, token, left_, rt_, pos_fin, delim_, - ipos_, jdelim_, delimLen_, pos_find, pos, delim, - ipos, jdelim, delimLen, leftTok, rightTok, - currentToken, left, rt, notDone, foundBangToken, - temp1, temp2, temp3 >> - -Lbl_34 == /\ pc = "Lbl_34" - /\ IF returnVal < 0 - THEN /\ returnVal' = << >> - /\ pc' = Head(stack).pc - /\ currentToken' = Head(stack).currentToken - /\ left' = Head(stack).left - /\ rt' = Head(stack).rt - /\ notDone' = Head(stack).notDone - /\ foundBangToken' = Head(stack).foundBangToken - /\ temp1' = Head(stack).temp1 - /\ temp2' = Head(stack).temp2 - /\ temp3' = Head(stack).temp3 - /\ stack' = Tail(stack) - ELSE /\ pc' = "Lbl_35" - /\ UNCHANGED << returnVal, stack, currentToken, left, rt, - notDone, foundBangToken, temp1, temp2, - temp3 >> - /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, - curPos, tempVar1, tempVar2, tempVar3, pos_, tokArray, - i, tokIdx, pos_f, token, left_, rt_, pos_fi, pos_fin, - delim_, ipos_, jdelim_, delimLen_, pos_find, pos, - delim, ipos, jdelim, delimLen, leftTok, rightTok >> - -Lbl_35 == /\ pc = "Lbl_35" - /\ curPos' = returnVal - /\ stack' = << [ procedure |-> "skipLeftOverSpaces", - pc |-> "Lbl_36" ] >> - \o stack - /\ pc' = "Lbl_29" - /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, - returnVal, tempVar1, tempVar2, tempVar3, pos_, - tokArray, i, tokIdx, pos_f, token, left_, rt_, - pos_fi, pos_fin, delim_, ipos_, jdelim_, delimLen_, - pos_find, pos, delim, ipos, jdelim, delimLen, - leftTok, rightTok, currentToken, left, rt, notDone, - foundBangToken, temp1, temp2, temp3 >> - -Lbl_36 == /\ pc = "Lbl_36" - /\ IF notLastToken - THEN /\ curPos' = curPos - 1 - /\ pc' = "Lbl_38" - /\ UNCHANGED << stack, pos_, tokArray, i, tokIdx >> - ELSE /\ IF line[curPos] \notin IdChar - THEN /\ /\ pos_' = curPos - /\ stack' = << [ procedure |-> "findTokenIn", - pc |-> "Lbl_37", - i |-> i, - tokIdx |-> tokIdx, - pos_ |-> pos_, - tokArray |-> tokArray ] >> - \o stack - /\ tokArray' = Operators - /\ i' = defaultInitValue - /\ tokIdx' = defaultInitValue - /\ pc' = "Lbl_1" - ELSE /\ pc' = "Lbl_38" - /\ UNCHANGED << stack, pos_, tokArray, i, - tokIdx >> - /\ UNCHANGED curPos - /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, - returnVal, tempVar1, tempVar2, tempVar3, pos_f, - token, left_, rt_, pos_fi, pos_fin, delim_, ipos_, - jdelim_, delimLen_, pos_find, pos, delim, ipos, - jdelim, delimLen, leftTok, rightTok, currentToken, - left, rt, notDone, foundBangToken, temp1, temp2, - temp3 >> - -Lbl_37 == /\ pc = "Lbl_37" - /\ IF returnVal = NullTokenSpec - THEN /\ curPos' = curPos - 1 - ELSE /\ TRUE - /\ UNCHANGED curPos - /\ pc' = "Lbl_38" - /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, - returnVal, tempVar1, tempVar2, tempVar3, stack, pos_, - tokArray, i, tokIdx, pos_f, token, left_, rt_, - pos_fi, pos_fin, delim_, ipos_, jdelim_, delimLen_, - pos_find, pos, delim, ipos, jdelim, delimLen, - leftTok, rightTok, currentToken, left, rt, notDone, - foundBangToken, temp1, temp2, temp3 >> - -Lbl_38 == /\ pc = "Lbl_38" - /\ IF line[curPos] \in IdChar - THEN /\ IF line[curPos] = "X" - THEN /\ /\ pos_' = curPos - /\ stack' = << [ procedure |-> "findTokenIn", - pc |-> "Lbl_39", - i |-> i, - tokIdx |-> tokIdx, - pos_ |-> pos_, - tokArray |-> tokArray ] >> - \o stack - /\ tokArray' = XSymbols - /\ i' = defaultInitValue - /\ tokIdx' = defaultInitValue - /\ pc' = "Lbl_1" - /\ UNCHANGED returnVal - ELSE /\ returnVal' = NullTokenSpec - /\ pc' = "Lbl_39" - /\ UNCHANGED << stack, pos_, tokArray, i, - tokIdx >> - ELSE /\ /\ pos_' = curPos - /\ stack' = << [ procedure |-> "findTokenIn", - pc |-> "Lbl_48", - i |-> i, - tokIdx |-> tokIdx, - pos_ |-> pos_, - tokArray |-> tokArray ] >> - \o stack - /\ tokArray' = Operators - /\ i' = defaultInitValue - /\ tokIdx' = defaultInitValue - /\ pc' = "Lbl_1" - /\ UNCHANGED returnVal - /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, - curPos, tempVar1, tempVar2, tempVar3, pos_f, token, - left_, rt_, pos_fi, pos_fin, delim_, ipos_, jdelim_, - delimLen_, pos_find, pos, delim, ipos, jdelim, - delimLen, leftTok, rightTok, currentToken, left, rt, - notDone, foundBangToken, temp1, temp2, temp3 >> - -Lbl_39 == /\ pc = "Lbl_39" - /\ IF returnVal # NullTokenSpec - THEN /\ foundTokenSpecs' = JavaSeq(<<returnVal>>) - /\ curPos' = returnVal.leftPos - /\ lastToken' = TRUE - /\ pc' = "Lbl_62" - /\ UNCHANGED << stack, pos_f, token, left_, rt_ >> - ELSE /\ /\ pos_f' = curPos - /\ stack' = << [ procedure |-> "findMaximalIdCharSeq", - pc |-> "Lbl_40", - token |-> token, - left_ |-> left_, - rt_ |-> rt_, - pos_f |-> pos_f ] >> - \o stack - /\ token' = << >> - /\ left_' = pos_f' - /\ rt_' = pos_f' - /\ pc' = "Lbl_5" - /\ UNCHANGED << foundTokenSpecs, lastToken, curPos >> - /\ UNCHANGED << line, notLastToken, returnVal, tempVar1, tempVar2, - tempVar3, pos_, tokArray, i, tokIdx, pos_fi, pos_fin, - delim_, ipos_, jdelim_, delimLen_, pos_find, pos, - delim, ipos, jdelim, delimLen, leftTok, rightTok, - currentToken, left, rt, notDone, foundBangToken, - temp1, temp2, temp3 >> - -Lbl_40 == /\ pc = "Lbl_40" - /\ currentToken' = returnVal - /\ IF line[currentToken'.leftPos-1] = ">" - THEN /\ /\ pos_f' = currentToken'.leftPos - 1 - /\ stack' = << [ procedure |-> "findMaximalIdCharSeq", - pc |-> "Lbl_41", - token |-> token, - left_ |-> left_, - rt_ |-> rt_, - pos_f |-> pos_f ] >> - \o stack - /\ token' = << >> - /\ left_' = pos_f' - /\ rt_' = pos_f' - /\ pc' = "Lbl_5" - ELSE /\ pc' = "Lbl_43" - /\ UNCHANGED << stack, pos_f, token, left_, rt_ >> - /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, - curPos, returnVal, tempVar1, tempVar2, tempVar3, - pos_, tokArray, i, tokIdx, pos_fi, pos_fin, delim_, - ipos_, jdelim_, delimLen_, pos_find, pos, delim, - ipos, jdelim, delimLen, leftTok, rightTok, left, rt, - notDone, foundBangToken, temp1, temp2, temp3 >> - -Lbl_41 == /\ pc = "Lbl_41" - /\ /\ leftTok' = returnVal - /\ rightTok' = currentToken - /\ stack' = << [ procedure |-> "checkIfStepName", - pc |-> "Lbl_42", - leftTok |-> leftTok, - rightTok |-> rightTok ] >> - \o stack - /\ pc' = "Lbl_27" - /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, - curPos, returnVal, tempVar1, tempVar2, tempVar3, - pos_, tokArray, i, tokIdx, pos_f, token, left_, rt_, - pos_fi, pos_fin, delim_, ipos_, jdelim_, delimLen_, - pos_find, pos, delim, ipos, jdelim, delimLen, - currentToken, left, rt, notDone, foundBangToken, - temp1, temp2, temp3 >> - -Lbl_42 == /\ pc = "Lbl_42" - /\ IF returnVal # NullTokenSpec - THEN /\ foundTokenSpecs' = JavaSeq(<<returnVal>>) - /\ returnVal' = FixOrigin(foundTokenSpecs') - /\ pc' = Head(stack).pc - /\ currentToken' = Head(stack).currentToken - /\ left' = Head(stack).left - /\ rt' = Head(stack).rt - /\ notDone' = Head(stack).notDone - /\ foundBangToken' = Head(stack).foundBangToken - /\ temp1' = Head(stack).temp1 - /\ temp2' = Head(stack).temp2 - /\ temp3' = Head(stack).temp3 - /\ stack' = Tail(stack) - ELSE /\ pc' = "Lbl_43" - /\ UNCHANGED << foundTokenSpecs, returnVal, stack, - currentToken, left, rt, notDone, - foundBangToken, temp1, temp2, temp3 >> - /\ UNCHANGED << line, lastToken, notLastToken, curPos, tempVar1, - tempVar2, tempVar3, pos_, tokArray, i, tokIdx, pos_f, - token, left_, rt_, pos_fi, pos_fin, delim_, ipos_, - jdelim_, delimLen_, pos_find, pos, delim, ipos, - jdelim, delimLen, leftTok, rightTok >> - -Lbl_43 == /\ pc = "Lbl_43" - /\ IF line[currentToken.rightPos] = ">" - THEN /\ /\ pos_f' = currentToken.rightPos+1 - /\ stack' = << [ procedure |-> "findMaximalIdCharSeq", - pc |-> "Lbl_44", - token |-> token, - left_ |-> left_, - rt_ |-> rt_, - pos_f |-> pos_f ] >> - \o stack - /\ token' = << >> - /\ left_' = pos_f' - /\ rt_' = pos_f' - /\ pc' = "Lbl_5" - ELSE /\ pc' = "Lbl_46" - /\ UNCHANGED << stack, pos_f, token, left_, rt_ >> - /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, - curPos, returnVal, tempVar1, tempVar2, tempVar3, - pos_, tokArray, i, tokIdx, pos_fi, pos_fin, delim_, - ipos_, jdelim_, delimLen_, pos_find, pos, delim, - ipos, jdelim, delimLen, leftTok, rightTok, - currentToken, left, rt, notDone, foundBangToken, - temp1, temp2, temp3 >> - -Lbl_44 == /\ pc = "Lbl_44" - /\ /\ leftTok' = currentToken - /\ rightTok' = returnVal - /\ stack' = << [ procedure |-> "checkIfStepName", - pc |-> "Lbl_45", - leftTok |-> leftTok, - rightTok |-> rightTok ] >> - \o stack - /\ pc' = "Lbl_27" - /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, - curPos, returnVal, tempVar1, tempVar2, tempVar3, - pos_, tokArray, i, tokIdx, pos_f, token, left_, rt_, - pos_fi, pos_fin, delim_, ipos_, jdelim_, delimLen_, - pos_find, pos, delim, ipos, jdelim, delimLen, - currentToken, left, rt, notDone, foundBangToken, - temp1, temp2, temp3 >> - -Lbl_45 == /\ pc = "Lbl_45" - /\ IF returnVal # NullTokenSpec - THEN /\ foundTokenSpecs' = JavaSeq(<<returnVal>>) - /\ returnVal' = FixOrigin(foundTokenSpecs') - /\ pc' = Head(stack).pc - /\ currentToken' = Head(stack).currentToken - /\ left' = Head(stack).left - /\ rt' = Head(stack).rt - /\ notDone' = Head(stack).notDone - /\ foundBangToken' = Head(stack).foundBangToken - /\ temp1' = Head(stack).temp1 - /\ temp2' = Head(stack).temp2 - /\ temp3' = Head(stack).temp3 - /\ stack' = Tail(stack) - ELSE /\ pc' = "Lbl_46" - /\ UNCHANGED << foundTokenSpecs, returnVal, stack, - currentToken, left, rt, notDone, - foundBangToken, temp1, temp2, temp3 >> - /\ UNCHANGED << line, lastToken, notLastToken, curPos, tempVar1, - tempVar2, tempVar3, pos_, tokArray, i, tokIdx, pos_f, - token, left_, rt_, pos_fi, pos_fin, delim_, ipos_, - jdelim_, delimLen_, pos_find, pos, delim, ipos, - jdelim, delimLen, leftTok, rightTok >> - -Lbl_46 == /\ pc = "Lbl_46" - /\ IF IsNumber(currentToken.token) - THEN /\ returnVal' = << >> - /\ pc' = Head(stack).pc - /\ currentToken' = Head(stack).currentToken - /\ left' = Head(stack).left - /\ rt' = Head(stack).rt - /\ notDone' = Head(stack).notDone - /\ foundBangToken' = Head(stack).foundBangToken - /\ temp1' = Head(stack).temp1 - /\ temp2' = Head(stack).temp2 - /\ temp3' = Head(stack).temp3 - /\ stack' = Tail(stack) - ELSE /\ pc' = "Lbl_47" - /\ UNCHANGED << returnVal, stack, currentToken, left, rt, - notDone, foundBangToken, temp1, temp2, - temp3 >> - /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, - curPos, tempVar1, tempVar2, tempVar3, pos_, tokArray, - i, tokIdx, pos_f, token, left_, rt_, pos_fi, pos_fin, - delim_, ipos_, jdelim_, delimLen_, pos_find, pos, - delim, ipos, jdelim, delimLen, leftTok, rightTok >> - -Lbl_47 == /\ pc = "Lbl_47" - /\ left' = currentToken.leftPos - /\ rt' = currentToken.rightPos - /\ IF /\ line[left'-1] = "\\" - /\ line[left'-2] # "\\" - /\ \E ii \in DOMAIN TeXSymbols : - JavaSubseq(line, left'-1, rt') = TeXSymbols[ii] - THEN /\ lastToken' = TRUE - /\ currentToken' = [currentToken EXCEPT !.leftPos = left' - 1, - !.token = JavaSubseq(line, left'-1, rt')] - ELSE /\ TRUE - /\ UNCHANGED << lastToken, currentToken >> - /\ foundTokenSpecs' = JavaSeq( << currentToken' >>) - /\ curPos' = left' - /\ pc' = "Lbl_62" - /\ UNCHANGED << line, notLastToken, returnVal, tempVar1, tempVar2, - tempVar3, stack, pos_, tokArray, i, tokIdx, pos_f, - token, left_, rt_, pos_fi, pos_fin, delim_, ipos_, - jdelim_, delimLen_, pos_find, pos, delim, ipos, - jdelim, delimLen, leftTok, rightTok, notDone, - foundBangToken, temp1, temp2, temp3 >> - -Lbl_48 == /\ pc = "Lbl_48" - /\ currentToken' = returnVal - /\ IF currentToken' = NullTokenSpec - THEN /\ returnVal' = << >> - /\ pc' = "Lbl_49" - ELSE /\ pc' = "Lbl_50" - /\ UNCHANGED returnVal - /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, - curPos, tempVar1, tempVar2, tempVar3, stack, pos_, - tokArray, i, tokIdx, pos_f, token, left_, rt_, - pos_fi, pos_fin, delim_, ipos_, jdelim_, delimLen_, - pos_find, pos, delim, ipos, jdelim, delimLen, - leftTok, rightTok, left, rt, notDone, foundBangToken, - temp1, temp2, temp3 >> - -Lbl_49 == /\ pc = "Lbl_49" - /\ pc' = Head(stack).pc - /\ currentToken' = Head(stack).currentToken - /\ left' = Head(stack).left - /\ rt' = Head(stack).rt - /\ notDone' = Head(stack).notDone - /\ foundBangToken' = Head(stack).foundBangToken - /\ temp1' = Head(stack).temp1 - /\ temp2' = Head(stack).temp2 - /\ temp3' = Head(stack).temp3 - /\ stack' = Tail(stack) - /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, - curPos, returnVal, tempVar1, tempVar2, tempVar3, - pos_, tokArray, i, tokIdx, pos_f, token, left_, rt_, - pos_fi, pos_fin, delim_, ipos_, jdelim_, delimLen_, - pos_find, pos, delim, ipos, jdelim, delimLen, - leftTok, rightTok >> - -Lbl_50 == /\ pc = "Lbl_50" - /\ /\ pos_' = curPos - /\ stack' = << [ procedure |-> "findTokenIn", - pc |-> "Lbl_51", - i |-> i, - tokIdx |-> tokIdx, - pos_ |-> pos_, - tokArray |-> tokArray ] >> - \o stack - /\ tokArray' = NonOperators - /\ i' = defaultInitValue - /\ tokIdx' = defaultInitValue - /\ pc' = "Lbl_1" - /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, - curPos, returnVal, tempVar1, tempVar2, tempVar3, - pos_f, token, left_, rt_, pos_fi, pos_fin, delim_, - ipos_, jdelim_, delimLen_, pos_find, pos, delim, - ipos, jdelim, delimLen, leftTok, rightTok, - currentToken, left, rt, notDone, foundBangToken, - temp1, temp2, temp3 >> - -Lbl_51 == /\ pc = "Lbl_51" - /\ IF returnVal # NullTokenSpec - THEN /\ returnVal' = << >> - /\ pc' = Head(stack).pc - /\ currentToken' = Head(stack).currentToken - /\ left' = Head(stack).left - /\ rt' = Head(stack).rt - /\ notDone' = Head(stack).notDone - /\ foundBangToken' = Head(stack).foundBangToken - /\ temp1' = Head(stack).temp1 - /\ temp2' = Head(stack).temp2 - /\ temp3' = Head(stack).temp3 - /\ stack' = Tail(stack) - ELSE /\ pc' = "Lbl_52" - /\ UNCHANGED << returnVal, stack, currentToken, left, rt, - notDone, foundBangToken, temp1, temp2, - temp3 >> - /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, - curPos, tempVar1, tempVar2, tempVar3, pos_, tokArray, - i, tokIdx, pos_f, token, left_, rt_, pos_fi, pos_fin, - delim_, ipos_, jdelim_, delimLen_, pos_find, pos, - delim, ipos, jdelim, delimLen, leftTok, rightTok >> - -Lbl_52 == /\ pc = "Lbl_52" - /\ IF currentToken.token = JavaSeq(<< "<" >>) - THEN /\ /\ pos_f' = currentToken.rightPos - /\ stack' = << [ procedure |-> "findMaximalIdCharSeq", - pc |-> "Lbl_53", - token |-> token, - left_ |-> left_, - rt_ |-> rt_, - pos_f |-> pos_f ] >> - \o stack - /\ token' = << >> - /\ left_' = pos_f' - /\ rt_' = pos_f' - /\ pc' = "Lbl_5" - ELSE /\ IF currentToken.token = JavaSeq(<< ">" >>) - THEN /\ /\ pos_f' = currentToken.leftPos - /\ stack' = << [ procedure |-> "findMaximalIdCharSeq", - pc |-> "Lbl_56", - token |-> token, - left_ |-> left_, - rt_ |-> rt_, - pos_f |-> pos_f ] >> - \o stack - /\ token' = << >> - /\ left_' = pos_f' - /\ rt_' = pos_f' - /\ pc' = "Lbl_5" - ELSE /\ pc' = "Lbl_59" - /\ UNCHANGED << stack, pos_f, token, left_, - rt_ >> - /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, - curPos, returnVal, tempVar1, tempVar2, tempVar3, - pos_, tokArray, i, tokIdx, pos_fi, pos_fin, delim_, - ipos_, jdelim_, delimLen_, pos_find, pos, delim, - ipos, jdelim, delimLen, leftTok, rightTok, - currentToken, left, rt, notDone, foundBangToken, - temp1, temp2, temp3 >> - -Lbl_53 == /\ pc = "Lbl_53" - /\ temp1' = returnVal - /\ IF /\ temp1' # NullTokenSpec - /\ line[temp1'.rightPos] = ">" - THEN /\ /\ pos_f' = temp1'.rightPos + 1 - /\ stack' = << [ procedure |-> "findMaximalIdCharSeq", - pc |-> "Lbl_54", - token |-> token, - left_ |-> left_, - rt_ |-> rt_, - pos_f |-> pos_f ] >> - \o stack - /\ token' = << >> - /\ left_' = pos_f' - /\ rt_' = pos_f' - /\ pc' = "Lbl_5" - ELSE /\ pc' = "Lbl_59" - /\ UNCHANGED << stack, pos_f, token, left_, rt_ >> - /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, - curPos, returnVal, tempVar1, tempVar2, tempVar3, - pos_, tokArray, i, tokIdx, pos_fi, pos_fin, delim_, - ipos_, jdelim_, delimLen_, pos_find, pos, delim, - ipos, jdelim, delimLen, leftTok, rightTok, - currentToken, left, rt, notDone, foundBangToken, - temp2, temp3 >> - -Lbl_54 == /\ pc = "Lbl_54" - /\ temp2' = returnVal - /\ /\ leftTok' = temp1 - /\ rightTok' = temp2' - /\ stack' = << [ procedure |-> "checkIfStepName", - pc |-> "Lbl_55", - leftTok |-> leftTok, - rightTok |-> rightTok ] >> - \o stack - /\ pc' = "Lbl_27" - /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, - curPos, returnVal, tempVar1, tempVar2, tempVar3, - pos_, tokArray, i, tokIdx, pos_f, token, left_, rt_, - pos_fi, pos_fin, delim_, ipos_, jdelim_, delimLen_, - pos_find, pos, delim, ipos, jdelim, delimLen, - currentToken, left, rt, notDone, foundBangToken, - temp1, temp3 >> - -Lbl_55 == /\ pc = "Lbl_55" - /\ IF returnVal # NullTokenSpec - THEN /\ foundTokenSpecs' = JavaSeq(<<returnVal>>) - /\ returnVal' = FixOrigin(foundTokenSpecs') - /\ pc' = Head(stack).pc - /\ currentToken' = Head(stack).currentToken - /\ left' = Head(stack).left - /\ rt' = Head(stack).rt - /\ notDone' = Head(stack).notDone - /\ foundBangToken' = Head(stack).foundBangToken - /\ temp1' = Head(stack).temp1 - /\ temp2' = Head(stack).temp2 - /\ temp3' = Head(stack).temp3 - /\ stack' = Tail(stack) - ELSE /\ pc' = "Lbl_59" - /\ UNCHANGED << foundTokenSpecs, returnVal, stack, - currentToken, left, rt, notDone, - foundBangToken, temp1, temp2, temp3 >> - /\ UNCHANGED << line, lastToken, notLastToken, curPos, tempVar1, - tempVar2, tempVar3, pos_, tokArray, i, tokIdx, pos_f, - token, left_, rt_, pos_fi, pos_fin, delim_, ipos_, - jdelim_, delimLen_, pos_find, pos, delim, ipos, - jdelim, delimLen, leftTok, rightTok >> - -Lbl_56 == /\ pc = "Lbl_56" - /\ temp1' = returnVal - /\ /\ pos_f' = currentToken.rightPos - /\ stack' = << [ procedure |-> "findMaximalIdCharSeq", - pc |-> "Lbl_57", - token |-> token, - left_ |-> left_, - rt_ |-> rt_, - pos_f |-> pos_f ] >> - \o stack - /\ token' = << >> - /\ left_' = pos_f' - /\ rt_' = pos_f' - /\ pc' = "Lbl_5" - /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, - curPos, returnVal, tempVar1, tempVar2, tempVar3, - pos_, tokArray, i, tokIdx, pos_fi, pos_fin, delim_, - ipos_, jdelim_, delimLen_, pos_find, pos, delim, - ipos, jdelim, delimLen, leftTok, rightTok, - currentToken, left, rt, notDone, foundBangToken, - temp2, temp3 >> - -Lbl_57 == /\ pc = "Lbl_57" - /\ temp2' = returnVal - /\ /\ leftTok' = temp1 - /\ rightTok' = temp2' - /\ stack' = << [ procedure |-> "checkIfStepName", - pc |-> "Lbl_58", - leftTok |-> leftTok, - rightTok |-> rightTok ] >> - \o stack - /\ pc' = "Lbl_27" - /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, - curPos, returnVal, tempVar1, tempVar2, tempVar3, - pos_, tokArray, i, tokIdx, pos_f, token, left_, rt_, - pos_fi, pos_fin, delim_, ipos_, jdelim_, delimLen_, - pos_find, pos, delim, ipos, jdelim, delimLen, - currentToken, left, rt, notDone, foundBangToken, - temp1, temp3 >> - -Lbl_58 == /\ pc = "Lbl_58" - /\ IF returnVal # NullTokenSpec - THEN /\ foundTokenSpecs' = JavaSeq(<<returnVal>>) - /\ returnVal' = FixOrigin(foundTokenSpecs') - /\ pc' = Head(stack).pc - /\ currentToken' = Head(stack).currentToken - /\ left' = Head(stack).left - /\ rt' = Head(stack).rt - /\ notDone' = Head(stack).notDone - /\ foundBangToken' = Head(stack).foundBangToken - /\ temp1' = Head(stack).temp1 - /\ temp2' = Head(stack).temp2 - /\ temp3' = Head(stack).temp3 - /\ stack' = Tail(stack) - ELSE /\ pc' = "Lbl_59" - /\ UNCHANGED << foundTokenSpecs, returnVal, stack, - currentToken, left, rt, notDone, - foundBangToken, temp1, temp2, temp3 >> - /\ UNCHANGED << line, lastToken, notLastToken, curPos, tempVar1, - tempVar2, tempVar3, pos_, tokArray, i, tokIdx, pos_f, - token, left_, rt_, pos_fi, pos_fin, delim_, ipos_, - jdelim_, delimLen_, pos_find, pos, delim, ipos, - jdelim, delimLen, leftTok, rightTok >> - -Lbl_59 == /\ pc = "Lbl_59" - /\ IF currentToken.token = JavaSeq(<<"\\">>) - THEN /\ /\ pos_f' = currentToken.rightPos - /\ stack' = << [ procedure |-> "findMaximalIdCharSeq", - pc |-> "Lbl_60", - token |-> token, - left_ |-> left_, - rt_ |-> rt_, - pos_f |-> pos_f ] >> - \o stack - /\ token' = << >> - /\ left_' = pos_f' - /\ rt_' = pos_f' - /\ pc' = "Lbl_5" - ELSE /\ pc' = "Lbl_61" - /\ UNCHANGED << stack, pos_f, token, left_, rt_ >> - /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, - curPos, returnVal, tempVar1, tempVar2, tempVar3, - pos_, tokArray, i, tokIdx, pos_fi, pos_fin, delim_, - ipos_, jdelim_, delimLen_, pos_find, pos, delim, - ipos, jdelim, delimLen, leftTok, rightTok, - currentToken, left, rt, notDone, foundBangToken, - temp1, temp2, temp3 >> - -Lbl_60 == /\ pc = "Lbl_60" - /\ IF /\ returnVal # NullTokenSpec - /\ \E ii \in DOMAIN TeXSymbols : - JavaSubseq(line, - currentToken.leftPos, - returnVal.rightPos) = TeXSymbols[ii] - THEN /\ currentToken' = [currentToken EXCEPT !.rightPos = returnVal.rightPos, - !.token = JavaSubseq(line, - currentToken.leftPos, - returnVal.rightPos)] - ELSE /\ TRUE - /\ UNCHANGED currentToken - /\ pc' = "Lbl_61" - /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, - curPos, returnVal, tempVar1, tempVar2, tempVar3, - stack, pos_, tokArray, i, tokIdx, pos_f, token, - left_, rt_, pos_fi, pos_fin, delim_, ipos_, jdelim_, - delimLen_, pos_find, pos, delim, ipos, jdelim, - delimLen, leftTok, rightTok, left, rt, notDone, - foundBangToken, temp1, temp2, temp3 >> - -Lbl_61 == /\ pc = "Lbl_61" - /\ foundTokenSpecs' = JavaSeq(<<currentToken>>) - /\ curPos' = currentToken.leftPos - /\ lastToken' = TRUE - /\ pc' = "Lbl_62" - /\ UNCHANGED << line, notLastToken, returnVal, tempVar1, tempVar2, - tempVar3, stack, pos_, tokArray, i, tokIdx, pos_f, - token, left_, rt_, pos_fi, pos_fin, delim_, ipos_, - jdelim_, delimLen_, pos_find, pos, delim, ipos, - jdelim, delimLen, leftTok, rightTok, currentToken, - left, rt, notDone, foundBangToken, temp1, temp2, - temp3 >> - -Lbl_62 == /\ pc = "Lbl_62" - /\ Assert(JavaLen(foundTokenSpecs) = 1, - "Failure of assertion at line 619, column 3.") - /\ curPos' = foundTokenSpecs[0].leftPos - /\ notDone' = TRUE - /\ pc' = "Lbl_63" - /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, - returnVal, tempVar1, tempVar2, tempVar3, stack, pos_, - tokArray, i, tokIdx, pos_f, token, left_, rt_, - pos_fi, pos_fin, delim_, ipos_, jdelim_, delimLen_, - pos_find, pos, delim, ipos, jdelim, delimLen, - leftTok, rightTok, currentToken, left, rt, - foundBangToken, temp1, temp2, temp3 >> - -Lbl_63 == /\ pc = "Lbl_63" - /\ IF notDone - THEN /\ stack' = << [ procedure |-> "skipLeftOverSpaces", - pc |-> "Lbl_64" ] >> - \o stack - /\ pc' = "Lbl_29" - /\ UNCHANGED << returnVal, currentToken, left, rt, - notDone, foundBangToken, temp1, temp2, - temp3 >> - ELSE /\ Assert(foundTokenSpecs # << >>, - "Failure of assertion at line 661, column 3.") - /\ IF lastToken = TRUE - THEN /\ returnVal' = FixOrigin(foundTokenSpecs) - /\ pc' = Head(stack).pc - /\ currentToken' = Head(stack).currentToken - /\ left' = Head(stack).left - /\ rt' = Head(stack).rt - /\ notDone' = Head(stack).notDone - /\ foundBangToken' = Head(stack).foundBangToken - /\ temp1' = Head(stack).temp1 - /\ temp2' = Head(stack).temp2 - /\ temp3' = Head(stack).temp3 - /\ stack' = Tail(stack) - ELSE /\ pc' = "Lbl_69" - /\ UNCHANGED << returnVal, stack, currentToken, - left, rt, notDone, - foundBangToken, temp1, temp2, - temp3 >> - /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, - curPos, tempVar1, tempVar2, tempVar3, pos_, tokArray, - i, tokIdx, pos_f, token, left_, rt_, pos_fi, pos_fin, - delim_, ipos_, jdelim_, delimLen_, pos_find, pos, - delim, ipos, jdelim, delimLen, leftTok, rightTok >> - -Lbl_64 == /\ pc = "Lbl_64" - /\ IF curPos < 0 \/ line[curPos-1] = ";" - THEN /\ notDone' = FALSE - /\ pc' = "Lbl_63" - /\ UNCHANGED << curPos, stack >> - ELSE /\ IF line[curPos-1] = "!" /\ (line[curPos-2] # "!") - THEN /\ curPos' = curPos - 1 - /\ stack' = << [ procedure |-> "skipLeftOverSpaces", - pc |-> "Lbl_65" ] >> - \o stack - /\ pc' = "Lbl_29" - /\ UNCHANGED notDone - ELSE /\ notDone' = FALSE - /\ pc' = "Lbl_63" - /\ UNCHANGED << curPos, stack >> - /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, - returnVal, tempVar1, tempVar2, tempVar3, pos_, - tokArray, i, tokIdx, pos_f, token, left_, rt_, - pos_fi, pos_fin, delim_, ipos_, jdelim_, delimLen_, - pos_find, pos, delim, ipos, jdelim, delimLen, - leftTok, rightTok, currentToken, left, rt, - foundBangToken, temp1, temp2, temp3 >> - -Lbl_65 == /\ pc = "Lbl_65" - /\ /\ pos_fi' = curPos - /\ stack' = << [ procedure |-> "findMatchingLeftParen", - pc |-> "Lbl_66", - pos_fi |-> pos_fi ] >> - \o stack - /\ pc' = "Lbl_7" - /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, - curPos, returnVal, tempVar1, tempVar2, tempVar3, - pos_, tokArray, i, tokIdx, pos_f, token, left_, rt_, - pos_fin, delim_, ipos_, jdelim_, delimLen_, pos_find, - pos, delim, ipos, jdelim, delimLen, leftTok, - rightTok, currentToken, left, rt, notDone, - foundBangToken, temp1, temp2, temp3 >> - -Lbl_66 == /\ pc = "Lbl_66" - /\ curPos' = returnVal - /\ IF curPos' < 0 - THEN /\ notDone' = FALSE - /\ pc' = "Lbl_63" - /\ stack' = stack - ELSE /\ stack' = << [ procedure |-> "skipLeftOverSpaces", - pc |-> "Lbl_67" ] >> - \o stack - /\ pc' = "Lbl_29" - /\ UNCHANGED notDone - /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, - returnVal, tempVar1, tempVar2, tempVar3, pos_, - tokArray, i, tokIdx, pos_f, token, left_, rt_, - pos_fi, pos_fin, delim_, ipos_, jdelim_, delimLen_, - pos_find, pos, delim, ipos, jdelim, delimLen, - leftTok, rightTok, currentToken, left, rt, - foundBangToken, temp1, temp2, temp3 >> - -Lbl_67 == /\ pc = "Lbl_67" - /\ /\ pos_f' = curPos - /\ stack' = << [ procedure |-> "findMaximalIdCharSeq", - pc |-> "Lbl_68", - token |-> token, - left_ |-> left_, - rt_ |-> rt_, - pos_f |-> pos_f ] >> - \o stack - /\ token' = << >> - /\ left_' = pos_f' - /\ rt_' = pos_f' - /\ pc' = "Lbl_5" - /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, - curPos, returnVal, tempVar1, tempVar2, tempVar3, - pos_, tokArray, i, tokIdx, pos_fi, pos_fin, delim_, - ipos_, jdelim_, delimLen_, pos_find, pos, delim, - ipos, jdelim, delimLen, leftTok, rightTok, - currentToken, left, rt, notDone, foundBangToken, - temp1, temp2, temp3 >> - -Lbl_68 == /\ pc = "Lbl_68" - /\ currentToken' = returnVal - /\ IF \/ currentToken' = NullTokenSpec - \/ IsNumber(currentToken'.token) - THEN /\ notDone' = FALSE - /\ UNCHANGED << foundTokenSpecs, curPos >> - ELSE /\ curPos' = currentToken'.leftPos - /\ foundTokenSpecs' = [foundTokenSpecs EXCEPT ![0] = [token |-> JavaConcatenate( - JavaAppend(currentToken'.token, "!"), - foundTokenSpecs[0].token), - leftPos |-> curPos', - rightPos |-> foundTokenSpecs[0].rightPos]] - /\ UNCHANGED notDone - /\ pc' = "Lbl_63" - /\ UNCHANGED << line, lastToken, notLastToken, returnVal, tempVar1, - tempVar2, tempVar3, stack, pos_, tokArray, i, tokIdx, - pos_f, token, left_, rt_, pos_fi, pos_fin, delim_, - ipos_, jdelim_, delimLen_, pos_find, pos, delim, - ipos, jdelim, delimLen, leftTok, rightTok, left, rt, - foundBangToken, temp1, temp2, temp3 >> - -Lbl_69 == /\ pc = "Lbl_69" - /\ curPos' = foundTokenSpecs[0].rightPos - /\ foundBangToken' = FALSE - /\ notDone' = TRUE - /\ pc' = "Lbl_70" - /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, - returnVal, tempVar1, tempVar2, tempVar3, stack, pos_, - tokArray, i, tokIdx, pos_f, token, left_, rt_, - pos_fi, pos_fin, delim_, ipos_, jdelim_, delimLen_, - pos_find, pos, delim, ipos, jdelim, delimLen, - leftTok, rightTok, currentToken, left, rt, temp1, - temp2, temp3 >> - -Lbl_70 == /\ pc = "Lbl_70" - /\ IF notDone - THEN /\ stack' = << [ procedure |-> "skipRightOverSpaces", - pc |-> "Lbl_71" ] >> - \o stack - /\ pc' = "Lbl_30" - /\ UNCHANGED << returnVal, currentToken, left, rt, - notDone, foundBangToken, temp1, temp2, - temp3 >> - ELSE /\ IF notLastToken /\ ~ foundBangToken - THEN /\ returnVal' = << >> - /\ pc' = Head(stack).pc - /\ currentToken' = Head(stack).currentToken - /\ left' = Head(stack).left - /\ rt' = Head(stack).rt - /\ notDone' = Head(stack).notDone - /\ foundBangToken' = Head(stack).foundBangToken - /\ temp1' = Head(stack).temp1 - /\ temp2' = Head(stack).temp2 - /\ temp3' = Head(stack).temp3 - /\ stack' = Tail(stack) - ELSE /\ pc' = "Lbl_76" - /\ UNCHANGED << returnVal, stack, currentToken, - left, rt, notDone, - foundBangToken, temp1, temp2, - temp3 >> - /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, - curPos, tempVar1, tempVar2, tempVar3, pos_, tokArray, - i, tokIdx, pos_f, token, left_, rt_, pos_fi, pos_fin, - delim_, ipos_, jdelim_, delimLen_, pos_find, pos, - delim, ipos, jdelim, delimLen, leftTok, rightTok >> - -Lbl_71 == /\ pc = "Lbl_71" - /\ /\ pos_find' = curPos - /\ stack' = << [ procedure |-> "findMatchingRightParen", - pc |-> "Lbl_72", - pos_find |-> pos_find ] >> - \o stack - /\ pc' = "Lbl_17" - /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, - curPos, returnVal, tempVar1, tempVar2, tempVar3, - pos_, tokArray, i, tokIdx, pos_f, token, left_, rt_, - pos_fi, pos_fin, delim_, ipos_, jdelim_, delimLen_, - pos, delim, ipos, jdelim, delimLen, leftTok, - rightTok, currentToken, left, rt, notDone, - foundBangToken, temp1, temp2, temp3 >> - -Lbl_72 == /\ pc = "Lbl_72" - /\ curPos' = returnVal - /\ IF curPos' < 0 - THEN /\ notDone' = FALSE - /\ pc' = "Lbl_70" - /\ stack' = stack - ELSE /\ stack' = << [ procedure |-> "skipRightOverSpaces", - pc |-> "Lbl_73" ] >> - \o stack - /\ pc' = "Lbl_30" - /\ UNCHANGED notDone - /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, - returnVal, tempVar1, tempVar2, tempVar3, pos_, - tokArray, i, tokIdx, pos_f, token, left_, rt_, - pos_fi, pos_fin, delim_, ipos_, jdelim_, delimLen_, - pos_find, pos, delim, ipos, jdelim, delimLen, - leftTok, rightTok, currentToken, left, rt, - foundBangToken, temp1, temp2, temp3 >> - -Lbl_73 == /\ pc = "Lbl_73" - /\ IF line[curPos] # "!" \/ line[curPos+1] = "!" - THEN /\ notDone' = FALSE - /\ pc' = "Lbl_70" - /\ UNCHANGED << curPos, stack >> - ELSE /\ curPos' = curPos + 1 - /\ stack' = << [ procedure |-> "skipRightOverSpaces", - pc |-> "Lbl_74" ] >> - \o stack - /\ pc' = "Lbl_30" - /\ UNCHANGED notDone - /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, - returnVal, tempVar1, tempVar2, tempVar3, pos_, - tokArray, i, tokIdx, pos_f, token, left_, rt_, - pos_fi, pos_fin, delim_, ipos_, jdelim_, delimLen_, - pos_find, pos, delim, ipos, jdelim, delimLen, - leftTok, rightTok, currentToken, left, rt, - foundBangToken, temp1, temp2, temp3 >> - -Lbl_74 == /\ pc = "Lbl_74" - /\ /\ pos_f' = curPos - /\ stack' = << [ procedure |-> "findMaximalIdCharSeq", - pc |-> "Lbl_75", - token |-> token, - left_ |-> left_, - rt_ |-> rt_, - pos_f |-> pos_f ] >> - \o stack - /\ token' = << >> - /\ left_' = pos_f' - /\ rt_' = pos_f' - /\ pc' = "Lbl_5" - /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, - curPos, returnVal, tempVar1, tempVar2, tempVar3, - pos_, tokArray, i, tokIdx, pos_fi, pos_fin, delim_, - ipos_, jdelim_, delimLen_, pos_find, pos, delim, - ipos, jdelim, delimLen, leftTok, rightTok, - currentToken, left, rt, notDone, foundBangToken, - temp1, temp2, temp3 >> - -Lbl_75 == /\ pc = "Lbl_75" - /\ currentToken' = returnVal - /\ IF \/ currentToken' = NullTokenSpec - \/ IsNumber(currentToken'.token) - THEN /\ notDone' = FALSE - /\ UNCHANGED << foundTokenSpecs, curPos, foundBangToken >> - ELSE /\ foundBangToken' = TRUE - /\ foundTokenSpecs' = JavaConcatenate( - JavaSeq( - << [token |-> - JavaConcatenate(JavaAppend(foundTokenSpecs[0].token, - "!"), - currentToken'.token), - leftPos |-> foundTokenSpecs[0].leftPos, - rightPos |-> currentToken'.rightPos] - >> ) , - foundTokenSpecs) - /\ curPos' = currentToken'.rightPos - /\ UNCHANGED notDone - /\ pc' = "Lbl_70" - /\ UNCHANGED << line, lastToken, notLastToken, returnVal, tempVar1, - tempVar2, tempVar3, stack, pos_, tokArray, i, tokIdx, - pos_f, token, left_, rt_, pos_fi, pos_fin, delim_, - ipos_, jdelim_, delimLen_, pos_find, pos, delim, - ipos, jdelim, delimLen, leftTok, rightTok, left, rt, - temp1, temp2, temp3 >> - -Lbl_76 == /\ pc = "Lbl_76" - /\ returnVal' = FixOrigin(foundTokenSpecs) - /\ pc' = Head(stack).pc - /\ currentToken' = Head(stack).currentToken - /\ left' = Head(stack).left - /\ rt' = Head(stack).rt - /\ notDone' = Head(stack).notDone - /\ foundBangToken' = Head(stack).foundBangToken - /\ temp1' = Head(stack).temp1 - /\ temp2' = Head(stack).temp2 - /\ temp3' = Head(stack).temp3 - /\ stack' = Tail(stack) - /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, - curPos, tempVar1, tempVar2, tempVar3, pos_, tokArray, - i, tokIdx, pos_f, token, left_, rt_, pos_fi, pos_fin, - delim_, ipos_, jdelim_, delimLen_, pos_find, pos, - delim, ipos, jdelim, delimLen, leftTok, rightTok >> - -findTokenSpecs == Lbl_31 \/ Lbl_32 \/ Lbl_33 \/ Lbl_34 \/ Lbl_35 \/ Lbl_36 - \/ Lbl_37 \/ Lbl_38 \/ Lbl_39 \/ Lbl_40 \/ Lbl_41 \/ Lbl_42 - \/ Lbl_43 \/ Lbl_44 \/ Lbl_45 \/ Lbl_46 \/ Lbl_47 \/ Lbl_48 - \/ Lbl_49 \/ Lbl_50 \/ Lbl_51 \/ Lbl_52 \/ Lbl_53 \/ Lbl_54 - \/ Lbl_55 \/ Lbl_56 \/ Lbl_57 \/ Lbl_58 \/ Lbl_59 \/ Lbl_60 - \/ Lbl_61 \/ Lbl_62 \/ Lbl_63 \/ Lbl_64 \/ Lbl_65 \/ Lbl_66 - \/ Lbl_67 \/ Lbl_68 \/ Lbl_69 \/ Lbl_70 \/ Lbl_71 \/ Lbl_72 - \/ Lbl_73 \/ Lbl_74 \/ Lbl_75 \/ Lbl_76 - -Lbl_77 == /\ pc = "Lbl_77" - /\ curPos' = JavaLen(Padding) - /\ tempVar1' = (-1 :> "") - /\ tempVar2' = JavaLen(Padding) - /\ pc' = "Lbl_78" - /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, - returnVal, tempVar3, stack, pos_, tokArray, i, - tokIdx, pos_f, token, left_, rt_, pos_fi, pos_fin, - delim_, ipos_, jdelim_, delimLen_, pos_find, pos, - delim, ipos, jdelim, delimLen, leftTok, rightTok, - currentToken, left, rt, notDone, foundBangToken, - temp1, temp2, temp3 >> - -Lbl_78 == /\ pc = "Lbl_78" - /\ IF tempVar2 < JavaLen(lineInput) + JavaLen(Padding) - THEN /\ curPos' = tempVar2 - /\ foundTokenSpecs' = << >> - /\ lastToken' = FALSE - /\ notLastToken' = FALSE - /\ stack' = << [ procedure |-> "findTokenSpecs", - pc |-> "Lbl_79", - currentToken |-> currentToken, - left |-> left, - rt |-> rt, - notDone |-> notDone, - foundBangToken |-> foundBangToken, - temp1 |-> temp1, - temp2 |-> temp2, - temp3 |-> temp3 ] >> - \o stack - /\ currentToken' = defaultInitValue - /\ left' = defaultInitValue - /\ rt' = defaultInitValue - /\ notDone' = defaultInitValue - /\ foundBangToken' = defaultInitValue - /\ temp1' = defaultInitValue - /\ temp2' = defaultInitValue - /\ temp3' = defaultInitValue - /\ pc' = "Lbl_31" - ELSE /\ PrintT("goodby world") - /\ pc' = "Done" - /\ UNCHANGED << foundTokenSpecs, lastToken, notLastToken, - curPos, stack, currentToken, left, rt, - notDone, foundBangToken, temp1, temp2, - temp3 >> - /\ UNCHANGED << line, returnVal, tempVar1, tempVar2, tempVar3, pos_, - tokArray, i, tokIdx, pos_f, token, left_, rt_, - pos_fi, pos_fin, delim_, ipos_, jdelim_, delimLen_, - pos_find, pos, delim, ipos, jdelim, delimLen, - leftTok, rightTok >> - -Lbl_79 == /\ pc = "Lbl_79" - /\ tempVar1' = returnVal - /\ tempVar2' = tempVar2 + 1 - /\ pc' = "Lbl_78" - /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, - curPos, returnVal, tempVar3, stack, pos_, tokArray, - i, tokIdx, pos_f, token, left_, rt_, pos_fi, pos_fin, - delim_, ipos_, jdelim_, delimLen_, pos_find, pos, - delim, ipos, jdelim, delimLen, leftTok, rightTok, - currentToken, left, rt, notDone, foundBangToken, - temp1, temp2, temp3 >> - -Next == findTokenIn \/ findMaximalIdCharSeq \/ findMatchingLeftParen - \/ findMatchingLeftInner \/ findMatchingRightParen - \/ findMatchingRightInner \/ checkIfStepName \/ skipLeftOverSpaces - \/ skipRightOverSpaces \/ findTokenSpecs \/ Lbl_77 \/ Lbl_78 \/ Lbl_79 - \/ (* Disjunct to prevent deadlock on termination *) - (pc = "Done" /\ UNCHANGED vars) - -Spec == Init /\ [][Next]_vars - -Termination == <>(pc = "Done") - -\* END TRANSLATION -============================================================================= + temp2, temp3 >> + +Init == (* Global variables *) + /\ line = JavaConcatenate (Padding, JavaConcatenate(lineInput, Padding)) + /\ foundTokenSpecs = << >> + /\ lastToken = FALSE + /\ notLastToken = FALSE + /\ curPos = currentPosition + JavaLen(Padding) + /\ returnVal = defaultInitValue + /\ tempVar1 = defaultInitValue + /\ tempVar2 = defaultInitValue + /\ tempVar3 = defaultInitValue + (* Procedure findTokenIn *) + /\ pos_ = defaultInitValue + /\ tokArray = defaultInitValue + /\ i = defaultInitValue + /\ tokIdx = defaultInitValue + (* Procedure findMaximalIdCharSeq *) + /\ pos_f = defaultInitValue + /\ token = << >> + /\ left_ = pos_f + /\ rt_ = pos_f + (* Procedure findMatchingLeftParen *) + /\ pos_fi = defaultInitValue + (* Procedure findMatchingLeftInner *) + /\ pos_fin = defaultInitValue + /\ delim_ = defaultInitValue + /\ ipos_ = pos_fin + /\ jdelim_ = defaultInitValue + /\ delimLen_ = defaultInitValue + (* Procedure findMatchingRightParen *) + /\ pos_find = defaultInitValue + (* Procedure findMatchingRightInner *) + /\ pos = defaultInitValue + /\ delim = defaultInitValue + /\ ipos = pos + /\ jdelim = defaultInitValue + /\ delimLen = defaultInitValue + (* Procedure checkIfStepName *) + /\ leftTok = defaultInitValue + /\ rightTok = defaultInitValue + (* Procedure findTokenSpecs *) + /\ currentToken = defaultInitValue + /\ left = defaultInitValue + /\ rt = defaultInitValue + /\ notDone = defaultInitValue + /\ foundBangToken = defaultInitValue + /\ temp1 = defaultInitValue + /\ temp2 = defaultInitValue + /\ temp3 = defaultInitValue + /\ stack = << >> + /\ pc = "Lbl_77" + +Lbl_1 == /\ pc = "Lbl_1" + /\ i' = 0 + /\ pc' = "Lbl_2" + /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, + curPos, returnVal, tempVar1, tempVar2, tempVar3, + stack, pos_, tokArray, tokIdx, pos_f, token, left_, + rt_, pos_fi, pos_fin, delim_, ipos_, jdelim_, + delimLen_, pos_find, pos, delim, ipos, jdelim, + delimLen, leftTok, rightTok, currentToken, left, rt, + notDone, foundBangToken, temp1, temp2, temp3 >> + +Lbl_2 == /\ pc = "Lbl_2" + /\ IF i < JavaLen(tokArray) + THEN /\ tokIdx' = JavaIndex(tokArray[i], line[pos_], 0) + /\ pc' = "Lbl_3" + /\ UNCHANGED << returnVal, stack, pos_, tokArray, i >> + ELSE /\ returnVal' = NullTokenSpec + /\ pc' = Head(stack).pc + /\ i' = Head(stack).i + /\ tokIdx' = Head(stack).tokIdx + /\ pos_' = Head(stack).pos_ + /\ tokArray' = Head(stack).tokArray + /\ stack' = Tail(stack) + /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, + curPos, tempVar1, tempVar2, tempVar3, pos_f, token, + left_, rt_, pos_fi, pos_fin, delim_, ipos_, jdelim_, + delimLen_, pos_find, pos, delim, ipos, jdelim, + delimLen, leftTok, rightTok, currentToken, left, rt, + notDone, foundBangToken, temp1, temp2, temp3 >> + +Lbl_3 == /\ pc = "Lbl_3" + /\ IF tokIdx # -1 + THEN /\ LET ftlft == pos_ - tokIdx IN + LET ftrt == pos_ - tokIdx + JavaLen(tokArray[i]) IN + IF tokArray[i] = JavaSubseq(line, ftlft, ftrt) + THEN /\ returnVal' = [token |-> tokArray[i], + leftPos |-> ftlft, rightPos |-> ftrt] + /\ pc' = Head(stack).pc + /\ i' = Head(stack).i + /\ tokIdx' = Head(stack).tokIdx + /\ pos_' = Head(stack).pos_ + /\ tokArray' = Head(stack).tokArray + /\ stack' = Tail(stack) + ELSE /\ pc' = "Lbl_4" + /\ UNCHANGED << returnVal, stack, pos_, + tokArray, i, tokIdx >> + ELSE /\ i' = i+1 + /\ pc' = "Lbl_2" + /\ UNCHANGED << returnVal, stack, pos_, tokArray, tokIdx >> + /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, + curPos, tempVar1, tempVar2, tempVar3, pos_f, token, + left_, rt_, pos_fi, pos_fin, delim_, ipos_, jdelim_, + delimLen_, pos_find, pos, delim, ipos, jdelim, + delimLen, leftTok, rightTok, currentToken, left, rt, + notDone, foundBangToken, temp1, temp2, temp3 >> + +Lbl_4 == /\ pc = "Lbl_4" + /\ tokIdx' = JavaIndex(tokArray[i], line[pos_], tokIdx+1) + /\ pc' = "Lbl_3" + /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, + curPos, returnVal, tempVar1, tempVar2, tempVar3, + stack, pos_, tokArray, i, pos_f, token, left_, rt_, + pos_fi, pos_fin, delim_, ipos_, jdelim_, delimLen_, + pos_find, pos, delim, ipos, jdelim, delimLen, leftTok, + rightTok, currentToken, left, rt, notDone, + foundBangToken, temp1, temp2, temp3 >> + +findTokenIn == Lbl_1 \/ Lbl_2 \/ Lbl_3 \/ Lbl_4 + +Lbl_5 == /\ pc = "Lbl_5" + /\ IF line[left_-1] \in IdChar + THEN /\ left_' = left_-1 + /\ pc' = "Lbl_5" + ELSE /\ pc' = "Lbl_6" + /\ left_' = left_ + /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, + curPos, returnVal, tempVar1, tempVar2, tempVar3, + stack, pos_, tokArray, i, tokIdx, pos_f, token, rt_, + pos_fi, pos_fin, delim_, ipos_, jdelim_, delimLen_, + pos_find, pos, delim, ipos, jdelim, delimLen, leftTok, + rightTok, currentToken, left, rt, notDone, + foundBangToken, temp1, temp2, temp3 >> + +Lbl_6 == /\ pc = "Lbl_6" + /\ IF line[rt_] \in IdChar + THEN /\ rt_' = rt_+1 + /\ pc' = "Lbl_6" + /\ UNCHANGED << returnVal, stack, pos_f, token, left_ >> + ELSE /\ IF left_ = rt_ + THEN /\ returnVal' = NullTokenSpec + /\ pc' = Head(stack).pc + /\ token' = Head(stack).token + /\ left_' = Head(stack).left_ + /\ rt_' = Head(stack).rt_ + /\ pos_f' = Head(stack).pos_f + /\ stack' = Tail(stack) + ELSE /\ returnVal' = [token |-> JavaSubseq(line, left_, rt_), + leftPos |-> left_, rightPos |-> rt_] + /\ pc' = Head(stack).pc + /\ token' = Head(stack).token + /\ left_' = Head(stack).left_ + /\ rt_' = Head(stack).rt_ + /\ pos_f' = Head(stack).pos_f + /\ stack' = Tail(stack) + /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, + curPos, tempVar1, tempVar2, tempVar3, pos_, tokArray, + i, tokIdx, pos_fi, pos_fin, delim_, ipos_, jdelim_, + delimLen_, pos_find, pos, delim, ipos, jdelim, + delimLen, leftTok, rightTok, currentToken, left, rt, + notDone, foundBangToken, temp1, temp2, temp3 >> + +findMaximalIdCharSeq == Lbl_5 \/ Lbl_6 + +Lbl_7 == /\ pc = "Lbl_7" + /\ IF line[pos_fi-1] # ")" + THEN /\ returnVal' = pos_fi + /\ pc' = Head(stack).pc + /\ pos_fi' = Head(stack).pos_fi + /\ stack' = Tail(stack) + ELSE /\ pc' = "Lbl_8" + /\ UNCHANGED << returnVal, stack, pos_fi >> + /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, + curPos, tempVar1, tempVar2, tempVar3, pos_, tokArray, + i, tokIdx, pos_f, token, left_, rt_, pos_fin, delim_, + ipos_, jdelim_, delimLen_, pos_find, pos, delim, ipos, + jdelim, delimLen, leftTok, rightTok, currentToken, + left, rt, notDone, foundBangToken, temp1, temp2, + temp3 >> + +Lbl_8 == /\ pc = "Lbl_8" + /\ /\ delim_' = 0 + /\ pos_fin' = pos_fi + /\ stack' = << [ procedure |-> "findMatchingLeftInner", + pc |-> Head(stack).pc, + ipos_ |-> ipos_, + jdelim_ |-> jdelim_, + delimLen_ |-> delimLen_, + pos_fin |-> pos_fin, + delim_ |-> delim_ ] >> + \o Tail(stack) + /\ ipos_' = pos_fin' + /\ jdelim_' = defaultInitValue + /\ delimLen_' = defaultInitValue + /\ pc' = "Lbl_9" + /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, + curPos, returnVal, tempVar1, tempVar2, tempVar3, pos_, + tokArray, i, tokIdx, pos_f, token, left_, rt_, pos_fi, + pos_find, pos, delim, ipos, jdelim, delimLen, leftTok, + rightTok, currentToken, left, rt, notDone, + foundBangToken, temp1, temp2, temp3 >> + +findMatchingLeftParen == Lbl_7 \/ Lbl_8 + +Lbl_9 == /\ pc = "Lbl_9" + /\ delimLen_' = JavaLen(LeftDelimiters[delim_]) + /\ ipos_' = pos_fin - delimLen_' + /\ pc' = "Lbl_10" + /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, + curPos, returnVal, tempVar1, tempVar2, tempVar3, + stack, pos_, tokArray, i, tokIdx, pos_f, token, left_, + rt_, pos_fi, pos_fin, delim_, jdelim_, pos_find, pos, + delim, ipos, jdelim, delimLen, leftTok, rightTok, + currentToken, left, rt, notDone, foundBangToken, + temp1, temp2, temp3 >> + +Lbl_10 == /\ pc = "Lbl_10" + /\ IF JavaSubseq(line, ipos_-delimLen_, ipos_) # LeftDelimiters[delim_] + THEN /\ IF line[ipos_-1] = ";" + THEN /\ returnVal' = -1 + /\ pc' = Head(stack).pc + /\ ipos_' = Head(stack).ipos_ + /\ jdelim_' = Head(stack).jdelim_ + /\ delimLen_' = Head(stack).delimLen_ + /\ pos_fin' = Head(stack).pos_fin + /\ delim_' = Head(stack).delim_ + /\ stack' = Tail(stack) + ELSE /\ pc' = "Lbl_11" + /\ UNCHANGED << returnVal, stack, pos_fin, + delim_, ipos_, jdelim_, + delimLen_ >> + ELSE /\ returnVal' = ipos_-delimLen_ + /\ pc' = Head(stack).pc + /\ ipos_' = Head(stack).ipos_ + /\ jdelim_' = Head(stack).jdelim_ + /\ delimLen_' = Head(stack).delimLen_ + /\ pos_fin' = Head(stack).pos_fin + /\ delim_' = Head(stack).delim_ + /\ stack' = Tail(stack) + /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, + curPos, tempVar1, tempVar2, tempVar3, pos_, tokArray, + i, tokIdx, pos_f, token, left_, rt_, pos_fi, + pos_find, pos, delim, ipos, jdelim, delimLen, + leftTok, rightTok, currentToken, left, rt, notDone, + foundBangToken, temp1, temp2, temp3 >> + +Lbl_11 == /\ pc = "Lbl_11" + /\ ipos_' = ipos_-1 + /\ jdelim_' = 0 + /\ pc' = "Lbl_12" + /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, + curPos, returnVal, tempVar1, tempVar2, tempVar3, + stack, pos_, tokArray, i, tokIdx, pos_f, token, + left_, rt_, pos_fi, pos_fin, delim_, delimLen_, + pos_find, pos, delim, ipos, jdelim, delimLen, + leftTok, rightTok, currentToken, left, rt, notDone, + foundBangToken, temp1, temp2, temp3 >> + +Lbl_12 == /\ pc = "Lbl_12" + /\ IF jdelim_ < JavaLen(LeftDelimiters) + THEN /\ IF JavaSubseq(line, ipos_-delimLen_, ipos_) = RightDelimiters[jdelim_] + THEN /\ /\ delim_' = jdelim_ + /\ pos_fin' = ipos_ + /\ stack' = << [ procedure |-> "findMatchingLeftInner", + pc |-> "Lbl_13", + ipos_ |-> ipos_, + jdelim_ |-> jdelim_, + delimLen_ |-> delimLen_, + pos_fin |-> pos_fin, + delim_ |-> delim_ ] >> + \o stack + /\ ipos_' = pos_fin' + /\ jdelim_' = defaultInitValue + /\ delimLen_' = defaultInitValue + /\ pc' = "Lbl_9" + ELSE /\ pc' = "Lbl_16" + /\ UNCHANGED << stack, pos_fin, delim_, ipos_, + jdelim_, delimLen_ >> + ELSE /\ pc' = "Lbl_10" + /\ UNCHANGED << stack, pos_fin, delim_, ipos_, jdelim_, + delimLen_ >> + /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, + curPos, returnVal, tempVar1, tempVar2, tempVar3, + pos_, tokArray, i, tokIdx, pos_f, token, left_, rt_, + pos_fi, pos_find, pos, delim, ipos, jdelim, delimLen, + leftTok, rightTok, currentToken, left, rt, notDone, + foundBangToken, temp1, temp2, temp3 >> + +Lbl_16 == /\ pc = "Lbl_16" + /\ jdelim_' = jdelim_+1 + /\ pc' = "Lbl_12" + /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, + curPos, returnVal, tempVar1, tempVar2, tempVar3, + stack, pos_, tokArray, i, tokIdx, pos_f, token, + left_, rt_, pos_fi, pos_fin, delim_, ipos_, + delimLen_, pos_find, pos, delim, ipos, jdelim, + delimLen, leftTok, rightTok, currentToken, left, rt, + notDone, foundBangToken, temp1, temp2, temp3 >> + +Lbl_13 == /\ pc = "Lbl_13" + /\ ipos_' = returnVal + /\ IF ipos_' < 0 + THEN /\ returnVal' = -1 + /\ pc' = "Lbl_14" + ELSE /\ pc' = "Lbl_15" + /\ UNCHANGED returnVal + /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, + curPos, tempVar1, tempVar2, tempVar3, stack, pos_, + tokArray, i, tokIdx, pos_f, token, left_, rt_, + pos_fi, pos_fin, delim_, jdelim_, delimLen_, + pos_find, pos, delim, ipos, jdelim, delimLen, + leftTok, rightTok, currentToken, left, rt, notDone, + foundBangToken, temp1, temp2, temp3 >> + +Lbl_14 == /\ pc = "Lbl_14" + /\ pc' = Head(stack).pc + /\ ipos_' = Head(stack).ipos_ + /\ jdelim_' = Head(stack).jdelim_ + /\ delimLen_' = Head(stack).delimLen_ + /\ pos_fin' = Head(stack).pos_fin + /\ delim_' = Head(stack).delim_ + /\ stack' = Tail(stack) + /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, + curPos, returnVal, tempVar1, tempVar2, tempVar3, + pos_, tokArray, i, tokIdx, pos_f, token, left_, rt_, + pos_fi, pos_find, pos, delim, ipos, jdelim, delimLen, + leftTok, rightTok, currentToken, left, rt, notDone, + foundBangToken, temp1, temp2, temp3 >> + +Lbl_15 == /\ pc = "Lbl_15" + /\ jdelim_' = 99 + /\ pc' = "Lbl_16" + /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, + curPos, returnVal, tempVar1, tempVar2, tempVar3, + stack, pos_, tokArray, i, tokIdx, pos_f, token, + left_, rt_, pos_fi, pos_fin, delim_, ipos_, + delimLen_, pos_find, pos, delim, ipos, jdelim, + delimLen, leftTok, rightTok, currentToken, left, rt, + notDone, foundBangToken, temp1, temp2, temp3 >> + +findMatchingLeftInner == Lbl_9 \/ Lbl_10 \/ Lbl_11 \/ Lbl_12 \/ Lbl_16 + \/ Lbl_13 \/ Lbl_14 \/ Lbl_15 + +Lbl_17 == /\ pc = "Lbl_17" + /\ IF line[pos_find] # "(" + THEN /\ returnVal' = pos_find + /\ pc' = Head(stack).pc + /\ pos_find' = Head(stack).pos_find + /\ stack' = Tail(stack) + ELSE /\ pc' = "Lbl_18" + /\ UNCHANGED << returnVal, stack, pos_find >> + /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, + curPos, tempVar1, tempVar2, tempVar3, pos_, tokArray, + i, tokIdx, pos_f, token, left_, rt_, pos_fi, pos_fin, + delim_, ipos_, jdelim_, delimLen_, pos, delim, ipos, + jdelim, delimLen, leftTok, rightTok, currentToken, + left, rt, notDone, foundBangToken, temp1, temp2, + temp3 >> + +Lbl_18 == /\ pc = "Lbl_18" + /\ /\ delim' = 0 + /\ pos' = pos_find + /\ stack' = << [ procedure |-> "findMatchingRightInner", + pc |-> Head(stack).pc, + ipos |-> ipos, + jdelim |-> jdelim, + delimLen |-> delimLen, + pos |-> pos, + delim |-> delim ] >> + \o Tail(stack) + /\ ipos' = pos' + /\ jdelim' = defaultInitValue + /\ delimLen' = defaultInitValue + /\ pc' = "Lbl_19" + /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, + curPos, returnVal, tempVar1, tempVar2, tempVar3, + pos_, tokArray, i, tokIdx, pos_f, token, left_, rt_, + pos_fi, pos_fin, delim_, ipos_, jdelim_, delimLen_, + pos_find, leftTok, rightTok, currentToken, left, rt, + notDone, foundBangToken, temp1, temp2, temp3 >> + +findMatchingRightParen == Lbl_17 \/ Lbl_18 + +Lbl_19 == /\ pc = "Lbl_19" + /\ delimLen' = JavaLen(RightDelimiters[delim]) + /\ ipos' = pos + delimLen' + /\ pc' = "Lbl_20" + /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, + curPos, returnVal, tempVar1, tempVar2, tempVar3, + stack, pos_, tokArray, i, tokIdx, pos_f, token, + left_, rt_, pos_fi, pos_fin, delim_, ipos_, jdelim_, + delimLen_, pos_find, pos, delim, jdelim, leftTok, + rightTok, currentToken, left, rt, notDone, + foundBangToken, temp1, temp2, temp3 >> + +Lbl_20 == /\ pc = "Lbl_20" + /\ IF JavaSubseq(line, ipos, ipos+delimLen) # RightDelimiters[delim] + THEN /\ IF line[ipos] = ";" + THEN /\ returnVal' = -1 + /\ pc' = Head(stack).pc + /\ ipos' = Head(stack).ipos + /\ jdelim' = Head(stack).jdelim + /\ delimLen' = Head(stack).delimLen + /\ pos' = Head(stack).pos + /\ delim' = Head(stack).delim + /\ stack' = Tail(stack) + ELSE /\ pc' = "Lbl_21" + /\ UNCHANGED << returnVal, stack, pos, delim, + ipos, jdelim, delimLen >> + ELSE /\ returnVal' = ipos+delimLen + /\ pc' = Head(stack).pc + /\ ipos' = Head(stack).ipos + /\ jdelim' = Head(stack).jdelim + /\ delimLen' = Head(stack).delimLen + /\ pos' = Head(stack).pos + /\ delim' = Head(stack).delim + /\ stack' = Tail(stack) + /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, + curPos, tempVar1, tempVar2, tempVar3, pos_, tokArray, + i, tokIdx, pos_f, token, left_, rt_, pos_fi, pos_fin, + delim_, ipos_, jdelim_, delimLen_, pos_find, leftTok, + rightTok, currentToken, left, rt, notDone, + foundBangToken, temp1, temp2, temp3 >> + +Lbl_21 == /\ pc = "Lbl_21" + /\ ipos' = ipos+1 + /\ jdelim' = 0 + /\ pc' = "Lbl_22" + /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, + curPos, returnVal, tempVar1, tempVar2, tempVar3, + stack, pos_, tokArray, i, tokIdx, pos_f, token, + left_, rt_, pos_fi, pos_fin, delim_, ipos_, jdelim_, + delimLen_, pos_find, pos, delim, delimLen, leftTok, + rightTok, currentToken, left, rt, notDone, + foundBangToken, temp1, temp2, temp3 >> + +Lbl_22 == /\ pc = "Lbl_22" + /\ IF jdelim < JavaLen(RightDelimiters) + THEN /\ IF JavaSubseq(line, ipos, ipos+delimLen) = LeftDelimiters[jdelim] + THEN /\ /\ delim' = jdelim + /\ pos' = ipos + /\ stack' = << [ procedure |-> "findMatchingRightInner", + pc |-> "Lbl_23", + ipos |-> ipos, + jdelim |-> jdelim, + delimLen |-> delimLen, + pos |-> pos, + delim |-> delim ] >> + \o stack + /\ ipos' = pos' + /\ jdelim' = defaultInitValue + /\ delimLen' = defaultInitValue + /\ pc' = "Lbl_19" + ELSE /\ pc' = "Lbl_26" + /\ UNCHANGED << stack, pos, delim, ipos, + jdelim, delimLen >> + ELSE /\ pc' = "Lbl_20" + /\ UNCHANGED << stack, pos, delim, ipos, jdelim, delimLen >> + /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, + curPos, returnVal, tempVar1, tempVar2, tempVar3, + pos_, tokArray, i, tokIdx, pos_f, token, left_, rt_, + pos_fi, pos_fin, delim_, ipos_, jdelim_, delimLen_, + pos_find, leftTok, rightTok, currentToken, left, rt, + notDone, foundBangToken, temp1, temp2, temp3 >> + +Lbl_26 == /\ pc = "Lbl_26" + /\ jdelim' = jdelim+1 + /\ pc' = "Lbl_22" + /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, + curPos, returnVal, tempVar1, tempVar2, tempVar3, + stack, pos_, tokArray, i, tokIdx, pos_f, token, + left_, rt_, pos_fi, pos_fin, delim_, ipos_, jdelim_, + delimLen_, pos_find, pos, delim, ipos, delimLen, + leftTok, rightTok, currentToken, left, rt, notDone, + foundBangToken, temp1, temp2, temp3 >> + +Lbl_23 == /\ pc = "Lbl_23" + /\ ipos' = returnVal + /\ IF ipos' < 0 + THEN /\ returnVal' = -1 + /\ pc' = "Lbl_24" + ELSE /\ pc' = "Lbl_25" + /\ UNCHANGED returnVal + /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, + curPos, tempVar1, tempVar2, tempVar3, stack, pos_, + tokArray, i, tokIdx, pos_f, token, left_, rt_, + pos_fi, pos_fin, delim_, ipos_, jdelim_, delimLen_, + pos_find, pos, delim, jdelim, delimLen, leftTok, + rightTok, currentToken, left, rt, notDone, + foundBangToken, temp1, temp2, temp3 >> + +Lbl_24 == /\ pc = "Lbl_24" + /\ pc' = Head(stack).pc + /\ ipos' = Head(stack).ipos + /\ jdelim' = Head(stack).jdelim + /\ delimLen' = Head(stack).delimLen + /\ pos' = Head(stack).pos + /\ delim' = Head(stack).delim + /\ stack' = Tail(stack) + /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, + curPos, returnVal, tempVar1, tempVar2, tempVar3, + pos_, tokArray, i, tokIdx, pos_f, token, left_, rt_, + pos_fi, pos_fin, delim_, ipos_, jdelim_, delimLen_, + pos_find, leftTok, rightTok, currentToken, left, rt, + notDone, foundBangToken, temp1, temp2, temp3 >> + +Lbl_25 == /\ pc = "Lbl_25" + /\ jdelim' = 99 + /\ pc' = "Lbl_26" + /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, + curPos, returnVal, tempVar1, tempVar2, tempVar3, + stack, pos_, tokArray, i, tokIdx, pos_f, token, + left_, rt_, pos_fi, pos_fin, delim_, ipos_, jdelim_, + delimLen_, pos_find, pos, delim, ipos, delimLen, + leftTok, rightTok, currentToken, left, rt, notDone, + foundBangToken, temp1, temp2, temp3 >> + +findMatchingRightInner == Lbl_19 \/ Lbl_20 \/ Lbl_21 \/ Lbl_22 \/ Lbl_26 + \/ Lbl_23 \/ Lbl_24 \/ Lbl_25 + +Lbl_27 == /\ pc = "Lbl_27" + /\ IF leftTok = NullTokenSpec \/ rightTok = NullTokenSpec + THEN /\ returnVal' = NullTokenSpec + /\ pc' = Head(stack).pc + /\ leftTok' = Head(stack).leftTok + /\ rightTok' = Head(stack).rightTok + /\ stack' = Tail(stack) + ELSE /\ pc' = "Lbl_28" + /\ UNCHANGED << returnVal, stack, leftTok, rightTok >> + /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, + curPos, tempVar1, tempVar2, tempVar3, pos_, tokArray, + i, tokIdx, pos_f, token, left_, rt_, pos_fi, pos_fin, + delim_, ipos_, jdelim_, delimLen_, pos_find, pos, + delim, ipos, jdelim, delimLen, currentToken, left, + rt, notDone, foundBangToken, temp1, temp2, temp3 >> + +Lbl_28 == /\ pc = "Lbl_28" + /\ IF /\ IsNumber(leftTok.token) + /\ line[leftTok.leftPos-1] = "<" + /\ line[leftTok.leftPos-2] # "<" + THEN /\ returnVal' = [token |-> JavaSubseq(line, + leftTok.leftPos-1, + rightTok.rightPos), + leftPos |-> leftTok.leftPos-1, + rightPos |-> rightTok.rightPos] + /\ pc' = Head(stack).pc + /\ leftTok' = Head(stack).leftTok + /\ rightTok' = Head(stack).rightTok + /\ stack' = Tail(stack) + ELSE /\ returnVal' = NullTokenSpec + /\ pc' = Head(stack).pc + /\ leftTok' = Head(stack).leftTok + /\ rightTok' = Head(stack).rightTok + /\ stack' = Tail(stack) + /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, + curPos, tempVar1, tempVar2, tempVar3, pos_, tokArray, + i, tokIdx, pos_f, token, left_, rt_, pos_fi, pos_fin, + delim_, ipos_, jdelim_, delimLen_, pos_find, pos, + delim, ipos, jdelim, delimLen, currentToken, left, + rt, notDone, foundBangToken, temp1, temp2, temp3 >> + +checkIfStepName == Lbl_27 \/ Lbl_28 + +Lbl_29 == /\ pc = "Lbl_29" + /\ IF line[curPos-1] = " " + THEN /\ curPos' = curPos - 1 + /\ pc' = "Lbl_29" + /\ stack' = stack + ELSE /\ pc' = Head(stack).pc + /\ stack' = Tail(stack) + /\ UNCHANGED curPos + /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, + returnVal, tempVar1, tempVar2, tempVar3, pos_, + tokArray, i, tokIdx, pos_f, token, left_, rt_, + pos_fi, pos_fin, delim_, ipos_, jdelim_, delimLen_, + pos_find, pos, delim, ipos, jdelim, delimLen, + leftTok, rightTok, currentToken, left, rt, notDone, + foundBangToken, temp1, temp2, temp3 >> + +skipLeftOverSpaces == Lbl_29 + +Lbl_30 == /\ pc = "Lbl_30" + /\ IF line[curPos] = " " + THEN /\ curPos' = curPos+1 + /\ pc' = "Lbl_30" + /\ stack' = stack + ELSE /\ pc' = Head(stack).pc + /\ stack' = Tail(stack) + /\ UNCHANGED curPos + /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, + returnVal, tempVar1, tempVar2, tempVar3, pos_, + tokArray, i, tokIdx, pos_f, token, left_, rt_, + pos_fi, pos_fin, delim_, ipos_, jdelim_, delimLen_, + pos_find, pos, delim, ipos, jdelim, delimLen, + leftTok, rightTok, currentToken, left, rt, notDone, + foundBangToken, temp1, temp2, temp3 >> + +skipRightOverSpaces == Lbl_30 + +Lbl_31 == /\ pc = "Lbl_31" + /\ IF line[curPos] = " " + THEN /\ stack' = << [ procedure |-> "skipLeftOverSpaces", + pc |-> "Lbl_32" ] >> + \o stack + /\ pc' = "Lbl_29" + /\ UNCHANGED notLastToken + ELSE /\ IF line[curPos] = "!" /\ line[curPos-1] # "!" /\ line[curPos+1] # "!" + THEN /\ notLastToken' = TRUE + /\ stack' = << [ procedure |-> "skipLeftOverSpaces", + pc |-> "Lbl_33" ] >> + \o stack + /\ pc' = "Lbl_29" + ELSE /\ pc' = "Lbl_33" + /\ UNCHANGED << notLastToken, stack >> + /\ UNCHANGED << line, foundTokenSpecs, lastToken, curPos, returnVal, + tempVar1, tempVar2, tempVar3, pos_, tokArray, i, + tokIdx, pos_f, token, left_, rt_, pos_fi, pos_fin, + delim_, ipos_, jdelim_, delimLen_, pos_find, pos, + delim, ipos, jdelim, delimLen, leftTok, rightTok, + currentToken, left, rt, notDone, foundBangToken, + temp1, temp2, temp3 >> + +Lbl_32 == /\ pc = "Lbl_32" + /\ IF line[curPos-1] = "!" /\ line[curPos-2] # "!" + THEN /\ notLastToken' = TRUE + /\ curPos' = curPos - 1 + /\ stack' = << [ procedure |-> "skipLeftOverSpaces", + pc |-> "Lbl_33" ] >> + \o stack + /\ pc' = "Lbl_29" + ELSE /\ pc' = "Lbl_33" + /\ UNCHANGED << notLastToken, curPos, stack >> + /\ UNCHANGED << line, foundTokenSpecs, lastToken, returnVal, + tempVar1, tempVar2, tempVar3, pos_, tokArray, i, + tokIdx, pos_f, token, left_, rt_, pos_fi, pos_fin, + delim_, ipos_, jdelim_, delimLen_, pos_find, pos, + delim, ipos, jdelim, delimLen, leftTok, rightTok, + currentToken, left, rt, notDone, foundBangToken, + temp1, temp2, temp3 >> + +Lbl_33 == /\ pc = "Lbl_33" + /\ IF /\ \/ notLastToken + \/ line[curPos] = " " + /\ line[curPos-1] = ")" + THEN /\ notLastToken' = TRUE + /\ /\ pos_fi' = curPos + /\ stack' = << [ procedure |-> "findMatchingLeftParen", + pc |-> "Lbl_34", + pos_fi |-> pos_fi ] >> + \o stack + /\ pc' = "Lbl_7" + ELSE /\ pc' = "Lbl_36" + /\ UNCHANGED << notLastToken, stack, pos_fi >> + /\ UNCHANGED << line, foundTokenSpecs, lastToken, curPos, returnVal, + tempVar1, tempVar2, tempVar3, pos_, tokArray, i, + tokIdx, pos_f, token, left_, rt_, pos_fin, delim_, + ipos_, jdelim_, delimLen_, pos_find, pos, delim, + ipos, jdelim, delimLen, leftTok, rightTok, + currentToken, left, rt, notDone, foundBangToken, + temp1, temp2, temp3 >> + +Lbl_34 == /\ pc = "Lbl_34" + /\ IF returnVal < 0 + THEN /\ returnVal' = << >> + /\ pc' = Head(stack).pc + /\ currentToken' = Head(stack).currentToken + /\ left' = Head(stack).left + /\ rt' = Head(stack).rt + /\ notDone' = Head(stack).notDone + /\ foundBangToken' = Head(stack).foundBangToken + /\ temp1' = Head(stack).temp1 + /\ temp2' = Head(stack).temp2 + /\ temp3' = Head(stack).temp3 + /\ stack' = Tail(stack) + ELSE /\ pc' = "Lbl_35" + /\ UNCHANGED << returnVal, stack, currentToken, left, rt, + notDone, foundBangToken, temp1, temp2, + temp3 >> + /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, + curPos, tempVar1, tempVar2, tempVar3, pos_, tokArray, + i, tokIdx, pos_f, token, left_, rt_, pos_fi, pos_fin, + delim_, ipos_, jdelim_, delimLen_, pos_find, pos, + delim, ipos, jdelim, delimLen, leftTok, rightTok >> + +Lbl_35 == /\ pc = "Lbl_35" + /\ curPos' = returnVal + /\ stack' = << [ procedure |-> "skipLeftOverSpaces", + pc |-> "Lbl_36" ] >> + \o stack + /\ pc' = "Lbl_29" + /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, + returnVal, tempVar1, tempVar2, tempVar3, pos_, + tokArray, i, tokIdx, pos_f, token, left_, rt_, + pos_fi, pos_fin, delim_, ipos_, jdelim_, delimLen_, + pos_find, pos, delim, ipos, jdelim, delimLen, + leftTok, rightTok, currentToken, left, rt, notDone, + foundBangToken, temp1, temp2, temp3 >> + +Lbl_36 == /\ pc = "Lbl_36" + /\ IF notLastToken + THEN /\ curPos' = curPos - 1 + /\ pc' = "Lbl_38" + /\ UNCHANGED << stack, pos_, tokArray, i, tokIdx >> + ELSE /\ IF line[curPos] \notin IdChar + THEN /\ /\ pos_' = curPos + /\ stack' = << [ procedure |-> "findTokenIn", + pc |-> "Lbl_37", + i |-> i, + tokIdx |-> tokIdx, + pos_ |-> pos_, + tokArray |-> tokArray ] >> + \o stack + /\ tokArray' = Operators + /\ i' = defaultInitValue + /\ tokIdx' = defaultInitValue + /\ pc' = "Lbl_1" + ELSE /\ pc' = "Lbl_38" + /\ UNCHANGED << stack, pos_, tokArray, i, + tokIdx >> + /\ UNCHANGED curPos + /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, + returnVal, tempVar1, tempVar2, tempVar3, pos_f, + token, left_, rt_, pos_fi, pos_fin, delim_, ipos_, + jdelim_, delimLen_, pos_find, pos, delim, ipos, + jdelim, delimLen, leftTok, rightTok, currentToken, + left, rt, notDone, foundBangToken, temp1, temp2, + temp3 >> + +Lbl_37 == /\ pc = "Lbl_37" + /\ IF returnVal = NullTokenSpec + THEN /\ curPos' = curPos - 1 + ELSE /\ TRUE + /\ UNCHANGED curPos + /\ pc' = "Lbl_38" + /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, + returnVal, tempVar1, tempVar2, tempVar3, stack, pos_, + tokArray, i, tokIdx, pos_f, token, left_, rt_, + pos_fi, pos_fin, delim_, ipos_, jdelim_, delimLen_, + pos_find, pos, delim, ipos, jdelim, delimLen, + leftTok, rightTok, currentToken, left, rt, notDone, + foundBangToken, temp1, temp2, temp3 >> + +Lbl_38 == /\ pc = "Lbl_38" + /\ IF line[curPos] \in IdChar + THEN /\ IF line[curPos] = "X" + THEN /\ /\ pos_' = curPos + /\ stack' = << [ procedure |-> "findTokenIn", + pc |-> "Lbl_39", + i |-> i, + tokIdx |-> tokIdx, + pos_ |-> pos_, + tokArray |-> tokArray ] >> + \o stack + /\ tokArray' = XSymbols + /\ i' = defaultInitValue + /\ tokIdx' = defaultInitValue + /\ pc' = "Lbl_1" + /\ UNCHANGED returnVal + ELSE /\ returnVal' = NullTokenSpec + /\ pc' = "Lbl_39" + /\ UNCHANGED << stack, pos_, tokArray, i, + tokIdx >> + ELSE /\ /\ pos_' = curPos + /\ stack' = << [ procedure |-> "findTokenIn", + pc |-> "Lbl_48", + i |-> i, + tokIdx |-> tokIdx, + pos_ |-> pos_, + tokArray |-> tokArray ] >> + \o stack + /\ tokArray' = Operators + /\ i' = defaultInitValue + /\ tokIdx' = defaultInitValue + /\ pc' = "Lbl_1" + /\ UNCHANGED returnVal + /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, + curPos, tempVar1, tempVar2, tempVar3, pos_f, token, + left_, rt_, pos_fi, pos_fin, delim_, ipos_, jdelim_, + delimLen_, pos_find, pos, delim, ipos, jdelim, + delimLen, leftTok, rightTok, currentToken, left, rt, + notDone, foundBangToken, temp1, temp2, temp3 >> + +Lbl_39 == /\ pc = "Lbl_39" + /\ IF returnVal # NullTokenSpec + THEN /\ foundTokenSpecs' = JavaSeq(<<returnVal>>) + /\ curPos' = returnVal.leftPos + /\ lastToken' = TRUE + /\ pc' = "Lbl_62" + /\ UNCHANGED << stack, pos_f, token, left_, rt_ >> + ELSE /\ /\ pos_f' = curPos + /\ stack' = << [ procedure |-> "findMaximalIdCharSeq", + pc |-> "Lbl_40", + token |-> token, + left_ |-> left_, + rt_ |-> rt_, + pos_f |-> pos_f ] >> + \o stack + /\ token' = << >> + /\ left_' = pos_f' + /\ rt_' = pos_f' + /\ pc' = "Lbl_5" + /\ UNCHANGED << foundTokenSpecs, lastToken, curPos >> + /\ UNCHANGED << line, notLastToken, returnVal, tempVar1, tempVar2, + tempVar3, pos_, tokArray, i, tokIdx, pos_fi, pos_fin, + delim_, ipos_, jdelim_, delimLen_, pos_find, pos, + delim, ipos, jdelim, delimLen, leftTok, rightTok, + currentToken, left, rt, notDone, foundBangToken, + temp1, temp2, temp3 >> + +Lbl_40 == /\ pc = "Lbl_40" + /\ currentToken' = returnVal + /\ IF line[currentToken'.leftPos-1] = ">" + THEN /\ /\ pos_f' = currentToken'.leftPos - 1 + /\ stack' = << [ procedure |-> "findMaximalIdCharSeq", + pc |-> "Lbl_41", + token |-> token, + left_ |-> left_, + rt_ |-> rt_, + pos_f |-> pos_f ] >> + \o stack + /\ token' = << >> + /\ left_' = pos_f' + /\ rt_' = pos_f' + /\ pc' = "Lbl_5" + ELSE /\ pc' = "Lbl_43" + /\ UNCHANGED << stack, pos_f, token, left_, rt_ >> + /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, + curPos, returnVal, tempVar1, tempVar2, tempVar3, + pos_, tokArray, i, tokIdx, pos_fi, pos_fin, delim_, + ipos_, jdelim_, delimLen_, pos_find, pos, delim, + ipos, jdelim, delimLen, leftTok, rightTok, left, rt, + notDone, foundBangToken, temp1, temp2, temp3 >> + +Lbl_41 == /\ pc = "Lbl_41" + /\ /\ leftTok' = returnVal + /\ rightTok' = currentToken + /\ stack' = << [ procedure |-> "checkIfStepName", + pc |-> "Lbl_42", + leftTok |-> leftTok, + rightTok |-> rightTok ] >> + \o stack + /\ pc' = "Lbl_27" + /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, + curPos, returnVal, tempVar1, tempVar2, tempVar3, + pos_, tokArray, i, tokIdx, pos_f, token, left_, rt_, + pos_fi, pos_fin, delim_, ipos_, jdelim_, delimLen_, + pos_find, pos, delim, ipos, jdelim, delimLen, + currentToken, left, rt, notDone, foundBangToken, + temp1, temp2, temp3 >> + +Lbl_42 == /\ pc = "Lbl_42" + /\ IF returnVal # NullTokenSpec + THEN /\ foundTokenSpecs' = JavaSeq(<<returnVal>>) + /\ returnVal' = FixOrigin(foundTokenSpecs') + /\ pc' = Head(stack).pc + /\ currentToken' = Head(stack).currentToken + /\ left' = Head(stack).left + /\ rt' = Head(stack).rt + /\ notDone' = Head(stack).notDone + /\ foundBangToken' = Head(stack).foundBangToken + /\ temp1' = Head(stack).temp1 + /\ temp2' = Head(stack).temp2 + /\ temp3' = Head(stack).temp3 + /\ stack' = Tail(stack) + ELSE /\ pc' = "Lbl_43" + /\ UNCHANGED << foundTokenSpecs, returnVal, stack, + currentToken, left, rt, notDone, + foundBangToken, temp1, temp2, temp3 >> + /\ UNCHANGED << line, lastToken, notLastToken, curPos, tempVar1, + tempVar2, tempVar3, pos_, tokArray, i, tokIdx, pos_f, + token, left_, rt_, pos_fi, pos_fin, delim_, ipos_, + jdelim_, delimLen_, pos_find, pos, delim, ipos, + jdelim, delimLen, leftTok, rightTok >> + +Lbl_43 == /\ pc = "Lbl_43" + /\ IF line[currentToken.rightPos] = ">" + THEN /\ /\ pos_f' = currentToken.rightPos+1 + /\ stack' = << [ procedure |-> "findMaximalIdCharSeq", + pc |-> "Lbl_44", + token |-> token, + left_ |-> left_, + rt_ |-> rt_, + pos_f |-> pos_f ] >> + \o stack + /\ token' = << >> + /\ left_' = pos_f' + /\ rt_' = pos_f' + /\ pc' = "Lbl_5" + ELSE /\ pc' = "Lbl_46" + /\ UNCHANGED << stack, pos_f, token, left_, rt_ >> + /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, + curPos, returnVal, tempVar1, tempVar2, tempVar3, + pos_, tokArray, i, tokIdx, pos_fi, pos_fin, delim_, + ipos_, jdelim_, delimLen_, pos_find, pos, delim, + ipos, jdelim, delimLen, leftTok, rightTok, + currentToken, left, rt, notDone, foundBangToken, + temp1, temp2, temp3 >> + +Lbl_44 == /\ pc = "Lbl_44" + /\ /\ leftTok' = currentToken + /\ rightTok' = returnVal + /\ stack' = << [ procedure |-> "checkIfStepName", + pc |-> "Lbl_45", + leftTok |-> leftTok, + rightTok |-> rightTok ] >> + \o stack + /\ pc' = "Lbl_27" + /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, + curPos, returnVal, tempVar1, tempVar2, tempVar3, + pos_, tokArray, i, tokIdx, pos_f, token, left_, rt_, + pos_fi, pos_fin, delim_, ipos_, jdelim_, delimLen_, + pos_find, pos, delim, ipos, jdelim, delimLen, + currentToken, left, rt, notDone, foundBangToken, + temp1, temp2, temp3 >> + +Lbl_45 == /\ pc = "Lbl_45" + /\ IF returnVal # NullTokenSpec + THEN /\ foundTokenSpecs' = JavaSeq(<<returnVal>>) + /\ returnVal' = FixOrigin(foundTokenSpecs') + /\ pc' = Head(stack).pc + /\ currentToken' = Head(stack).currentToken + /\ left' = Head(stack).left + /\ rt' = Head(stack).rt + /\ notDone' = Head(stack).notDone + /\ foundBangToken' = Head(stack).foundBangToken + /\ temp1' = Head(stack).temp1 + /\ temp2' = Head(stack).temp2 + /\ temp3' = Head(stack).temp3 + /\ stack' = Tail(stack) + ELSE /\ pc' = "Lbl_46" + /\ UNCHANGED << foundTokenSpecs, returnVal, stack, + currentToken, left, rt, notDone, + foundBangToken, temp1, temp2, temp3 >> + /\ UNCHANGED << line, lastToken, notLastToken, curPos, tempVar1, + tempVar2, tempVar3, pos_, tokArray, i, tokIdx, pos_f, + token, left_, rt_, pos_fi, pos_fin, delim_, ipos_, + jdelim_, delimLen_, pos_find, pos, delim, ipos, + jdelim, delimLen, leftTok, rightTok >> + +Lbl_46 == /\ pc = "Lbl_46" + /\ IF IsNumber(currentToken.token) + THEN /\ returnVal' = << >> + /\ pc' = Head(stack).pc + /\ currentToken' = Head(stack).currentToken + /\ left' = Head(stack).left + /\ rt' = Head(stack).rt + /\ notDone' = Head(stack).notDone + /\ foundBangToken' = Head(stack).foundBangToken + /\ temp1' = Head(stack).temp1 + /\ temp2' = Head(stack).temp2 + /\ temp3' = Head(stack).temp3 + /\ stack' = Tail(stack) + ELSE /\ pc' = "Lbl_47" + /\ UNCHANGED << returnVal, stack, currentToken, left, rt, + notDone, foundBangToken, temp1, temp2, + temp3 >> + /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, + curPos, tempVar1, tempVar2, tempVar3, pos_, tokArray, + i, tokIdx, pos_f, token, left_, rt_, pos_fi, pos_fin, + delim_, ipos_, jdelim_, delimLen_, pos_find, pos, + delim, ipos, jdelim, delimLen, leftTok, rightTok >> + +Lbl_47 == /\ pc = "Lbl_47" + /\ left' = currentToken.leftPos + /\ rt' = currentToken.rightPos + /\ IF /\ line[left'-1] = "\\" + /\ line[left'-2] # "\\" + /\ \E ii \in DOMAIN TeXSymbols : + JavaSubseq(line, left'-1, rt') = TeXSymbols[ii] + THEN /\ lastToken' = TRUE + /\ currentToken' = [currentToken EXCEPT !.leftPos = left' - 1, + !.token = JavaSubseq(line, left'-1, rt')] + ELSE /\ TRUE + /\ UNCHANGED << lastToken, currentToken >> + /\ foundTokenSpecs' = JavaSeq( << currentToken' >>) + /\ curPos' = left' + /\ pc' = "Lbl_62" + /\ UNCHANGED << line, notLastToken, returnVal, tempVar1, tempVar2, + tempVar3, stack, pos_, tokArray, i, tokIdx, pos_f, + token, left_, rt_, pos_fi, pos_fin, delim_, ipos_, + jdelim_, delimLen_, pos_find, pos, delim, ipos, + jdelim, delimLen, leftTok, rightTok, notDone, + foundBangToken, temp1, temp2, temp3 >> + +Lbl_48 == /\ pc = "Lbl_48" + /\ currentToken' = returnVal + /\ IF currentToken' = NullTokenSpec + THEN /\ returnVal' = << >> + /\ pc' = "Lbl_49" + ELSE /\ pc' = "Lbl_50" + /\ UNCHANGED returnVal + /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, + curPos, tempVar1, tempVar2, tempVar3, stack, pos_, + tokArray, i, tokIdx, pos_f, token, left_, rt_, + pos_fi, pos_fin, delim_, ipos_, jdelim_, delimLen_, + pos_find, pos, delim, ipos, jdelim, delimLen, + leftTok, rightTok, left, rt, notDone, foundBangToken, + temp1, temp2, temp3 >> + +Lbl_49 == /\ pc = "Lbl_49" + /\ pc' = Head(stack).pc + /\ currentToken' = Head(stack).currentToken + /\ left' = Head(stack).left + /\ rt' = Head(stack).rt + /\ notDone' = Head(stack).notDone + /\ foundBangToken' = Head(stack).foundBangToken + /\ temp1' = Head(stack).temp1 + /\ temp2' = Head(stack).temp2 + /\ temp3' = Head(stack).temp3 + /\ stack' = Tail(stack) + /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, + curPos, returnVal, tempVar1, tempVar2, tempVar3, + pos_, tokArray, i, tokIdx, pos_f, token, left_, rt_, + pos_fi, pos_fin, delim_, ipos_, jdelim_, delimLen_, + pos_find, pos, delim, ipos, jdelim, delimLen, + leftTok, rightTok >> + +Lbl_50 == /\ pc = "Lbl_50" + /\ /\ pos_' = curPos + /\ stack' = << [ procedure |-> "findTokenIn", + pc |-> "Lbl_51", + i |-> i, + tokIdx |-> tokIdx, + pos_ |-> pos_, + tokArray |-> tokArray ] >> + \o stack + /\ tokArray' = NonOperators + /\ i' = defaultInitValue + /\ tokIdx' = defaultInitValue + /\ pc' = "Lbl_1" + /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, + curPos, returnVal, tempVar1, tempVar2, tempVar3, + pos_f, token, left_, rt_, pos_fi, pos_fin, delim_, + ipos_, jdelim_, delimLen_, pos_find, pos, delim, + ipos, jdelim, delimLen, leftTok, rightTok, + currentToken, left, rt, notDone, foundBangToken, + temp1, temp2, temp3 >> + +Lbl_51 == /\ pc = "Lbl_51" + /\ IF returnVal # NullTokenSpec + THEN /\ returnVal' = << >> + /\ pc' = Head(stack).pc + /\ currentToken' = Head(stack).currentToken + /\ left' = Head(stack).left + /\ rt' = Head(stack).rt + /\ notDone' = Head(stack).notDone + /\ foundBangToken' = Head(stack).foundBangToken + /\ temp1' = Head(stack).temp1 + /\ temp2' = Head(stack).temp2 + /\ temp3' = Head(stack).temp3 + /\ stack' = Tail(stack) + ELSE /\ pc' = "Lbl_52" + /\ UNCHANGED << returnVal, stack, currentToken, left, rt, + notDone, foundBangToken, temp1, temp2, + temp3 >> + /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, + curPos, tempVar1, tempVar2, tempVar3, pos_, tokArray, + i, tokIdx, pos_f, token, left_, rt_, pos_fi, pos_fin, + delim_, ipos_, jdelim_, delimLen_, pos_find, pos, + delim, ipos, jdelim, delimLen, leftTok, rightTok >> + +Lbl_52 == /\ pc = "Lbl_52" + /\ IF currentToken.token = JavaSeq(<< "<" >>) + THEN /\ /\ pos_f' = currentToken.rightPos + /\ stack' = << [ procedure |-> "findMaximalIdCharSeq", + pc |-> "Lbl_53", + token |-> token, + left_ |-> left_, + rt_ |-> rt_, + pos_f |-> pos_f ] >> + \o stack + /\ token' = << >> + /\ left_' = pos_f' + /\ rt_' = pos_f' + /\ pc' = "Lbl_5" + ELSE /\ IF currentToken.token = JavaSeq(<< ">" >>) + THEN /\ /\ pos_f' = currentToken.leftPos + /\ stack' = << [ procedure |-> "findMaximalIdCharSeq", + pc |-> "Lbl_56", + token |-> token, + left_ |-> left_, + rt_ |-> rt_, + pos_f |-> pos_f ] >> + \o stack + /\ token' = << >> + /\ left_' = pos_f' + /\ rt_' = pos_f' + /\ pc' = "Lbl_5" + ELSE /\ pc' = "Lbl_59" + /\ UNCHANGED << stack, pos_f, token, left_, + rt_ >> + /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, + curPos, returnVal, tempVar1, tempVar2, tempVar3, + pos_, tokArray, i, tokIdx, pos_fi, pos_fin, delim_, + ipos_, jdelim_, delimLen_, pos_find, pos, delim, + ipos, jdelim, delimLen, leftTok, rightTok, + currentToken, left, rt, notDone, foundBangToken, + temp1, temp2, temp3 >> + +Lbl_53 == /\ pc = "Lbl_53" + /\ temp1' = returnVal + /\ IF /\ temp1' # NullTokenSpec + /\ line[temp1'.rightPos] = ">" + THEN /\ /\ pos_f' = temp1'.rightPos + 1 + /\ stack' = << [ procedure |-> "findMaximalIdCharSeq", + pc |-> "Lbl_54", + token |-> token, + left_ |-> left_, + rt_ |-> rt_, + pos_f |-> pos_f ] >> + \o stack + /\ token' = << >> + /\ left_' = pos_f' + /\ rt_' = pos_f' + /\ pc' = "Lbl_5" + ELSE /\ pc' = "Lbl_59" + /\ UNCHANGED << stack, pos_f, token, left_, rt_ >> + /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, + curPos, returnVal, tempVar1, tempVar2, tempVar3, + pos_, tokArray, i, tokIdx, pos_fi, pos_fin, delim_, + ipos_, jdelim_, delimLen_, pos_find, pos, delim, + ipos, jdelim, delimLen, leftTok, rightTok, + currentToken, left, rt, notDone, foundBangToken, + temp2, temp3 >> + +Lbl_54 == /\ pc = "Lbl_54" + /\ temp2' = returnVal + /\ /\ leftTok' = temp1 + /\ rightTok' = temp2' + /\ stack' = << [ procedure |-> "checkIfStepName", + pc |-> "Lbl_55", + leftTok |-> leftTok, + rightTok |-> rightTok ] >> + \o stack + /\ pc' = "Lbl_27" + /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, + curPos, returnVal, tempVar1, tempVar2, tempVar3, + pos_, tokArray, i, tokIdx, pos_f, token, left_, rt_, + pos_fi, pos_fin, delim_, ipos_, jdelim_, delimLen_, + pos_find, pos, delim, ipos, jdelim, delimLen, + currentToken, left, rt, notDone, foundBangToken, + temp1, temp3 >> + +Lbl_55 == /\ pc = "Lbl_55" + /\ IF returnVal # NullTokenSpec + THEN /\ foundTokenSpecs' = JavaSeq(<<returnVal>>) + /\ returnVal' = FixOrigin(foundTokenSpecs') + /\ pc' = Head(stack).pc + /\ currentToken' = Head(stack).currentToken + /\ left' = Head(stack).left + /\ rt' = Head(stack).rt + /\ notDone' = Head(stack).notDone + /\ foundBangToken' = Head(stack).foundBangToken + /\ temp1' = Head(stack).temp1 + /\ temp2' = Head(stack).temp2 + /\ temp3' = Head(stack).temp3 + /\ stack' = Tail(stack) + ELSE /\ pc' = "Lbl_59" + /\ UNCHANGED << foundTokenSpecs, returnVal, stack, + currentToken, left, rt, notDone, + foundBangToken, temp1, temp2, temp3 >> + /\ UNCHANGED << line, lastToken, notLastToken, curPos, tempVar1, + tempVar2, tempVar3, pos_, tokArray, i, tokIdx, pos_f, + token, left_, rt_, pos_fi, pos_fin, delim_, ipos_, + jdelim_, delimLen_, pos_find, pos, delim, ipos, + jdelim, delimLen, leftTok, rightTok >> + +Lbl_56 == /\ pc = "Lbl_56" + /\ temp1' = returnVal + /\ /\ pos_f' = currentToken.rightPos + /\ stack' = << [ procedure |-> "findMaximalIdCharSeq", + pc |-> "Lbl_57", + token |-> token, + left_ |-> left_, + rt_ |-> rt_, + pos_f |-> pos_f ] >> + \o stack + /\ token' = << >> + /\ left_' = pos_f' + /\ rt_' = pos_f' + /\ pc' = "Lbl_5" + /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, + curPos, returnVal, tempVar1, tempVar2, tempVar3, + pos_, tokArray, i, tokIdx, pos_fi, pos_fin, delim_, + ipos_, jdelim_, delimLen_, pos_find, pos, delim, + ipos, jdelim, delimLen, leftTok, rightTok, + currentToken, left, rt, notDone, foundBangToken, + temp2, temp3 >> + +Lbl_57 == /\ pc = "Lbl_57" + /\ temp2' = returnVal + /\ /\ leftTok' = temp1 + /\ rightTok' = temp2' + /\ stack' = << [ procedure |-> "checkIfStepName", + pc |-> "Lbl_58", + leftTok |-> leftTok, + rightTok |-> rightTok ] >> + \o stack + /\ pc' = "Lbl_27" + /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, + curPos, returnVal, tempVar1, tempVar2, tempVar3, + pos_, tokArray, i, tokIdx, pos_f, token, left_, rt_, + pos_fi, pos_fin, delim_, ipos_, jdelim_, delimLen_, + pos_find, pos, delim, ipos, jdelim, delimLen, + currentToken, left, rt, notDone, foundBangToken, + temp1, temp3 >> + +Lbl_58 == /\ pc = "Lbl_58" + /\ IF returnVal # NullTokenSpec + THEN /\ foundTokenSpecs' = JavaSeq(<<returnVal>>) + /\ returnVal' = FixOrigin(foundTokenSpecs') + /\ pc' = Head(stack).pc + /\ currentToken' = Head(stack).currentToken + /\ left' = Head(stack).left + /\ rt' = Head(stack).rt + /\ notDone' = Head(stack).notDone + /\ foundBangToken' = Head(stack).foundBangToken + /\ temp1' = Head(stack).temp1 + /\ temp2' = Head(stack).temp2 + /\ temp3' = Head(stack).temp3 + /\ stack' = Tail(stack) + ELSE /\ pc' = "Lbl_59" + /\ UNCHANGED << foundTokenSpecs, returnVal, stack, + currentToken, left, rt, notDone, + foundBangToken, temp1, temp2, temp3 >> + /\ UNCHANGED << line, lastToken, notLastToken, curPos, tempVar1, + tempVar2, tempVar3, pos_, tokArray, i, tokIdx, pos_f, + token, left_, rt_, pos_fi, pos_fin, delim_, ipos_, + jdelim_, delimLen_, pos_find, pos, delim, ipos, + jdelim, delimLen, leftTok, rightTok >> + +Lbl_59 == /\ pc = "Lbl_59" + /\ IF currentToken.token = JavaSeq(<<"\\">>) + THEN /\ /\ pos_f' = currentToken.rightPos + /\ stack' = << [ procedure |-> "findMaximalIdCharSeq", + pc |-> "Lbl_60", + token |-> token, + left_ |-> left_, + rt_ |-> rt_, + pos_f |-> pos_f ] >> + \o stack + /\ token' = << >> + /\ left_' = pos_f' + /\ rt_' = pos_f' + /\ pc' = "Lbl_5" + ELSE /\ pc' = "Lbl_61" + /\ UNCHANGED << stack, pos_f, token, left_, rt_ >> + /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, + curPos, returnVal, tempVar1, tempVar2, tempVar3, + pos_, tokArray, i, tokIdx, pos_fi, pos_fin, delim_, + ipos_, jdelim_, delimLen_, pos_find, pos, delim, + ipos, jdelim, delimLen, leftTok, rightTok, + currentToken, left, rt, notDone, foundBangToken, + temp1, temp2, temp3 >> + +Lbl_60 == /\ pc = "Lbl_60" + /\ IF /\ returnVal # NullTokenSpec + /\ \E ii \in DOMAIN TeXSymbols : + JavaSubseq(line, + currentToken.leftPos, + returnVal.rightPos) = TeXSymbols[ii] + THEN /\ currentToken' = [currentToken EXCEPT !.rightPos = returnVal.rightPos, + !.token = JavaSubseq(line, + currentToken.leftPos, + returnVal.rightPos)] + ELSE /\ TRUE + /\ UNCHANGED currentToken + /\ pc' = "Lbl_61" + /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, + curPos, returnVal, tempVar1, tempVar2, tempVar3, + stack, pos_, tokArray, i, tokIdx, pos_f, token, + left_, rt_, pos_fi, pos_fin, delim_, ipos_, jdelim_, + delimLen_, pos_find, pos, delim, ipos, jdelim, + delimLen, leftTok, rightTok, left, rt, notDone, + foundBangToken, temp1, temp2, temp3 >> + +Lbl_61 == /\ pc = "Lbl_61" + /\ foundTokenSpecs' = JavaSeq(<<currentToken>>) + /\ curPos' = currentToken.leftPos + /\ lastToken' = TRUE + /\ pc' = "Lbl_62" + /\ UNCHANGED << line, notLastToken, returnVal, tempVar1, tempVar2, + tempVar3, stack, pos_, tokArray, i, tokIdx, pos_f, + token, left_, rt_, pos_fi, pos_fin, delim_, ipos_, + jdelim_, delimLen_, pos_find, pos, delim, ipos, + jdelim, delimLen, leftTok, rightTok, currentToken, + left, rt, notDone, foundBangToken, temp1, temp2, + temp3 >> + +Lbl_62 == /\ pc = "Lbl_62" + /\ Assert(JavaLen(foundTokenSpecs) = 1, + "Failure of assertion at line 619, column 3.") + /\ curPos' = foundTokenSpecs[0].leftPos + /\ notDone' = TRUE + /\ pc' = "Lbl_63" + /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, + returnVal, tempVar1, tempVar2, tempVar3, stack, pos_, + tokArray, i, tokIdx, pos_f, token, left_, rt_, + pos_fi, pos_fin, delim_, ipos_, jdelim_, delimLen_, + pos_find, pos, delim, ipos, jdelim, delimLen, + leftTok, rightTok, currentToken, left, rt, + foundBangToken, temp1, temp2, temp3 >> + +Lbl_63 == /\ pc = "Lbl_63" + /\ IF notDone + THEN /\ stack' = << [ procedure |-> "skipLeftOverSpaces", + pc |-> "Lbl_64" ] >> + \o stack + /\ pc' = "Lbl_29" + /\ UNCHANGED << returnVal, currentToken, left, rt, + notDone, foundBangToken, temp1, temp2, + temp3 >> + ELSE /\ Assert(foundTokenSpecs # << >>, + "Failure of assertion at line 661, column 3.") + /\ IF lastToken = TRUE + THEN /\ returnVal' = FixOrigin(foundTokenSpecs) + /\ pc' = Head(stack).pc + /\ currentToken' = Head(stack).currentToken + /\ left' = Head(stack).left + /\ rt' = Head(stack).rt + /\ notDone' = Head(stack).notDone + /\ foundBangToken' = Head(stack).foundBangToken + /\ temp1' = Head(stack).temp1 + /\ temp2' = Head(stack).temp2 + /\ temp3' = Head(stack).temp3 + /\ stack' = Tail(stack) + ELSE /\ pc' = "Lbl_69" + /\ UNCHANGED << returnVal, stack, currentToken, + left, rt, notDone, + foundBangToken, temp1, temp2, + temp3 >> + /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, + curPos, tempVar1, tempVar2, tempVar3, pos_, tokArray, + i, tokIdx, pos_f, token, left_, rt_, pos_fi, pos_fin, + delim_, ipos_, jdelim_, delimLen_, pos_find, pos, + delim, ipos, jdelim, delimLen, leftTok, rightTok >> + +Lbl_64 == /\ pc = "Lbl_64" + /\ IF curPos < 0 \/ line[curPos-1] = ";" + THEN /\ notDone' = FALSE + /\ pc' = "Lbl_63" + /\ UNCHANGED << curPos, stack >> + ELSE /\ IF line[curPos-1] = "!" /\ (line[curPos-2] # "!") + THEN /\ curPos' = curPos - 1 + /\ stack' = << [ procedure |-> "skipLeftOverSpaces", + pc |-> "Lbl_65" ] >> + \o stack + /\ pc' = "Lbl_29" + /\ UNCHANGED notDone + ELSE /\ notDone' = FALSE + /\ pc' = "Lbl_63" + /\ UNCHANGED << curPos, stack >> + /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, + returnVal, tempVar1, tempVar2, tempVar3, pos_, + tokArray, i, tokIdx, pos_f, token, left_, rt_, + pos_fi, pos_fin, delim_, ipos_, jdelim_, delimLen_, + pos_find, pos, delim, ipos, jdelim, delimLen, + leftTok, rightTok, currentToken, left, rt, + foundBangToken, temp1, temp2, temp3 >> + +Lbl_65 == /\ pc = "Lbl_65" + /\ /\ pos_fi' = curPos + /\ stack' = << [ procedure |-> "findMatchingLeftParen", + pc |-> "Lbl_66", + pos_fi |-> pos_fi ] >> + \o stack + /\ pc' = "Lbl_7" + /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, + curPos, returnVal, tempVar1, tempVar2, tempVar3, + pos_, tokArray, i, tokIdx, pos_f, token, left_, rt_, + pos_fin, delim_, ipos_, jdelim_, delimLen_, pos_find, + pos, delim, ipos, jdelim, delimLen, leftTok, + rightTok, currentToken, left, rt, notDone, + foundBangToken, temp1, temp2, temp3 >> + +Lbl_66 == /\ pc = "Lbl_66" + /\ curPos' = returnVal + /\ IF curPos' < 0 + THEN /\ notDone' = FALSE + /\ pc' = "Lbl_63" + /\ stack' = stack + ELSE /\ stack' = << [ procedure |-> "skipLeftOverSpaces", + pc |-> "Lbl_67" ] >> + \o stack + /\ pc' = "Lbl_29" + /\ UNCHANGED notDone + /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, + returnVal, tempVar1, tempVar2, tempVar3, pos_, + tokArray, i, tokIdx, pos_f, token, left_, rt_, + pos_fi, pos_fin, delim_, ipos_, jdelim_, delimLen_, + pos_find, pos, delim, ipos, jdelim, delimLen, + leftTok, rightTok, currentToken, left, rt, + foundBangToken, temp1, temp2, temp3 >> + +Lbl_67 == /\ pc = "Lbl_67" + /\ /\ pos_f' = curPos + /\ stack' = << [ procedure |-> "findMaximalIdCharSeq", + pc |-> "Lbl_68", + token |-> token, + left_ |-> left_, + rt_ |-> rt_, + pos_f |-> pos_f ] >> + \o stack + /\ token' = << >> + /\ left_' = pos_f' + /\ rt_' = pos_f' + /\ pc' = "Lbl_5" + /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, + curPos, returnVal, tempVar1, tempVar2, tempVar3, + pos_, tokArray, i, tokIdx, pos_fi, pos_fin, delim_, + ipos_, jdelim_, delimLen_, pos_find, pos, delim, + ipos, jdelim, delimLen, leftTok, rightTok, + currentToken, left, rt, notDone, foundBangToken, + temp1, temp2, temp3 >> + +Lbl_68 == /\ pc = "Lbl_68" + /\ currentToken' = returnVal + /\ IF \/ currentToken' = NullTokenSpec + \/ IsNumber(currentToken'.token) + THEN /\ notDone' = FALSE + /\ UNCHANGED << foundTokenSpecs, curPos >> + ELSE /\ curPos' = currentToken'.leftPos + /\ foundTokenSpecs' = [foundTokenSpecs EXCEPT ![0] = [token |-> JavaConcatenate( + JavaAppend(currentToken'.token, "!"), + foundTokenSpecs[0].token), + leftPos |-> curPos', + rightPos |-> foundTokenSpecs[0].rightPos]] + /\ UNCHANGED notDone + /\ pc' = "Lbl_63" + /\ UNCHANGED << line, lastToken, notLastToken, returnVal, tempVar1, + tempVar2, tempVar3, stack, pos_, tokArray, i, tokIdx, + pos_f, token, left_, rt_, pos_fi, pos_fin, delim_, + ipos_, jdelim_, delimLen_, pos_find, pos, delim, + ipos, jdelim, delimLen, leftTok, rightTok, left, rt, + foundBangToken, temp1, temp2, temp3 >> + +Lbl_69 == /\ pc = "Lbl_69" + /\ curPos' = foundTokenSpecs[0].rightPos + /\ foundBangToken' = FALSE + /\ notDone' = TRUE + /\ pc' = "Lbl_70" + /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, + returnVal, tempVar1, tempVar2, tempVar3, stack, pos_, + tokArray, i, tokIdx, pos_f, token, left_, rt_, + pos_fi, pos_fin, delim_, ipos_, jdelim_, delimLen_, + pos_find, pos, delim, ipos, jdelim, delimLen, + leftTok, rightTok, currentToken, left, rt, temp1, + temp2, temp3 >> + +Lbl_70 == /\ pc = "Lbl_70" + /\ IF notDone + THEN /\ stack' = << [ procedure |-> "skipRightOverSpaces", + pc |-> "Lbl_71" ] >> + \o stack + /\ pc' = "Lbl_30" + /\ UNCHANGED << returnVal, currentToken, left, rt, + notDone, foundBangToken, temp1, temp2, + temp3 >> + ELSE /\ IF notLastToken /\ ~ foundBangToken + THEN /\ returnVal' = << >> + /\ pc' = Head(stack).pc + /\ currentToken' = Head(stack).currentToken + /\ left' = Head(stack).left + /\ rt' = Head(stack).rt + /\ notDone' = Head(stack).notDone + /\ foundBangToken' = Head(stack).foundBangToken + /\ temp1' = Head(stack).temp1 + /\ temp2' = Head(stack).temp2 + /\ temp3' = Head(stack).temp3 + /\ stack' = Tail(stack) + ELSE /\ pc' = "Lbl_76" + /\ UNCHANGED << returnVal, stack, currentToken, + left, rt, notDone, + foundBangToken, temp1, temp2, + temp3 >> + /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, + curPos, tempVar1, tempVar2, tempVar3, pos_, tokArray, + i, tokIdx, pos_f, token, left_, rt_, pos_fi, pos_fin, + delim_, ipos_, jdelim_, delimLen_, pos_find, pos, + delim, ipos, jdelim, delimLen, leftTok, rightTok >> + +Lbl_71 == /\ pc = "Lbl_71" + /\ /\ pos_find' = curPos + /\ stack' = << [ procedure |-> "findMatchingRightParen", + pc |-> "Lbl_72", + pos_find |-> pos_find ] >> + \o stack + /\ pc' = "Lbl_17" + /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, + curPos, returnVal, tempVar1, tempVar2, tempVar3, + pos_, tokArray, i, tokIdx, pos_f, token, left_, rt_, + pos_fi, pos_fin, delim_, ipos_, jdelim_, delimLen_, + pos, delim, ipos, jdelim, delimLen, leftTok, + rightTok, currentToken, left, rt, notDone, + foundBangToken, temp1, temp2, temp3 >> + +Lbl_72 == /\ pc = "Lbl_72" + /\ curPos' = returnVal + /\ IF curPos' < 0 + THEN /\ notDone' = FALSE + /\ pc' = "Lbl_70" + /\ stack' = stack + ELSE /\ stack' = << [ procedure |-> "skipRightOverSpaces", + pc |-> "Lbl_73" ] >> + \o stack + /\ pc' = "Lbl_30" + /\ UNCHANGED notDone + /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, + returnVal, tempVar1, tempVar2, tempVar3, pos_, + tokArray, i, tokIdx, pos_f, token, left_, rt_, + pos_fi, pos_fin, delim_, ipos_, jdelim_, delimLen_, + pos_find, pos, delim, ipos, jdelim, delimLen, + leftTok, rightTok, currentToken, left, rt, + foundBangToken, temp1, temp2, temp3 >> + +Lbl_73 == /\ pc = "Lbl_73" + /\ IF line[curPos] # "!" \/ line[curPos+1] = "!" + THEN /\ notDone' = FALSE + /\ pc' = "Lbl_70" + /\ UNCHANGED << curPos, stack >> + ELSE /\ curPos' = curPos + 1 + /\ stack' = << [ procedure |-> "skipRightOverSpaces", + pc |-> "Lbl_74" ] >> + \o stack + /\ pc' = "Lbl_30" + /\ UNCHANGED notDone + /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, + returnVal, tempVar1, tempVar2, tempVar3, pos_, + tokArray, i, tokIdx, pos_f, token, left_, rt_, + pos_fi, pos_fin, delim_, ipos_, jdelim_, delimLen_, + pos_find, pos, delim, ipos, jdelim, delimLen, + leftTok, rightTok, currentToken, left, rt, + foundBangToken, temp1, temp2, temp3 >> + +Lbl_74 == /\ pc = "Lbl_74" + /\ /\ pos_f' = curPos + /\ stack' = << [ procedure |-> "findMaximalIdCharSeq", + pc |-> "Lbl_75", + token |-> token, + left_ |-> left_, + rt_ |-> rt_, + pos_f |-> pos_f ] >> + \o stack + /\ token' = << >> + /\ left_' = pos_f' + /\ rt_' = pos_f' + /\ pc' = "Lbl_5" + /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, + curPos, returnVal, tempVar1, tempVar2, tempVar3, + pos_, tokArray, i, tokIdx, pos_fi, pos_fin, delim_, + ipos_, jdelim_, delimLen_, pos_find, pos, delim, + ipos, jdelim, delimLen, leftTok, rightTok, + currentToken, left, rt, notDone, foundBangToken, + temp1, temp2, temp3 >> + +Lbl_75 == /\ pc = "Lbl_75" + /\ currentToken' = returnVal + /\ IF \/ currentToken' = NullTokenSpec + \/ IsNumber(currentToken'.token) + THEN /\ notDone' = FALSE + /\ UNCHANGED << foundTokenSpecs, curPos, foundBangToken >> + ELSE /\ foundBangToken' = TRUE + /\ foundTokenSpecs' = JavaConcatenate( + JavaSeq( + << [token |-> + JavaConcatenate(JavaAppend(foundTokenSpecs[0].token, + "!"), + currentToken'.token), + leftPos |-> foundTokenSpecs[0].leftPos, + rightPos |-> currentToken'.rightPos] + >> ) , + foundTokenSpecs) + /\ curPos' = currentToken'.rightPos + /\ UNCHANGED notDone + /\ pc' = "Lbl_70" + /\ UNCHANGED << line, lastToken, notLastToken, returnVal, tempVar1, + tempVar2, tempVar3, stack, pos_, tokArray, i, tokIdx, + pos_f, token, left_, rt_, pos_fi, pos_fin, delim_, + ipos_, jdelim_, delimLen_, pos_find, pos, delim, + ipos, jdelim, delimLen, leftTok, rightTok, left, rt, + temp1, temp2, temp3 >> + +Lbl_76 == /\ pc = "Lbl_76" + /\ returnVal' = FixOrigin(foundTokenSpecs) + /\ pc' = Head(stack).pc + /\ currentToken' = Head(stack).currentToken + /\ left' = Head(stack).left + /\ rt' = Head(stack).rt + /\ notDone' = Head(stack).notDone + /\ foundBangToken' = Head(stack).foundBangToken + /\ temp1' = Head(stack).temp1 + /\ temp2' = Head(stack).temp2 + /\ temp3' = Head(stack).temp3 + /\ stack' = Tail(stack) + /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, + curPos, tempVar1, tempVar2, tempVar3, pos_, tokArray, + i, tokIdx, pos_f, token, left_, rt_, pos_fi, pos_fin, + delim_, ipos_, jdelim_, delimLen_, pos_find, pos, + delim, ipos, jdelim, delimLen, leftTok, rightTok >> + +findTokenSpecs == Lbl_31 \/ Lbl_32 \/ Lbl_33 \/ Lbl_34 \/ Lbl_35 \/ Lbl_36 + \/ Lbl_37 \/ Lbl_38 \/ Lbl_39 \/ Lbl_40 \/ Lbl_41 \/ Lbl_42 + \/ Lbl_43 \/ Lbl_44 \/ Lbl_45 \/ Lbl_46 \/ Lbl_47 \/ Lbl_48 + \/ Lbl_49 \/ Lbl_50 \/ Lbl_51 \/ Lbl_52 \/ Lbl_53 \/ Lbl_54 + \/ Lbl_55 \/ Lbl_56 \/ Lbl_57 \/ Lbl_58 \/ Lbl_59 \/ Lbl_60 + \/ Lbl_61 \/ Lbl_62 \/ Lbl_63 \/ Lbl_64 \/ Lbl_65 \/ Lbl_66 + \/ Lbl_67 \/ Lbl_68 \/ Lbl_69 \/ Lbl_70 \/ Lbl_71 \/ Lbl_72 + \/ Lbl_73 \/ Lbl_74 \/ Lbl_75 \/ Lbl_76 + +Lbl_77 == /\ pc = "Lbl_77" + /\ curPos' = JavaLen(Padding) + /\ tempVar1' = (-1 :> "") + /\ tempVar2' = JavaLen(Padding) + /\ pc' = "Lbl_78" + /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, + returnVal, tempVar3, stack, pos_, tokArray, i, + tokIdx, pos_f, token, left_, rt_, pos_fi, pos_fin, + delim_, ipos_, jdelim_, delimLen_, pos_find, pos, + delim, ipos, jdelim, delimLen, leftTok, rightTok, + currentToken, left, rt, notDone, foundBangToken, + temp1, temp2, temp3 >> + +Lbl_78 == /\ pc = "Lbl_78" + /\ IF tempVar2 < JavaLen(lineInput) + JavaLen(Padding) + THEN /\ curPos' = tempVar2 + /\ foundTokenSpecs' = << >> + /\ lastToken' = FALSE + /\ notLastToken' = FALSE + /\ stack' = << [ procedure |-> "findTokenSpecs", + pc |-> "Lbl_79", + currentToken |-> currentToken, + left |-> left, + rt |-> rt, + notDone |-> notDone, + foundBangToken |-> foundBangToken, + temp1 |-> temp1, + temp2 |-> temp2, + temp3 |-> temp3 ] >> + \o stack + /\ currentToken' = defaultInitValue + /\ left' = defaultInitValue + /\ rt' = defaultInitValue + /\ notDone' = defaultInitValue + /\ foundBangToken' = defaultInitValue + /\ temp1' = defaultInitValue + /\ temp2' = defaultInitValue + /\ temp3' = defaultInitValue + /\ pc' = "Lbl_31" + ELSE /\ PrintT("goodby world") + /\ pc' = "Done" + /\ UNCHANGED << foundTokenSpecs, lastToken, notLastToken, + curPos, stack, currentToken, left, rt, + notDone, foundBangToken, temp1, temp2, + temp3 >> + /\ UNCHANGED << line, returnVal, tempVar1, tempVar2, tempVar3, pos_, + tokArray, i, tokIdx, pos_f, token, left_, rt_, + pos_fi, pos_fin, delim_, ipos_, jdelim_, delimLen_, + pos_find, pos, delim, ipos, jdelim, delimLen, + leftTok, rightTok >> + +Lbl_79 == /\ pc = "Lbl_79" + /\ tempVar1' = returnVal + /\ tempVar2' = tempVar2 + 1 + /\ pc' = "Lbl_78" + /\ UNCHANGED << line, foundTokenSpecs, lastToken, notLastToken, + curPos, returnVal, tempVar3, stack, pos_, tokArray, + i, tokIdx, pos_f, token, left_, rt_, pos_fi, pos_fin, + delim_, ipos_, jdelim_, delimLen_, pos_find, pos, + delim, ipos, jdelim, delimLen, leftTok, rightTok, + currentToken, left, rt, notDone, foundBangToken, + temp1, temp2, temp3 >> + +Next == findTokenIn \/ findMaximalIdCharSeq \/ findMatchingLeftParen + \/ findMatchingLeftInner \/ findMatchingRightParen + \/ findMatchingRightInner \/ checkIfStepName \/ skipLeftOverSpaces + \/ skipRightOverSpaces \/ findTokenSpecs \/ Lbl_77 \/ Lbl_78 \/ Lbl_79 + \/ (* Disjunct to prevent deadlock on termination *) + (pc = "Done" /\ UNCHANGED vars) + +Spec == Init /\ [][Next]_vars + +Termination == <>(pc = "Done") + +\* END TRANSLATION +============================================================================= \* Modification History -\* Last modified Tue Jun 21 11:33:07 CEST 2011 by markus -\* Last modified Tue Jun 21 02:08:39 PDT 2011 by lamport -\* Created Mon Sep 20 06:42:12 PDT 2010 by lamport - -c: if (lastToken = TRUE) {return FixOrigin(foundTokens);} - while -} \* end algorithm -****************************************************************************) - +\* Last modified Tue Jun 21 11:33:07 CEST 2011 by markus +\* Last modified Tue Jun 21 02:08:39 PDT 2011 by lamport +\* Created Mon Sep 20 06:42:12 PDT 2010 by lamport + +c: if (lastToken = TRUE) {return FixOrigin(foundTokens);} + while +} \* end algorithm +****************************************************************************) + diff --git a/tlatools/test-model/CallGotoUnlabeledTest.tla b/tlatools/test-model/CallGotoUnlabeledTest.tla new file mode 100644 index 0000000000000000000000000000000000000000..23c92f7c48b07b63c3e2bdf3a354982bb9aab125 --- /dev/null +++ b/tlatools/test-model/CallGotoUnlabeledTest.tla @@ -0,0 +1,69 @@ +---- MODULE CallGotoUnlabeledTest ---- + +(* --algorithm CallGotoUnlabeledTest + +variable x = 0; + +procedure Foo() +begin +\*Q: \* Not needed anymore. + x := x + 1; + return; +end procedure; + +begin +A: + call Foo(); + goto C; +\*B: \* Not needed anymore. + x := 13; +C: + x := x - 1; + goto A; + +end algorithm *) +\* BEGIN TRANSLATION +VARIABLES x, pc, stack + +vars == << x, pc, stack >> + +Init == (* Global variables *) + /\ x = 0 + /\ stack = << >> + /\ pc = "A" + +Lbl_1 == /\ pc = "Lbl_1" + /\ x' = x + 1 + /\ pc' = Head(stack).pc + /\ stack' = Tail(stack) + +Foo == Lbl_1 + +A == /\ pc = "A" + /\ stack' = << [ procedure |-> "Foo", + pc |-> "C" ] >> + \o stack + /\ pc' = "Lbl_1" + /\ x' = x + +Lbl_2 == /\ pc = "Lbl_2" + /\ x' = 13 + /\ pc' = "C" + /\ stack' = stack + +C == /\ pc = "C" + /\ x' = x - 1 + /\ pc' = "A" + /\ stack' = stack + +Next == Foo \/ A \/ Lbl_2 \/ C + \/ (* Disjunct to prevent deadlock on termination *) + (pc = "Done" /\ UNCHANGED vars) + +Spec == Init /\ [][Next]_vars + +Termination == <>(pc = "Done") + +\* END TRANSLATION + +==== diff --git a/tlatools/test-model/CodePlexBug08/AgentRingMC.tla b/tlatools/test-model/CodePlexBug08/AgentRingMC.tla index acd6fc07679129f8295e00f3e36e0b31f561a952..04ff75f3250fe770d575baa2dd06bba3aacffa4d 100644 --- a/tlatools/test-model/CodePlexBug08/AgentRingMC.tla +++ b/tlatools/test-model/CodePlexBug08/AgentRingMC.tla @@ -23,5 +23,5 @@ prop_142745588773041000 == Test ---- ============================================================================= -\* Modification History -\* Created Fri Mar 27 12:31:27 CET 2015 by makuppe +\* Modification History +\* Created Fri Mar 27 12:31:27 CET 2015 by makuppe diff --git a/tlatools/test-model/CodePlexBug08/checkpoint.zip b/tlatools/test-model/CodePlexBug08/checkpoint.zip index 6488c8a654a465c77dce134b81c37e8200eeb107..7ec0a6bf7e431bf80d098a17cf312261a8fb3bae 100644 Binary files a/tlatools/test-model/CodePlexBug08/checkpoint.zip and b/tlatools/test-model/CodePlexBug08/checkpoint.zip differ diff --git a/tlatools/test-model/DoInitFunctor/DoInitFunctorInvariantContinue.cfg b/tlatools/test-model/DoInitFunctor/DoInitFunctorInvariantContinue.cfg new file mode 100644 index 0000000000000000000000000000000000000000..6a89e0901c7fa1bcc62bf2ffba508d385d572ca4 --- /dev/null +++ b/tlatools/test-model/DoInitFunctor/DoInitFunctorInvariantContinue.cfg @@ -0,0 +1,4 @@ +SPECIFICATION +Spec +INVARIANT +Inv diff --git a/tlatools/test-model/DoInitFunctor/DoInitFunctorInvariantContinue.tla b/tlatools/test-model/DoInitFunctor/DoInitFunctorInvariantContinue.tla new file mode 100644 index 0000000000000000000000000000000000000000..df785bda8dfb7ca8df064c132e22a5c5826513e5 --- /dev/null +++ b/tlatools/test-model/DoInitFunctor/DoInitFunctorInvariantContinue.tla @@ -0,0 +1,15 @@ +--------------------------- MODULE DoInitFunctorInvariantContinue --------------------------- +EXTENDS Integers + +VARIABLES x +vars == <<x>> + +Init == x \in 1..10 + +Next == x' = 0 + +Spec == Init /\ [][Next]_vars + +(* This property is violated by all of the init states *) +Inv == x \notin Nat +============================================================================= diff --git a/tlatools/test-model/DoInitFunctor/DoInitFunctorMinimalErrorStack.cfg b/tlatools/test-model/DoInitFunctor/DoInitFunctorMinimalErrorStack.cfg new file mode 100644 index 0000000000000000000000000000000000000000..6a89e0901c7fa1bcc62bf2ffba508d385d572ca4 --- /dev/null +++ b/tlatools/test-model/DoInitFunctor/DoInitFunctorMinimalErrorStack.cfg @@ -0,0 +1,4 @@ +SPECIFICATION +Spec +INVARIANT +Inv diff --git a/tlatools/test-model/DoInitFunctor/DoInitFunctorMinimalErrorStack.tla b/tlatools/test-model/DoInitFunctor/DoInitFunctorMinimalErrorStack.tla new file mode 100644 index 0000000000000000000000000000000000000000..f29ac16460c7768c18b783e9386086be4a05250c --- /dev/null +++ b/tlatools/test-model/DoInitFunctor/DoInitFunctorMinimalErrorStack.tla @@ -0,0 +1,15 @@ +------------------ MODULE DoInitFunctorMinimalErrorStack -------------------- +EXTENDS Naturals + +VARIABLES a, b +vars == <<a, b>> + +Init == + /\ a \in [1..2 -> 1..3] + /\ b = TRUE + +Spec == Init /\ [][UNCHANGED vars]_vars + +(* This property is violated by all of the init states *) +Inv == a >= 0 +============================================================================= diff --git a/tlatools/test-model/IncompleteNextMultipleActions.cfg b/tlatools/test-model/IncompleteNextMultipleActions.cfg new file mode 100644 index 0000000000000000000000000000000000000000..bc224b9def594b0819de3f0b45ede63ea8213c7b --- /dev/null +++ b/tlatools/test-model/IncompleteNextMultipleActions.cfg @@ -0,0 +1,2 @@ +SPECIFICATION +Spec diff --git a/tlatools/test-model/IncompleteNextMultipleActions.tla b/tlatools/test-model/IncompleteNextMultipleActions.tla new file mode 100644 index 0000000000000000000000000000000000000000..d39ea6a603226b3bc571f83b2004712c08a49472 --- /dev/null +++ b/tlatools/test-model/IncompleteNextMultipleActions.tla @@ -0,0 +1,11 @@ +--------------------------- MODULE IncompleteNextMultipleActions --------------------------- +EXTENDS Integers, TLC + +VARIABLES x, y, z + +A1 == x'= x + 1 + +A2 == x'= 1 /\ y' = 1 /\ z' = 1 + +Spec == (x=0) /\ (y=0) /\ (z=0) /\ [][A1 \/ A2]_<<x,y,z>> +============================================================================= diff --git a/tlatools/test-model/MinimalSetOfInitStates.cfg b/tlatools/test-model/MinimalSetOfInitStates.cfg new file mode 100644 index 0000000000000000000000000000000000000000..e3e8c3d2505a0163440775d92531a92d4321811c --- /dev/null +++ b/tlatools/test-model/MinimalSetOfInitStates.cfg @@ -0,0 +1,2 @@ +INIT Init +NEXT Next diff --git a/tlatools/test-model/MinimalSetOfInitStates.tla b/tlatools/test-model/MinimalSetOfInitStates.tla new file mode 100644 index 0000000000000000000000000000000000000000..cd0480fa0da8661b7d71c1267dd4311172ab8110 --- /dev/null +++ b/tlatools/test-model/MinimalSetOfInitStates.tla @@ -0,0 +1,62 @@ +--------- MODULE MinimalSetOfInitStates ------------ +VARIABLE x + +\* x = 0 true because _second_ conjunct is true. +\* The allAssigned branch in Tool#getInitStates(ActionItemList, TLCState, IStateFunctor) +\* prevents TLC from generating three states with x = 0. +I1a == /\ x = 0 + /\ \/ 1 = 1 + \/ 2 = 2 + \/ 3 = 3 + +\* x = 1 true because _first_ conjunct is true. +\* The allAssigned branch in Tool#getInitStates(ActionItemList, TLCState, IStateFunctor) +\* _does not_ prevents TLC from generating three states with x = 1. +I1b == /\ \/ 1 = 1 + \/ 2 = 2 + \/ 3 = 3 + /\ x = 1 + +\* x = 2 true because _first_ conjunct is true. +\* The allAssigned branch in Tool#getInitStates(ActionItemList, TLCState, IStateFunctor) +\* _does not_ prevents TLC from generating three states with x = 2. The "~~" trick prevents +\* TLC from generating three states with x = 2 because the default case in Tool line 729 +\* simply evaluates the first conjunct without generating states. +I1c == /\ ~~(\/ 1 = 1 + \/ 2 = 2 + \/ 3 = 3) + /\ x = 2 + +\* Doesn't assign 1 bc pred is false, thus not counted as init. +I2 == /\ x = 3 + /\ \/ 1 = 2 + \/ 2 = 3 + \/ 3 = 1 + +\* Doesn't assign 1 because pred is false, +\* but counted as init because pred comes first. +I3 == /\ \/ 1 = 2 + \/ 2 = 3 + \/ 3 = 1 + /\ x = 4 + +I4 == \/ x = 5 + \/ x = 6 + /\ \/ \/ 1 = 2 + \/ 1 = 1 + \/ 2 = 3 + \/ 3 = 2 + +I5 == /\ x = 7 + +Init == \/ I1a + \/ I1b + \/ I1c + \/ I2 + \/ I3 + \/ I4 + \/ I5 + + +Next == UNCHANGED x +==================================================== diff --git a/tlatools/test-model/MinimalSetOfNextStates.cfg b/tlatools/test-model/MinimalSetOfNextStates.cfg new file mode 100644 index 0000000000000000000000000000000000000000..fd959cf27ec2f77af7c36fb2497c44c0c88b6d0e --- /dev/null +++ b/tlatools/test-model/MinimalSetOfNextStates.cfg @@ -0,0 +1,3 @@ +INIT Init +NEXT Next +INVARIANT Inv diff --git a/tlatools/test-model/MinimalSetOfNextStates.tla b/tlatools/test-model/MinimalSetOfNextStates.tla new file mode 100644 index 0000000000000000000000000000000000000000..d211a935d3b78beab2c57a059fe3a253eed9a9f2 --- /dev/null +++ b/tlatools/test-model/MinimalSetOfNextStates.tla @@ -0,0 +1,61 @@ +--------- MODULE MinimalSetOfNextStates ------------ +VARIABLE x + +Init == x = 42 + + +\* x = 0 true because _second_ conjunct is true. +\* The allAssigned branch in Tool#getInitStates(ActionItemList, TLCState, IStateFunctor) +\* prevents TLC from generating duplicate states with x = 0. +N1a == /\ x' = 0 + /\ \/ 1 = 1 + \/ 2 = 2 + \/ 3 = 3 + +\* x = 1 true because _first_ conjunct is true. +\* The allAssigned branch in Tool#getInitStates(ActionItemList, TLCState, IStateFunctor) +\* _does not_ prevents TLC from generating duplicate states with x = 1. +N1b == /\ \/ 1 = 1 + \/ 2 = 2 + \/ 3 = 3 + /\ x' = 1 + +\* x = 2 true because _first_ conjunct is true. +\* The allAssigned branch in Tool#getInitStates(ActionItemList, TLCState, IStateFunctor) +\* _does not_ prevents TLC from generating three states with x = 2. The "~~" trick prevents +\* TLC from generating duplicate states with x = 2 because Tool simply evaluates the first +\* conjunct without generating states. +N1c == /\ ~~(\/ 1 = 1 + \/ 2 = 2 + \/ 3 = 3) + /\ x' = 2 + +N2 == /\ x' = 3 \* Pred FALSE + /\ \/ 1 = 2 + \/ 2 = 3 + \/ 3 = 1 + +N3 == /\ \/ 1 = 2 \* Pred FALSE + \/ 2 = 3 + \/ 3 = 1 + /\ x' = 4 + +N4 == \/ x' = 5 + \/ x' = 6 + /\ \/ \/ 1 = 2 + \/ 1 = 1 + \/ 2 = 3 + \/ 3 = 2 + +N5 == /\ x' = 7 + +Next == \/ N1a + \/ N1b + \/ N1c + \/ N2 + \/ N3 + \/ N4 + \/ N5 + +Inv == x \in {42,0,1,2,5,6,7} +==================================================== diff --git a/tlatools/test-model/ModuleOverwrites/ModuleOverwrites.cfg b/tlatools/test-model/ModuleOverwrites/ModuleOverwrites.cfg new file mode 100644 index 0000000000000000000000000000000000000000..07b4e01c6a7aa827151c2f43bac3e72657abe857 --- /dev/null +++ b/tlatools/test-model/ModuleOverwrites/ModuleOverwrites.cfg @@ -0,0 +1,6 @@ +INIT Init +NEXT Next +INVARIANT +InvNoModuleOverwrite +InvAsModuleOverwrite +InvAsModuleOverwriteLinear \ No newline at end of file diff --git a/tlatools/test-model/ModuleOverwrites/ModuleOverwrites.tla b/tlatools/test-model/ModuleOverwrites/ModuleOverwrites.tla new file mode 100644 index 0000000000000000000000000000000000000000..6995b9fcce0c7d5351787ea27271fd623e1adbd6 --- /dev/null +++ b/tlatools/test-model/ModuleOverwrites/ModuleOverwrites.tla @@ -0,0 +1,32 @@ +-------------------------- MODULE ModuleOverwrites -------------------------- +EXTENDS Integers, Sequences + +VARIABLES t + +Init == t = [ i \in 1..10 |-> i ] + +Next == t' = t + +----------------------------------------------------------------------------- + +noDupesOverwrite(arr, emp) == FALSE + +InvAsModuleOverwrite == noDupesOverwrite(t, -1) + +----------------------------------------------------------------------------- + +noDupesOverwriteLinear(arr, emp) == FALSE + +InvAsModuleOverwriteLinear == noDupesOverwriteLinear(t, -1) + +----------------------------------------------------------------------------- + +noDupes(arr, emp) == LET sub == SelectSeq(t, LAMBDA e: e # -1) + abs(number) == IF number < 0 THEN -1 * number ELSE number + IN IF Len(sub) < 2 THEN TRUE + ELSE \A i \in 1..(Len(sub) - 1): + \A j \in (i+1)..Len(sub): + abs(sub[i]) # abs(sub[j]) + +InvNoModuleOverwrite == noDupes(t, -1) +============================================================================= diff --git a/tlatools/test-model/RandomElement.cfg b/tlatools/test-model/RandomElement.cfg new file mode 100644 index 0000000000000000000000000000000000000000..c8cffbe64c3dcc8bce148218f2e7b66a7537f573 --- /dev/null +++ b/tlatools/test-model/RandomElement.cfg @@ -0,0 +1,4 @@ +SPECIFICATION +Spec +INVARIANT +Inv \ No newline at end of file diff --git a/tlatools/test-model/RandomElement.tla b/tlatools/test-model/RandomElement.tla new file mode 100644 index 0000000000000000000000000000000000000000..a6f235186e58fc39f7a4fc638b64fcfb33d2a624 --- /dev/null +++ b/tlatools/test-model/RandomElement.tla @@ -0,0 +1,17 @@ +--------------------------- MODULE RandomElement --------------------------- +EXTENDS Integers, TLC + +VARIABLE x, y + +Init == /\ x = RandomElement(1..1000) + /\ y = 0 + +Next == /\ \/ x' = RandomElement(1..1000) + \/ x' = x + /\ y' = y + 1 + + +Spec == Init /\ [][Next]_<<x,y>> + +Inv == y < 10 +============================================================================= diff --git a/tlatools/test-model/RandomElementXandY.cfg b/tlatools/test-model/RandomElementXandY.cfg new file mode 100644 index 0000000000000000000000000000000000000000..c8cffbe64c3dcc8bce148218f2e7b66a7537f573 --- /dev/null +++ b/tlatools/test-model/RandomElementXandY.cfg @@ -0,0 +1,4 @@ +SPECIFICATION +Spec +INVARIANT +Inv \ No newline at end of file diff --git a/tlatools/test-model/RandomElementXandY.tla b/tlatools/test-model/RandomElementXandY.tla new file mode 100644 index 0000000000000000000000000000000000000000..c804ce1cfa05ed5c002bfe8f7ef388aae6bc25c5 --- /dev/null +++ b/tlatools/test-model/RandomElementXandY.tla @@ -0,0 +1,16 @@ +--------------------------- MODULE RandomElementXandY --------------------------- +EXTENDS Integers, TLC + +VARIABLE x, y + +Init == /\ x = 0 + /\ y = 0 + +Next == /\ x' = RandomElement(0..1) + /\ y' = RandomElement(0..1) + + +Spec == Init /\ [][Next]_<<x,y>> + +Inv == x = y +============================================================================= diff --git a/tlatools/test-model/RandomSubset.cfg b/tlatools/test-model/RandomSubset.cfg new file mode 100644 index 0000000000000000000000000000000000000000..c8cffbe64c3dcc8bce148218f2e7b66a7537f573 --- /dev/null +++ b/tlatools/test-model/RandomSubset.cfg @@ -0,0 +1,4 @@ +SPECIFICATION +Spec +INVARIANT +Inv \ No newline at end of file diff --git a/tlatools/test-model/RandomSubset.tla b/tlatools/test-model/RandomSubset.tla new file mode 100644 index 0000000000000000000000000000000000000000..b9def6f097273dfe0999f1ca51e8065a5f8082a8 --- /dev/null +++ b/tlatools/test-model/RandomSubset.tla @@ -0,0 +1,17 @@ +--------------------------- MODULE RandomSubset --------------------------- +EXTENDS Integers, Randomization + +VARIABLE x, y, z + +Init == /\ x \in RandomSubset(1001, 1..100000000) + /\ y \in RandomSubset(2, 100000000..100000010) + /\ z = TRUE + +Next == /\ UNCHANGED <<x, y>> + /\ z' = FALSE + + +Spec == Init /\ [][Next]_<<x,y,z>> + +Inv == z = TRUE +============================================================================= diff --git a/tlatools/test-model/RandomSubsetNext.cfg b/tlatools/test-model/RandomSubsetNext.cfg new file mode 100644 index 0000000000000000000000000000000000000000..c8cffbe64c3dcc8bce148218f2e7b66a7537f573 --- /dev/null +++ b/tlatools/test-model/RandomSubsetNext.cfg @@ -0,0 +1,4 @@ +SPECIFICATION +Spec +INVARIANT +Inv \ No newline at end of file diff --git a/tlatools/test-model/RandomSubsetNext.tla b/tlatools/test-model/RandomSubsetNext.tla new file mode 100644 index 0000000000000000000000000000000000000000..0feeb377e3e9287307aec25b2e898572024cbb0e --- /dev/null +++ b/tlatools/test-model/RandomSubsetNext.tla @@ -0,0 +1,15 @@ +------------------------- MODULE RandomSubsetNext ------------------------- +EXTENDS Integers, Randomization + +VARIABLE x, y + +Init == /\ x \in RandomSubset(10, 1..1000) + /\ y = 0 + +Next == /\ x'\in RandomSubset(10, 1..1000) + /\ y' = y + 1 + +Spec == Init /\ [][Next]_<<x,y>> + +Inv == y < 10 +============================================================================= diff --git a/tlatools/test-model/RandomSubsetSetOfFcns.cfg b/tlatools/test-model/RandomSubsetSetOfFcns.cfg new file mode 100644 index 0000000000000000000000000000000000000000..c8cffbe64c3dcc8bce148218f2e7b66a7537f573 --- /dev/null +++ b/tlatools/test-model/RandomSubsetSetOfFcns.cfg @@ -0,0 +1,4 @@ +SPECIFICATION +Spec +INVARIANT +Inv \ No newline at end of file diff --git a/tlatools/test-model/RandomSubsetSetOfFcns.tla b/tlatools/test-model/RandomSubsetSetOfFcns.tla new file mode 100644 index 0000000000000000000000000000000000000000..968b8467522724e0fa79b7504444686758a79309 --- /dev/null +++ b/tlatools/test-model/RandomSubsetSetOfFcns.tla @@ -0,0 +1,21 @@ +--------------------------- MODULE RandomSubsetSetOfFcns --------------------------- +EXTENDS Integers, Randomization + +VARIABLE x + +S == {1,2,3,4,5,6,7,8,9} +T == 1..10 + +\* [S->T] has 10^8 elements of which we want 1k. +\* Explicitly enumerating all 10^8 elements will +\* definitely timeout the tests. |[S -> T]| of +\* sizes exceeding Integer.MAX_VALUE are not yet +\* supported. +Init == /\ x \in RandomSubset(1000, [ S -> T ]) + +Next == /\ UNCHANGED <<x>> + +Spec == Init /\ [][Next]_<<x>> + +Inv == TRUE +============================================================================= diff --git a/tlatools/test-model/StandardModules.cfg b/tlatools/test-model/StandardModules.cfg new file mode 100644 index 0000000000000000000000000000000000000000..647db03515f896fda377c6760f9db2bb57cc380c --- /dev/null +++ b/tlatools/test-model/StandardModules.cfg @@ -0,0 +1,2 @@ +INIT Init +NEXT Next \ No newline at end of file diff --git a/tlatools/test-model/StandardModules.tla b/tlatools/test-model/StandardModules.tla new file mode 100644 index 0000000000000000000000000000000000000000..b1316d0c1e7521d9eb90b9ac3cb6409fd5c3bcfa --- /dev/null +++ b/tlatools/test-model/StandardModules.tla @@ -0,0 +1,6 @@ +------------------------------- MODULE StandardModules ------------------------------- +EXTENDS Bags, Sequences, FiniteSets, TLC, RealTime, Naturals, Integers, Randomization +VARIABLES x +Init == FALSE /\ x = 0 +Next == [][FALSE /\ x' = x]_<<x>> +============================================================================ diff --git a/tlatools/test-model/SubsetEq.tla b/tlatools/test-model/SubsetEq.tla index 41bed5772bc4e8dec5f9419714d16de591f19882..8f92096de78df8f2ea787cf481ef2c98248b88f4 100644 --- a/tlatools/test-model/SubsetEq.tla +++ b/tlatools/test-model/SubsetEq.tla @@ -18,5 +18,5 @@ Next == b' = /\ (SUBSET (1..23) \subseteq SUBSET (1..42)) Spec == Init /\ [][Next]_<<b>> -Inv == b = TRUE +Inv == b = TRUE /\ b \in BOOLEAN ============================================================================= diff --git a/tlatools/test-model/TSnapShot/MC.tla b/tlatools/test-model/TSnapShot/MC.tla index 177b7ca354c4e015c2e11cfb6b624e71dc8cf45d..c1ac31b94e748c5dddf4b79cef44230878e12558 100644 --- a/tlatools/test-model/TSnapShot/MC.tla +++ b/tlatools/test-model/TSnapShot/MC.tla @@ -27,7 +27,7 @@ def_ov_1446808092454110000 == ---- \* CONSTRAINT definition @modelParameterContraint:0 constr_1446808092464111000 == -LET maxNat == CHOOSE n \in Nat : \A m \in Nat : n >= m IN +LET maxNat == CHOOSE n \in Nat : \A m \in Nat : n >= m IN \A w \in Writer : iwriter[w] < maxNat ---- \* Constant expression definition @modelExpressionEval diff --git a/tlatools/test-model/TSnapShot/TSnapShot.tla b/tlatools/test-model/TSnapShot/TSnapShot.tla index b180942842e901d257db35976f5527cd903fe346..79e914c22c23ad5daf27907f7812e591214342a8 100644 --- a/tlatools/test-model/TSnapShot/TSnapShot.tla +++ b/tlatools/test-model/TSnapShot/TSnapShot.tla @@ -1,170 +1,170 @@ ------------------------------ MODULE TSnapShot ----------------------------- -(**************************************************************************** -This spec describes an algorithm by Afek et al. described in - - https://en.wikipedia.org/wiki/Shared_snapshot_objects - -This is the unbounded memory algorithm described there. - -This implementation satisfies the TSnapSpec spec, with internal -variables hidden. -****************************************************************************) -EXTENDS Integers, TLC - -CONSTANTS Reader, Writer - -ASSUME Reader \cap Writer = { } - -Process == Reader \cup Writer -(***************************************************************************) -(* To make it easier to modify the spec to one in which processes write *) -(* values in some arbitrary set, we write `Value' instead of `Nat'. *) -(***************************************************************************) -Value == Nat -Memory == [Writer -> Value] -InitMemory == [w \in Writer |-> 0] -NotAMemory == [w \in Writer |-> -1] - -VARIABLES - rstate, wstate, \* These variables are the same as in TSnapSpec, since - \* they describe the externally visible state. - rwstate, \* Like rstate, except has a copy for the writer's state - \* of reading as well - mem, iwriter, \* The same as in TSnapSpec - snap, \* snap[w] is the last snapshot value obtained by - \* writer w during its read. - \* The following are arrays indexed by Reader \cup Writer, since - \* both readers and writers perform a read operation. - rd1, rd2, \* Two arrays of arrays holding the values obtained in - \* the two reads. - (*view1,*) view2, \* Two arrays of arrays holding the snap obtained in - \* the second reads. - notRd1, notRd2, \* Two arrays holding the sets of writers whose values - \* haven't yet been read by each of the reads. - moved \* moved[r][w] is the number of times different - \* values of mem[w] have been read by r during its - \* current read operation. - -vars == <<rstate, wstate, rwstate, mem, iwriter, rd1, rd2, - (*view1,*) view2, notRd1, notRd2, moved, snap>> - -TypeOK == (* /\ rstate \in [Reader -> Memory \cup {NotAMemory}] - /\ wstate \in [Writer -> {"idle", "busy"}] - /\ rwstate \in [Process -> Memory \cup {NotAMemory}] - /\ mem \in Memory - /\ iwriter \in [Writer -> Nat] - /\ snap \in [Writer -> Memory] - /\ rd1 \in [Process -> Memory] - /\ rd2 \in [Process -> Memory] *) -\* /\ view1 \in [Process -> [Writer -> Memory]] - /\ view2 \in [Process -> [Writer -> Memory]] -(* /\ notRd1 \in [Process -> SUBSET Writer] - /\ notRd2 \in [Process -> SUBSET Writer] - /\ moved \in [Process -> [Writer -> BOOLEAN]] *) -TypeOK2 == view2 \in [Process -> [Writer -> Memory]] -Init == /\ rstate = [r \in Reader |-> InitMemory] - /\ rwstate = [r \in Process |-> InitMemory] - /\ wstate = [r \in Writer |-> "idle"] - /\ mem = InitMemory - /\ iwriter = [r \in Writer |-> 0] - /\ rd1 = [r \in Process |-> InitMemory] - /\ rd2 = [r \in Process |-> InitMemory] -\* /\ view1 = [r \in Process |-> [w \in Writer |-> Memory]] - /\ view2 = [r \in Process |-> [w \in Writer |-> InitMemory]] - /\ notRd1 = [r \in Process |-> Writer] - /\ notRd2 = [r \in Process |-> Writer] - /\ moved = [r \in Process |-> [w \in Writer |-> FALSE]] - /\ snap = [r \in Writer |-> InitMemory] - -TypeOK3 == PrintT(TypeOK2) -(***************************************************************************) -(* Define Assign(array, idx, val) to essentially mean *) -(* *) -(* array[idx] := val *) -(* *) -(* so the reader of the spec doesn't have to deal with EXCEPT. *) -(***************************************************************************) -Assign(array, idx, val) == array' = [array EXCEPT ![idx] = val] - -(***************************************************************************) -(* Define Assign(array, idx1, idx2, val) to essentially mean *) -(* *) -(* array[idx1][idx2] := val *) -(* *) -(* so the reader of the spec doesn't have to deal with EXCEPT. *) -(***************************************************************************) -AAssign(array, idx1, idx2, val) == array' = [array EXCEPT ![idx1][idx2] = val] - - -BeginRead(r) == /\ rstate[r] # NotAMemory - /\ Assign(rstate, r, NotAMemory) - /\ Assign(rwstate, r, NotAMemory) - /\ UNCHANGED <<wstate, mem, iwriter, rd1, rd2, - view2, notRd1, notRd2, moved, snap>> - -\*vars == <<rstate, wstate, rwstate, mem, iwriter, rd1, rd2, -\* (*view1,*) view2, notRd1, notRd2, moved, snap>> -DoRd1(r) == /\ rwstate[r] = NotAMemory - /\ \E w \in notRd1[r] : /\ Assign(notRd1, r, notRd1[r] \ {w}) - /\ AAssign(rd1, r, w, mem[w]) -\* /\ AAssign(view1, r, w, scan[w]) - /\ UNCHANGED <<rstate, rwstate, wstate, mem, iwriter, rd2, view2, notRd2, - moved, snap>> - -DoRd2(r) == /\ (rwstate[r] = NotAMemory) /\ (notRd1[r] = {}) - /\ \E w \in notRd2[r] : /\ Assign(notRd2, r, notRd2[r] \ {w}) - /\ AAssign(rd2, r, w, mem[w]) - /\ AAssign(view2, r, w, snap[w]) - /\ UNCHANGED <<rstate, rwstate, wstate, mem, iwriter, rd1, notRd1, - moved, snap>> - -TryEnding(r) == /\ (rwstate[r] = NotAMemory) /\ (notRd1[r] = {}) - /\ IF rd1[r] = rd2[r] - THEN Assign(rwstate, r, rd1[r]) - ELSE LET F(w) == /\ rd1[r][w] # rd2[r][w] - /\ moved[r][w] - IN IF \E w \in Writer : F(w) - THEN Assign(rwstate,r, - view2[CHOOSE w \in Writer : F(w)]) - ELSE /\ UNCHANGED rwstate - /\ moved[r] = [w \in Writer |-> - moved[r] \/ (rd1[r][w] # rd2[r][w])] - /\ IF r \in Reader - THEN Assign(rstate, r, rwstate'[r]) - ELSE UNCHANGED rstate - /\ Assign(moved, r, [w \in Writer |-> FALSE]) - /\ Assign(notRd1, r, Writer) - /\ Assign(notRd2, r, Writer) - /\ Assign(rd1, r, InitMemory) \* To reduce state space - /\ Assign(rd2, r, InitMemory) \* To reduce state space - /\ Assign(view2, r, InitMemory) \* To reduce state space - /\ UNCHANGED <<wstate, mem, snap, iwriter>> - - -BeginWrite(w) == /\ wstate[w] = "idle" - /\ Assign(wstate, w, "busy") - /\ Assign(iwriter, w, iwriter[w] + 1) - /\ Assign(rwstate, w, NotAMemory) - /\ UNCHANGED <<rstate, mem, rd1, rd2, view2, notRd1, notRd2, moved, snap>> - -DoWrite(w) == /\ iwriter[w] # mem[w] - /\ rwstate[w] # NotAMemory - /\ Assign(mem, w, mem[w]+1) - /\ Assign(snap, w, rwstate[w]) - /\ UNCHANGED <<rstate, wstate, iwriter, rd1, rd2, view2, notRd1, - notRd2, moved>> - -EndWrite(w) == /\ wstate[w] = "busy" - /\ Assign(wstate, w, "idle") - /\ UNCHANGED <<rstate, rwstate, mem, snap, iwriter, rd1, rd2, - view2, notRd1, notRd2, moved>> - -Next == \/ \E w \in Writer : BeginWrite(w) \/ DoWrite(w) \/ EndWrite(w) - \/ \E r \in Reader : - BeginRead(r) \/ DoRd1(r) \/ DoRd2(r) \/ TryEnding(r) - -Spec == Init /\ [][Next]_vars +----------------------------- MODULE TSnapShot ----------------------------- +(**************************************************************************** +This spec describes an algorithm by Afek et al. described in + + https://en.wikipedia.org/wiki/Shared_snapshot_objects + +This is the unbounded memory algorithm described there. + +This implementation satisfies the TSnapSpec spec, with internal +variables hidden. +****************************************************************************) +EXTENDS Integers, TLC + +CONSTANTS Reader, Writer + +ASSUME Reader \cap Writer = { } + +Process == Reader \cup Writer +(***************************************************************************) +(* To make it easier to modify the spec to one in which processes write *) +(* values in some arbitrary set, we write `Value' instead of `Nat'. *) +(***************************************************************************) +Value == Nat +Memory == [Writer -> Value] +InitMemory == [w \in Writer |-> 0] +NotAMemory == [w \in Writer |-> -1] + +VARIABLES + rstate, wstate, \* These variables are the same as in TSnapSpec, since + \* they describe the externally visible state. + rwstate, \* Like rstate, except has a copy for the writer's state + \* of reading as well + mem, iwriter, \* The same as in TSnapSpec + snap, \* snap[w] is the last snapshot value obtained by + \* writer w during its read. + \* The following are arrays indexed by Reader \cup Writer, since + \* both readers and writers perform a read operation. + rd1, rd2, \* Two arrays of arrays holding the values obtained in + \* the two reads. + (*view1,*) view2, \* Two arrays of arrays holding the snap obtained in + \* the second reads. + notRd1, notRd2, \* Two arrays holding the sets of writers whose values + \* haven't yet been read by each of the reads. + moved \* moved[r][w] is the number of times different + \* values of mem[w] have been read by r during its + \* current read operation. + +vars == <<rstate, wstate, rwstate, mem, iwriter, rd1, rd2, + (*view1,*) view2, notRd1, notRd2, moved, snap>> + +TypeOK == (* /\ rstate \in [Reader -> Memory \cup {NotAMemory}] + /\ wstate \in [Writer -> {"idle", "busy"}] + /\ rwstate \in [Process -> Memory \cup {NotAMemory}] + /\ mem \in Memory + /\ iwriter \in [Writer -> Nat] + /\ snap \in [Writer -> Memory] + /\ rd1 \in [Process -> Memory] + /\ rd2 \in [Process -> Memory] *) +\* /\ view1 \in [Process -> [Writer -> Memory]] + /\ view2 \in [Process -> [Writer -> Memory]] +(* /\ notRd1 \in [Process -> SUBSET Writer] + /\ notRd2 \in [Process -> SUBSET Writer] + /\ moved \in [Process -> [Writer -> BOOLEAN]] *) +TypeOK2 == view2 \in [Process -> [Writer -> Memory]] +Init == /\ rstate = [r \in Reader |-> InitMemory] + /\ rwstate = [r \in Process |-> InitMemory] + /\ wstate = [r \in Writer |-> "idle"] + /\ mem = InitMemory + /\ iwriter = [r \in Writer |-> 0] + /\ rd1 = [r \in Process |-> InitMemory] + /\ rd2 = [r \in Process |-> InitMemory] +\* /\ view1 = [r \in Process |-> [w \in Writer |-> Memory]] + /\ view2 = [r \in Process |-> [w \in Writer |-> InitMemory]] + /\ notRd1 = [r \in Process |-> Writer] + /\ notRd2 = [r \in Process |-> Writer] + /\ moved = [r \in Process |-> [w \in Writer |-> FALSE]] + /\ snap = [r \in Writer |-> InitMemory] + +TypeOK3 == PrintT(TypeOK2) +(***************************************************************************) +(* Define Assign(array, idx, val) to essentially mean *) +(* *) +(* array[idx] := val *) +(* *) +(* so the reader of the spec doesn't have to deal with EXCEPT. *) +(***************************************************************************) +Assign(array, idx, val) == array' = [array EXCEPT ![idx] = val] + +(***************************************************************************) +(* Define Assign(array, idx1, idx2, val) to essentially mean *) +(* *) +(* array[idx1][idx2] := val *) +(* *) +(* so the reader of the spec doesn't have to deal with EXCEPT. *) +(***************************************************************************) +AAssign(array, idx1, idx2, val) == array' = [array EXCEPT ![idx1][idx2] = val] + + +BeginRead(r) == /\ rstate[r] # NotAMemory + /\ Assign(rstate, r, NotAMemory) + /\ Assign(rwstate, r, NotAMemory) + /\ UNCHANGED <<wstate, mem, iwriter, rd1, rd2, + view2, notRd1, notRd2, moved, snap>> + +\*vars == <<rstate, wstate, rwstate, mem, iwriter, rd1, rd2, +\* (*view1,*) view2, notRd1, notRd2, moved, snap>> +DoRd1(r) == /\ rwstate[r] = NotAMemory + /\ \E w \in notRd1[r] : /\ Assign(notRd1, r, notRd1[r] \ {w}) + /\ AAssign(rd1, r, w, mem[w]) +\* /\ AAssign(view1, r, w, scan[w]) + /\ UNCHANGED <<rstate, rwstate, wstate, mem, iwriter, rd2, view2, notRd2, + moved, snap>> + +DoRd2(r) == /\ (rwstate[r] = NotAMemory) /\ (notRd1[r] = {}) + /\ \E w \in notRd2[r] : /\ Assign(notRd2, r, notRd2[r] \ {w}) + /\ AAssign(rd2, r, w, mem[w]) + /\ AAssign(view2, r, w, snap[w]) + /\ UNCHANGED <<rstate, rwstate, wstate, mem, iwriter, rd1, notRd1, + moved, snap>> + +TryEnding(r) == /\ (rwstate[r] = NotAMemory) /\ (notRd1[r] = {}) + /\ IF rd1[r] = rd2[r] + THEN Assign(rwstate, r, rd1[r]) + ELSE LET F(w) == /\ rd1[r][w] # rd2[r][w] + /\ moved[r][w] + IN IF \E w \in Writer : F(w) + THEN Assign(rwstate,r, + view2[CHOOSE w \in Writer : F(w)]) + ELSE /\ UNCHANGED rwstate + /\ moved[r] = [w \in Writer |-> + moved[r] \/ (rd1[r][w] # rd2[r][w])] + /\ IF r \in Reader + THEN Assign(rstate, r, rwstate'[r]) + ELSE UNCHANGED rstate + /\ Assign(moved, r, [w \in Writer |-> FALSE]) + /\ Assign(notRd1, r, Writer) + /\ Assign(notRd2, r, Writer) + /\ Assign(rd1, r, InitMemory) \* To reduce state space + /\ Assign(rd2, r, InitMemory) \* To reduce state space + /\ Assign(view2, r, InitMemory) \* To reduce state space + /\ UNCHANGED <<wstate, mem, snap, iwriter>> + + +BeginWrite(w) == /\ wstate[w] = "idle" + /\ Assign(wstate, w, "busy") + /\ Assign(iwriter, w, iwriter[w] + 1) + /\ Assign(rwstate, w, NotAMemory) + /\ UNCHANGED <<rstate, mem, rd1, rd2, view2, notRd1, notRd2, moved, snap>> + +DoWrite(w) == /\ iwriter[w] # mem[w] + /\ rwstate[w] # NotAMemory + /\ Assign(mem, w, mem[w]+1) + /\ Assign(snap, w, rwstate[w]) + /\ UNCHANGED <<rstate, wstate, iwriter, rd1, rd2, view2, notRd1, + notRd2, moved>> + +EndWrite(w) == /\ wstate[w] = "busy" + /\ Assign(wstate, w, "idle") + /\ UNCHANGED <<rstate, rwstate, mem, snap, iwriter, rd1, rd2, + view2, notRd1, notRd2, moved>> + +Next == \/ \E w \in Writer : BeginWrite(w) \/ DoWrite(w) \/ EndWrite(w) + \/ \E r \in Reader : + BeginRead(r) \/ DoRd1(r) \/ DoRd2(r) \/ TryEnding(r) + +Spec == Init /\ [][Next]_vars ============================================================================= -\* Modification History -\* Last modified Mon Nov 02 18:16:48 PST 2015 by lamport -\* Created Mon Nov 02 13:33:53 PST 2015 by lamport +\* Modification History +\* Last modified Mon Nov 02 18:16:48 PST 2015 by lamport +\* Created Mon Nov 02 13:33:53 PST 2015 by lamport diff --git a/tlatools/test-model/ViewMap.cfg b/tlatools/test-model/ViewMap.cfg new file mode 100644 index 0000000000000000000000000000000000000000..96d6a36718587ae6ccaab59c90e98f3b9b069693 --- /dev/null +++ b/tlatools/test-model/ViewMap.cfg @@ -0,0 +1,24 @@ +\* MV CONSTANT declarations +CONSTANTS +c1 = c1 +c2 = c2 +\* MV CONSTANT declarations +CONSTANTS +p1 = p1 +\* MV CONSTANT definitions +CONSTANT +C = {c1, c2} +\* MV CONSTANT definitions +CONSTANT +P = {p1} +\* CONSTANT definitions +CONSTANT +K = 1 +\* VIEW definition +VIEW +view +\* SPECIFICATION definition +SPECIFICATION +Spec +INVARIANT +Inv diff --git a/tlatools/test-model/ViewMap.tla b/tlatools/test-model/ViewMap.tla new file mode 100644 index 0000000000000000000000000000000000000000..ec4eccb93d6c20e274b6699ac30fa8f5fa2e45f5 --- /dev/null +++ b/tlatools/test-model/ViewMap.tla @@ -0,0 +1,102 @@ +--------------------------- MODULE ViewMap --------------------------- +EXTENDS Integers, FiniteSets, Sequences + +CONSTANT P, \* Set of Producers + C, \* Set of Consumers + K \* Capacity of buffer/queue + +RemoveLast(seq) == [ i \in 1..(Len(seq) - 1) |-> seq[i] ] + +(* +--algorithm JBuffer01Pcal { + variables buffer = <<>>, waitset = {}; + + process (p \in P) { + lbp: while (Len(buffer) >= K) { + (* wait *) + waitset := waitset \cup {self}; + }; + buffer := Append(buffer, "d"); + (* notify *) + if (waitset # {}) { + with (x \in waitset) { + waitset := waitset \ {x}; + } + }; + goto lbp; + } + + process (c \in C) { + lbc: while (Len(buffer) = 0) { + (* wait *) + waitset := waitset \cup {self}; + }; + buffer := RemoveLast(buffer); + (* notify *) + if (waitset # {}) { + with (x \in waitset) { + waitset := waitset \ {x}; + } + }; + goto lbc; + } +} +*) +\* BEGIN TRANSLATION +VARIABLES buffer, waitset, pc + +vars == << buffer, waitset, pc >> + +ProcSet == (P) \cup (C) + +Init == (* Global variables *) + /\ buffer = <<>> + /\ waitset = {} + /\ pc = [self \in ProcSet |-> CASE self \in P -> "lbp" + [] self \in C -> "lbc"] + +lbp(self) == /\ pc[self] = "lbp" + /\ IF Len(buffer) >= K + THEN /\ waitset' = (waitset \cup {self}) + /\ pc' = [pc EXCEPT ![self] = "lbp"] + /\ UNCHANGED buffer + ELSE /\ buffer' = Append(buffer, "d") + /\ IF waitset # {} + THEN /\ \E x \in waitset: + waitset' = waitset \ {x} + ELSE /\ TRUE + /\ UNCHANGED waitset + /\ pc' = [pc EXCEPT ![self] = "lbp"] + +p(self) == lbp(self) + +lbc(self) == /\ pc[self] = "lbc" + /\ IF Len(buffer) = 0 + THEN /\ waitset' = (waitset \cup {self}) + /\ pc' = [pc EXCEPT ![self] = "lbc"] + /\ UNCHANGED buffer + ELSE /\ buffer' = RemoveLast(buffer) + /\ IF waitset # {} + THEN /\ \E x \in waitset: + waitset' = waitset \ {x} + ELSE /\ TRUE + /\ UNCHANGED waitset + /\ pc' = [pc EXCEPT ![self] = "lbc"] + +c(self) == lbc(self) + +Next == (\E self \in P: p(self)) + \/ (\E self \in C: c(self)) + \/ (* Disjunct to prevent deadlock on termination *) + ((\A self \in ProcSet: pc[self] = "Done") /\ UNCHANGED vars) + +Spec == Init /\ [][Next]_vars + +Termination == <>(\A self \in ProcSet: pc[self] = "Done") + +\* END TRANSLATION + +Inv == waitset # ProcSet + +view == <<buffer, waitset>> +============================================================================= diff --git a/tlatools/test-model/VoteProof/VoteProof.tla b/tlatools/test-model/VoteProof/VoteProof.tla index 75a9c636b5215607e5c6947c1795b6bc985b4628..518f983d1fcd66ad0caff9a504ab45eaed5c28f7 100644 --- a/tlatools/test-model/VoteProof/VoteProof.tla +++ b/tlatools/test-model/VoteProof/VoteProof.tla @@ -1,785 +1,785 @@ ------------------------------ MODULE VoteProof ------------------------------ - -(*************************************************************************) -(* !!!! REGRESSION TESTS ONLY !!!! *) -(* *) -(* This file is not meant as a reference to TLA+ in general, nor for *) -(* VoteProof in particular. Please search the web for an official *) -(* version of the VoteProof spec. *) -(* *) -(*************************************************************************) - -EXTENDS Integers , FiniteSets, TLC, TLAPS - -CONSTANT Value, \* As in module Consensus, the set of choosable values. - Acceptor, \* The set of all acceptors. - Quorum \* The set of all quorums. - -ASSUME QA == /\ \A Q \in Quorum : Q \subseteq Acceptor - /\ \A Q1, Q2 \in Quorum : Q1 \cap Q2 # {} - -THEOREM QuorumNonEmpty == \A Q \in Quorum : Q # {} -PROOF BY QA - -Ballot == Nat - -(*************************** ---algorithm Voting { - variables votes = [a \in Acceptor |-> {}], - maxBal = [a \in Acceptor |-> -1]; - define { - VotedFor(a, b, v) == <<b, v>> \in votes[a] - DidNotVoteIn(a, b) == \A v \in Value : ~ VotedFor(a, b, v) - - SafeAt(b, v) == - LET SA[bb \in Ballot] == - \/ bb = 0 - \/ \E Q \in Quorum : - /\ \A a \in Q : maxBal[a] \geq bb - /\ \E c \in -1..(bb-1) : - /\ (c # -1) => /\ SA[c] - /\ \A a \in Q : - \A w \in Value : - VotedFor(a, c, w) => (w = v) - /\ \A d \in (c+1)..(bb-1), a \in Q : DidNotVoteIn(a, d) - IN SA[b] - } - macro IncreaseMaxBal(b) { - when b > maxBal[self] ; - maxBal[self] := b - } - - macro VoteFor(b, v) { - when /\ maxBal[self] \leq b - /\ DidNotVoteIn(self, b) - /\ \A p \in Acceptor \ {self} : - \A w \in Value : VotedFor(p, b, w) => (w = v) - /\ SafeAt(b, v) ; - votes[self] := votes[self] \cup {<<b, v>>}; - maxBal[self] := b - } - - process (acceptor \in Acceptor) { - acc : while (TRUE) { - with (b \in Ballot) { - either IncreaseMaxBal(b) - or with (v \in Value) { VoteFor(b, v) } - } - } - } -} - -The following is the TLA+ specification produced by the translation. -Blank lines, produced by the translation because of the comments, have -been deleted. -****************************) -\* BEGIN TRANSLATION -VARIABLES votes, maxBal - -(* define statement *) -VotedFor(a, b, v) == <<b, v>> \in votes[a] - - - -DidNotVoteIn(a, b) == \A v \in Value : ~ VotedFor(a, b, v) - - - - - - - - - - - - - - - - - - - - - -SafeAt(b, v) == - LET SA[bb \in Ballot] == - - - - \/ bb = 0 - \/ \E Q \in Quorum : - /\ \A a \in Q : maxBal[a] \geq bb - /\ \E c \in -1..(bb-1) : - /\ (c # -1) => /\ SA[c] - /\ \A a \in Q : - \A w \in Value : - VotedFor(a, c, w) => (w = v) - /\ \A d \in (c+1)..(bb-1), a \in Q : DidNotVoteIn(a, d) - IN SA[b] - - -vars == << votes, maxBal >> - -ProcSet == (Acceptor) - -Init == (* Global variables *) - /\ votes = [a \in Acceptor |-> {}] - /\ maxBal = [a \in Acceptor |-> -1] - -acceptor(self) == \E b \in Ballot: - \/ /\ b > maxBal[self] - /\ maxBal' = [maxBal EXCEPT ![self] = b] - /\ votes' = votes - \/ /\ \E v \in Value: - /\ /\ maxBal[self] \leq b - /\ DidNotVoteIn(self, b) - /\ \A p \in Acceptor \ {self} : - \A w \in Value : VotedFor(p, b, w) => (w = v) - /\ SafeAt(b, v) - /\ votes' = [votes EXCEPT ![self] = votes[self] \cup {<<b, v>>}] - /\ maxBal' = [maxBal EXCEPT ![self] = b] - -Next == (\E self \in Acceptor: acceptor(self)) - -Spec == Init /\ [][Next]_vars - -\* END TRANSLATION - -THEOREM RecursiveFcnOfNat == - ASSUME NEW Def(_,_), - \A n \in Nat : - \A g, h : (\A i \in 0..(n-1) : g[i] = h[i]) => (Def(g, n) = Def(h, n)) - PROVE LET f[n \in Nat] == Def(f, n) - IN f = [n \in Nat |-> Def(f, n)] -PROOF OMITTED - -THEOREM SafeAtProp == - \A b \in Ballot, v \in Value : - SafeAt(b, v) = - \/ b = 0 - \/ \E Q \in Quorum : - /\ \A a \in Q : maxBal[a] \geq b - /\ \E c \in -1..(b-1) : - /\ (c # -1) => /\ SafeAt(c, v) - /\ \A a \in Q : - \A w \in Value : - VotedFor(a, c, w) => (w = v) - /\ \A d \in (c+1)..(b-1), a \in Q : DidNotVoteIn(a, d) -<1>1. SUFFICES ASSUME NEW v \in Value - PROVE \A b \in Ballot : SafeAtProp!(b, v) - OBVIOUS -<1> USE DEF Ballot -<1> DEFINE Def(SA, bb) == - \/ bb = 0 - \/ \E Q \in Quorum : - /\ \A a \in Q : maxBal[a] \geq bb - /\ \E c \in -1..(bb-1) : - /\ (c # -1) => /\ SA[c] - /\ \A a \in Q : - \A w \in Value : - VotedFor(a, c, w) => (w = v) - /\ \A d \in (c+1)..(bb-1), a \in Q : DidNotVoteIn(a, d) - SA[bb \in Ballot] == Def(SA, bb) -<1>2. \A b : SafeAt(b, v) = SA[b] - BY DEF SafeAt -<1>3. \A n \in Nat : - \A g, h : (\A i \in 0..(n-1) : g[i] = h[i]) => (Def(g, n) = Def(h, n)) - BY SMT -<1> HIDE DEF Def -<1>4. SA = [b \in Ballot |-> Def(SA, b)] - BY ONLY <1>3, RecursiveFcnOfNat -<1>5. \A b \in Ballot : SA[b] = Def(SA, b) - BY <1>4 -<1>6. QED - BY <1>2, <1>5 DEF SafeAt, Def - -TypeOK == /\ votes \in [Acceptor -> SUBSET (Ballot \X Value)] - /\ maxBal \in [Acceptor -> Ballot \cup {-1}] - -ChosenIn(b, v) == \E Q \in Quorum : \A a \in Q : VotedFor(a, b, v) - -chosen == {v \in Value : \E b \in Ballot : ChosenIn(b, v)} - -AXIOM SimpleNatInduction == \A f : /\ f[0] - /\ \A n \in Nat : f[n] => f[n+1] - => \A n \in Nat : f[n] - -THEOREM GeneralNatInduction == - \A f : /\ f[0] - /\ \A n \in Nat : (\A j \in 0..n : f[j]) => f[n+1] - => \A n \in Nat : f[n] -<1>1. SUFFICES ASSUME NEW f, - f[0], - \A m \in Nat : (\A j \in 0..m : f[j]) => f[m+1], - NEW n \in Nat - PROVE f[n] - OBVIOUS -<1> DEFINE g == [m \in Nat |-> \A j \in 0..m : f[j]] -<1>2. g[0] - BY <1>1, SMT -<1>3. ASSUME NEW k \in Nat, g[k] - PROVE g[k+1] - BY <1>1, <1>3, SMT -<1>4. \A k \in Nat : g[k] - BY <1>2, <1>3, SimpleNatInduction -<1>5. QED - BY <1>4, SMT - -LEMMA SafeLemma == - TypeOK => - \A b \in Ballot : - \A v \in Value : - SafeAt(b, v) => - \A c \in 0..(b-1) : - \E Q \in Quorum : - \A a \in Q : /\ maxBal[a] >= c - /\ \/ DidNotVoteIn(a, c) - \/ VotedFor(a, c, v) -<1> SUFFICES ASSUME TypeOK - PROVE SafeLemma!2 - OBVIOUS -<1> DEFINE P[b \in Ballot] == \A c \in 0..b : SafeLemma!2!(c) -<1>1. P[0] - BY SMT DEF Ballot -<1>2. ASSUME NEW b \in Ballot, P[b] - PROVE P[b+1] - <2>1. /\ b+1 \in Ballot - /\ (b+1) - 1 = b - BY SMT DEF Ballot - <2>2. 0..(b+1) = (0..b) \cup {b+1} - BY SMT DEF Ballot - <2>3. SUFFICES ASSUME NEW v \in Value, - SafeAt(b+1, v), - NEW c \in 0..b - PROVE \E Q \in Quorum : - \A a \in Q : /\ maxBal[a] >= c - /\ \/ DidNotVoteIn(a, c) - \/ VotedFor(a, c, v) - BY <1>2, <2>1, <2>2 - <2>4. PICK Q \in Quorum : - /\ \A a \in Q : maxBal[a] \geq (b+1) - /\ \E cc \in -1..b : - /\ (cc # -1) => /\ SafeAt(cc, v) - /\ \A a \in Q : - \A w \in Value : - VotedFor(a, cc, w) => (w = v) - /\ \A d \in (cc+1)..b, a \in Q : DidNotVoteIn(a, d) - <3>1. b+1 # 0 - BY SMT DEF Ballot - <3>2. SafeAt(b+1,v) = SafeAtProp!(b+1,v)!2 - BY SafeAtProp, <2>1 - <3>3. @ = SafeAtProp!(b+1,v)!2!2 - BY <3>1 - <3>4. @ = \E Q \in Quorum : - /\ \A a \in Q : maxBal[a] \geq (b+1) - /\ \E cc \in -1..b : - /\ (cc # -1) => /\ SafeAt(cc, v) - /\ \A a \in Q : - \A w \in Value : - VotedFor(a, cc, w) => (w = v) - /\ \A d \in (cc+1)..b, a \in Q : DidNotVoteIn(a, d) - BY <2>1 - <3>5. QED - BY <3>2, <3>3, <3>4, <2>3 - <2>5. PICK cc \in -1..b : - /\ (cc # -1) => /\ SafeAt(cc, v) - /\ \A a \in Q : - \A w \in Value : - VotedFor(a, cc, w) => (w = v) - /\ \A d \in (cc+1)..b, a \in Q : DidNotVoteIn(a, d) - BY <2>4 - <2>6. CASE c > cc - BY <2>6, <2>5, <2>4, QA, SMT DEF TypeOK, Ballot - <2>7. CASE c =< cc - <3>1. /\ cc \in 0..b - /\ cc # -1 - BY <2>7, SMT DEF Ballot - <3>2. SafeLemma!2!(cc)!(v) - BY <1>2, <3>1 - <3>3. SafeAt(cc, v) - BY <2>5, <3>1 - <3>4. CASE c = cc - BY <3>4, <3>1, <2>5, <2>4, SMT DEF Ballot, TypeOK, DidNotVoteIn - <3>5. CASE c < cc - <4>1. c \in 0..(cc-1) - BY <3>1, <3>5, SMT - <4>2. SafeLemma!2!(cc) - BY <3>1, <1>2 - <4>3. QED - BY <4>1,<4>2, <4>2, <3>3 - <3>6. QED - BY <2>7, <3>4, <3>5, SMT DEF Ballot - <2>8. QED - BY <2>6, <2>7, SMT DEF Ballot -<1>3. \A b \in Ballot : P[b] - BY <1>1, <1>2, SimpleNatInduction DEF Ballot -<1>4. QED - BY <1>3, Z3 DEF Ballot \* SMT fails - -VInv1 == \A a \in Acceptor, b \in Ballot, v, w \in Value : - VotedFor(a, b, v) /\ VotedFor(a, b, w) => (v = w) - -VInv2 == \A a \in Acceptor, b \in Ballot, v \in Value : - VotedFor(a, b, v) => SafeAt(b, v) - -VInv3 == \A a1, a2 \in Acceptor, b \in Ballot, v1, v2 \in Value : - VotedFor(a1, b, v1) /\ VotedFor(a2, b, v2) => (v1 = v2) - -THEOREM VInv3 => VInv1 -BY DEF VInv1, VInv3 - -LEMMA VT0 == /\ TypeOK - /\ VInv1 - /\ VInv2 - => \A v, w \in Value, b, c \in Ballot : - (b > c) /\ SafeAt(b, v) /\ ChosenIn(c, w) => (v = w) -<1> SUFFICES ASSUME TypeOK, VInv1, VInv2, - NEW v \in Value, NEW w \in Value - PROVE \A b, c \in Ballot : - (b > c) /\ SafeAt(b, v) /\ ChosenIn(c, w) => (v = w) - OBVIOUS -<1> P == [b \in Ballot |-> - \A c \in Ballot : - (b > c) /\ SafeAt(b, v) /\ ChosenIn(c, w) => (v = w)] - -<1>1. P[0] - BY SMT DEF Ballot (* This works *) -<1>2. ASSUME NEW b \in Ballot, \A i \in 0..b : P[i] - PROVE P[b+1] - <2>1. b+1 \in Ballot - BY SMT DEF Ballot - <2>2. SUFFICES ASSUME NEW c \in Ballot, b+1 > c, SafeAt(b+1, v), ChosenIn(c, w) - PROVE v=w - BY <2>1 - <2>3. PICK Q \in Quorum : \A a \in Q : VotedFor(a, c, w) - BY <2>2 DEF ChosenIn - <2>4. b+1 # 0 /\ ((b+1)-1 = b) - BY SMT DEF Ballot - <2>5. PICK QQ \in Quorum, - d \in -1..((b+1)-1) : - /\ (d # -1) => /\ SafeAt(d, v) - /\ \A a \in QQ : - \A x \in Value : - VotedFor(a, d, x) => (x = v) - /\ \A e \in (d+1)..((b+1)-1), a \in QQ : DidNotVoteIn(a, e) - BY <2>1, <2>2, <2>4, SafeAtProp - <2> PICK aa \in QQ \cap Q : TRUE - BY QA - <2>6. c \leq d - BY <2>2, <2>3, <2>5, SMT DEF DidNotVoteIn, Ballot - <2>7. d # -1 - BY <2>6, SMT DEF Ballot - <2>8. CASE c = d - BY <2>3, <2>5, <2>7, <2>8 - <2>9. CASE d > c - <3>1. SafeAt(d, v) - BY <2>5, <2>7 - <3>2. d \in Ballot /\ d \in 0..b - BY <2>6, SMT DEF Ballot - <3>3. P[d] - BY <1>2, <3>2 - <3>4. QED - BY <2>2, <2>9, <3>1, <3>2, <3>3 - <2>10. QED - BY <2>3, <2>6, <2>8, <2>9, SMT DEF Ballot -<1>3. \A b \in Ballot : P[b] - BY <1>1, <1>2, GeneralNatInduction DEF Ballot - -<1>4. QED - BY <1>3 - -THEOREM VT1 == /\ TypeOK - /\ VInv1 - /\ VInv2 - => \A v, w : - (v \in chosen) /\ (w \in chosen) => (v = w) -<1>1. SUFFICES ASSUME TypeOK, VInv1, VInv2, - NEW v, NEW w, - v \in chosen, w \in chosen - PROVE v = w - OBVIOUS -<1>2. v \in Value /\ w \in Value - BY <1>1 DEF chosen -<1>3. PICK b \in Ballot, c \in Ballot : ChosenIn(b, v) /\ ChosenIn(c, w) - BY <1>1 DEF chosen -<1>4. PICK Q \in Quorum, R \in Quorum : - /\ \A a \in Q : VotedFor(a, b, v) - /\ \A a \in R : VotedFor(a, c, w) - BY <1>3 DEF ChosenIn -<1>5. PICK av \in Q, aw \in R: /\ VotedFor(av, b, v) - /\ VotedFor(aw, c, w) - BY <1>4, QuorumNonEmpty -<1>6. SafeAt(b, v) /\ SafeAt(c, w) - BY <1>1, <1>2, <1>5, QA DEF VInv2 -<1>7. CASE b = c - <2> PICK a \in Q \cap R : TRUE - BY QA - <2>1. /\ VotedFor(a, b, v) - /\ VotedFor(a, c, w) - BY <1>4 - <2>2. QED - BY <1>1, <1>2, <1>7, <2>1, QA DEF VInv1 -<1>8. CASE b > c - BY <1>1, <1>6, <1>3, <1>8, VT0, <1>2 \* <2>1 -<1>9. CASE c > b - BY <1>1, <1>6, <1>3, <1>9, VT0, <1>2 \* <2>1 -<1>10. QED - BY <1>7, <1>8, <1>9 DEF Ballot - -VInv4 == \A a \in Acceptor, b \in Ballot : - maxBal[a] < b => DidNotVoteIn(a, b) - -VInv == TypeOK /\ VInv2 /\ VInv3 /\ VInv4 - -IncreaseMaxBal(self, b) == - /\ b > maxBal[self] - /\ maxBal' = [maxBal EXCEPT ![self] = b] - /\ UNCHANGED votes - -VoteFor(self, b, v) == - /\ maxBal[self] \leq b - /\ DidNotVoteIn(self, b) - /\ \A p \in Acceptor \ {self} : - \A w \in Value : VotedFor(p, b, w) => (w = v) - /\ SafeAt(b, v) - /\ votes' = [votes EXCEPT ![self] = votes[self] \cup {<<b, v>>}] - /\ maxBal' = [maxBal EXCEPT ![self] = b] - -BallotAction(self, b) == - \/ IncreaseMaxBal(self, b) - \/ \E v \in Value : VoteFor(self, b, v) - -ASSUME AcceptorNonempty == Acceptor # {} - -LEMMA NextDef == - TypeOK => - (Next = \E self \in Acceptor : - \E b \in Ballot : BallotAction(self, b) ) -<1> HAVE TypeOK -<1>2. Next = \E self \in Acceptor: acceptor(self) - BY AcceptorNonempty DEF Next, ProcSet -<1>3. @ = NextDef!2!2 - BY DEF Next, BallotAction, IncreaseMaxBal, VoteFor, ProcSet, acceptor -<1>4. QED - BY <1>2, <1>3 - -THEOREM InductiveInvariance == VInv /\ [Next]_vars => VInv' -<1>1. VInv /\ (vars' = vars) => VInv' - \* SMT can't do this because it requires the definition of SafeAt, - \* which uses a recursive function definition. - <2> SUFFICES ASSUME VInv, vars' = vars - PROVE VInv' - OBVIOUS - <2> USE DEF vars, VInv - <2>1. TypeOK' - BY DEF TypeOK - <2>2. VInv2' - BY DEF VInv2, VotedFor, SafeAt, DidNotVoteIn - <2>3. VInv3' - BY DEF VInv3, VotedFor - <2>4. VInv4' - BY DEF VInv4, DidNotVoteIn, VotedFor - <2>5. QED - BY <2>1, <2>2, <2>3, <2>4 - -<1> SUFFICES ASSUME VInv, - NEW self \in Acceptor, - NEW b \in Ballot, - BallotAction(self, b) - PROVE VInv' - BY <1>1, NextDef DEF VInv - -<1>2. TypeOK' - <2>1. CASE IncreaseMaxBal(self, b) - BY <2>1 DEF IncreaseMaxBal, VInv, TypeOK - <2>2. CASE \E v \in Value : VoteFor(self, b, v) - BY <2>2 DEF VInv, TypeOK, VoteFor \* SMT and Zenon failed - <2>3. QED - BY <2>1, <2>2 DEF BallotAction - -<1>3. ASSUME NEW a \in Acceptor, NEW c \in Ballot, NEW w \in Value, - ~VotedFor(a, c, w), VotedFor(a, c, w)' - PROVE (a = self) /\ (c = b) /\ VoteFor(self, b, w) - BY <1>3, SMT DEF IncreaseMaxBal, VInv, TypeOK, VotedFor, VoteFor, BallotAction - -<1>4. ASSUME NEW a \in Acceptor - PROVE /\ maxBal[a] \in Ballot \cup {-1} - /\ maxBal'[a] \in Ballot \cup {-1} - /\ maxBal'[a] >= maxBal[a] - BY SMT DEF VInv, TypeOK, IncreaseMaxBal, VInv, VoteFor, BallotAction, - DidNotVoteIn, VotedFor, Ballot - -<1>5. ASSUME NEW c \in Ballot, NEW w \in Value, - SafeAt(c, w) - PROVE SafeAt(c, w)' - <2>SafeAtPropPrime. SafeAtProp' - BY SafeAtProp, PTL - <2> DEFINE P[i \in Ballot] == \A j \in 0..i : SafeAt(j, w) => SafeAt(j, w)' - <2>1. P[0] - <3>1. 0 \in Ballot /\ \A i \in 0..0 : i = 0 - BY SMT DEF Ballot - <3>2. QED - BY <2>SafeAtPropPrime, <3>1 - <2>2. ASSUME NEW d \in Ballot, P[d] - PROVE P[d+1] - <3>1. d+1 \in Ballot /\ d+1 # 0 - BY SMT DEF Ballot - <3>2. SUFFICES ASSUME NEW e \in 0..(d+1), SafeAt(e, w) - PROVE SafeAt(e, w)' - BY <3>1 - <3>3. e \in 0..d \/ e = d+1 - BY SMT DEF Ballot - <3>4. CASE e \in 0..d - BY <2>2, <3>2, <3>4 - <3>5. CASE e = d+1 - <4>1. PICK Q \in Quorum : SafeAtProp!(e, w)!2!2!(Q) - BY <3>1, <3>2, <3>5, SafeAtProp - <4>2. \A aa \in Q : maxBal'[aa] \geq e - BY <1>4, <4>1, QA, SMT DEF Ballot - <4>3. \E cc \in -1..(e-1) : - /\ (cc # -1) => /\ SafeAt(cc, w)' - /\ \A ax \in Q : - \A z \in Value : - VotedFor(ax, cc, z)' => (z = w) - /\ \A dd \in (cc+1)..(e-1), ax \in Q : DidNotVoteIn(ax, dd)' - <5>1. PICK cc \in -1..(e-1) : - /\ (cc # -1) => /\ SafeAt(cc, w) - /\ \A ax \in Q : - \A z \in Value : - VotedFor(ax, cc, z) => (z = w) - /\ \A dd \in (cc+1)..(e-1), ax \in Q : DidNotVoteIn(ax, dd) - BY <1>5, <3>3, <2>2, <4>1 - <5>2. (cc # -1) => (SafeAt(cc, w) => SafeAt(cc, w)') - BY <2>2 DEF Ballot - <5>3. CASE IncreaseMaxBal(self, b) - <6>1. /\ \A x, y, z : VotedFor(x, y, z)' = VotedFor(x,y,z) - /\ \A x, y: DidNotVoteIn(x, y)' = DidNotVoteIn(x, y) - BY <5>3 DEF IncreaseMaxBal, VotedFor, DidNotVoteIn - <6>2 QED - BY <5>1, <5>2, <6>1 - <5>4. CASE \E v \in Value : VoteFor(self, b, v) - <6> PICK v \in Value : VoteFor(self, b, v) - BY <5>4 - <6> QED - BY <5>4, <4>2, <5>1, <5>2, <2>2, QA - DEF VoteFor, VotedFor, DidNotVoteIn, VInv, TypeOK, Ballot - <5>5. QED - BY <5>3, <5>4 DEF BallotAction - <4>4. \/ e = 0 - \/ \E Q_1 \in Quorum : - /\ \A aa \in Q_1 : maxBal'[aa] \geq e - /\ \E c_1 \in -1..e - 1 : - /\ c_1 # -1 - => (/\ SafeAt(c_1, w)' - /\ \A aa \in Q_1 : - \A w_1 \in Value : - VotedFor(aa, c_1, w_1)' => w_1 = w) - /\ \A d_1 \in c_1 + 1..e - 1, aa \in Q_1 : - DidNotVoteIn(aa, d_1)' - BY <4>2, <4>3, <3>1, <3>5 - <4>5. e \in Ballot - BY <3>1, <3>5 - <4>6. SafeAt(e, w)' = <4>4 - BY <2>SafeAtPropPrime, <4>5 - <4>7. QED - BY <4>2, <4>3, <4>6 - <3>6. QED - BY <3>3, <3>4, <3>5 - <2>3. \A d \in Ballot : P[d] - BY <2>1, <2>2, SimpleNatInduction DEF Ballot - <2>4. QED - BY <2>3, <1>5, SMT DEF Ballot - -<1>6. VInv2' - BY <1>3, <1>5, SMT DEF VInv, VInv2, VoteFor - -<1>7. VInv3' - BY <1>3, SMT DEF VoteFor, DidNotVoteIn, VInv, TypeOK, VotedFor, VInv, VInv3 - -<1>8. VInv4' - BY <1>3, <1>4, SMT DEF Ballot, VInv, VInv4, VoteFor, DidNotVoteIn, TypeOK - -<1>9. QED - BY <1>2, <1>6, <1>7, <1>8 DEF VInv - -THEOREM InitImpliesInv == Init => VInv -<1> SUFFICES ASSUME Init PROVE VInv - OBVIOUS -<1> USE DEF Init -<1>1. TypeOK - BY DEF TypeOK, ProcSet -<1>2. VInv2 - BY DEF VInv2, VotedFor -<1>3. VInv3 - BY DEF VInv3, VotedFor -<1>4. VInv4 - BY DEF VInv4, DidNotVoteIn, VotedFor -<1>5. QED - BY <1>1, <1>2, <1>3, <1>4 DEF VInv - -THEOREM VT2 == Spec => []VInv - BY InductiveInvariance, InitImpliesInv, PTL DEF Spec - -C == INSTANCE Consensus - -THEOREM VT3 == Spec => C!Spec -<1>1. Init => C!Init - BY QuorumNonEmpty, QA, SMT DEF Init, C!Init, chosen, ChosenIn, VotedFor - -<1>2. ASSUME VInv, VInv', [Next]_vars - PROVE [C!Next]_C!vars - <2> USE VInv - <2>1. CASE vars' = vars - BY <2>1 DEF vars, C!vars, chosen, ChosenIn, VotedFor - <2>2. SUFFICES ASSUME NEW self \in Acceptor, - NEW b \in Ballot, - BallotAction(self, b) - PROVE [C!Next]_C!vars - BY <1>2, <2>1, NextDef DEF VInv - <2>3. ASSUME IncreaseMaxBal(self, b) - PROVE C!vars' = C!vars - BY <2>3 DEF IncreaseMaxBal, C!vars, chosen, ChosenIn, VotedFor - <2>4. ASSUME NEW v \in Value, - VoteFor(self, b, v) - PROVE [C!Next]_C!vars - <3>3. ASSUME NEW w \in chosen - PROVE w \in chosen' - BY <3>3, <2>4, <1>2, QA, SMT - DEF VoteFor, VInv, TypeOK, chosen, ChosenIn, VotedFor - <3>VT1P. VT1' - BY VT1, PTL - <3>1. ASSUME NEW w \in chosen, - v \in chosen' - PROVE w = v - BY <1>2, <3>1, <3>3, <3>VT1P, SMT DEF VInv, VInv1, VInv3 - <3>2. ASSUME NEW w, w \notin chosen, w \in chosen' - PROVE w = v - BY <3>2, <2>4, <1>2, QA, SMT - DEF chosen, ChosenIn, VotedFor, VoteFor, VInv, TypeOK - <3>4. CASE chosen' = chosen - BY <3>4 DEF C!vars - <3>5. CASE chosen' # chosen - <4>1. chosen \subseteq chosen' - BY <3>3 - <4>2. PICK w \in chosen' : w \notin chosen - BY <3>5, <4>1 - <4>3. w = v - BY <4>2, <3>2 - <4>4. chosen' = chosen \cup {v} - BY <3>2, <4>1, <4>3 - <4>5. chosen = {} - BY <4>4, <3>1, <3>5 - <4>6. QED - BY <4>4, <4>5 DEF C!Next - <3>6. QED - BY <3>4, <3>5 - <2>5. QED - BY <2>2, <2>3, <2>4 DEF BallotAction - -<1>3. QED - BY <1>1, <1>2, VT2, PTL DEF C!Spec, Spec - -ASSUME AcceptorFinite == IsFiniteSet(Acceptor) - -ASSUME ValueNonempty == Value # {} - -AXIOM SubsetOfFiniteSetFinite == - \A S, T : IsFiniteSet(T) /\ (S \subseteq T) => IsFiniteSet(S) - -AXIOM FiniteSetHasMax == - \A S \in SUBSET Int : - IsFiniteSet(S) /\ (S # {}) => \E max \in S : \A x \in S : max >= x - -AXIOM IntervalFinite == \A i, j \in Int : IsFiniteSet(i..j) - -THEOREM VT4 == TypeOK /\ VInv2 /\ VInv3 => - \A Q \in Quorum, b \in Ballot : - (\A a \in Q : (maxBal[a] >= b)) => \E v \in Value : SafeAt(b,v) - -<1>1. SUFFICES ASSUME TypeOK, VInv2, VInv3, - NEW Q \in Quorum, NEW b \in Ballot, - (\A a \in Q : (maxBal[a] >= b)) - PROVE \E v \in Value : SafeAt(b, v) - OBVIOUS -<1>2. CASE b = 0 - BY ValueNonempty, <1>1, SafeAtProp, <1>2 -<1>3. SUFFICES ASSUME b # 0 - PROVE \E v \in Value : SafeAt(b, v) - BY <1>2 -<1>4. SUFFICES \E v \in Value : - \E c \in -1..(b-1) : - /\ (c # -1) => /\ SafeAt(c, v) - /\ \A a \in Q : - \A w \in Value : - VotedFor(a, c, w) => (w = v) - /\ \A d \in (c+1)..(b-1), a \in Q : DidNotVoteIn(a, d) - <2>1. SUFFICES ASSUME NEW v \in Value, - <1>4!1!(v) - PROVE SafeAt(b, v) - OBVIOUS - <2>2. SafeAtProp!(b, v) - BY SafeAtProp - <2>3. QED - BY <2>1, <2>2, <1>1, <1>3 -<1>5. CASE \A a \in Q, c \in 0..(b-1) : DidNotVoteIn(a, c) - <2>1. PICK v \in Value : TRUE - BY ValueNonempty - <2> -1 \in -1..(b-1) - BY SMT DEF Ballot - <2>2. WITNESS v \in Value - <2>3. WITNESS -1 \in -1..(b-1) - <2>4. QED - BY <1>5 -<1>6. CASE \E a \in Q, c \in 0..(b-1) : ~DidNotVoteIn(a, c) - <2>1. PICK c \in 0..(b-1) : - /\ \E a \in Q : ~DidNotVoteIn(a, c) - /\ \A d \in (c+1)..(b-1), a \in Q : DidNotVoteIn(a, d) - <3> DEFINE S == {c \in 0..(b-1) : \E a \in Q : ~DidNotVoteIn(a, c)} - <3>1. S # {} - BY <1>6 - <3>2. PICK c \in S : \A d \in S : c >= d - <4>1. (0 \in Int) /\ (b-1 \in Int) /\ (\A x \in 0..(b-1) : x \in Int) - BY <1>3, SMT DEF Ballot - <4>2. (S \in SUBSET Int) - BY <4>1 - <4>3. IsFiniteSet(S) - BY <4>1, IntervalFinite, SubsetOfFiniteSetFinite - <4>4. QED - BY <3>1, <4>2, <4>3, FiniteSetHasMax - <3>3. c \in 0..(b-1) - OBVIOUS - <3>4. \A d \in (c+1)..(b-1) : d \in 0..(b-1) /\ ~(c >= d) - BY <3>3, SMT DEF Ballot (* This works *) - <3>5. \A d \in (c+1)..(b-1), a \in Q : DidNotVoteIn(a, d) - BY <3>2, <3>4 - <3>6. \E a \in Q : ~DidNotVoteIn(a, c) - BY <3>1 - <3>7. QED - BY <3>3, <3>5, <3>6 - <2>2. (c \in -1..(b-1)) /\ (c # -1) /\ (c \in Ballot) - BY SMT DEF Ballot - <2>3. PICK a0 \in Q : ~DidNotVoteIn(a0, c) - BY <2>1 - <2>4. PICK v \in Value : VotedFor(a0, c, v) - BY <2>3 DEF DidNotVoteIn - <2>5. \A a \in Q : \A w \in Value : - VotedFor(a, c, w) => (w = v) - BY <2>2, <2>4, QA, <1>1 DEF VInv3 - <2>6. SafeAt(c, v) - BY <1>1, <2>4, QA, <2>2 DEF VInv2 - <2>7. QED - BY <2>1, <2>2, <2>5, <2>6 - -<1>7. QED - BY <1>5, <1>6 - -LiveAssumption == - \E Q \in Quorum, b \in Ballot : - \A self \in Q : - /\ WF_vars(BallotAction(self, b)) - /\ [] [\A c \in Ballot : (c > b) => ~ BallotAction(self, c)]_vars - -LiveSpec == Spec /\ LiveAssumption -=============================================================================== +----------------------------- MODULE VoteProof ------------------------------ + +(*************************************************************************) +(* !!!! REGRESSION TESTS ONLY !!!! *) +(* *) +(* This file is not meant as a reference to TLA+ in general, nor for *) +(* VoteProof in particular. Please search the web for an official *) +(* version of the VoteProof spec. *) +(* *) +(*************************************************************************) + +EXTENDS Integers , FiniteSets, TLC, TLAPS + +CONSTANT Value, \* As in module Consensus, the set of choosable values. + Acceptor, \* The set of all acceptors. + Quorum \* The set of all quorums. + +ASSUME QA == /\ \A Q \in Quorum : Q \subseteq Acceptor + /\ \A Q1, Q2 \in Quorum : Q1 \cap Q2 # {} + +THEOREM QuorumNonEmpty == \A Q \in Quorum : Q # {} +PROOF BY QA + +Ballot == Nat + +(*************************** +--algorithm Voting { + variables votes = [a \in Acceptor |-> {}], + maxBal = [a \in Acceptor |-> -1]; + define { + VotedFor(a, b, v) == <<b, v>> \in votes[a] + DidNotVoteIn(a, b) == \A v \in Value : ~ VotedFor(a, b, v) + + SafeAt(b, v) == + LET SA[bb \in Ballot] == + \/ bb = 0 + \/ \E Q \in Quorum : + /\ \A a \in Q : maxBal[a] \geq bb + /\ \E c \in -1..(bb-1) : + /\ (c # -1) => /\ SA[c] + /\ \A a \in Q : + \A w \in Value : + VotedFor(a, c, w) => (w = v) + /\ \A d \in (c+1)..(bb-1), a \in Q : DidNotVoteIn(a, d) + IN SA[b] + } + macro IncreaseMaxBal(b) { + when b > maxBal[self] ; + maxBal[self] := b + } + + macro VoteFor(b, v) { + when /\ maxBal[self] \leq b + /\ DidNotVoteIn(self, b) + /\ \A p \in Acceptor \ {self} : + \A w \in Value : VotedFor(p, b, w) => (w = v) + /\ SafeAt(b, v) ; + votes[self] := votes[self] \cup {<<b, v>>}; + maxBal[self] := b + } + + process (acceptor \in Acceptor) { + acc : while (TRUE) { + with (b \in Ballot) { + either IncreaseMaxBal(b) + or with (v \in Value) { VoteFor(b, v) } + } + } + } +} + +The following is the TLA+ specification produced by the translation. +Blank lines, produced by the translation because of the comments, have +been deleted. +****************************) +\* BEGIN TRANSLATION +VARIABLES votes, maxBal + +(* define statement *) +VotedFor(a, b, v) == <<b, v>> \in votes[a] + + + +DidNotVoteIn(a, b) == \A v \in Value : ~ VotedFor(a, b, v) + + + + + + + + + + + + + + + + + + + + + +SafeAt(b, v) == + LET SA[bb \in Ballot] == + + + + \/ bb = 0 + \/ \E Q \in Quorum : + /\ \A a \in Q : maxBal[a] \geq bb + /\ \E c \in -1..(bb-1) : + /\ (c # -1) => /\ SA[c] + /\ \A a \in Q : + \A w \in Value : + VotedFor(a, c, w) => (w = v) + /\ \A d \in (c+1)..(bb-1), a \in Q : DidNotVoteIn(a, d) + IN SA[b] + + +vars == << votes, maxBal >> + +ProcSet == (Acceptor) + +Init == (* Global variables *) + /\ votes = [a \in Acceptor |-> {}] + /\ maxBal = [a \in Acceptor |-> -1] + +acceptor(self) == \E b \in Ballot: + \/ /\ b > maxBal[self] + /\ maxBal' = [maxBal EXCEPT ![self] = b] + /\ votes' = votes + \/ /\ \E v \in Value: + /\ /\ maxBal[self] \leq b + /\ DidNotVoteIn(self, b) + /\ \A p \in Acceptor \ {self} : + \A w \in Value : VotedFor(p, b, w) => (w = v) + /\ SafeAt(b, v) + /\ votes' = [votes EXCEPT ![self] = votes[self] \cup {<<b, v>>}] + /\ maxBal' = [maxBal EXCEPT ![self] = b] + +Next == (\E self \in Acceptor: acceptor(self)) + +Spec == Init /\ [][Next]_vars + +\* END TRANSLATION + +THEOREM RecursiveFcnOfNat == + ASSUME NEW Def(_,_), + \A n \in Nat : + \A g, h : (\A i \in 0..(n-1) : g[i] = h[i]) => (Def(g, n) = Def(h, n)) + PROVE LET f[n \in Nat] == Def(f, n) + IN f = [n \in Nat |-> Def(f, n)] +PROOF OMITTED + +THEOREM SafeAtProp == + \A b \in Ballot, v \in Value : + SafeAt(b, v) = + \/ b = 0 + \/ \E Q \in Quorum : + /\ \A a \in Q : maxBal[a] \geq b + /\ \E c \in -1..(b-1) : + /\ (c # -1) => /\ SafeAt(c, v) + /\ \A a \in Q : + \A w \in Value : + VotedFor(a, c, w) => (w = v) + /\ \A d \in (c+1)..(b-1), a \in Q : DidNotVoteIn(a, d) +<1>1. SUFFICES ASSUME NEW v \in Value + PROVE \A b \in Ballot : SafeAtProp!(b, v) + OBVIOUS +<1> USE DEF Ballot +<1> DEFINE Def(SA, bb) == + \/ bb = 0 + \/ \E Q \in Quorum : + /\ \A a \in Q : maxBal[a] \geq bb + /\ \E c \in -1..(bb-1) : + /\ (c # -1) => /\ SA[c] + /\ \A a \in Q : + \A w \in Value : + VotedFor(a, c, w) => (w = v) + /\ \A d \in (c+1)..(bb-1), a \in Q : DidNotVoteIn(a, d) + SA[bb \in Ballot] == Def(SA, bb) +<1>2. \A b : SafeAt(b, v) = SA[b] + BY DEF SafeAt +<1>3. \A n \in Nat : + \A g, h : (\A i \in 0..(n-1) : g[i] = h[i]) => (Def(g, n) = Def(h, n)) + BY SMT +<1> HIDE DEF Def +<1>4. SA = [b \in Ballot |-> Def(SA, b)] + BY ONLY <1>3, RecursiveFcnOfNat +<1>5. \A b \in Ballot : SA[b] = Def(SA, b) + BY <1>4 +<1>6. QED + BY <1>2, <1>5 DEF SafeAt, Def + +TypeOK == /\ votes \in [Acceptor -> SUBSET (Ballot \X Value)] + /\ maxBal \in [Acceptor -> Ballot \cup {-1}] + +ChosenIn(b, v) == \E Q \in Quorum : \A a \in Q : VotedFor(a, b, v) + +chosen == {v \in Value : \E b \in Ballot : ChosenIn(b, v)} + +AXIOM SimpleNatInduction == \A f : /\ f[0] + /\ \A n \in Nat : f[n] => f[n+1] + => \A n \in Nat : f[n] + +THEOREM GeneralNatInduction == + \A f : /\ f[0] + /\ \A n \in Nat : (\A j \in 0..n : f[j]) => f[n+1] + => \A n \in Nat : f[n] +<1>1. SUFFICES ASSUME NEW f, + f[0], + \A m \in Nat : (\A j \in 0..m : f[j]) => f[m+1], + NEW n \in Nat + PROVE f[n] + OBVIOUS +<1> DEFINE g == [m \in Nat |-> \A j \in 0..m : f[j]] +<1>2. g[0] + BY <1>1, SMT +<1>3. ASSUME NEW k \in Nat, g[k] + PROVE g[k+1] + BY <1>1, <1>3, SMT +<1>4. \A k \in Nat : g[k] + BY <1>2, <1>3, SimpleNatInduction +<1>5. QED + BY <1>4, SMT + +LEMMA SafeLemma == + TypeOK => + \A b \in Ballot : + \A v \in Value : + SafeAt(b, v) => + \A c \in 0..(b-1) : + \E Q \in Quorum : + \A a \in Q : /\ maxBal[a] >= c + /\ \/ DidNotVoteIn(a, c) + \/ VotedFor(a, c, v) +<1> SUFFICES ASSUME TypeOK + PROVE SafeLemma!2 + OBVIOUS +<1> DEFINE P[b \in Ballot] == \A c \in 0..b : SafeLemma!2!(c) +<1>1. P[0] + BY SMT DEF Ballot +<1>2. ASSUME NEW b \in Ballot, P[b] + PROVE P[b+1] + <2>1. /\ b+1 \in Ballot + /\ (b+1) - 1 = b + BY SMT DEF Ballot + <2>2. 0..(b+1) = (0..b) \cup {b+1} + BY SMT DEF Ballot + <2>3. SUFFICES ASSUME NEW v \in Value, + SafeAt(b+1, v), + NEW c \in 0..b + PROVE \E Q \in Quorum : + \A a \in Q : /\ maxBal[a] >= c + /\ \/ DidNotVoteIn(a, c) + \/ VotedFor(a, c, v) + BY <1>2, <2>1, <2>2 + <2>4. PICK Q \in Quorum : + /\ \A a \in Q : maxBal[a] \geq (b+1) + /\ \E cc \in -1..b : + /\ (cc # -1) => /\ SafeAt(cc, v) + /\ \A a \in Q : + \A w \in Value : + VotedFor(a, cc, w) => (w = v) + /\ \A d \in (cc+1)..b, a \in Q : DidNotVoteIn(a, d) + <3>1. b+1 # 0 + BY SMT DEF Ballot + <3>2. SafeAt(b+1,v) = SafeAtProp!(b+1,v)!2 + BY SafeAtProp, <2>1 + <3>3. @ = SafeAtProp!(b+1,v)!2!2 + BY <3>1 + <3>4. @ = \E Q \in Quorum : + /\ \A a \in Q : maxBal[a] \geq (b+1) + /\ \E cc \in -1..b : + /\ (cc # -1) => /\ SafeAt(cc, v) + /\ \A a \in Q : + \A w \in Value : + VotedFor(a, cc, w) => (w = v) + /\ \A d \in (cc+1)..b, a \in Q : DidNotVoteIn(a, d) + BY <2>1 + <3>5. QED + BY <3>2, <3>3, <3>4, <2>3 + <2>5. PICK cc \in -1..b : + /\ (cc # -1) => /\ SafeAt(cc, v) + /\ \A a \in Q : + \A w \in Value : + VotedFor(a, cc, w) => (w = v) + /\ \A d \in (cc+1)..b, a \in Q : DidNotVoteIn(a, d) + BY <2>4 + <2>6. CASE c > cc + BY <2>6, <2>5, <2>4, QA, SMT DEF TypeOK, Ballot + <2>7. CASE c =< cc + <3>1. /\ cc \in 0..b + /\ cc # -1 + BY <2>7, SMT DEF Ballot + <3>2. SafeLemma!2!(cc)!(v) + BY <1>2, <3>1 + <3>3. SafeAt(cc, v) + BY <2>5, <3>1 + <3>4. CASE c = cc + BY <3>4, <3>1, <2>5, <2>4, SMT DEF Ballot, TypeOK, DidNotVoteIn + <3>5. CASE c < cc + <4>1. c \in 0..(cc-1) + BY <3>1, <3>5, SMT + <4>2. SafeLemma!2!(cc) + BY <3>1, <1>2 + <4>3. QED + BY <4>1,<4>2, <4>2, <3>3 + <3>6. QED + BY <2>7, <3>4, <3>5, SMT DEF Ballot + <2>8. QED + BY <2>6, <2>7, SMT DEF Ballot +<1>3. \A b \in Ballot : P[b] + BY <1>1, <1>2, SimpleNatInduction DEF Ballot +<1>4. QED + BY <1>3, Z3 DEF Ballot \* SMT fails + +VInv1 == \A a \in Acceptor, b \in Ballot, v, w \in Value : + VotedFor(a, b, v) /\ VotedFor(a, b, w) => (v = w) + +VInv2 == \A a \in Acceptor, b \in Ballot, v \in Value : + VotedFor(a, b, v) => SafeAt(b, v) + +VInv3 == \A a1, a2 \in Acceptor, b \in Ballot, v1, v2 \in Value : + VotedFor(a1, b, v1) /\ VotedFor(a2, b, v2) => (v1 = v2) + +THEOREM VInv3 => VInv1 +BY DEF VInv1, VInv3 + +LEMMA VT0 == /\ TypeOK + /\ VInv1 + /\ VInv2 + => \A v, w \in Value, b, c \in Ballot : + (b > c) /\ SafeAt(b, v) /\ ChosenIn(c, w) => (v = w) +<1> SUFFICES ASSUME TypeOK, VInv1, VInv2, + NEW v \in Value, NEW w \in Value + PROVE \A b, c \in Ballot : + (b > c) /\ SafeAt(b, v) /\ ChosenIn(c, w) => (v = w) + OBVIOUS +<1> P == [b \in Ballot |-> + \A c \in Ballot : + (b > c) /\ SafeAt(b, v) /\ ChosenIn(c, w) => (v = w)] + +<1>1. P[0] + BY SMT DEF Ballot (* This works *) +<1>2. ASSUME NEW b \in Ballot, \A i \in 0..b : P[i] + PROVE P[b+1] + <2>1. b+1 \in Ballot + BY SMT DEF Ballot + <2>2. SUFFICES ASSUME NEW c \in Ballot, b+1 > c, SafeAt(b+1, v), ChosenIn(c, w) + PROVE v=w + BY <2>1 + <2>3. PICK Q \in Quorum : \A a \in Q : VotedFor(a, c, w) + BY <2>2 DEF ChosenIn + <2>4. b+1 # 0 /\ ((b+1)-1 = b) + BY SMT DEF Ballot + <2>5. PICK QQ \in Quorum, + d \in -1..((b+1)-1) : + /\ (d # -1) => /\ SafeAt(d, v) + /\ \A a \in QQ : + \A x \in Value : + VotedFor(a, d, x) => (x = v) + /\ \A e \in (d+1)..((b+1)-1), a \in QQ : DidNotVoteIn(a, e) + BY <2>1, <2>2, <2>4, SafeAtProp + <2> PICK aa \in QQ \cap Q : TRUE + BY QA + <2>6. c \leq d + BY <2>2, <2>3, <2>5, SMT DEF DidNotVoteIn, Ballot + <2>7. d # -1 + BY <2>6, SMT DEF Ballot + <2>8. CASE c = d + BY <2>3, <2>5, <2>7, <2>8 + <2>9. CASE d > c + <3>1. SafeAt(d, v) + BY <2>5, <2>7 + <3>2. d \in Ballot /\ d \in 0..b + BY <2>6, SMT DEF Ballot + <3>3. P[d] + BY <1>2, <3>2 + <3>4. QED + BY <2>2, <2>9, <3>1, <3>2, <3>3 + <2>10. QED + BY <2>3, <2>6, <2>8, <2>9, SMT DEF Ballot +<1>3. \A b \in Ballot : P[b] + BY <1>1, <1>2, GeneralNatInduction DEF Ballot + +<1>4. QED + BY <1>3 + +THEOREM VT1 == /\ TypeOK + /\ VInv1 + /\ VInv2 + => \A v, w : + (v \in chosen) /\ (w \in chosen) => (v = w) +<1>1. SUFFICES ASSUME TypeOK, VInv1, VInv2, + NEW v, NEW w, + v \in chosen, w \in chosen + PROVE v = w + OBVIOUS +<1>2. v \in Value /\ w \in Value + BY <1>1 DEF chosen +<1>3. PICK b \in Ballot, c \in Ballot : ChosenIn(b, v) /\ ChosenIn(c, w) + BY <1>1 DEF chosen +<1>4. PICK Q \in Quorum, R \in Quorum : + /\ \A a \in Q : VotedFor(a, b, v) + /\ \A a \in R : VotedFor(a, c, w) + BY <1>3 DEF ChosenIn +<1>5. PICK av \in Q, aw \in R: /\ VotedFor(av, b, v) + /\ VotedFor(aw, c, w) + BY <1>4, QuorumNonEmpty +<1>6. SafeAt(b, v) /\ SafeAt(c, w) + BY <1>1, <1>2, <1>5, QA DEF VInv2 +<1>7. CASE b = c + <2> PICK a \in Q \cap R : TRUE + BY QA + <2>1. /\ VotedFor(a, b, v) + /\ VotedFor(a, c, w) + BY <1>4 + <2>2. QED + BY <1>1, <1>2, <1>7, <2>1, QA DEF VInv1 +<1>8. CASE b > c + BY <1>1, <1>6, <1>3, <1>8, VT0, <1>2 \* <2>1 +<1>9. CASE c > b + BY <1>1, <1>6, <1>3, <1>9, VT0, <1>2 \* <2>1 +<1>10. QED + BY <1>7, <1>8, <1>9 DEF Ballot + +VInv4 == \A a \in Acceptor, b \in Ballot : + maxBal[a] < b => DidNotVoteIn(a, b) + +VInv == TypeOK /\ VInv2 /\ VInv3 /\ VInv4 + +IncreaseMaxBal(self, b) == + /\ b > maxBal[self] + /\ maxBal' = [maxBal EXCEPT ![self] = b] + /\ UNCHANGED votes + +VoteFor(self, b, v) == + /\ maxBal[self] \leq b + /\ DidNotVoteIn(self, b) + /\ \A p \in Acceptor \ {self} : + \A w \in Value : VotedFor(p, b, w) => (w = v) + /\ SafeAt(b, v) + /\ votes' = [votes EXCEPT ![self] = votes[self] \cup {<<b, v>>}] + /\ maxBal' = [maxBal EXCEPT ![self] = b] + +BallotAction(self, b) == + \/ IncreaseMaxBal(self, b) + \/ \E v \in Value : VoteFor(self, b, v) + +ASSUME AcceptorNonempty == Acceptor # {} + +LEMMA NextDef == + TypeOK => + (Next = \E self \in Acceptor : + \E b \in Ballot : BallotAction(self, b) ) +<1> HAVE TypeOK +<1>2. Next = \E self \in Acceptor: acceptor(self) + BY AcceptorNonempty DEF Next, ProcSet +<1>3. @ = NextDef!2!2 + BY DEF Next, BallotAction, IncreaseMaxBal, VoteFor, ProcSet, acceptor +<1>4. QED + BY <1>2, <1>3 + +THEOREM InductiveInvariance == VInv /\ [Next]_vars => VInv' +<1>1. VInv /\ (vars' = vars) => VInv' + \* SMT can't do this because it requires the definition of SafeAt, + \* which uses a recursive function definition. + <2> SUFFICES ASSUME VInv, vars' = vars + PROVE VInv' + OBVIOUS + <2> USE DEF vars, VInv + <2>1. TypeOK' + BY DEF TypeOK + <2>2. VInv2' + BY DEF VInv2, VotedFor, SafeAt, DidNotVoteIn + <2>3. VInv3' + BY DEF VInv3, VotedFor + <2>4. VInv4' + BY DEF VInv4, DidNotVoteIn, VotedFor + <2>5. QED + BY <2>1, <2>2, <2>3, <2>4 + +<1> SUFFICES ASSUME VInv, + NEW self \in Acceptor, + NEW b \in Ballot, + BallotAction(self, b) + PROVE VInv' + BY <1>1, NextDef DEF VInv + +<1>2. TypeOK' + <2>1. CASE IncreaseMaxBal(self, b) + BY <2>1 DEF IncreaseMaxBal, VInv, TypeOK + <2>2. CASE \E v \in Value : VoteFor(self, b, v) + BY <2>2 DEF VInv, TypeOK, VoteFor \* SMT and Zenon failed + <2>3. QED + BY <2>1, <2>2 DEF BallotAction + +<1>3. ASSUME NEW a \in Acceptor, NEW c \in Ballot, NEW w \in Value, + ~VotedFor(a, c, w), VotedFor(a, c, w)' + PROVE (a = self) /\ (c = b) /\ VoteFor(self, b, w) + BY <1>3, SMT DEF IncreaseMaxBal, VInv, TypeOK, VotedFor, VoteFor, BallotAction + +<1>4. ASSUME NEW a \in Acceptor + PROVE /\ maxBal[a] \in Ballot \cup {-1} + /\ maxBal'[a] \in Ballot \cup {-1} + /\ maxBal'[a] >= maxBal[a] + BY SMT DEF VInv, TypeOK, IncreaseMaxBal, VInv, VoteFor, BallotAction, + DidNotVoteIn, VotedFor, Ballot + +<1>5. ASSUME NEW c \in Ballot, NEW w \in Value, + SafeAt(c, w) + PROVE SafeAt(c, w)' + <2>SafeAtPropPrime. SafeAtProp' + BY SafeAtProp, PTL + <2> DEFINE P[i \in Ballot] == \A j \in 0..i : SafeAt(j, w) => SafeAt(j, w)' + <2>1. P[0] + <3>1. 0 \in Ballot /\ \A i \in 0..0 : i = 0 + BY SMT DEF Ballot + <3>2. QED + BY <2>SafeAtPropPrime, <3>1 + <2>2. ASSUME NEW d \in Ballot, P[d] + PROVE P[d+1] + <3>1. d+1 \in Ballot /\ d+1 # 0 + BY SMT DEF Ballot + <3>2. SUFFICES ASSUME NEW e \in 0..(d+1), SafeAt(e, w) + PROVE SafeAt(e, w)' + BY <3>1 + <3>3. e \in 0..d \/ e = d+1 + BY SMT DEF Ballot + <3>4. CASE e \in 0..d + BY <2>2, <3>2, <3>4 + <3>5. CASE e = d+1 + <4>1. PICK Q \in Quorum : SafeAtProp!(e, w)!2!2!(Q) + BY <3>1, <3>2, <3>5, SafeAtProp + <4>2. \A aa \in Q : maxBal'[aa] \geq e + BY <1>4, <4>1, QA, SMT DEF Ballot + <4>3. \E cc \in -1..(e-1) : + /\ (cc # -1) => /\ SafeAt(cc, w)' + /\ \A ax \in Q : + \A z \in Value : + VotedFor(ax, cc, z)' => (z = w) + /\ \A dd \in (cc+1)..(e-1), ax \in Q : DidNotVoteIn(ax, dd)' + <5>1. PICK cc \in -1..(e-1) : + /\ (cc # -1) => /\ SafeAt(cc, w) + /\ \A ax \in Q : + \A z \in Value : + VotedFor(ax, cc, z) => (z = w) + /\ \A dd \in (cc+1)..(e-1), ax \in Q : DidNotVoteIn(ax, dd) + BY <1>5, <3>3, <2>2, <4>1 + <5>2. (cc # -1) => (SafeAt(cc, w) => SafeAt(cc, w)') + BY <2>2 DEF Ballot + <5>3. CASE IncreaseMaxBal(self, b) + <6>1. /\ \A x, y, z : VotedFor(x, y, z)' = VotedFor(x,y,z) + /\ \A x, y: DidNotVoteIn(x, y)' = DidNotVoteIn(x, y) + BY <5>3 DEF IncreaseMaxBal, VotedFor, DidNotVoteIn + <6>2 QED + BY <5>1, <5>2, <6>1 + <5>4. CASE \E v \in Value : VoteFor(self, b, v) + <6> PICK v \in Value : VoteFor(self, b, v) + BY <5>4 + <6> QED + BY <5>4, <4>2, <5>1, <5>2, <2>2, QA + DEF VoteFor, VotedFor, DidNotVoteIn, VInv, TypeOK, Ballot + <5>5. QED + BY <5>3, <5>4 DEF BallotAction + <4>4. \/ e = 0 + \/ \E Q_1 \in Quorum : + /\ \A aa \in Q_1 : maxBal'[aa] \geq e + /\ \E c_1 \in -1..e - 1 : + /\ c_1 # -1 + => (/\ SafeAt(c_1, w)' + /\ \A aa \in Q_1 : + \A w_1 \in Value : + VotedFor(aa, c_1, w_1)' => w_1 = w) + /\ \A d_1 \in c_1 + 1..e - 1, aa \in Q_1 : + DidNotVoteIn(aa, d_1)' + BY <4>2, <4>3, <3>1, <3>5 + <4>5. e \in Ballot + BY <3>1, <3>5 + <4>6. SafeAt(e, w)' = <4>4 + BY <2>SafeAtPropPrime, <4>5 + <4>7. QED + BY <4>2, <4>3, <4>6 + <3>6. QED + BY <3>3, <3>4, <3>5 + <2>3. \A d \in Ballot : P[d] + BY <2>1, <2>2, SimpleNatInduction DEF Ballot + <2>4. QED + BY <2>3, <1>5, SMT DEF Ballot + +<1>6. VInv2' + BY <1>3, <1>5, SMT DEF VInv, VInv2, VoteFor + +<1>7. VInv3' + BY <1>3, SMT DEF VoteFor, DidNotVoteIn, VInv, TypeOK, VotedFor, VInv, VInv3 + +<1>8. VInv4' + BY <1>3, <1>4, SMT DEF Ballot, VInv, VInv4, VoteFor, DidNotVoteIn, TypeOK + +<1>9. QED + BY <1>2, <1>6, <1>7, <1>8 DEF VInv + +THEOREM InitImpliesInv == Init => VInv +<1> SUFFICES ASSUME Init PROVE VInv + OBVIOUS +<1> USE DEF Init +<1>1. TypeOK + BY DEF TypeOK, ProcSet +<1>2. VInv2 + BY DEF VInv2, VotedFor +<1>3. VInv3 + BY DEF VInv3, VotedFor +<1>4. VInv4 + BY DEF VInv4, DidNotVoteIn, VotedFor +<1>5. QED + BY <1>1, <1>2, <1>3, <1>4 DEF VInv + +THEOREM VT2 == Spec => []VInv + BY InductiveInvariance, InitImpliesInv, PTL DEF Spec + +C == INSTANCE Consensus + +THEOREM VT3 == Spec => C!Spec +<1>1. Init => C!Init + BY QuorumNonEmpty, QA, SMT DEF Init, C!Init, chosen, ChosenIn, VotedFor + +<1>2. ASSUME VInv, VInv', [Next]_vars + PROVE [C!Next]_C!vars + <2> USE VInv + <2>1. CASE vars' = vars + BY <2>1 DEF vars, C!vars, chosen, ChosenIn, VotedFor + <2>2. SUFFICES ASSUME NEW self \in Acceptor, + NEW b \in Ballot, + BallotAction(self, b) + PROVE [C!Next]_C!vars + BY <1>2, <2>1, NextDef DEF VInv + <2>3. ASSUME IncreaseMaxBal(self, b) + PROVE C!vars' = C!vars + BY <2>3 DEF IncreaseMaxBal, C!vars, chosen, ChosenIn, VotedFor + <2>4. ASSUME NEW v \in Value, + VoteFor(self, b, v) + PROVE [C!Next]_C!vars + <3>3. ASSUME NEW w \in chosen + PROVE w \in chosen' + BY <3>3, <2>4, <1>2, QA, SMT + DEF VoteFor, VInv, TypeOK, chosen, ChosenIn, VotedFor + <3>VT1P. VT1' + BY VT1, PTL + <3>1. ASSUME NEW w \in chosen, + v \in chosen' + PROVE w = v + BY <1>2, <3>1, <3>3, <3>VT1P, SMT DEF VInv, VInv1, VInv3 + <3>2. ASSUME NEW w, w \notin chosen, w \in chosen' + PROVE w = v + BY <3>2, <2>4, <1>2, QA, SMT + DEF chosen, ChosenIn, VotedFor, VoteFor, VInv, TypeOK + <3>4. CASE chosen' = chosen + BY <3>4 DEF C!vars + <3>5. CASE chosen' # chosen + <4>1. chosen \subseteq chosen' + BY <3>3 + <4>2. PICK w \in chosen' : w \notin chosen + BY <3>5, <4>1 + <4>3. w = v + BY <4>2, <3>2 + <4>4. chosen' = chosen \cup {v} + BY <3>2, <4>1, <4>3 + <4>5. chosen = {} + BY <4>4, <3>1, <3>5 + <4>6. QED + BY <4>4, <4>5 DEF C!Next + <3>6. QED + BY <3>4, <3>5 + <2>5. QED + BY <2>2, <2>3, <2>4 DEF BallotAction + +<1>3. QED + BY <1>1, <1>2, VT2, PTL DEF C!Spec, Spec + +ASSUME AcceptorFinite == IsFiniteSet(Acceptor) + +ASSUME ValueNonempty == Value # {} + +AXIOM SubsetOfFiniteSetFinite == + \A S, T : IsFiniteSet(T) /\ (S \subseteq T) => IsFiniteSet(S) + +AXIOM FiniteSetHasMax == + \A S \in SUBSET Int : + IsFiniteSet(S) /\ (S # {}) => \E max \in S : \A x \in S : max >= x + +AXIOM IntervalFinite == \A i, j \in Int : IsFiniteSet(i..j) + +THEOREM VT4 == TypeOK /\ VInv2 /\ VInv3 => + \A Q \in Quorum, b \in Ballot : + (\A a \in Q : (maxBal[a] >= b)) => \E v \in Value : SafeAt(b,v) + +<1>1. SUFFICES ASSUME TypeOK, VInv2, VInv3, + NEW Q \in Quorum, NEW b \in Ballot, + (\A a \in Q : (maxBal[a] >= b)) + PROVE \E v \in Value : SafeAt(b, v) + OBVIOUS +<1>2. CASE b = 0 + BY ValueNonempty, <1>1, SafeAtProp, <1>2 +<1>3. SUFFICES ASSUME b # 0 + PROVE \E v \in Value : SafeAt(b, v) + BY <1>2 +<1>4. SUFFICES \E v \in Value : + \E c \in -1..(b-1) : + /\ (c # -1) => /\ SafeAt(c, v) + /\ \A a \in Q : + \A w \in Value : + VotedFor(a, c, w) => (w = v) + /\ \A d \in (c+1)..(b-1), a \in Q : DidNotVoteIn(a, d) + <2>1. SUFFICES ASSUME NEW v \in Value, + <1>4!1!(v) + PROVE SafeAt(b, v) + OBVIOUS + <2>2. SafeAtProp!(b, v) + BY SafeAtProp + <2>3. QED + BY <2>1, <2>2, <1>1, <1>3 +<1>5. CASE \A a \in Q, c \in 0..(b-1) : DidNotVoteIn(a, c) + <2>1. PICK v \in Value : TRUE + BY ValueNonempty + <2> -1 \in -1..(b-1) + BY SMT DEF Ballot + <2>2. WITNESS v \in Value + <2>3. WITNESS -1 \in -1..(b-1) + <2>4. QED + BY <1>5 +<1>6. CASE \E a \in Q, c \in 0..(b-1) : ~DidNotVoteIn(a, c) + <2>1. PICK c \in 0..(b-1) : + /\ \E a \in Q : ~DidNotVoteIn(a, c) + /\ \A d \in (c+1)..(b-1), a \in Q : DidNotVoteIn(a, d) + <3> DEFINE S == {c \in 0..(b-1) : \E a \in Q : ~DidNotVoteIn(a, c)} + <3>1. S # {} + BY <1>6 + <3>2. PICK c \in S : \A d \in S : c >= d + <4>1. (0 \in Int) /\ (b-1 \in Int) /\ (\A x \in 0..(b-1) : x \in Int) + BY <1>3, SMT DEF Ballot + <4>2. (S \in SUBSET Int) + BY <4>1 + <4>3. IsFiniteSet(S) + BY <4>1, IntervalFinite, SubsetOfFiniteSetFinite + <4>4. QED + BY <3>1, <4>2, <4>3, FiniteSetHasMax + <3>3. c \in 0..(b-1) + OBVIOUS + <3>4. \A d \in (c+1)..(b-1) : d \in 0..(b-1) /\ ~(c >= d) + BY <3>3, SMT DEF Ballot (* This works *) + <3>5. \A d \in (c+1)..(b-1), a \in Q : DidNotVoteIn(a, d) + BY <3>2, <3>4 + <3>6. \E a \in Q : ~DidNotVoteIn(a, c) + BY <3>1 + <3>7. QED + BY <3>3, <3>5, <3>6 + <2>2. (c \in -1..(b-1)) /\ (c # -1) /\ (c \in Ballot) + BY SMT DEF Ballot + <2>3. PICK a0 \in Q : ~DidNotVoteIn(a0, c) + BY <2>1 + <2>4. PICK v \in Value : VotedFor(a0, c, v) + BY <2>3 DEF DidNotVoteIn + <2>5. \A a \in Q : \A w \in Value : + VotedFor(a, c, w) => (w = v) + BY <2>2, <2>4, QA, <1>1 DEF VInv3 + <2>6. SafeAt(c, v) + BY <1>1, <2>4, QA, <2>2 DEF VInv2 + <2>7. QED + BY <2>1, <2>2, <2>5, <2>6 + +<1>7. QED + BY <1>5, <1>6 + +LiveAssumption == + \E Q \in Quorum, b \in Ballot : + \A self \in Q : + /\ WF_vars(BallotAction(self, b)) + /\ [] [\A c \in Ballot : (c > b) => ~ BallotAction(self, c)]_vars + +LiveSpec == Spec /\ LiveAssumption +=============================================================================== diff --git a/tlatools/test-model/pcal/.gitignore b/tlatools/test-model/pcal/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..9c80bdb55a33e4c24f2350408a3b543eb16da4e9 --- /dev/null +++ b/tlatools/test-model/pcal/.gitignore @@ -0,0 +1,52 @@ +*.old +/MPNoParams.cfg +/CallReturn1.cfg +/Euclid2.cfg +/EvenOdd.cfg +/EvenOddBad.cfg +/Factorial.cfg +/Factorial2.cfg +/InnerLabeledIf.cfg +/MultiAssignment.cfg +/MultiProc2.cfg +/MultiprocDefine.cfg +/NoLoop.cfg +/NoLoop2.cfg +/NoParams.cfg +/NotSoSimpleLoop.cfg +/Quicksort.cfg +/SimpleLoop.cfg +/SimpleLoopWithProcedure.cfg +/SimpleMultiProc.cfg +/TestTabs.cfg +/UniprocDefine.cfg +/bug_05_10_03.cfg +/bug_05_12_10a.cfg +/bug_05_12_16b.cfg +/bug_05_12_31.cfg +/bug_06_01_25.cfg +/bug_07_03_30.cfg +/bug_07_06_05.cfg +/Either1.cfg +/Either2.cfg +/Either3.cfg +/Either4.cfg +/Either5.cfg +/Euclid3.cfg +/MPFactorial.cfg +/MPFactorial2.cfg +/TestReplace.cfg +/SubSub.cfg +/TestPCandStack.cfg +/Test.cfg +/ULCallReturn1.cfg +/ULFactorial2.cfg +/ReallySimpleMultiProc.cfg +/NestedMacros.cfg +/FairSeq2.cfg +/DiningPhilosophers2.cfg +/CallReturn2.cfg +/CCallReturn1.cfg +/CMultiprocDefine.cfg +/CEither1.cfg +/StackTest.cfg diff --git a/tlatools/test-model/pcal/Bakery.cfg b/tlatools/test-model/pcal/Bakery.cfg new file mode 100644 index 0000000000000000000000000000000000000000..9209a00c6288aab93977bdf9e85b204efd16702f --- /dev/null +++ b/tlatools/test-model/pcal/Bakery.cfg @@ -0,0 +1,7 @@ +SPECIFICATION Spec +\* Add statements after this line. +CONSTANTS NumProcs = 2 + MaxNum = 3 +INVARIANT Invariant +CONSTRAINT Constraint + diff --git a/tlatools/test-model/pcal/Bakery.tla b/tlatools/test-model/pcal/Bakery.tla new file mode 100644 index 0000000000000000000000000000000000000000..b840cf6e69330a3a659351351e0c659b4795fa40 --- /dev/null +++ b/tlatools/test-model/pcal/Bakery.tla @@ -0,0 +1,139 @@ +------------------------------- MODULE Bakery -------------------------------- +EXTENDS Naturals, TLC + +CONSTANTS NumProcs, \* The number of processes + MaxNum \* For TLC, the maximum value of num[i]. + +Proc == 1..NumProcs \* The set of processes + +(* + + --algorithm Bakery + variable num = [i \in Proc |-> 0] ; + choosing = [i \in Proc |-> FALSE]; + process proc \in Proc + variables read = { }; max = 0 ; nxt = self ; + begin loop : while TRUE + do choosing[self] := TRUE; + read := { self }; + max := 0 ; + d1 : while read # Proc + do with p \in Proc \ read + do if num[p] > max + then max := num[p]; + end if ; + read := read \cup {p}; + end with ; + end while ; + d2 : num[self] := max + 1 ; + d3 : choosing[self] := FALSE ; + read := { self } ; + w1 : while read # Proc + do with p \in Proc \ read + do when ~ choosing[p] ; + nxt := p ; + end with; + w2: when \/ num[nxt] = 0 + \/ num[nxt] > num[self] + \/ /\ num[nxt] = num[self] + /\ nxt > self ; + read := read \cup { nxt } ; + end while; + cs : when TRUE ; + exit : num[self] := 0; + end while; + end process + end algorithm + + +*) + +(***** BEGIN TRANSLATION ***) +VARIABLES num, choosing, pc, read, max, nxt + +vars == << num, choosing, pc, read, max, nxt >> + +ProcSet == (Proc) + +Init == (* Global variables *) + /\ num = [i \in Proc |-> 0] + /\ choosing = [i \in Proc |-> FALSE] + (* Process proc *) + /\ read = [self \in Proc |-> { }] + /\ max = [self \in Proc |-> 0] + /\ nxt = [self \in Proc |-> self] + /\ pc = [self \in ProcSet |-> "loop"] + +loop(self) == /\ pc[self] = "loop" + /\ choosing' = [choosing EXCEPT ![self] = TRUE] + /\ read' = [read EXCEPT ![self] = { self }] + /\ max' = [max EXCEPT ![self] = 0] + /\ pc' = [pc EXCEPT ![self] = "d1"] + /\ UNCHANGED << num, nxt >> + +d1(self) == /\ pc[self] = "d1" + /\ IF read[self] # Proc + THEN /\ \E p \in Proc \ read[self]: + /\ IF num[p] > max[self] + THEN /\ max' = [max EXCEPT ![self] = num[p]] + ELSE /\ TRUE + /\ max' = max + /\ read' = [read EXCEPT ![self] = read[self] \cup {p}] + /\ pc' = [pc EXCEPT ![self] = "d1"] + ELSE /\ pc' = [pc EXCEPT ![self] = "d2"] + /\ UNCHANGED << read, max >> + /\ UNCHANGED << num, choosing, nxt >> + +d2(self) == /\ pc[self] = "d2" + /\ num' = [num EXCEPT ![self] = max[self] + 1] + /\ pc' = [pc EXCEPT ![self] = "d3"] + /\ UNCHANGED << choosing, read, max, nxt >> + +d3(self) == /\ pc[self] = "d3" + /\ choosing' = [choosing EXCEPT ![self] = FALSE] + /\ read' = [read EXCEPT ![self] = { self }] + /\ pc' = [pc EXCEPT ![self] = "w1"] + /\ UNCHANGED << num, max, nxt >> + +w1(self) == /\ pc[self] = "w1" + /\ IF read[self] # Proc + THEN /\ \E p \in Proc \ read[self]: + /\ ~ choosing[p] + /\ nxt' = [nxt EXCEPT ![self] = p] + /\ pc' = [pc EXCEPT ![self] = "w2"] + ELSE /\ pc' = [pc EXCEPT ![self] = "cs"] + /\ nxt' = nxt + /\ UNCHANGED << num, choosing, read, max >> + +w2(self) == /\ pc[self] = "w2" + /\ \/ num[nxt[self]] = 0 + \/ num[nxt[self]] > num[self] + \/ /\ num[nxt[self]] = num[self] + /\ nxt[self] > self + /\ read' = [read EXCEPT ![self] = read[self] \cup { nxt[self] }] + /\ pc' = [pc EXCEPT ![self] = "w1"] + /\ UNCHANGED << num, choosing, max, nxt >> + +cs(self) == /\ pc[self] = "cs" + /\ TRUE + /\ pc' = [pc EXCEPT ![self] = "exit"] + /\ UNCHANGED << num, choosing, read, max, nxt >> + +exit(self) == /\ pc[self] = "exit" + /\ num' = [num EXCEPT ![self] = 0] + /\ pc' = [pc EXCEPT ![self] = "loop"] + /\ UNCHANGED << choosing, read, max, nxt >> + +proc(self) == loop(self) \/ d1(self) \/ d2(self) \/ d3(self) \/ w1(self) + \/ w2(self) \/ cs(self) \/ exit(self) + +Next == (\E self \in Proc: proc(self)) + +Spec == Init /\ [][Next]_vars + +(***** END TRANSLATION ***) + +Constraint == \A i \in Proc : num[i] \leq MaxNum + +Invariant == \A i, j \in Proc : (pc[i] = "cs") /\ (pc[j] = "cs") => (i = j) +============================================================================= diff --git a/tlatools/test-model/pcal/CBakery.cfg b/tlatools/test-model/pcal/CBakery.cfg new file mode 100644 index 0000000000000000000000000000000000000000..160ae67b63d374a55ca52cb9be22f91b17a00535 --- /dev/null +++ b/tlatools/test-model/pcal/CBakery.cfg @@ -0,0 +1,5 @@ +SPECIFICATION Spec +\* Add statements after this line. +CONSTANT NumProcs = 2 MaxNum = 2 +INVARIANT Invariant +CONSTRAINT Constraint diff --git a/tlatools/test-model/pcal/CBakery.tla b/tlatools/test-model/pcal/CBakery.tla new file mode 100644 index 0000000000000000000000000000000000000000..86115029006d0a52e23fb4bfec8e4590fb847a3e --- /dev/null +++ b/tlatools/test-model/pcal/CBakery.tla @@ -0,0 +1,128 @@ +------------------------------- MODULE CBakery ------------------------------- +EXTENDS Naturals, TLC + +CONSTANTS NumProcs, \* The number of processes + MaxNum \* For TLC, the maximum value of num[i]. + +Proc == 1..NumProcs \* The set of processes + +(******** + --algorithm Bakery { + variable num = [i \in Proc |-> 0] ; + choosing = [i \in Proc |-> FALSE]; + process (proc \in Proc) + variables read = { }; max = 0 ; nxt = self ; + { loop : while (TRUE) { + choosing[self] := TRUE; + read := { self }; + max := 0 ; + d1 : while (read # Proc) + with (p \in Proc \ read) { + if (num[p] > max) max := num[p]; + read := read \cup {p} } ; + d2 : num[self] := max + 1 ; + d3 : choosing[self] := FALSE ; + read := { self } ; + w1 : while (read # Proc) { + with (p \in Proc \ read) { + when ~ choosing[p] ; + nxt := p } ; + w2: when \/ num[nxt] = 0 + \/ num[nxt] > num[self] + \/ /\ num[nxt] = num[self] + /\ nxt > self ; + read := read \cup { nxt } }; + cs : when TRUE ; + exit : num[self] := 0; } } } +********) + + +\******** BEGIN TRANSLATION ******** +VARIABLES num, choosing, pc, read, max, nxt + +vars == << num, choosing, pc, read, max, nxt >> + +ProcSet == (Proc) + +Init == (* Global variables *) + /\ num = [i \in Proc |-> 0] + /\ choosing = [i \in Proc |-> FALSE] + (* Process proc *) + /\ read = [self \in Proc |-> { }] + /\ max = [self \in Proc |-> 0] + /\ nxt = [self \in Proc |-> self] + /\ pc = [self \in ProcSet |-> "loop"] + +loop(self) == /\ pc[self] = "loop" + /\ choosing' = [choosing EXCEPT ![self] = TRUE] + /\ read' = [read EXCEPT ![self] = { self }] + /\ max' = [max EXCEPT ![self] = 0] + /\ pc' = [pc EXCEPT ![self] = "d1"] + /\ UNCHANGED << num, nxt >> + +d1(self) == /\ pc[self] = "d1" + /\ IF read[self] # Proc + THEN /\ \E p \in Proc \ read[self]: + /\ IF num[p] > max[self] + THEN /\ max' = [max EXCEPT ![self] = num[p]] + ELSE /\ TRUE + /\ max' = max + /\ read' = [read EXCEPT ![self] = read[self] \cup {p}] + /\ pc' = [pc EXCEPT ![self] = "d1"] + ELSE /\ pc' = [pc EXCEPT ![self] = "d2"] + /\ UNCHANGED << read, max >> + /\ UNCHANGED << num, choosing, nxt >> + +d2(self) == /\ pc[self] = "d2" + /\ num' = [num EXCEPT ![self] = max[self] + 1] + /\ pc' = [pc EXCEPT ![self] = "d3"] + /\ UNCHANGED << choosing, read, max, nxt >> + +d3(self) == /\ pc[self] = "d3" + /\ choosing' = [choosing EXCEPT ![self] = FALSE] + /\ read' = [read EXCEPT ![self] = { self }] + /\ pc' = [pc EXCEPT ![self] = "w1"] + /\ UNCHANGED << num, max, nxt >> + +w1(self) == /\ pc[self] = "w1" + /\ IF read[self] # Proc + THEN /\ \E p \in Proc \ read[self]: + /\ ~ choosing[p] + /\ nxt' = [nxt EXCEPT ![self] = p] + /\ pc' = [pc EXCEPT ![self] = "w2"] + ELSE /\ pc' = [pc EXCEPT ![self] = "cs"] + /\ nxt' = nxt + /\ UNCHANGED << num, choosing, read, max >> + +w2(self) == /\ pc[self] = "w2" + /\ \/ num[nxt[self]] = 0 + \/ num[nxt[self]] > num[self] + \/ /\ num[nxt[self]] = num[self] + /\ nxt[self] > self + /\ read' = [read EXCEPT ![self] = read[self] \cup { nxt[self] }] + /\ pc' = [pc EXCEPT ![self] = "w1"] + /\ UNCHANGED << num, choosing, max, nxt >> + +cs(self) == /\ pc[self] = "cs" + /\ TRUE + /\ pc' = [pc EXCEPT ![self] = "exit"] + /\ UNCHANGED << num, choosing, read, max, nxt >> + +exit(self) == /\ pc[self] = "exit" + /\ num' = [num EXCEPT ![self] = 0] + /\ pc' = [pc EXCEPT ![self] = "loop"] + /\ UNCHANGED << choosing, read, max, nxt >> + +proc(self) == loop(self) \/ d1(self) \/ d2(self) \/ d3(self) \/ w1(self) + \/ w2(self) \/ cs(self) \/ exit(self) + +Next == (\E self \in Proc: proc(self)) + +Spec == Init /\ [][Next]_vars + +\******** END TRANSLATION ******** +Constraint +== \A i \in Proc : num[i] \leq MaxNum + +Invariant == \A i, j \in Proc : (pc[i] = "cs") /\ (pc[j] = "cs") => (i = j) +============================================================================= diff --git a/tlatools/test-model/pcal/CCallReturn1.tla b/tlatools/test-model/pcal/CCallReturn1.tla new file mode 100644 index 0000000000000000000000000000000000000000..5d0361ccbdc65799105abc5ff13a24a3681a50ec --- /dev/null +++ b/tlatools/test-model/pcal/CCallReturn1.tla @@ -0,0 +1,122 @@ +------------------------------ MODULE CCallReturn1 -------------------------- +EXTENDS Sequences, Naturals, TLC + +(* + --algorithm CallReturn1 { + procedure Proc1(arg1 = 0) + variable u = 1 ; + { p1 : u := 2 ; + call Proc2 ( 2 * u ) ; + p2 : assert u = 2; + assert arg1 = 4 ; + call Proc2 ( 2 * u + 1 ) ; + return ; } + + procedure Proc2(arg2 = 0) + variable v = 42 ; + { q1 : assert v = 42; + assert arg2 \in {4, 5} ; + call Proc3 ( v + arg2 ) ; + return } + + procedure Proc3(arg3 = 0) + { r1 : assert arg3 \in {46, 47} ; + return ; } ; + + { + a1 : call Proc1( 4 ) ; + } } + +*) + +(***** BEGIN TRANSLATION ***) +VARIABLES pc, stack, arg1, u, arg2, v, arg3 + +vars == << pc, stack, arg1, u, arg2, v, arg3 >> + +Init == (* Procedure Proc1 *) + /\ arg1 = 0 + /\ u = 1 + (* Procedure Proc2 *) + /\ arg2 = 0 + /\ v = 42 + (* Procedure Proc3 *) + /\ arg3 = 0 + /\ stack = << >> + /\ pc = "a1" + +p1 == /\ pc = "p1" + /\ u' = 2 + /\ /\ arg2' = 2 * u' + /\ stack' = << [ procedure |-> "Proc2", + pc |-> "p2", + v |-> v, + arg2 |-> arg2 ] >> + \o stack + /\ v' = 42 + /\ pc' = "q1" + /\ UNCHANGED << arg1, arg3 >> + +p2 == /\ pc = "p2" + /\ Assert(u = 2, "Failure of assertion at line 10, column 18.") + /\ Assert(arg1 = 4, "Failure of assertion at line 11, column 18.") + /\ /\ arg2' = 2 * u + 1 + /\ stack' = << [ procedure |-> "Proc2", + pc |-> Head(stack).pc, + v |-> v, + arg2 |-> arg2 ] >> + \o Tail(stack) + /\ u' = Head(stack).u + /\ v' = 42 + /\ pc' = "q1" + /\ UNCHANGED << arg1, arg3 >> + +Proc1 == p1 \/ p2 + +q1 == /\ pc = "q1" + /\ Assert(v = 42, "Failure of assertion at line 17, column 18.") + /\ Assert(arg2 \in {4, 5}, + "Failure of assertion at line 18, column 18.") + /\ /\ arg3' = v + arg2 + /\ stack' = << [ procedure |-> "Proc3", + pc |-> Head(stack).pc, + arg3 |-> arg3 ] >> + \o Tail(stack) + /\ v' = Head(stack).v + /\ pc' = "r1" + /\ UNCHANGED << arg1, u, arg2 >> + +Proc2 == q1 + +r1 == /\ pc = "r1" + /\ Assert(arg3 \in {46, 47}, + "Failure of assertion at line 23, column 18.") + /\ pc' = Head(stack).pc + /\ arg3' = Head(stack).arg3 + /\ stack' = Tail(stack) + /\ UNCHANGED << arg1, u, arg2, v >> + +Proc3 == r1 + +a1 == /\ pc = "a1" + /\ /\ arg1' = 4 + /\ stack' = << [ procedure |-> "Proc1", + pc |-> "Done", + u |-> u, + arg1 |-> arg1 ] >> + \o stack + /\ u' = 1 + /\ pc' = "p1" + /\ UNCHANGED << arg2, v, arg3 >> + +Next == Proc1 \/ Proc2 \/ Proc3 \/ a1 + \/ (* Disjunct to prevent deadlock on termination *) + (pc = "Done" /\ UNCHANGED vars) + +Spec == /\ Init /\ [][Next]_vars + /\ WF_vars(Next) + +Termination == <>(pc = "Done") + +(***** END TRANSLATION ***) +============================================================================= diff --git a/tlatools/test-model/pcal/CDiningPhilosophers.cfg b/tlatools/test-model/pcal/CDiningPhilosophers.cfg new file mode 100644 index 0000000000000000000000000000000000000000..3085671a0184b6469a675a0dc98a806ed20d917e --- /dev/null +++ b/tlatools/test-model/pcal/CDiningPhilosophers.cfg @@ -0,0 +1,4 @@ +SPECIFICATION Spec +\* Add statements after this line. +INVARIANT Invariant +CONSTANT N = 4 diff --git a/tlatools/test-model/pcal/CDiningPhilosophers.tla b/tlatools/test-model/pcal/CDiningPhilosophers.tla new file mode 100644 index 0000000000000000000000000000000000000000..43ac828828221099d99ec2f28c487cecc3674c10 --- /dev/null +++ b/tlatools/test-model/pcal/CDiningPhilosophers.tla @@ -0,0 +1,120 @@ +-------------------------- MODULE CDiningPhilosophers ------------------------ + +(***************************************************************************) +(* A simple solution to the Dining Philosophers problem in which processes *) +(* 1 through N-1 pick up their lef then their right forks, and process 0 *) +(* picks them up in the opposite order. *) +(***************************************************************************) + +EXTENDS Naturals + +CONSTANT N + +ASSUME N \in Nat + +(******** +--algorithm DiningPhilosophers { + variable sem = [i \in 0..(N-1) |-> 1] ; + +process (Proc \in 1..(N-1)) { +l1 : while (TRUE) { + { when sem[self] = 1 ; \* Get right fork. + sem[self] := 0 } ; + l2 : { when sem[(self-1) % N] = 1 ; \* Get left fork. + sem[(self-1) % N] := 0 } ; + e : { skip } ; \* Eat + l3 : { sem[self] := 1 } ; \* Release right fork. + l4 : { sem[(self-1) % N] := 1 } ; \* Release left fork. + }} + +process (Proc0 = 0) +{ +l01 : while (TRUE) + { when sem[N-1] = 1 ; \* get left fork + sem[N-1] := 0 ; + l02 : when sem[0] = 1 ; \* get right fork + sem[0] := 0 ; + e0 : skip ; \* eat + l03 : sem[0] := 1 ; \* release left fork + l04 : sem[N-1] := 1 ; \* release right fork + } +} } +********) +\******** BEGIN TRANSLATION ******** +VARIABLES sem, pc + +vars == << sem, pc >> + +ProcSet == (1..(N-1)) \cup {0} + +Init == (* Global variables *) + /\ sem = [i \in 0..(N-1) |-> 1] + /\ pc = [self \in ProcSet |-> CASE self \in 1..(N-1) -> "l1" + [] self = 0 -> "l01"] + +l1(self) == /\ pc[self] = "l1" + /\ sem[self] = 1 + /\ sem' = [sem EXCEPT ![self] = 0] + /\ pc' = [pc EXCEPT ![self] = "l2"] + +l2(self) == /\ pc[self] = "l2" + /\ sem[(self-1) % N] = 1 + /\ sem' = [sem EXCEPT ![(self-1) % N] = 0] + /\ pc' = [pc EXCEPT ![self] = "e"] + +e(self) == /\ pc[self] = "e" + /\ TRUE + /\ pc' = [pc EXCEPT ![self] = "l3"] + /\ sem' = sem + +l3(self) == /\ pc[self] = "l3" + /\ sem' = [sem EXCEPT ![self] = 1] + /\ pc' = [pc EXCEPT ![self] = "l4"] + +l4(self) == /\ pc[self] = "l4" + /\ sem' = [sem EXCEPT ![(self-1) % N] = 1] + /\ pc' = [pc EXCEPT ![self] = "l1"] + +Proc(self) == l1(self) \/ l2(self) \/ e(self) \/ l3(self) \/ l4(self) + +l01 == /\ pc[0] = "l01" + /\ sem[N-1] = 1 + /\ sem' = [sem EXCEPT ![N-1] = 0] + /\ pc' = [pc EXCEPT ![0] = "l02"] + +l02 == /\ pc[0] = "l02" + /\ sem[0] = 1 + /\ sem' = [sem EXCEPT ![0] = 0] + /\ pc' = [pc EXCEPT ![0] = "e0"] + +e0 == /\ pc[0] = "e0" + /\ TRUE + /\ pc' = [pc EXCEPT ![0] = "l03"] + /\ sem' = sem + +l03 == /\ pc[0] = "l03" + /\ sem' = [sem EXCEPT ![0] = 1] + /\ pc' = [pc EXCEPT ![0] = "l04"] + +l04 == /\ pc[0] = "l04" + /\ sem' = [sem EXCEPT ![N-1] = 1] + /\ pc' = [pc EXCEPT ![0] = "l01"] + +Proc0 == l01 \/ l02 \/ e0 \/ l03 \/ l04 + +Next == Proc0 + \/ (\E self \in 1..(N-1): Proc(self)) + +Spec == /\ Init /\ [][Next]_vars + /\ \A self \in 1..(N-1) : SF_vars(Proc(self)) + /\ SF_vars(Proc0) + +\******** END TRANSLATION ******** + +IsEating(i) == IF i = 0 THEN pc[i] = "e0" + ELSE pc[i] = "e" + +Invariant == \A i \in 0..(N-1) : ~ (IsEating(i) /\ IsEating((i+1)%N)) + +StarvationFree == \A i \in 0..(N-1) : []<> IsEating(i) +============================================================================= diff --git a/tlatools/test-model/pcal/CEither1.tla b/tlatools/test-model/pcal/CEither1.tla new file mode 100644 index 0000000000000000000000000000000000000000..69efa80a27cc8ba79f3a5be18d796a840a8c8667 --- /dev/null +++ b/tlatools/test-model/pcal/CEither1.tla @@ -0,0 +1,58 @@ +------------------------------- MODULE CEither1 ----------------------------- +EXTENDS Naturals, Sequences, TLC + +(* --algorithm Either { + variables x = 0 ; y = 0 ; + { a: either {x := 1 ; b: x := x + 1;} ; + or { y := 1 ; c: y := y + 1;} ; +\* end either ; + d: assert x+y = 2 ; + } } + +*) + +\* BEGIN TRANSLATION +VARIABLES x, y, pc + +vars == << x, y, pc >> + +Init == (* Global variables *) + /\ x = 0 + /\ y = 0 + /\ pc = "a" + +a == /\ pc = "a" + /\ \/ /\ x' = 1 + /\ pc' = "b" + /\ y' = y + \/ /\ y' = 1 + /\ pc' = "c" + /\ x' = x + +b == /\ pc = "b" + /\ x' = x + 1 + /\ pc' = "d" + /\ y' = y + +c == /\ pc = "c" + /\ y' = y + 1 + /\ pc' = "d" + /\ x' = x + +d == /\ pc = "d" + /\ Assert(x+y = 2, "Failure of assertion at line 9, column 16.") + /\ pc' = "Done" + /\ UNCHANGED << x, y >> + +Next == a \/ b \/ c \/ d + \/ (* Disjunct to prevent deadlock on termination *) + (pc = "Done" /\ UNCHANGED vars) + +Spec == /\ Init /\ [][Next]_vars + /\ WF_vars(Next) + +Termination == <>(pc = "Done") + +\* END TRANSLATION + +============================================================================= diff --git a/tlatools/test-model/pcal/CMultiprocDefine.tla b/tlatools/test-model/pcal/CMultiprocDefine.tla new file mode 100644 index 0000000000000000000000000000000000000000..020e5eb3d0affe7a510fc4860e416f2f1d610168 --- /dev/null +++ b/tlatools/test-model/pcal/CMultiprocDefine.tla @@ -0,0 +1,56 @@ +---------------------------- MODULE CMultiprocDefine ------------------------- +EXTENDS Naturals, Sequences, TLC + +(* +--algorithm MultiprocDefine { + variables n = 0 ; + define { nplus1 == n + 1 + nplus2 == nplus1 + 1 } ; + process (Proc \in {1, 2, 3}) + variables i ; + { main : i := nplus2 ; + assert i = 2 ; + } } + +*) + +(***** BEGIN TRANSLATION ***) +CONSTANT defaultInitValue +VARIABLES n, pc + +(* define statement *) +nplus1 == n + 1 +nplus2 == nplus1 + 1 + +VARIABLE i + +vars == << n, pc, i >> + +ProcSet == ({1, 2, 3}) + +Init == (* Global variables *) + /\ n = 0 + (* Process Proc *) + /\ i = [self \in {1, 2, 3} |-> defaultInitValue] + /\ pc = [self \in ProcSet |-> "main"] + +main(self) == /\ pc[self] = "main" + /\ i' = [i EXCEPT ![self] = nplus2] + /\ Assert(i'[self] = 2, + "Failure of assertion at line 12, column 14.") + /\ pc' = [pc EXCEPT ![self] = "Done"] + /\ n' = n + +Proc(self) == main(self) + +Next == (\E self \in {1, 2, 3}: Proc(self)) + \/ (* Disjunct to prevent deadlock on termination *) + ((\A self \in ProcSet: pc[self] = "Done") /\ UNCHANGED vars) + +Spec == /\ Init /\ [][Next]_vars + /\ \A self \in {1, 2, 3} : WF_vars(Proc(self)) + +Termination == <>(\A self \in ProcSet: pc[self] = "Done") + +(***** END TRANSLATION ***) +============================================================================= diff --git a/tlatools/test-model/pcal/CallReturn1.tla b/tlatools/test-model/pcal/CallReturn1.tla new file mode 100644 index 0000000000000000000000000000000000000000..ca26d0b2cc3670d8ae537748b424989aad2b2b15 --- /dev/null +++ b/tlatools/test-model/pcal/CallReturn1.tla @@ -0,0 +1,124 @@ +------------------------------ MODULE CallReturn1 --------------------------- +EXTENDS Sequences, Naturals, TLC + +(******** +--algorithm CallReturn1 + procedure Proc1(arg1) + variable u ; + begin p1 : u := 2 ; + call Proc2 ( 2 * u ) ; + p2 : assert u = 2; + assert arg1 = 4 ; + call Proc2 ( 2 * u + 1 ) ; + return ; + end procedure + procedure Proc2(arg2 = 0) + variable v = 42 ; + begin q1 : assert v = 42; + assert arg2 \in {4, 5} ; + call Proc3 ( v + arg2 ) ; + return ; + end procedure + procedure Proc3(arg3 = 0) + begin r1 : assert arg3 \in {46, 47} ; + return ; + end procedure + begin + a1 : call Proc1( 4 ) ; + end algorithm +*****) + +\******** BEGIN TRANSLATION ******** +CONSTANT defaultInitValue +VARIABLES pc, stack, arg1, u, arg2, v, arg3 + +vars == << pc, stack, arg1, u, arg2, v, arg3 >> + +Init == (* Procedure Proc1 *) + /\ arg1 = defaultInitValue + /\ u = defaultInitValue + (* Procedure Proc2 *) + /\ arg2 = 0 + /\ v = 42 + (* Procedure Proc3 *) + /\ arg3 = 0 + /\ stack = << >> + /\ pc = "a1" + +p1 == /\ pc = "p1" + /\ u' = 2 + /\ /\ arg2' = 2 * u' + /\ stack' = << [ procedure |-> "Proc2", + pc |-> "p2", + v |-> v, + arg2 |-> arg2 ] >> + \o stack + /\ v' = 42 + /\ pc' = "q1" + /\ UNCHANGED << arg1, arg3 >> + +p2 == /\ pc = "p2" + /\ Assert(u = 2, "Failure of assertion at line 10, column 18.") + /\ Assert(arg1 = 4, "Failure of assertion at line 11, column 18.") + /\ /\ arg2' = 2 * u + 1 + /\ stack' = << [ procedure |-> "Proc2", + pc |-> Head(stack).pc, + v |-> v, + arg2 |-> arg2 ] >> + \o Tail(stack) + /\ u' = Head(stack).u + /\ v' = 42 + /\ pc' = "q1" + /\ UNCHANGED << arg1, arg3 >> + +Proc1 == p1 \/ p2 + +q1 == /\ pc = "q1" + /\ Assert(v = 42, "Failure of assertion at line 17, column 18.") + /\ Assert(arg2 \in {4, 5}, + "Failure of assertion at line 18, column 18.") + /\ /\ arg3' = v + arg2 + /\ stack' = << [ procedure |-> "Proc3", + pc |-> Head(stack).pc, + arg3 |-> arg3 ] >> + \o Tail(stack) + /\ v' = Head(stack).v + /\ pc' = "r1" + /\ UNCHANGED << arg1, u, arg2 >> + +Proc2 == q1 + +r1 == /\ pc = "r1" + /\ Assert(arg3 \in {46, 47}, + "Failure of assertion at line 23, column 18.") + /\ pc' = Head(stack).pc + /\ arg3' = Head(stack).arg3 + /\ stack' = Tail(stack) + /\ UNCHANGED << arg1, u, arg2, v >> + +Proc3 == r1 + +a1 == /\ pc = "a1" + /\ /\ arg1' = 4 + /\ stack' = << [ procedure |-> "Proc1", + pc |-> "Done", + u |-> u, + arg1 |-> arg1 ] >> + \o stack + /\ u' = defaultInitValue + /\ pc' = "p1" + /\ UNCHANGED << arg2, v, arg3 >> + +Next == Proc1 \/ Proc2 \/ Proc3 \/ a1 + \/ (* Disjunct to prevent deadlock on termination *) + (pc = "Done" /\ UNCHANGED vars) + +Spec == /\ Init /\ [][Next]_vars + /\ WF_vars(Next) + +Termination == <>(pc = "Done") + +\******** END TRANSLATION ******** + + +============================================================================= diff --git a/tlatools/test-model/pcal/CallReturn2.tla b/tlatools/test-model/pcal/CallReturn2.tla new file mode 100644 index 0000000000000000000000000000000000000000..a7b88d2c7c161524b519012ca957070345fc52ee --- /dev/null +++ b/tlatools/test-model/pcal/CallReturn2.tla @@ -0,0 +1,197 @@ +The translator is not properly initializing the local procedure variables. +The assertions indicate how they should be initialized. (The OldPlusCal +and Pcal translations have this problem too.) + +----------------------------- MODULE CallReturn2 ----------------------------- +EXTENDS Naturals, Sequences, TLC + + +(* +--algorithm Test + variable depth = 3 + procedure P(a = 7) + variable x = a ; y = x+1 ; + begin P1: assert a = 1; + assert x = a; + assert y = a+1; + return; + end procedure + procedure Q() + begin Q1: call P(1) ; + return ; + end procedure + procedure PP(aa = 7) + variable xx = aa ; yy = xx+1 ; + begin PP1: if depth > 0 + then assert aa = 1; + assert xx = aa; + assert yy = aa+1; + depth := depth - 1 ; + call PP(1) ; + return; + else return + end if + end procedure + procedure R(r = 0) + variable x + begin R1: x := 2 ; + R2: call S(x) ; + return + end procedure + procedure S(s) + begin S1: assert s = 2 ; + return ; + end procedure + begin A: call P(1) ; + B: call Q() ; + C: call PP(1) ; + end algorithm +*) + +(***** BEGIN TRANSLATION ***) +\* Procedure variable x of procedure P at line 13 col 16 changed to x_ +CONSTANT defaultInitValue +VARIABLES depth, pc, stack, a, x_, y, aa, xx, yy, r, x, s + +vars == << depth, pc, stack, a, x_, y, aa, xx, yy, r, x, s >> + +Init == (* Global variables *) + /\ depth = 3 + (* Procedure P *) + /\ a = 7 + /\ x_ = a + /\ y = x_+1 + (* Procedure PP *) + /\ aa = 7 + /\ xx = aa + /\ yy = xx+1 + (* Procedure R *) + /\ r = 0 + /\ x = defaultInitValue + (* Procedure S *) + /\ s = defaultInitValue + /\ stack = << >> + /\ pc = "A" + +P1 == /\ pc = "P1" + /\ Assert(a = 1, "Failure of assertion at line 14, column 17.") + /\ Assert(x_ = a, "Failure of assertion at line 15, column 17.") + /\ Assert(y = a+1, "Failure of assertion at line 16, column 17.") + /\ pc' = Head(stack).pc + /\ x_' = Head(stack).x_ + /\ y' = Head(stack).y + /\ a' = Head(stack).a + /\ stack' = Tail(stack) + /\ UNCHANGED << depth, aa, xx, yy, r, x, s >> + +P == P1 + +Q1 == /\ pc = "Q1" + /\ /\ a' = 1 + /\ stack' = << [ procedure |-> "P", + pc |-> Head(stack).pc, + x_ |-> x_, + y |-> y, + a |-> a ] >> + \o Tail(stack) + /\ x_' = a' + /\ y' = x_'+1 + /\ pc' = "P1" + /\ UNCHANGED << depth, aa, xx, yy, r, x, s >> + +Q == Q1 + +PP1 == /\ pc = "PP1" + /\ IF depth > 0 + THEN /\ Assert(aa = 1, + "Failure of assertion at line 26, column 24.") + /\ Assert(xx = aa, + "Failure of assertion at line 27, column 22.") + /\ Assert(yy = aa+1, + "Failure of assertion at line 28, column 22.") + /\ depth' = depth - 1 + /\ aa' = 1 + /\ xx' = aa' + /\ yy' = xx'+1 + /\ pc' = "PP1" + /\ stack' = stack + ELSE /\ pc' = Head(stack).pc + /\ xx' = Head(stack).xx + /\ yy' = Head(stack).yy + /\ aa' = Head(stack).aa + /\ stack' = Tail(stack) + /\ depth' = depth + /\ UNCHANGED << a, x_, y, r, x, s >> + +PP == PP1 + +R1 == /\ pc = "R1" + /\ x' = 2 + /\ pc' = "R2" + /\ UNCHANGED << depth, stack, a, x_, y, aa, xx, yy, r, s >> + +R2 == /\ pc = "R2" + /\ /\ s' = x + /\ stack' = << [ procedure |-> "S", + pc |-> Head(stack).pc, + s |-> s ] >> + \o Tail(stack) + /\ x' = Head(stack).x + /\ pc' = "S1" + /\ UNCHANGED << depth, a, x_, y, aa, xx, yy, r >> + +R == R1 \/ R2 + +S1 == /\ pc = "S1" + /\ Assert(s = 2, "Failure of assertion at line 42, column 15.") + /\ pc' = Head(stack).pc + /\ s' = Head(stack).s + /\ stack' = Tail(stack) + /\ UNCHANGED << depth, a, x_, y, aa, xx, yy, r, x >> + +S == S1 + +A == /\ pc = "A" + /\ /\ a' = 1 + /\ stack' = << [ procedure |-> "P", + pc |-> "B", + x_ |-> x_, + y |-> y, + a |-> a ] >> + \o stack + /\ x_' = a' + /\ y' = x_'+1 + /\ pc' = "P1" + /\ UNCHANGED << depth, aa, xx, yy, r, x, s >> + +B == /\ pc = "B" + /\ stack' = << [ procedure |-> "Q", + pc |-> "C" ] >> + \o stack + /\ pc' = "Q1" + /\ UNCHANGED << depth, a, x_, y, aa, xx, yy, r, x, s >> + +C == /\ pc = "C" + /\ /\ aa' = 1 + /\ stack' = << [ procedure |-> "PP", + pc |-> "Done", + xx |-> xx, + yy |-> yy, + aa |-> aa ] >> + \o stack + /\ xx' = aa' + /\ yy' = xx'+1 + /\ pc' = "PP1" + /\ UNCHANGED << depth, a, x_, y, r, x, s >> + +Next == P \/ Q \/ PP \/ R \/ S \/ A \/ B \/ C + \/ (* Disjunct to prevent deadlock on termination *) + (pc = "Done" /\ UNCHANGED vars) + +Spec == /\ Init /\ [][Next]_vars + /\ WF_vars(Next) + +Termination == <>(pc = "Done") + +(***** END TRANSLATION ***) +============================================================================= diff --git a/tlatools/test-model/pcal/DetlefSpec.cfg b/tlatools/test-model/pcal/DetlefSpec.cfg new file mode 100644 index 0000000000000000000000000000000000000000..69620fba44afdea8180a8923da52a55736e4ddf0 --- /dev/null +++ b/tlatools/test-model/pcal/DetlefSpec.cfg @@ -0,0 +1,7 @@ +SPECIFICATION Spec +\* Add statements after this line. +CONSTANTS Val = {v1} + Procs = {p1} + N = 3 + null = null +CONSTRAINT Constraint diff --git a/tlatools/test-model/pcal/DetlefSpec.tla b/tlatools/test-model/pcal/DetlefSpec.tla new file mode 100644 index 0000000000000000000000000000000000000000..d9222457c1515b8782bc1dd37facc10f11155259 --- /dev/null +++ b/tlatools/test-model/pcal/DetlefSpec.tla @@ -0,0 +1,79 @@ +----------------------------- MODULE DetlefSpec ----------------------------- +EXTENDS Sequences, Naturals + +CONSTANTS Val, Procs, null + + +(* --algorithm Spec { + variable queue = << >> ; + process (P \in Procs) + variable rV = null ; { +L1: while (TRUE) { + either + with (v \in Val) { + either { queue := queue \o <<v>> ; + rV := "okay" } + or { queue := <<v>> \o queue ; + rV := "okay"} + or rV := "full" ; + } + or { if (queue # << >>) + { either { rV := Head(queue) ; + queue := Tail(queue) } + or { rV := queue[Len(queue)] ; + queue := [ i \in 1 .. (Len(queue) - 1) |-> queue[i]]} + } + else { rV := "empty" } + } ; +L2: rV := null + } } } +*) + +\* BEGIN TRANSLATION +VARIABLES queue, pc, rV + +vars == << queue, pc, rV >> + +ProcSet == (Procs) + +Init == (* Global variables *) + /\ queue = << >> + (* Process P *) + /\ rV = [self \in Procs |-> null] + /\ pc = [self \in ProcSet |-> "L1"] + +L1(self) == /\ pc[self] = "L1" + /\ \/ /\ \E v \in Val: + \/ /\ queue' = queue \o <<v>> + /\ rV' = [rV EXCEPT ![self] = "okay"] + \/ /\ queue' = <<v>> \o queue + /\ rV' = [rV EXCEPT ![self] = "okay"] + \/ /\ rV' = [rV EXCEPT ![self] = "full"] + /\ queue' = queue + \/ /\ IF queue # << >> + THEN /\ \/ /\ rV' = [rV EXCEPT ![self] = Head(queue)] + /\ queue' = Tail(queue) + \/ /\ rV' = [rV EXCEPT ![self] = queue[Len(queue)]] + /\ queue' = [ i \in 1 .. (Len(queue) - 1) |-> queue[i]] + ELSE /\ rV' = [rV EXCEPT ![self] = "empty"] + /\ queue' = queue + /\ pc' = [pc EXCEPT ![self] = "L2"] + +L2(self) == /\ pc[self] = "L2" + /\ rV' = [rV EXCEPT ![self] = null] + /\ pc' = [pc EXCEPT ![self] = "L1"] + /\ queue' = queue + +P(self) == L1(self) \/ L2(self) + +Next == (\E self \in Procs: P(self)) + +Spec == /\ Init /\ [][Next]_vars + /\ \A self \in Procs : WF_vars(P(self)) + +\* END TRANSLATION + +CONSTANT N + +Constraint == Len(queue) \leq N +============================================================================= diff --git a/tlatools/test-model/pcal/DetlefTest.cfg b/tlatools/test-model/pcal/DetlefTest.cfg new file mode 100644 index 0000000000000000000000000000000000000000..71587f4bf5be09b735bbc537455aef25bb113bbd --- /dev/null +++ b/tlatools/test-model/pcal/DetlefTest.cfg @@ -0,0 +1,10 @@ +SPECIFICATION XSpec +CONSTANTS a1=a1 a2=a2 a3=a3 a4=a4 v1=v1 v2=v2 p1=p1 p2=p2 p3=p3 + Val = {v1} + Address = {a1, a2, a3, a4} + Dummy = a1 + Procs = {p1, p2} \* , p3} + null = null + +PROPERTY XQSpec + diff --git a/tlatools/test-model/pcal/DetlefTest.tla b/tlatools/test-model/pcal/DetlefTest.tla new file mode 100644 index 0000000000000000000000000000000000000000..9b73cf79009e626ca463dd1818d09f16ad0321ea --- /dev/null +++ b/tlatools/test-model/pcal/DetlefTest.tla @@ -0,0 +1,49 @@ +----------------------------- MODULE DetlefTest ----------------------------- +EXTENDS Detlefs2 + +qRFrom[adr \in Address] == IF adr = LeftHat + THEN <<Mem[adr].V>> + ELSE qRFrom[Mem[adr].R] \o <<Mem[adr].V>> + +qBar == IF Mem[RightHat].R = RightHat + THEN << >> + ELSE qRFrom[RightHat] + +rVBar == [p \in Procs |-> + CASE + pc[p] \in {"M4", "M7"} -> Mem[rh[p]].V + [] pc[p] = "M8" -> result[p] + [] pc[p] \in {"O5", "O8"} -> Mem[rh[p]].V + [] pc[p] = "O9" -> result[p] + [] OTHER -> rVal[p]] + +pcBar == [p \in Procs |-> IF rVBar[p] = null THEN "L1" ELSE "L2"] + +SpecBar == INSTANCE DetlefSpec WITH rV <- rVBar, pc <- pcBar, + N <- 100 +QSpec == SpecBar!Spec + +CONSTANTS a1, a2, a3, a4, v1, v2, p1, p2, p3 +XInit == +/\ lh = (p1 :> a1 @@ p2 :> a1) +/\ LeftHat = a2 +/\ nd = (p1 :> a2 @@ p2 :> null) +/\ RightHat = a2 +/\ rVal = (p1 :> "okay" @@ p2 :> null) +/\ valBag = (v1 :> 0) +/\ pc = (p1 :> "Return" @@ p2 :> "M2") +/\ temp = (p1 :> TRUE @@ p2 :> a1) +/\ rh = (p1 :> a1 @@ p2 :> a1) +/\ Mem = ( a1 :> [V |-> null, R |-> a1, L |-> a1] @@ + a2 :> [V |-> v1, R |-> a1, L |-> a1] @@ + a3 :> [V |-> null, R |-> null, L |-> null] @@ + a4 :> [V |-> null, R |-> null, L |-> null] ) +/\ queue = << v1 >> +/\ ptr = (p1 :> a1 @@ p2 :> a1) +/\ result = (p1 :> v1 @@ p2 :> v1) +/\ freeList = {a3, a4} + +XSpec == XInit /\ [][Next]_vars + +XQSpec == [][SpecBar!Next]_(SpecBar!vars) +============================================================================= \ No newline at end of file diff --git a/tlatools/test-model/pcal/Detlefs.cfg b/tlatools/test-model/pcal/Detlefs.cfg new file mode 100644 index 0000000000000000000000000000000000000000..ca8ad7597a33b1c48943fa444f567bf0f34b7f6a --- /dev/null +++ b/tlatools/test-model/pcal/Detlefs.cfg @@ -0,0 +1,11 @@ +SPECIFICATION Spec +CONSTANT defaultInitValue = defaultInitValue +\* Add statements after this line. +CONSTANTS Val = {v1} + Address = {a1, a2, a3, a4} + Dummy = a1 + Procs = {p1, p2} \* , p3} + null = null + GC = GC +\* PROPERTY Liveness +SYMMETRY Symmetry diff --git a/tlatools/test-model/pcal/Detlefs.tla b/tlatools/test-model/pcal/Detlefs.tla new file mode 100644 index 0000000000000000000000000000000000000000..4bde20a127acb10d05a574ffb56ca5d6fd4c7e69 --- /dev/null +++ b/tlatools/test-model/pcal/Detlefs.tla @@ -0,0 +1,1006 @@ +------------------------------- MODULE Detlefs ------------------------------ +EXTENDS Naturals, Sequences, TLC, FiniteSets + +CONSTANTS Val, Address, Dummy, Procs, GC +ASSUME Dummy \in Address +ASSUME GC \notin Procs + + +null == CHOOSE n: n \notin Address +Node == [R : Address \cup {null}, L : Address \cup {null}, V : Val] +DummyNode == [R |-> Dummy, L |-> Dummy, V |-> null] +InitNode == [R |-> null, L |-> null, V |-> null] + +(* +\* boolean DCAS(val *addr1, val *addr2, +\* val old1, val old2, +\* val new1, val new2) { +\* atomically { +\* if (( *addr1 == old1) && +\* ( *addr2 == old2)) { +\* *addr1 = new1; +\* *addr2 = new2; +\* return true; +\* } else return false; } } + +--algorithm Snark { +variables Mem = [i \in Address |-> IF i = Dummy THEN DummyNode ELSE InitNode], + freeList = Address \ {Dummy}, + LeftHat = Dummy, + RightHat = Dummy, + rVal = [i \in Procs |-> "okay"] , \* Used for returning values + valBag = [i \in Val |-> 0] ; + \* For testing: valBag[i] is the number of copies of i + \* that can be in the queue. + +macro New(result) { + if (freeList # {}) { + result := CHOOSE a \in freeList : TRUE ; + freeList := freeList \ {result} ; + } else result := null +} + +macro DCAS(result, addr1, addr2, old1, old2, new1, new2) { + if ( /\ addr1 = old1 + /\ addr2 = old2) { + addr1 := new1 || + addr2 := new2 ; + result := TRUE; + } else result := FALSE; } + + +\* val pushRight(val v) { +\* nd = new Node(); /* Allocate new Node structure */ +\* if (nd == null) return "full"; +\* nd�>R = Dummy; +\* nd�>V = v; +\* while (true) { +\* rh = RightHat; /* Labels A, B, */ +\* rhR = rh�>R; /* etc., are used */ +\* if (rhR == rh) { /* in the proof */ +\* nd�>L = Dummy; /* of correctness */ +\* lh = LeftHat; +\* if (DCAS(&RightHat, &LeftHat, rh, lh, nd, nd)) /* A */ +\* return "okay"; +\* } else { +\* nd�>L = rh; +\* if (DCAS(&RightHat, &rh�>R, rh, rhR, nd, nd)) /* B */ +\* return "okay"; +\* } } } // Please forgive this brace style + +procedure pushRight(v) + variables nd = null , rh = Dummy, rhR = Dummy, lh = Dummy, + temp = Dummy ; { +L1: New(nd) ; + if (nd = null) { rVal[self] := "full"; L1a: return } ; +L1b: Mem[nd].R := Dummy || \* Since no other thread can access nd here, + Mem[nd].V := v ; +L4: while (TRUE) { + rh := RightHat; +L5: rhR := Mem[rh].R; +L6: if (rhR = rh) { + Mem[nd].L := Dummy; + lh := LeftHat; +L7: DCAS(temp, RightHat, LeftHat, rh, lh, nd, nd) ; + if (temp) { + rVal[self] := "okay"; L7a: return} + } else { +L8: Mem[nd].L := rh; +L9: DCAS(temp, RightHat, Mem[rh].R, rh, rhR, nd, nd) ; + if (temp) { + rVal[self] := "okay"; L8a: return } +} } } + + +\* val popRight() { +\* while (true) { +\* rh = RightHat; // Delicate order of operations +\* lh = LeftHat; // here (see proof of Theorem 4 +\* if (rh�>R == rh) return "empty"; // and the Conclusions section) +\* if (rh == lh) { +\* if (DCAS(&RightHat, &LeftHat, rh, lh, Dummy, Dummy)) /* C */ +\* return rh�>V; +\* } else { +\* rhL = rh�>L; +\* if (DCAS(&RightHat, &rh�>L, rh, rhL, rhL, rh)) { /* D */ +\* result = rh�>V; +\* rh�>R = Dummy; /* E */ +\* rh�>V = null; /* optional (see text) */ +\* return result; +\* } } } } // Stacking braces this way saves space +\* + +procedure popRight() + variables rh = Dummy, lh = Dummy, rhL = Dummy, + temp = Dummy , result = null ; { +M1: while (TRUE) { + rh := RightHat; +M2: lh := LeftHat; + if (Mem[rh].R = rh) {rVal[self] := "empty"; M2a: return ;} ; +M3: if (rh = lh) { + DCAS(temp, RightHat, LeftHat, rh, lh, Dummy, Dummy) ; + if (temp) { +M4: rVal[self] := Mem[rh].V ; M4a: return;} + } else { +M5: rhL := Mem[rh].L ; +M6: DCAS(temp, RightHat, Mem[rh].L, rh, rhL, rhL, rh) ; + if (temp) { +M7: result := Mem[rh].V; +M8: Mem[rh].R := Dummy || + Mem[rh].V := null; + rVal[self] := result ; M9a: return ; +} } } } + +\* val pushLeft(val v) { +\* nd = new Node(); /* Allocate new Node structure */ +\* if (nd == null) return "full"; +\* nd�>L = Dummy; +\* nd�>V = v; +\* while (true) { +\* lh = LeftHat; +\* lhL = lh�>L; +\* if (lhL == lh) { +\* nd�>R = Dummy; +\* rh = RightHat; +\* if (DCAS(&LeftHat, &RightHat, lh, rh, nd, nd)) /* A' */ +\* return "okay"; +\* } else { +\* nd�>R = lh; +\* if (DCAS(&LeftHat, &lh�>L, lh, lhL, nd, nd)) /* B' */ +\* return "okay"; +\* } } } // We were given a firm limit of 15 pages + +procedure pushLeft(v) + variables nd = null , rh = Dummy, lhL = Dummy, lh = Dummy, + temp = Dummy ; { +N1: New(nd) ; + if (nd = null) {rVal[self] := "full"; N1a: return ;} ; +N1b: Mem[nd].L := Dummy || \* Since no other thread can access nd here, + Mem[nd].V := v; \* we can represent this as a single action. +N2: while (TRUE) { + lh := LeftHat; +N3: lhL := Mem[lh].L; + if (lhL = lh) { +N4: Mem[nd].R := Dummy; +N5: rh := RightHat; +N6: DCAS(temp, LeftHat, RightHat, lh, rh, nd, nd) ; + if (temp) { + rVal[self] := "okay"; nd := null ; N6a: return;} + } else { +N7: Mem[nd].R := lh; +N8: DCAS(temp, LeftHat, Mem[lh].L, lh, lhL, nd, nd) ; + if (temp) { + rVal[self] := "okay"; nd := null ; N8a: return } +} } } + +\* val popLeft() { +\* while (true) { +\* lh = LeftHat; // Delicate order of operations +\* rh = RightHat; // here (see proof of Theorem 4 +\* if (lh�>L == lh) return "empty"; // and the Conclusions section) +\* if (lh == rh) { +\* if (DCAS(&LeftHat, &RightHat, lh, rh, Dummy, Dummy)) /* C' */ +\* return lh�>V; +\* } else { +\* lhR = lh�>R; +\* if (DCAS(&LeftHat, &lh�>R, lh, lhR, lhR, lh)) { /* D' */ +\* result = lh�>V; +\* lh�>L = Dummy; /* E' */ +\* lh�>V = null; /* optional (see text) */ +\* return result; +\* } } } } // Better to stack braces than to omit a lemma + +procedure popLeft() + variables rh = Dummy, lh = Dummy, lhR = Dummy, + temp = Dummy , result = null ; { +O1: while (TRUE) { + lh := LeftHat; +O2: rh := RightHat; +O3: if (Mem[lh].L = lh) {rVal[self] := "empty"; O3a: return ;} ; +O4: if (lh = rh) { + DCAS(temp, LeftHat, RightHat, lh, rh, Dummy, Dummy) ; + if (temp) { +O5: rVal[self] := Mem[lh].V; O5a: return; } + } else { +O6: lhR := Mem[lh].R; +O7: DCAS(temp, LeftHat, Mem[lh].R, lh, lhR, lhR, lh) ; + if (temp) { +O8: result := Mem[lh].V; +O9: Mem[lh].L := Dummy || + Mem[lh].V := null; + rVal[self] := result; O10a: return ; +} } } } + + +\* process (GarbageCollet = GC) { +\* GC1: while (TRUE) { +\* with (adr \in Address \ (freeList \cup {Dummy})) { +\* when Mem[adr].canGC ; +\* when \A b \in Address \ (freeList \cup {Dummy, adr}) : +\* /\ adr # Mem[b].L +\* /\ adr # Mem[b].R ; +\* freeList := freeList \cup {adr} ; +\* Mem[adr] := InitNode; +\* } } } + +process (test \in Procs) +variables pushedVal = null ; { +T1: while(TRUE) { + either { \* push + with (x \in Val) {pushedVal := x} ; + valBag[pushedVal] := valBag[pushedVal] + 1 ; + either call pushLeft(pushedVal) or call pushRight(pushedVal) ; +T2: if (rVal[self] = "full") valBag[pushedVal] := valBag[pushedVal] - 1 + } + or { \* pop + either call popLeft() or call popRight() ; +T3: if (rVal[self] # "empty") { + assert valBag[rVal[self]] > 0 ; + valBag[rVal[self]] := valBag[rVal[self]] - 1; + } +} } }} +*) + +\* BEGIN TRANSLATION +\* Procedure variable nd of procedure pushRight at line 72 col 12 changed to nd_ +\* Procedure variable rh of procedure pushRight at line 72 col 24 changed to rh_ +\* Procedure variable lh of procedure pushRight at line 72 col 49 changed to lh_ +\* Procedure variable temp of procedure pushRight at line 73 col 12 changed to temp_ +\* Procedure variable rh of procedure popRight at line 114 col 12 changed to rh_p +\* Procedure variable lh of procedure popRight at line 114 col 24 changed to lh_p +\* Procedure variable temp of procedure popRight at line 115 col 12 changed to temp_p +\* Procedure variable result of procedure popRight at line 115 col 27 changed to result_ +\* Procedure variable rh of procedure pushLeft at line 154 col 24 changed to rh_pu +\* Procedure variable lh of procedure pushLeft at line 154 col 49 changed to lh_pu +\* Procedure variable temp of procedure pushLeft at line 155 col 12 changed to temp_pu +\* Parameter v of procedure pushRight at line 71 col 21 changed to v_ +CONSTANT defaultInitValue +VARIABLES Mem, freeList, LeftHat, RightHat, rVal, valBag, pc, stack, v_, nd_, + rh_, rhR, lh_, temp_, rh_p, lh_p, rhL, temp_p, result_, v, nd, + rh_pu, lhL, lh_pu, temp_pu, rh, lh, lhR, temp, result, pushedVal + +vars == << Mem, freeList, LeftHat, RightHat, rVal, valBag, pc, stack, v_, nd_, + rh_, rhR, lh_, temp_, rh_p, lh_p, rhL, temp_p, result_, v, nd, + rh_pu, lhL, lh_pu, temp_pu, rh, lh, lhR, temp, result, pushedVal + >> + +ProcSet == (Procs) + +Init == (* Global variables *) + /\ Mem = [i \in Address |-> IF i = Dummy THEN DummyNode ELSE InitNode] + /\ freeList = Address \ {Dummy} + /\ LeftHat = Dummy + /\ RightHat = Dummy + /\ rVal = [i \in Procs |-> "okay"] + /\ valBag = [i \in Val |-> 0] + (* Procedure pushRight *) + /\ v_ = [ self \in ProcSet |-> defaultInitValue] + /\ nd_ = [ self \in ProcSet |-> null] + /\ rh_ = [ self \in ProcSet |-> Dummy] + /\ rhR = [ self \in ProcSet |-> Dummy] + /\ lh_ = [ self \in ProcSet |-> Dummy] + /\ temp_ = [ self \in ProcSet |-> Dummy] + (* Procedure popRight *) + /\ rh_p = [ self \in ProcSet |-> Dummy] + /\ lh_p = [ self \in ProcSet |-> Dummy] + /\ rhL = [ self \in ProcSet |-> Dummy] + /\ temp_p = [ self \in ProcSet |-> Dummy] + /\ result_ = [ self \in ProcSet |-> null] + (* Procedure pushLeft *) + /\ v = [ self \in ProcSet |-> defaultInitValue] + /\ nd = [ self \in ProcSet |-> null] + /\ rh_pu = [ self \in ProcSet |-> Dummy] + /\ lhL = [ self \in ProcSet |-> Dummy] + /\ lh_pu = [ self \in ProcSet |-> Dummy] + /\ temp_pu = [ self \in ProcSet |-> Dummy] + (* Procedure popLeft *) + /\ rh = [ self \in ProcSet |-> Dummy] + /\ lh = [ self \in ProcSet |-> Dummy] + /\ lhR = [ self \in ProcSet |-> Dummy] + /\ temp = [ self \in ProcSet |-> Dummy] + /\ result = [ self \in ProcSet |-> null] + (* Process test *) + /\ pushedVal = [self \in Procs |-> null] + /\ stack = [self \in ProcSet |-> << >>] + /\ pc = [self \in ProcSet |-> "T1"] + +L1(self) == /\ pc[self] = "L1" + /\ IF freeList # {} + THEN /\ nd_' = [nd_ EXCEPT ![self] = CHOOSE a \in freeList : TRUE] + /\ freeList' = freeList \ {nd_'[self]} + ELSE /\ nd_' = [nd_ EXCEPT ![self] = null] + /\ UNCHANGED freeList + /\ IF nd_'[self] = null + THEN /\ rVal' = [rVal EXCEPT ![self] = "full"] + /\ pc' = [pc EXCEPT ![self] = "L1a"] + ELSE /\ pc' = [pc EXCEPT ![self] = "L1b"] + /\ rVal' = rVal + /\ UNCHANGED << Mem, LeftHat, RightHat, valBag, stack, v_, rh_, + rhR, lh_, temp_, rh_p, lh_p, rhL, temp_p, result_, + v, nd, rh_pu, lhL, lh_pu, temp_pu, rh, lh, lhR, + temp, result, pushedVal >> + +L1a(self) == /\ pc[self] = "L1a" + /\ pc' = [pc EXCEPT ![self] = Head(stack[self]).pc] + /\ nd_' = [nd_ EXCEPT ![self] = Head(stack[self]).nd_] + /\ rh_' = [rh_ EXCEPT ![self] = Head(stack[self]).rh_] + /\ rhR' = [rhR EXCEPT ![self] = Head(stack[self]).rhR] + /\ lh_' = [lh_ EXCEPT ![self] = Head(stack[self]).lh_] + /\ temp_' = [temp_ EXCEPT ![self] = Head(stack[self]).temp_] + /\ v_' = [v_ EXCEPT ![self] = Head(stack[self]).v_] + /\ stack' = [stack EXCEPT ![self] = Tail(stack[self])] + /\ UNCHANGED << Mem, freeList, LeftHat, RightHat, rVal, valBag, + rh_p, lh_p, rhL, temp_p, result_, v, nd, rh_pu, + lhL, lh_pu, temp_pu, rh, lh, lhR, temp, result, + pushedVal >> + +L1b(self) == /\ pc[self] = "L1b" + /\ Mem' = [Mem EXCEPT ![nd_[self]].R = Dummy, + ![nd_[self]].V = v_[self]] + /\ pc' = [pc EXCEPT ![self] = "L4"] + /\ UNCHANGED << freeList, LeftHat, RightHat, rVal, valBag, stack, + v_, nd_, rh_, rhR, lh_, temp_, rh_p, lh_p, rhL, + temp_p, result_, v, nd, rh_pu, lhL, lh_pu, + temp_pu, rh, lh, lhR, temp, result, pushedVal >> + +L4(self) == /\ pc[self] = "L4" + /\ rh_' = [rh_ EXCEPT ![self] = RightHat] + /\ pc' = [pc EXCEPT ![self] = "L5"] + /\ UNCHANGED << Mem, freeList, LeftHat, RightHat, rVal, valBag, + stack, v_, nd_, rhR, lh_, temp_, rh_p, lh_p, rhL, + temp_p, result_, v, nd, rh_pu, lhL, lh_pu, temp_pu, + rh, lh, lhR, temp, result, pushedVal >> + +L5(self) == /\ pc[self] = "L5" + /\ rhR' = [rhR EXCEPT ![self] = Mem[rh_[self]].R] + /\ pc' = [pc EXCEPT ![self] = "L6"] + /\ UNCHANGED << Mem, freeList, LeftHat, RightHat, rVal, valBag, + stack, v_, nd_, rh_, lh_, temp_, rh_p, lh_p, rhL, + temp_p, result_, v, nd, rh_pu, lhL, lh_pu, temp_pu, + rh, lh, lhR, temp, result, pushedVal >> + +L6(self) == /\ pc[self] = "L6" + /\ IF rhR[self] = rh_[self] + THEN /\ Mem' = [Mem EXCEPT ![nd_[self]].L = Dummy] + /\ lh_' = [lh_ EXCEPT ![self] = LeftHat] + /\ pc' = [pc EXCEPT ![self] = "L7"] + ELSE /\ pc' = [pc EXCEPT ![self] = "L8"] + /\ UNCHANGED << Mem, lh_ >> + /\ UNCHANGED << freeList, LeftHat, RightHat, rVal, valBag, stack, + v_, nd_, rh_, rhR, temp_, rh_p, lh_p, rhL, temp_p, + result_, v, nd, rh_pu, lhL, lh_pu, temp_pu, rh, lh, + lhR, temp, result, pushedVal >> + +L7(self) == /\ pc[self] = "L7" + /\ IF /\ RightHat = rh_[self] + /\ LeftHat = lh_[self] + THEN /\ /\ LeftHat' = nd_[self] + /\ RightHat' = nd_[self] + /\ temp_' = [temp_ EXCEPT ![self] = TRUE] + ELSE /\ temp_' = [temp_ EXCEPT ![self] = FALSE] + /\ UNCHANGED << LeftHat, RightHat >> + /\ IF temp_'[self] + THEN /\ rVal' = [rVal EXCEPT ![self] = "okay"] + /\ pc' = [pc EXCEPT ![self] = "L7a"] + ELSE /\ pc' = [pc EXCEPT ![self] = "L4"] + /\ rVal' = rVal + /\ UNCHANGED << Mem, freeList, valBag, stack, v_, nd_, rh_, rhR, + lh_, rh_p, lh_p, rhL, temp_p, result_, v, nd, + rh_pu, lhL, lh_pu, temp_pu, rh, lh, lhR, temp, + result, pushedVal >> + +L7a(self) == /\ pc[self] = "L7a" + /\ pc' = [pc EXCEPT ![self] = Head(stack[self]).pc] + /\ nd_' = [nd_ EXCEPT ![self] = Head(stack[self]).nd_] + /\ rh_' = [rh_ EXCEPT ![self] = Head(stack[self]).rh_] + /\ rhR' = [rhR EXCEPT ![self] = Head(stack[self]).rhR] + /\ lh_' = [lh_ EXCEPT ![self] = Head(stack[self]).lh_] + /\ temp_' = [temp_ EXCEPT ![self] = Head(stack[self]).temp_] + /\ v_' = [v_ EXCEPT ![self] = Head(stack[self]).v_] + /\ stack' = [stack EXCEPT ![self] = Tail(stack[self])] + /\ UNCHANGED << Mem, freeList, LeftHat, RightHat, rVal, valBag, + rh_p, lh_p, rhL, temp_p, result_, v, nd, rh_pu, + lhL, lh_pu, temp_pu, rh, lh, lhR, temp, result, + pushedVal >> + +L8(self) == /\ pc[self] = "L8" + /\ Mem' = [Mem EXCEPT ![nd_[self]].L = rh_[self]] + /\ pc' = [pc EXCEPT ![self] = "L9"] + /\ UNCHANGED << freeList, LeftHat, RightHat, rVal, valBag, stack, + v_, nd_, rh_, rhR, lh_, temp_, rh_p, lh_p, rhL, + temp_p, result_, v, nd, rh_pu, lhL, lh_pu, temp_pu, + rh, lh, lhR, temp, result, pushedVal >> + +L9(self) == /\ pc[self] = "L9" + /\ IF /\ RightHat = rh_[self] + /\ (Mem[rh_[self]].R) = rhR[self] + THEN /\ /\ Mem' = [Mem EXCEPT ![rh_[self]].R = nd_[self]] + /\ RightHat' = nd_[self] + /\ temp_' = [temp_ EXCEPT ![self] = TRUE] + ELSE /\ temp_' = [temp_ EXCEPT ![self] = FALSE] + /\ UNCHANGED << Mem, RightHat >> + /\ IF temp_'[self] + THEN /\ rVal' = [rVal EXCEPT ![self] = "okay"] + /\ pc' = [pc EXCEPT ![self] = "L8a"] + ELSE /\ pc' = [pc EXCEPT ![self] = "L4"] + /\ rVal' = rVal + /\ UNCHANGED << freeList, LeftHat, valBag, stack, v_, nd_, rh_, + rhR, lh_, rh_p, lh_p, rhL, temp_p, result_, v, nd, + rh_pu, lhL, lh_pu, temp_pu, rh, lh, lhR, temp, + result, pushedVal >> + +L8a(self) == /\ pc[self] = "L8a" + /\ pc' = [pc EXCEPT ![self] = Head(stack[self]).pc] + /\ nd_' = [nd_ EXCEPT ![self] = Head(stack[self]).nd_] + /\ rh_' = [rh_ EXCEPT ![self] = Head(stack[self]).rh_] + /\ rhR' = [rhR EXCEPT ![self] = Head(stack[self]).rhR] + /\ lh_' = [lh_ EXCEPT ![self] = Head(stack[self]).lh_] + /\ temp_' = [temp_ EXCEPT ![self] = Head(stack[self]).temp_] + /\ v_' = [v_ EXCEPT ![self] = Head(stack[self]).v_] + /\ stack' = [stack EXCEPT ![self] = Tail(stack[self])] + /\ UNCHANGED << Mem, freeList, LeftHat, RightHat, rVal, valBag, + rh_p, lh_p, rhL, temp_p, result_, v, nd, rh_pu, + lhL, lh_pu, temp_pu, rh, lh, lhR, temp, result, + pushedVal >> + +pushRight(self) == L1(self) \/ L1a(self) \/ L1b(self) \/ L4(self) + \/ L5(self) \/ L6(self) \/ L7(self) \/ L7a(self) + \/ L8(self) \/ L9(self) \/ L8a(self) + +M1(self) == /\ pc[self] = "M1" + /\ rh_p' = [rh_p EXCEPT ![self] = RightHat] + /\ pc' = [pc EXCEPT ![self] = "M2"] + /\ UNCHANGED << Mem, freeList, LeftHat, RightHat, rVal, valBag, + stack, v_, nd_, rh_, rhR, lh_, temp_, lh_p, rhL, + temp_p, result_, v, nd, rh_pu, lhL, lh_pu, temp_pu, + rh, lh, lhR, temp, result, pushedVal >> + +M2(self) == /\ pc[self] = "M2" + /\ lh_p' = [lh_p EXCEPT ![self] = LeftHat] + /\ IF Mem[rh_p[self]].R = rh_p[self] + THEN /\ rVal' = [rVal EXCEPT ![self] = "empty"] + /\ pc' = [pc EXCEPT ![self] = "M2a"] + ELSE /\ pc' = [pc EXCEPT ![self] = "M3"] + /\ rVal' = rVal + /\ UNCHANGED << Mem, freeList, LeftHat, RightHat, valBag, stack, + v_, nd_, rh_, rhR, lh_, temp_, rh_p, rhL, temp_p, + result_, v, nd, rh_pu, lhL, lh_pu, temp_pu, rh, lh, + lhR, temp, result, pushedVal >> + +M2a(self) == /\ pc[self] = "M2a" + /\ pc' = [pc EXCEPT ![self] = Head(stack[self]).pc] + /\ rh_p' = [rh_p EXCEPT ![self] = Head(stack[self]).rh_p] + /\ lh_p' = [lh_p EXCEPT ![self] = Head(stack[self]).lh_p] + /\ rhL' = [rhL EXCEPT ![self] = Head(stack[self]).rhL] + /\ temp_p' = [temp_p EXCEPT ![self] = Head(stack[self]).temp_p] + /\ result_' = [result_ EXCEPT ![self] = Head(stack[self]).result_] + /\ stack' = [stack EXCEPT ![self] = Tail(stack[self])] + /\ UNCHANGED << Mem, freeList, LeftHat, RightHat, rVal, valBag, + v_, nd_, rh_, rhR, lh_, temp_, v, nd, rh_pu, lhL, + lh_pu, temp_pu, rh, lh, lhR, temp, result, + pushedVal >> + +M3(self) == /\ pc[self] = "M3" + /\ IF rh_p[self] = lh_p[self] + THEN /\ IF /\ RightHat = rh_p[self] + /\ LeftHat = lh_p[self] + THEN /\ /\ LeftHat' = Dummy + /\ RightHat' = Dummy + /\ temp_p' = [temp_p EXCEPT ![self] = TRUE] + ELSE /\ temp_p' = [temp_p EXCEPT ![self] = FALSE] + /\ UNCHANGED << LeftHat, RightHat >> + /\ IF temp_p'[self] + THEN /\ pc' = [pc EXCEPT ![self] = "M4"] + ELSE /\ pc' = [pc EXCEPT ![self] = "M1"] + ELSE /\ pc' = [pc EXCEPT ![self] = "M5"] + /\ UNCHANGED << LeftHat, RightHat, temp_p >> + /\ UNCHANGED << Mem, freeList, rVal, valBag, stack, v_, nd_, rh_, + rhR, lh_, temp_, rh_p, lh_p, rhL, result_, v, nd, + rh_pu, lhL, lh_pu, temp_pu, rh, lh, lhR, temp, + result, pushedVal >> + +M5(self) == /\ pc[self] = "M5" + /\ rhL' = [rhL EXCEPT ![self] = Mem[rh_p[self]].L] + /\ pc' = [pc EXCEPT ![self] = "M6"] + /\ UNCHANGED << Mem, freeList, LeftHat, RightHat, rVal, valBag, + stack, v_, nd_, rh_, rhR, lh_, temp_, rh_p, lh_p, + temp_p, result_, v, nd, rh_pu, lhL, lh_pu, temp_pu, + rh, lh, lhR, temp, result, pushedVal >> + +M6(self) == /\ pc[self] = "M6" + /\ IF /\ RightHat = rh_p[self] + /\ (Mem[rh_p[self]].L) = rhL[self] + THEN /\ /\ Mem' = [Mem EXCEPT ![rh_p[self]].L = rh_p[self]] + /\ RightHat' = rhL[self] + /\ temp_p' = [temp_p EXCEPT ![self] = TRUE] + ELSE /\ temp_p' = [temp_p EXCEPT ![self] = FALSE] + /\ UNCHANGED << Mem, RightHat >> + /\ IF temp_p'[self] + THEN /\ pc' = [pc EXCEPT ![self] = "M7"] + ELSE /\ pc' = [pc EXCEPT ![self] = "M1"] + /\ UNCHANGED << freeList, LeftHat, rVal, valBag, stack, v_, nd_, + rh_, rhR, lh_, temp_, rh_p, lh_p, rhL, result_, v, + nd, rh_pu, lhL, lh_pu, temp_pu, rh, lh, lhR, temp, + result, pushedVal >> + +M7(self) == /\ pc[self] = "M7" + /\ result_' = [result_ EXCEPT ![self] = Mem[rh_p[self]].V] + /\ pc' = [pc EXCEPT ![self] = "M8"] + /\ UNCHANGED << Mem, freeList, LeftHat, RightHat, rVal, valBag, + stack, v_, nd_, rh_, rhR, lh_, temp_, rh_p, lh_p, + rhL, temp_p, v, nd, rh_pu, lhL, lh_pu, temp_pu, rh, + lh, lhR, temp, result, pushedVal >> + +M8(self) == /\ pc[self] = "M8" + /\ Mem' = [Mem EXCEPT ![rh_p[self]].R = Dummy, + ![rh_p[self]].V = null] + /\ rVal' = [rVal EXCEPT ![self] = result_[self]] + /\ pc' = [pc EXCEPT ![self] = "M9a"] + /\ UNCHANGED << freeList, LeftHat, RightHat, valBag, stack, v_, + nd_, rh_, rhR, lh_, temp_, rh_p, lh_p, rhL, temp_p, + result_, v, nd, rh_pu, lhL, lh_pu, temp_pu, rh, lh, + lhR, temp, result, pushedVal >> + +M9a(self) == /\ pc[self] = "M9a" + /\ pc' = [pc EXCEPT ![self] = Head(stack[self]).pc] + /\ rh_p' = [rh_p EXCEPT ![self] = Head(stack[self]).rh_p] + /\ lh_p' = [lh_p EXCEPT ![self] = Head(stack[self]).lh_p] + /\ rhL' = [rhL EXCEPT ![self] = Head(stack[self]).rhL] + /\ temp_p' = [temp_p EXCEPT ![self] = Head(stack[self]).temp_p] + /\ result_' = [result_ EXCEPT ![self] = Head(stack[self]).result_] + /\ stack' = [stack EXCEPT ![self] = Tail(stack[self])] + /\ UNCHANGED << Mem, freeList, LeftHat, RightHat, rVal, valBag, + v_, nd_, rh_, rhR, lh_, temp_, v, nd, rh_pu, lhL, + lh_pu, temp_pu, rh, lh, lhR, temp, result, + pushedVal >> + +M4(self) == /\ pc[self] = "M4" + /\ rVal' = [rVal EXCEPT ![self] = Mem[rh_p[self]].V] + /\ pc' = [pc EXCEPT ![self] = "M4a"] + /\ UNCHANGED << Mem, freeList, LeftHat, RightHat, valBag, stack, + v_, nd_, rh_, rhR, lh_, temp_, rh_p, lh_p, rhL, + temp_p, result_, v, nd, rh_pu, lhL, lh_pu, temp_pu, + rh, lh, lhR, temp, result, pushedVal >> + +M4a(self) == /\ pc[self] = "M4a" + /\ pc' = [pc EXCEPT ![self] = Head(stack[self]).pc] + /\ rh_p' = [rh_p EXCEPT ![self] = Head(stack[self]).rh_p] + /\ lh_p' = [lh_p EXCEPT ![self] = Head(stack[self]).lh_p] + /\ rhL' = [rhL EXCEPT ![self] = Head(stack[self]).rhL] + /\ temp_p' = [temp_p EXCEPT ![self] = Head(stack[self]).temp_p] + /\ result_' = [result_ EXCEPT ![self] = Head(stack[self]).result_] + /\ stack' = [stack EXCEPT ![self] = Tail(stack[self])] + /\ UNCHANGED << Mem, freeList, LeftHat, RightHat, rVal, valBag, + v_, nd_, rh_, rhR, lh_, temp_, v, nd, rh_pu, lhL, + lh_pu, temp_pu, rh, lh, lhR, temp, result, + pushedVal >> + +popRight(self) == M1(self) \/ M2(self) \/ M2a(self) \/ M3(self) \/ M5(self) + \/ M6(self) \/ M7(self) \/ M8(self) \/ M9a(self) + \/ M4(self) \/ M4a(self) + +N1(self) == /\ pc[self] = "N1" + /\ IF freeList # {} + THEN /\ nd' = [nd EXCEPT ![self] = CHOOSE a \in freeList : TRUE] + /\ freeList' = freeList \ {nd'[self]} + ELSE /\ nd' = [nd EXCEPT ![self] = null] + /\ UNCHANGED freeList + /\ IF nd'[self] = null + THEN /\ rVal' = [rVal EXCEPT ![self] = "full"] + /\ pc' = [pc EXCEPT ![self] = "N1a"] + ELSE /\ pc' = [pc EXCEPT ![self] = "N1b"] + /\ rVal' = rVal + /\ UNCHANGED << Mem, LeftHat, RightHat, valBag, stack, v_, nd_, + rh_, rhR, lh_, temp_, rh_p, lh_p, rhL, temp_p, + result_, v, rh_pu, lhL, lh_pu, temp_pu, rh, lh, + lhR, temp, result, pushedVal >> + +N1a(self) == /\ pc[self] = "N1a" + /\ pc' = [pc EXCEPT ![self] = Head(stack[self]).pc] + /\ nd' = [nd EXCEPT ![self] = Head(stack[self]).nd] + /\ rh_pu' = [rh_pu EXCEPT ![self] = Head(stack[self]).rh_pu] + /\ lhL' = [lhL EXCEPT ![self] = Head(stack[self]).lhL] + /\ lh_pu' = [lh_pu EXCEPT ![self] = Head(stack[self]).lh_pu] + /\ temp_pu' = [temp_pu EXCEPT ![self] = Head(stack[self]).temp_pu] + /\ v' = [v EXCEPT ![self] = Head(stack[self]).v] + /\ stack' = [stack EXCEPT ![self] = Tail(stack[self])] + /\ UNCHANGED << Mem, freeList, LeftHat, RightHat, rVal, valBag, + v_, nd_, rh_, rhR, lh_, temp_, rh_p, lh_p, rhL, + temp_p, result_, rh, lh, lhR, temp, result, + pushedVal >> + +N1b(self) == /\ pc[self] = "N1b" + /\ Mem' = [Mem EXCEPT ![nd[self]].L = Dummy, + ![nd[self]].V = v[self]] + /\ pc' = [pc EXCEPT ![self] = "N2"] + /\ UNCHANGED << freeList, LeftHat, RightHat, rVal, valBag, stack, + v_, nd_, rh_, rhR, lh_, temp_, rh_p, lh_p, rhL, + temp_p, result_, v, nd, rh_pu, lhL, lh_pu, + temp_pu, rh, lh, lhR, temp, result, pushedVal >> + +N2(self) == /\ pc[self] = "N2" + /\ lh_pu' = [lh_pu EXCEPT ![self] = LeftHat] + /\ pc' = [pc EXCEPT ![self] = "N3"] + /\ UNCHANGED << Mem, freeList, LeftHat, RightHat, rVal, valBag, + stack, v_, nd_, rh_, rhR, lh_, temp_, rh_p, lh_p, + rhL, temp_p, result_, v, nd, rh_pu, lhL, temp_pu, + rh, lh, lhR, temp, result, pushedVal >> + +N3(self) == /\ pc[self] = "N3" + /\ lhL' = [lhL EXCEPT ![self] = Mem[lh_pu[self]].L] + /\ IF lhL'[self] = lh_pu[self] + THEN /\ pc' = [pc EXCEPT ![self] = "N4"] + ELSE /\ pc' = [pc EXCEPT ![self] = "N7"] + /\ UNCHANGED << Mem, freeList, LeftHat, RightHat, rVal, valBag, + stack, v_, nd_, rh_, rhR, lh_, temp_, rh_p, lh_p, + rhL, temp_p, result_, v, nd, rh_pu, lh_pu, temp_pu, + rh, lh, lhR, temp, result, pushedVal >> + +N4(self) == /\ pc[self] = "N4" + /\ Mem' = [Mem EXCEPT ![nd[self]].R = Dummy] + /\ pc' = [pc EXCEPT ![self] = "N5"] + /\ UNCHANGED << freeList, LeftHat, RightHat, rVal, valBag, stack, + v_, nd_, rh_, rhR, lh_, temp_, rh_p, lh_p, rhL, + temp_p, result_, v, nd, rh_pu, lhL, lh_pu, temp_pu, + rh, lh, lhR, temp, result, pushedVal >> + +N5(self) == /\ pc[self] = "N5" + /\ rh_pu' = [rh_pu EXCEPT ![self] = RightHat] + /\ pc' = [pc EXCEPT ![self] = "N6"] + /\ UNCHANGED << Mem, freeList, LeftHat, RightHat, rVal, valBag, + stack, v_, nd_, rh_, rhR, lh_, temp_, rh_p, lh_p, + rhL, temp_p, result_, v, nd, lhL, lh_pu, temp_pu, + rh, lh, lhR, temp, result, pushedVal >> + +N6(self) == /\ pc[self] = "N6" + /\ IF /\ LeftHat = lh_pu[self] + /\ RightHat = rh_pu[self] + THEN /\ /\ LeftHat' = nd[self] + /\ RightHat' = nd[self] + /\ temp_pu' = [temp_pu EXCEPT ![self] = TRUE] + ELSE /\ temp_pu' = [temp_pu EXCEPT ![self] = FALSE] + /\ UNCHANGED << LeftHat, RightHat >> + /\ IF temp_pu'[self] + THEN /\ rVal' = [rVal EXCEPT ![self] = "okay"] + /\ nd' = [nd EXCEPT ![self] = null] + /\ pc' = [pc EXCEPT ![self] = "N6a"] + ELSE /\ pc' = [pc EXCEPT ![self] = "N2"] + /\ UNCHANGED << rVal, nd >> + /\ UNCHANGED << Mem, freeList, valBag, stack, v_, nd_, rh_, rhR, + lh_, temp_, rh_p, lh_p, rhL, temp_p, result_, v, + rh_pu, lhL, lh_pu, rh, lh, lhR, temp, result, + pushedVal >> + +N6a(self) == /\ pc[self] = "N6a" + /\ pc' = [pc EXCEPT ![self] = Head(stack[self]).pc] + /\ nd' = [nd EXCEPT ![self] = Head(stack[self]).nd] + /\ rh_pu' = [rh_pu EXCEPT ![self] = Head(stack[self]).rh_pu] + /\ lhL' = [lhL EXCEPT ![self] = Head(stack[self]).lhL] + /\ lh_pu' = [lh_pu EXCEPT ![self] = Head(stack[self]).lh_pu] + /\ temp_pu' = [temp_pu EXCEPT ![self] = Head(stack[self]).temp_pu] + /\ v' = [v EXCEPT ![self] = Head(stack[self]).v] + /\ stack' = [stack EXCEPT ![self] = Tail(stack[self])] + /\ UNCHANGED << Mem, freeList, LeftHat, RightHat, rVal, valBag, + v_, nd_, rh_, rhR, lh_, temp_, rh_p, lh_p, rhL, + temp_p, result_, rh, lh, lhR, temp, result, + pushedVal >> + +N7(self) == /\ pc[self] = "N7" + /\ Mem' = [Mem EXCEPT ![nd[self]].R = lh_pu[self]] + /\ pc' = [pc EXCEPT ![self] = "N8"] + /\ UNCHANGED << freeList, LeftHat, RightHat, rVal, valBag, stack, + v_, nd_, rh_, rhR, lh_, temp_, rh_p, lh_p, rhL, + temp_p, result_, v, nd, rh_pu, lhL, lh_pu, temp_pu, + rh, lh, lhR, temp, result, pushedVal >> + +N8(self) == /\ pc[self] = "N8" + /\ IF /\ LeftHat = lh_pu[self] + /\ (Mem[lh_pu[self]].L) = lhL[self] + THEN /\ /\ LeftHat' = nd[self] + /\ Mem' = [Mem EXCEPT ![lh_pu[self]].L = nd[self]] + /\ temp_pu' = [temp_pu EXCEPT ![self] = TRUE] + ELSE /\ temp_pu' = [temp_pu EXCEPT ![self] = FALSE] + /\ UNCHANGED << Mem, LeftHat >> + /\ IF temp_pu'[self] + THEN /\ rVal' = [rVal EXCEPT ![self] = "okay"] + /\ nd' = [nd EXCEPT ![self] = null] + /\ pc' = [pc EXCEPT ![self] = "N8a"] + ELSE /\ pc' = [pc EXCEPT ![self] = "N2"] + /\ UNCHANGED << rVal, nd >> + /\ UNCHANGED << freeList, RightHat, valBag, stack, v_, nd_, rh_, + rhR, lh_, temp_, rh_p, lh_p, rhL, temp_p, result_, + v, rh_pu, lhL, lh_pu, rh, lh, lhR, temp, result, + pushedVal >> + +N8a(self) == /\ pc[self] = "N8a" + /\ pc' = [pc EXCEPT ![self] = Head(stack[self]).pc] + /\ nd' = [nd EXCEPT ![self] = Head(stack[self]).nd] + /\ rh_pu' = [rh_pu EXCEPT ![self] = Head(stack[self]).rh_pu] + /\ lhL' = [lhL EXCEPT ![self] = Head(stack[self]).lhL] + /\ lh_pu' = [lh_pu EXCEPT ![self] = Head(stack[self]).lh_pu] + /\ temp_pu' = [temp_pu EXCEPT ![self] = Head(stack[self]).temp_pu] + /\ v' = [v EXCEPT ![self] = Head(stack[self]).v] + /\ stack' = [stack EXCEPT ![self] = Tail(stack[self])] + /\ UNCHANGED << Mem, freeList, LeftHat, RightHat, rVal, valBag, + v_, nd_, rh_, rhR, lh_, temp_, rh_p, lh_p, rhL, + temp_p, result_, rh, lh, lhR, temp, result, + pushedVal >> + +pushLeft(self) == N1(self) \/ N1a(self) \/ N1b(self) \/ N2(self) + \/ N3(self) \/ N4(self) \/ N5(self) \/ N6(self) + \/ N6a(self) \/ N7(self) \/ N8(self) \/ N8a(self) + +O1(self) == /\ pc[self] = "O1" + /\ lh' = [lh EXCEPT ![self] = LeftHat] + /\ pc' = [pc EXCEPT ![self] = "O2"] + /\ UNCHANGED << Mem, freeList, LeftHat, RightHat, rVal, valBag, + stack, v_, nd_, rh_, rhR, lh_, temp_, rh_p, lh_p, + rhL, temp_p, result_, v, nd, rh_pu, lhL, lh_pu, + temp_pu, rh, lhR, temp, result, pushedVal >> + +O2(self) == /\ pc[self] = "O2" + /\ rh' = [rh EXCEPT ![self] = RightHat] + /\ pc' = [pc EXCEPT ![self] = "O3"] + /\ UNCHANGED << Mem, freeList, LeftHat, RightHat, rVal, valBag, + stack, v_, nd_, rh_, rhR, lh_, temp_, rh_p, lh_p, + rhL, temp_p, result_, v, nd, rh_pu, lhL, lh_pu, + temp_pu, lh, lhR, temp, result, pushedVal >> + +O3(self) == /\ pc[self] = "O3" + /\ IF Mem[lh[self]].L = lh[self] + THEN /\ rVal' = [rVal EXCEPT ![self] = "empty"] + /\ pc' = [pc EXCEPT ![self] = "O3a"] + ELSE /\ pc' = [pc EXCEPT ![self] = "O4"] + /\ rVal' = rVal + /\ UNCHANGED << Mem, freeList, LeftHat, RightHat, valBag, stack, + v_, nd_, rh_, rhR, lh_, temp_, rh_p, lh_p, rhL, + temp_p, result_, v, nd, rh_pu, lhL, lh_pu, temp_pu, + rh, lh, lhR, temp, result, pushedVal >> + +O3a(self) == /\ pc[self] = "O3a" + /\ pc' = [pc EXCEPT ![self] = Head(stack[self]).pc] + /\ rh' = [rh EXCEPT ![self] = Head(stack[self]).rh] + /\ lh' = [lh EXCEPT ![self] = Head(stack[self]).lh] + /\ lhR' = [lhR EXCEPT ![self] = Head(stack[self]).lhR] + /\ temp' = [temp EXCEPT ![self] = Head(stack[self]).temp] + /\ result' = [result EXCEPT ![self] = Head(stack[self]).result] + /\ stack' = [stack EXCEPT ![self] = Tail(stack[self])] + /\ UNCHANGED << Mem, freeList, LeftHat, RightHat, rVal, valBag, + v_, nd_, rh_, rhR, lh_, temp_, rh_p, lh_p, rhL, + temp_p, result_, v, nd, rh_pu, lhL, lh_pu, + temp_pu, pushedVal >> + +O4(self) == /\ pc[self] = "O4" + /\ IF lh[self] = rh[self] + THEN /\ IF /\ LeftHat = lh[self] + /\ RightHat = rh[self] + THEN /\ /\ LeftHat' = Dummy + /\ RightHat' = Dummy + /\ temp' = [temp EXCEPT ![self] = TRUE] + ELSE /\ temp' = [temp EXCEPT ![self] = FALSE] + /\ UNCHANGED << LeftHat, RightHat >> + /\ IF temp'[self] + THEN /\ pc' = [pc EXCEPT ![self] = "O5"] + ELSE /\ pc' = [pc EXCEPT ![self] = "O1"] + ELSE /\ pc' = [pc EXCEPT ![self] = "O6"] + /\ UNCHANGED << LeftHat, RightHat, temp >> + /\ UNCHANGED << Mem, freeList, rVal, valBag, stack, v_, nd_, rh_, + rhR, lh_, temp_, rh_p, lh_p, rhL, temp_p, result_, + v, nd, rh_pu, lhL, lh_pu, temp_pu, rh, lh, lhR, + result, pushedVal >> + +O6(self) == /\ pc[self] = "O6" + /\ lhR' = [lhR EXCEPT ![self] = Mem[lh[self]].R] + /\ pc' = [pc EXCEPT ![self] = "O7"] + /\ UNCHANGED << Mem, freeList, LeftHat, RightHat, rVal, valBag, + stack, v_, nd_, rh_, rhR, lh_, temp_, rh_p, lh_p, + rhL, temp_p, result_, v, nd, rh_pu, lhL, lh_pu, + temp_pu, rh, lh, temp, result, pushedVal >> + +O7(self) == /\ pc[self] = "O7" + /\ IF /\ LeftHat = lh[self] + /\ (Mem[lh[self]].R) = lhR[self] + THEN /\ /\ LeftHat' = lhR[self] + /\ Mem' = [Mem EXCEPT ![lh[self]].R = lh[self]] + /\ temp' = [temp EXCEPT ![self] = TRUE] + ELSE /\ temp' = [temp EXCEPT ![self] = FALSE] + /\ UNCHANGED << Mem, LeftHat >> + /\ IF temp'[self] + THEN /\ pc' = [pc EXCEPT ![self] = "O8"] + ELSE /\ pc' = [pc EXCEPT ![self] = "O1"] + /\ UNCHANGED << freeList, RightHat, rVal, valBag, stack, v_, nd_, + rh_, rhR, lh_, temp_, rh_p, lh_p, rhL, temp_p, + result_, v, nd, rh_pu, lhL, lh_pu, temp_pu, rh, lh, + lhR, result, pushedVal >> + +O8(self) == /\ pc[self] = "O8" + /\ result' = [result EXCEPT ![self] = Mem[lh[self]].V] + /\ pc' = [pc EXCEPT ![self] = "O9"] + /\ UNCHANGED << Mem, freeList, LeftHat, RightHat, rVal, valBag, + stack, v_, nd_, rh_, rhR, lh_, temp_, rh_p, lh_p, + rhL, temp_p, result_, v, nd, rh_pu, lhL, lh_pu, + temp_pu, rh, lh, lhR, temp, pushedVal >> + +O9(self) == /\ pc[self] = "O9" + /\ Mem' = [Mem EXCEPT ![lh[self]].L = Dummy, + ![lh[self]].V = null] + /\ rVal' = [rVal EXCEPT ![self] = result[self]] + /\ pc' = [pc EXCEPT ![self] = "O10a"] + /\ UNCHANGED << freeList, LeftHat, RightHat, valBag, stack, v_, + nd_, rh_, rhR, lh_, temp_, rh_p, lh_p, rhL, temp_p, + result_, v, nd, rh_pu, lhL, lh_pu, temp_pu, rh, lh, + lhR, temp, result, pushedVal >> + +O10a(self) == /\ pc[self] = "O10a" + /\ pc' = [pc EXCEPT ![self] = Head(stack[self]).pc] + /\ rh' = [rh EXCEPT ![self] = Head(stack[self]).rh] + /\ lh' = [lh EXCEPT ![self] = Head(stack[self]).lh] + /\ lhR' = [lhR EXCEPT ![self] = Head(stack[self]).lhR] + /\ temp' = [temp EXCEPT ![self] = Head(stack[self]).temp] + /\ result' = [result EXCEPT ![self] = Head(stack[self]).result] + /\ stack' = [stack EXCEPT ![self] = Tail(stack[self])] + /\ UNCHANGED << Mem, freeList, LeftHat, RightHat, rVal, valBag, + v_, nd_, rh_, rhR, lh_, temp_, rh_p, lh_p, rhL, + temp_p, result_, v, nd, rh_pu, lhL, lh_pu, + temp_pu, pushedVal >> + +O5(self) == /\ pc[self] = "O5" + /\ rVal' = [rVal EXCEPT ![self] = Mem[lh[self]].V] + /\ pc' = [pc EXCEPT ![self] = "O5a"] + /\ UNCHANGED << Mem, freeList, LeftHat, RightHat, valBag, stack, + v_, nd_, rh_, rhR, lh_, temp_, rh_p, lh_p, rhL, + temp_p, result_, v, nd, rh_pu, lhL, lh_pu, temp_pu, + rh, lh, lhR, temp, result, pushedVal >> + +O5a(self) == /\ pc[self] = "O5a" + /\ pc' = [pc EXCEPT ![self] = Head(stack[self]).pc] + /\ rh' = [rh EXCEPT ![self] = Head(stack[self]).rh] + /\ lh' = [lh EXCEPT ![self] = Head(stack[self]).lh] + /\ lhR' = [lhR EXCEPT ![self] = Head(stack[self]).lhR] + /\ temp' = [temp EXCEPT ![self] = Head(stack[self]).temp] + /\ result' = [result EXCEPT ![self] = Head(stack[self]).result] + /\ stack' = [stack EXCEPT ![self] = Tail(stack[self])] + /\ UNCHANGED << Mem, freeList, LeftHat, RightHat, rVal, valBag, + v_, nd_, rh_, rhR, lh_, temp_, rh_p, lh_p, rhL, + temp_p, result_, v, nd, rh_pu, lhL, lh_pu, + temp_pu, pushedVal >> + +popLeft(self) == O1(self) \/ O2(self) \/ O3(self) \/ O3a(self) \/ O4(self) + \/ O6(self) \/ O7(self) \/ O8(self) \/ O9(self) + \/ O10a(self) \/ O5(self) \/ O5a(self) + +T1(self) == /\ pc[self] = "T1" + /\ \/ /\ \E x \in Val: + pushedVal' = [pushedVal EXCEPT ![self] = x] + /\ valBag' = [valBag EXCEPT ![pushedVal'[self]] = valBag[pushedVal'[self]] + 1] + /\ \/ /\ /\ stack' = [stack EXCEPT ![self] = << [ procedure |-> "pushLeft", + pc |-> "T2", + nd |-> nd[self], + rh_pu |-> rh_pu[self], + lhL |-> lhL[self], + lh_pu |-> lh_pu[self], + temp_pu |-> temp_pu[self], + v |-> v[self] ] >> + \o stack[self]] + /\ v' = [v EXCEPT ![self] = pushedVal'[self]] + /\ nd' = [nd EXCEPT ![self] = null] + /\ rh_pu' = [rh_pu EXCEPT ![self] = Dummy] + /\ lhL' = [lhL EXCEPT ![self] = Dummy] + /\ lh_pu' = [lh_pu EXCEPT ![self] = Dummy] + /\ temp_pu' = [temp_pu EXCEPT ![self] = Dummy] + /\ pc' = [pc EXCEPT ![self] = "N1"] + /\ UNCHANGED <<v_, nd_, rh_, rhR, lh_, temp_>> + \/ /\ /\ stack' = [stack EXCEPT ![self] = << [ procedure |-> "pushRight", + pc |-> "T2", + nd_ |-> nd_[self], + rh_ |-> rh_[self], + rhR |-> rhR[self], + lh_ |-> lh_[self], + temp_ |-> temp_[self], + v_ |-> v_[self] ] >> + \o stack[self]] + /\ v_' = [v_ EXCEPT ![self] = pushedVal'[self]] + /\ nd_' = [nd_ EXCEPT ![self] = null] + /\ rh_' = [rh_ EXCEPT ![self] = Dummy] + /\ rhR' = [rhR EXCEPT ![self] = Dummy] + /\ lh_' = [lh_ EXCEPT ![self] = Dummy] + /\ temp_' = [temp_ EXCEPT ![self] = Dummy] + /\ pc' = [pc EXCEPT ![self] = "L1"] + /\ UNCHANGED <<v, nd, rh_pu, lhL, lh_pu, temp_pu>> + /\ UNCHANGED <<rh_p, lh_p, rhL, temp_p, result_, rh, lh, lhR, temp, result>> + \/ /\ \/ /\ stack' = [stack EXCEPT ![self] = << [ procedure |-> "popLeft", + pc |-> "T3", + rh |-> rh[self], + lh |-> lh[self], + lhR |-> lhR[self], + temp |-> temp[self], + result |-> result[self] ] >> + \o stack[self]] + /\ rh' = [rh EXCEPT ![self] = Dummy] + /\ lh' = [lh EXCEPT ![self] = Dummy] + /\ lhR' = [lhR EXCEPT ![self] = Dummy] + /\ temp' = [temp EXCEPT ![self] = Dummy] + /\ result' = [result EXCEPT ![self] = null] + /\ pc' = [pc EXCEPT ![self] = "O1"] + /\ UNCHANGED <<rh_p, lh_p, rhL, temp_p, result_>> + \/ /\ stack' = [stack EXCEPT ![self] = << [ procedure |-> "popRight", + pc |-> "T3", + rh_p |-> rh_p[self], + lh_p |-> lh_p[self], + rhL |-> rhL[self], + temp_p |-> temp_p[self], + result_ |-> result_[self] ] >> + \o stack[self]] + /\ rh_p' = [rh_p EXCEPT ![self] = Dummy] + /\ lh_p' = [lh_p EXCEPT ![self] = Dummy] + /\ rhL' = [rhL EXCEPT ![self] = Dummy] + /\ temp_p' = [temp_p EXCEPT ![self] = Dummy] + /\ result_' = [result_ EXCEPT ![self] = null] + /\ pc' = [pc EXCEPT ![self] = "M1"] + /\ UNCHANGED <<rh, lh, lhR, temp, result>> + /\ UNCHANGED <<valBag, v_, nd_, rh_, rhR, lh_, temp_, v, nd, rh_pu, lhL, lh_pu, temp_pu, pushedVal>> + /\ UNCHANGED << Mem, freeList, LeftHat, RightHat, rVal >> + +T2(self) == /\ pc[self] = "T2" + /\ IF rVal[self] = "full" + THEN /\ valBag' = [valBag EXCEPT ![pushedVal[self]] = valBag[pushedVal[self]] - 1] + ELSE /\ TRUE + /\ UNCHANGED valBag + /\ pc' = [pc EXCEPT ![self] = "T1"] + /\ UNCHANGED << Mem, freeList, LeftHat, RightHat, rVal, stack, v_, + nd_, rh_, rhR, lh_, temp_, rh_p, lh_p, rhL, temp_p, + result_, v, nd, rh_pu, lhL, lh_pu, temp_pu, rh, lh, + lhR, temp, result, pushedVal >> + +T3(self) == /\ pc[self] = "T3" + /\ IF rVal[self] # "empty" + THEN /\ Assert(valBag[rVal[self]] > 0, + "Failure of assertion at line 238, column 11.") + /\ valBag' = [valBag EXCEPT ![rVal[self]] = valBag[rVal[self]] - 1] + ELSE /\ TRUE + /\ UNCHANGED valBag + /\ pc' = [pc EXCEPT ![self] = "T1"] + /\ UNCHANGED << Mem, freeList, LeftHat, RightHat, rVal, stack, v_, + nd_, rh_, rhR, lh_, temp_, rh_p, lh_p, rhL, temp_p, + result_, v, nd, rh_pu, lhL, lh_pu, temp_pu, rh, lh, + lhR, temp, result, pushedVal >> + +test(self) == T1(self) \/ T2(self) \/ T3(self) + +Next == (\E self \in ProcSet: \/ pushRight(self) \/ popRight(self) + \/ pushLeft(self) \/ popLeft(self)) + \/ (\E self \in Procs: test(self)) + +Spec == Init /\ [][Next]_vars + +\* END TRANSLATION + +Symmetry == Permutations(Address \ {Dummy}) \cup Permutations(Procs) + +Liveness == \A p \in Procs : []<> (pc[p] = "T1") +============================================================================= + +Checked on SVC-LAMPORT-3 with + CONSTANTS Val = {v1, v2} + Address = {a1, a2, a3} + Dummy = a1 + Procs = {p1, p2} + null = null + GC = GC + +found 2886585 states, depth 67, in 17 min 38.3 sec + +============================== + +Run on SVC-LAMPORT-2 with + + CONSTANTS Val = {v1} + Address = {a1, a2, a3, a4} + Dummy = a1 + Procs = {p1, p2, p3} + null = null + GC = GC + +stopped after 1482 min 40 sec, with +109078490 states generated, 37886049 distinct states, 5107502 states +left on queue. diff --git a/tlatools/test-model/pcal/Dijkstra1.cfg b/tlatools/test-model/pcal/Dijkstra1.cfg new file mode 100644 index 0000000000000000000000000000000000000000..2b93631d3e6bbf904652490bceaf2e39627dec59 --- /dev/null +++ b/tlatools/test-model/pcal/Dijkstra1.cfg @@ -0,0 +1,6 @@ +SPECIFICATION Spec +\* Add statements after this line. +CONSTANTS N = 4 + K = 5 +INVARIANT SomeoneHoldsToken +PROPERTY EventuallyJustOneHoldsToken diff --git a/tlatools/test-model/pcal/Dijkstra1.tla b/tlatools/test-model/pcal/Dijkstra1.tla new file mode 100644 index 0000000000000000000000000000000000000000..f5c2cee2bfb03951522502fbfabad5e6ed3b89ab --- /dev/null +++ b/tlatools/test-model/pcal/Dijkstra1.tla @@ -0,0 +1,84 @@ +--algorithm Dijkstra1 +variable M \in [ProcSet -> 0..(K-1)]; + + process P0 = 0 + begin +p0: while TRUE do + when M[0] = M[N-1]; +p1: M[0] := (M[0] + 1) % K; + end while + end process; + + process Pi \in 1..(N-1) + begin +pi: while (TRUE) do + when M[self] # M[self - 1]; +pj: M[self] := M[self - 1]; + end while + end process; + + end algorithm + +----------- MODULE Dijkstra1 ----------- +EXTENDS FiniteSets, Naturals + +CONSTANT K, N + +ASSUME (K > N) /\ (N > 0) + +\* BEGIN TRANSLATION +VARIABLES M, pc + +vars == << M, pc >> + +ProcSet == {0} \cup (1..(N-1)) + +Init == (* Global variables *) + /\ M \in [ProcSet -> 0..(K-1)] + /\ pc = [self \in ProcSet |-> CASE self = 0 -> "p0" + [] self \in 1..(N-1) -> "pi"] + +p0 == /\ pc[0] = "p0" + /\ M[0] = M[N-1] + /\ pc' = [pc EXCEPT ![0] = "p1"] + /\ M' = M + +p1 == /\ pc[0] = "p1" + /\ M' = [M EXCEPT ![0] = (M[0] + 1) % K] + /\ pc' = [pc EXCEPT ![0] = "p0"] + +P0 == p0 \/ p1 + +pi(self) == /\ pc[self] = "pi" + /\ M[self] # M[self - 1] + /\ pc' = [pc EXCEPT ![self] = "pj"] + /\ M' = M + +pj(self) == /\ pc[self] = "pj" + /\ M' = [M EXCEPT ![self] = M[self - 1]] + /\ pc' = [pc EXCEPT ![self] = "pi"] + +Pi(self) == pi(self) \/ pj(self) + +Next == P0 + \/ (\E self \in 1..(N-1): Pi(self)) + +Spec == /\ Init /\ [][Next]_vars + /\ WF_vars(P0) + /\ \A self \in 1..(N-1) : WF_vars(Pi(self)) + +\* END TRANSLATION + +HasToken(self) == \/ (self = 0) /\ (M[0] = M[N - 1]) + \/ (self > 0) /\ (M[self] # M[self - 1]) + +TokenHolders == {self \in ProcSet: HasToken(self)} + +SomeoneHoldsToken == Cardinality(TokenHolders) > 0 + +EventuallyJustOneHoldsToken == <>[] (Cardinality(TokenHolders) = 1) + +THEOREM Spec => [] SomeoneHoldsToken + +THEOREM Spec => EventuallyJustOneHoldsToken +======================================== diff --git a/tlatools/test-model/pcal/DiningPhilosophers.cfg b/tlatools/test-model/pcal/DiningPhilosophers.cfg new file mode 100644 index 0000000000000000000000000000000000000000..a174cf298c441c5cb0d1f0028577442a7726703b --- /dev/null +++ b/tlatools/test-model/pcal/DiningPhilosophers.cfg @@ -0,0 +1,5 @@ +SPECIFICATION Spec +\* Add statements after this line. +CONSTANT N = 4 +INVARIANT Invariant +PROPERTY StarvationFree diff --git a/tlatools/test-model/pcal/DiningPhilosophers.tla b/tlatools/test-model/pcal/DiningPhilosophers.tla new file mode 100644 index 0000000000000000000000000000000000000000..f5b59c19e34cd04c2dd26d425c82b4fcf599861e --- /dev/null +++ b/tlatools/test-model/pcal/DiningPhilosophers.tla @@ -0,0 +1,127 @@ +-------------------------- MODULE DiningPhilosophers ------------------------ + +(***************************************************************************) +(* A simple solution to the Dining Philosophers problem in which processes *) +(* 1 through N-1 pick up their lef then their right forks, and process 0 *) +(* picks them up in the opposite order. *) +(***************************************************************************) + +EXTENDS Naturals + +CONSTANT N + +ASSUME N \in Nat + +(********************** + +--algorithm DiningPhilosophers + variable sem = [i \in 0..(N-1) |-> 1] ; + +process Proc \in 1..(N-1) +begin +l1 : while TRUE + do when sem[self] = 1 ; \* Get right fork. + sem[self] := 0 ; + l2 : when sem[(self-1) % N] = 1 ; \* Get left fork. + sem[(self-1) % N] := 0 ; + e : skip ; \* Eat + l3 : sem[self] := 1 ; \* Release right fork. + l4 : sem[(self-1) % N] := 1 ; \* Release left fork. + end while ; +end process + +process Proc0 = 0 +begin +l01 : while TRUE + do when sem[N-1] = 1 ; \* get left fork + sem[N-1] := 0 ; + l02 : when sem[0] = 1 ; \* get right fork + sem[0] := 0 ; + e0 : skip ; \* eat + l03 : sem[0] := 1 ; \* release left fork + l04 : sem[N-1] := 1 ; \* release right fork + end while ; +end process + +end algorithm + +***********************) + +(**************** BEGIN TRANSLATION *******************************) +VARIABLES sem, pc + +vars == << sem, pc >> + +ProcSet == (1..(N-1)) \cup {0} + +Init == (* Global variables *) + /\ sem = [i \in 0..(N-1) |-> 1] + /\ pc = [self \in ProcSet |-> CASE self \in 1..(N-1) -> "l1" + [] self = 0 -> "l01"] + +l1(self) == /\ pc[self] = "l1" + /\ sem[self] = 1 + /\ sem' = [sem EXCEPT ![self] = 0] + /\ pc' = [pc EXCEPT ![self] = "l2"] + +l2(self) == /\ pc[self] = "l2" + /\ sem[(self-1) % N] = 1 + /\ sem' = [sem EXCEPT ![(self-1) % N] = 0] + /\ pc' = [pc EXCEPT ![self] = "e"] + +e(self) == /\ pc[self] = "e" + /\ TRUE + /\ pc' = [pc EXCEPT ![self] = "l3"] + /\ sem' = sem + +l3(self) == /\ pc[self] = "l3" + /\ sem' = [sem EXCEPT ![self] = 1] + /\ pc' = [pc EXCEPT ![self] = "l4"] + +l4(self) == /\ pc[self] = "l4" + /\ sem' = [sem EXCEPT ![(self-1) % N] = 1] + /\ pc' = [pc EXCEPT ![self] = "l1"] + +Proc(self) == l1(self) \/ l2(self) \/ e(self) \/ l3(self) \/ l4(self) + +l01 == /\ pc[0] = "l01" + /\ sem[N-1] = 1 + /\ sem' = [sem EXCEPT ![N-1] = 0] + /\ pc' = [pc EXCEPT ![0] = "l02"] + +l02 == /\ pc[0] = "l02" + /\ sem[0] = 1 + /\ sem' = [sem EXCEPT ![0] = 0] + /\ pc' = [pc EXCEPT ![0] = "e0"] + +e0 == /\ pc[0] = "e0" + /\ TRUE + /\ pc' = [pc EXCEPT ![0] = "l03"] + /\ sem' = sem + +l03 == /\ pc[0] = "l03" + /\ sem' = [sem EXCEPT ![0] = 1] + /\ pc' = [pc EXCEPT ![0] = "l04"] + +l04 == /\ pc[0] = "l04" + /\ sem' = [sem EXCEPT ![N-1] = 1] + /\ pc' = [pc EXCEPT ![0] = "l01"] + +Proc0 == l01 \/ l02 \/ e0 \/ l03 \/ l04 + +Next == Proc0 + \/ (\E self \in 1..(N-1): Proc(self)) + +Spec == /\ Init /\ [][Next]_vars + /\ \A self \in 1..(N-1) : SF_vars(Proc(self)) + /\ SF_vars(Proc0) + +(**************** END TRANSLATION *******************************) + +IsEating(i) == IF i = 0 THEN pc[i] = "e0" + ELSE pc[i] = "e" + +Invariant == \A i \in 0..(N-1) : ~ (IsEating(i) /\ IsEating((i+1)%N)) + +StarvationFree == \A i \in 0..(N-1) : []<> IsEating(i) +============================================================================= diff --git a/tlatools/test-model/pcal/DiningPhilosophers2.tla b/tlatools/test-model/pcal/DiningPhilosophers2.tla new file mode 100644 index 0000000000000000000000000000000000000000..07b756ae789f0dd03fb3a489259c3d6c27095ff2 --- /dev/null +++ b/tlatools/test-model/pcal/DiningPhilosophers2.tla @@ -0,0 +1,220 @@ + +-------------------------- MODULE DiningPhilosophers2 ------------------------ + +(***************************************************************************) +(* A simple solution to the Dining Philosophers problem in which processes *) +(* 1 through N-1 pick up their lef then their right forks, and process 0 *) +(* picks them up in the opposite order. *) +(***************************************************************************) + +EXTENDS Naturals + +CONSTANT N + +ASSUME N \in Nat + +(********************** + +--algorithm DiningPhilosophers + +variable sem = [i \in 0..(N-1) |-> 1] ; + procedure foo () + begin l2 :+ skip; + e :+ skip; + l3 :+ skip; + p4 : skip ; + return ; + end procedure + + procedure foo2 () + begin foo2begin : skip; + return; + end procedure ; + + fair process DummyProcessSet \in -3..0 + begin dp1: skip ; + end process + + fair process DummySingleProc = -42 + begin dp1: skip ; + end process; + + fair process Proc \in 1..(N-1) +begin +l1 : while TRUE + do when sem[self] = 1 ; \* Get right fork. + sem[self] := 0 ; + fox :+ when sem[(self-1) % N] = 1 ; \* Get left fork. + sem[(self-1) % N] := 0 ; + e :+ skip ; \* Eat + l3 :+ sem[self] := 1 ; \* Release right fork. + l4 :+ sem[(self-1) % N] := 1 ; \* Release left fork. + end while ; +end process + +process Leader = 0 \* Proc0 = 0 +begin +l01 : while TRUE + do when sem[N-1] = 1 ; \* get left fork + sem[N-1] := 0 ; + l2xx : when sem[0] = 1 ; \* get right fork + sem[0] := 0 ; + exx : call foo() ; \* eat + l03 :+ sem[0] := 1 ; \* release left fork + call foo() ; + l04 :+ sem[N-1] := 1 ; \* release right fork + end while ; +end process + +end algorithm + +***********************) + +(**************** BEGIN TRANSLATION *******************************) +\* Label e of procedure foo at line 23 col 16 changed to e_ +\* Label l3 of procedure foo at line 24 col 17 changed to l3_ +\* Label dp1 of process DummyProcessSet at line 35 col 15 changed to dp1_ +VARIABLES sem, pc, stack + +vars == << sem, pc, stack >> + +ProcSet == (-3..0) \cup {-42} \cup (1..(N-1)) \cup {0} + +Init == (* Global variables *) + /\ sem = [i \in 0..(N-1) |-> 1] + /\ stack = [self \in ProcSet |-> << >>] + /\ pc = [self \in ProcSet |-> CASE self \in -3..0 -> "dp1_" + [] self = -42 -> "dp1" + [] self \in 1..(N-1) -> "l1" + [] self = 0 -> "l01"] + +l2(self) == /\ pc[self] = "l2" + /\ TRUE + /\ pc' = [pc EXCEPT ![self] = "e_"] + /\ UNCHANGED << sem, stack >> + +e_(self) == /\ pc[self] = "e_" + /\ TRUE + /\ pc' = [pc EXCEPT ![self] = "l3_"] + /\ UNCHANGED << sem, stack >> + +l3_(self) == /\ pc[self] = "l3_" + /\ TRUE + /\ pc' = [pc EXCEPT ![self] = "p4"] + /\ UNCHANGED << sem, stack >> + +p4(self) == /\ pc[self] = "p4" + /\ TRUE + /\ pc' = [pc EXCEPT ![self] = Head(stack[self]).pc] + /\ stack' = [stack EXCEPT ![self] = Tail(stack[self])] + /\ sem' = sem + +foo(self) == l2(self) \/ e_(self) \/ l3_(self) \/ p4(self) + +foo2begin(self) == /\ pc[self] = "foo2begin" + /\ TRUE + /\ pc' = [pc EXCEPT ![self] = Head(stack[self]).pc] + /\ stack' = [stack EXCEPT ![self] = Tail(stack[self])] + /\ sem' = sem + +foo2(self) == foo2begin(self) + +dp1_(self) == /\ pc[self] = "dp1_" + /\ TRUE + /\ pc' = [pc EXCEPT ![self] = "Done"] + /\ UNCHANGED << sem, stack >> + +DummyProcessSet(self) == dp1_(self) + +dp1 == /\ pc[-42] = "dp1" + /\ TRUE + /\ pc' = [pc EXCEPT ![-42] = "Done"] + /\ UNCHANGED << sem, stack >> + +DummySingleProc == dp1 + +l1(self) == /\ pc[self] = "l1" + /\ sem[self] = 1 + /\ sem' = [sem EXCEPT ![self] = 0] + /\ pc' = [pc EXCEPT ![self] = "fox"] + /\ stack' = stack + +fox(self) == /\ pc[self] = "fox" + /\ sem[(self-1) % N] = 1 + /\ sem' = [sem EXCEPT ![(self-1) % N] = 0] + /\ pc' = [pc EXCEPT ![self] = "e"] + /\ stack' = stack + +e(self) == /\ pc[self] = "e" + /\ TRUE + /\ pc' = [pc EXCEPT ![self] = "l3"] + /\ UNCHANGED << sem, stack >> + +l3(self) == /\ pc[self] = "l3" + /\ sem' = [sem EXCEPT ![self] = 1] + /\ pc' = [pc EXCEPT ![self] = "l4"] + /\ stack' = stack + +l4(self) == /\ pc[self] = "l4" + /\ sem' = [sem EXCEPT ![(self-1) % N] = 1] + /\ pc' = [pc EXCEPT ![self] = "l1"] + /\ stack' = stack + +Proc(self) == l1(self) \/ fox(self) \/ e(self) \/ l3(self) \/ l4(self) + +l01 == /\ pc[0] = "l01" + /\ sem[N-1] = 1 + /\ sem' = [sem EXCEPT ![N-1] = 0] + /\ pc' = [pc EXCEPT ![0] = "l2xx"] + /\ stack' = stack + +l2xx == /\ pc[0] = "l2xx" + /\ sem[0] = 1 + /\ sem' = [sem EXCEPT ![0] = 0] + /\ pc' = [pc EXCEPT ![0] = "exx"] + /\ stack' = stack + +exx == /\ pc[0] = "exx" + /\ stack' = [stack EXCEPT ![0] = << [ procedure |-> "foo", + pc |-> "l03" ] >> + \o stack[0]] + /\ pc' = [pc EXCEPT ![0] = "l2"] + /\ sem' = sem + +l03 == /\ pc[0] = "l03" + /\ sem' = [sem EXCEPT ![0] = 1] + /\ stack' = [stack EXCEPT ![0] = << [ procedure |-> "foo", + pc |-> "l04" ] >> + \o stack[0]] + /\ pc' = [pc EXCEPT ![0] = "l2"] + +l04 == /\ pc[0] = "l04" + /\ sem' = [sem EXCEPT ![N-1] = 1] + /\ pc' = [pc EXCEPT ![0] = "l01"] + /\ stack' = stack + +Leader == l01 \/ l2xx \/ exx \/ l03 \/ l04 + +Next == DummySingleProc \/ Leader + \/ (\E self \in ProcSet: foo(self) \/ foo2(self)) + \/ (\E self \in -3..0: DummyProcessSet(self)) + \/ (\E self \in 1..(N-1): Proc(self)) + +Spec == /\ Init /\ [][Next]_vars + /\ \A self \in -3..0 : WF_vars(DummyProcessSet(self)) + /\ WF_vars(DummySingleProc) + /\ \A self \in 1..(N-1) : /\ WF_vars(Proc(self)) + /\ SF_vars(fox(self)) /\ SF_vars(e(self)) /\ SF_vars(l3(self)) /\ SF_vars(l4(self)) + /\ /\ WF_vars(Leader) /\ SF_vars(l03) /\ SF_vars(l04) + /\ WF_vars(foo(0)) + /\ SF_vars(l2(0)) /\ SF_vars(e_(0)) /\ SF_vars(l3_(0)) + +(**************** END TRANSLATION *******************************) + +IsEating(i) == IF i = 0 THEN pc[i] = "e0" + ELSE pc[i] = "e" + +Invariant == \A i \in 0..(N-1) : ~ (IsEating(i) /\ IsEating((i+1)%N)) + +StarvationFree == \A i \in 0..(N-1) : []<> IsEating(i) +============================================================================= diff --git a/tlatools/test-model/pcal/Either1.tla b/tlatools/test-model/pcal/Either1.tla new file mode 100644 index 0000000000000000000000000000000000000000..0c0915f5275e472f480b91c9df342c6880152f33 --- /dev/null +++ b/tlatools/test-model/pcal/Either1.tla @@ -0,0 +1,57 @@ +------------------------------- MODULE Either1 ------------------------------ +EXTENDS Naturals, Sequences, TLC + +(* --algorithm Either + variables x = 0 ; y = 0 ; + begin a: either x := 1 ; b: x := x + 1; + or y := 1 ; c: y := y + 1; + end either ; + d: assert x+y = 2 ; + end algorithm +*) + +\* BEGIN TRANSLATION +VARIABLES x, y, pc + +vars == << x, y, pc >> + +Init == (* Global variables *) + /\ x = 0 + /\ y = 0 + /\ pc = "a" + +a == /\ pc = "a" + /\ \/ /\ x' = 1 + /\ pc' = "b" + /\ y' = y + \/ /\ y' = 1 + /\ pc' = "c" + /\ x' = x + +b == /\ pc = "b" + /\ x' = x + 1 + /\ pc' = "d" + /\ y' = y + +c == /\ pc = "c" + /\ y' = y + 1 + /\ pc' = "d" + /\ x' = x + +d == /\ pc = "d" + /\ Assert(x+y = 2, "Failure of assertion at line 9, column 16.") + /\ pc' = "Done" + /\ UNCHANGED << x, y >> + +Next == a \/ b \/ c \/ d + \/ (* Disjunct to prevent deadlock on termination *) + (pc = "Done" /\ UNCHANGED vars) + +Spec == /\ Init /\ [][Next]_vars + /\ WF_vars(Next) + +Termination == <>(pc = "Done") + +\* END TRANSLATION + +============================================================================= diff --git a/tlatools/test-model/pcal/Either2.tla b/tlatools/test-model/pcal/Either2.tla new file mode 100644 index 0000000000000000000000000000000000000000..60f5f75fd1fb39e5e9ffc6a0dec0dce3d2fefe41 --- /dev/null +++ b/tlatools/test-model/pcal/Either2.tla @@ -0,0 +1,69 @@ +------------------------------- MODULE Either2 ------------------------------ +EXTENDS Naturals, Sequences, TLC + +(* --algorithm Either + variables x = 0 ; y = 0 ; z = 0 ; + begin a: either x := 1 ; + b: x := x + 1; + or y := 1 ; c: y := y + 1; + end either ; + d: either when x = 0 ; z := z + 1 ; + or when x = 2 ; z := z + 3 ; + end either ; + assert x+y = 2 ; + assert z = x + 1 ; + end algorithm +*) + +\* BEGIN TRANSLATION +VARIABLES x, y, z, pc + +vars == << x, y, z, pc >> + +Init == (* Global variables *) + /\ x = 0 + /\ y = 0 + /\ z = 0 + /\ pc = "a" + +a == /\ pc = "a" + /\ \/ /\ x' = 1 + /\ pc' = "b" + /\ y' = y + \/ /\ y' = 1 + /\ pc' = "c" + /\ x' = x + /\ z' = z + +b == /\ pc = "b" + /\ x' = x + 1 + /\ pc' = "d" + /\ UNCHANGED << y, z >> + +c == /\ pc = "c" + /\ y' = y + 1 + /\ pc' = "d" + /\ UNCHANGED << x, z >> + +d == /\ pc = "d" + /\ \/ /\ x = 0 + /\ z' = z + 1 + \/ /\ x = 2 + /\ z' = z + 3 + /\ Assert(x+y = 2, "Failure of assertion at line 13, column 16.") + /\ Assert(z' = x + 1, "Failure of assertion at line 14, column 16.") + /\ pc' = "Done" + /\ UNCHANGED << x, y >> + +Next == a \/ b \/ c \/ d + \/ (* Disjunct to prevent deadlock on termination *) + (pc = "Done" /\ UNCHANGED vars) + +Spec == /\ Init /\ [][Next]_vars + /\ WF_vars(Next) + +Termination == <>(pc = "Done") + +\* END TRANSLATION + +============================================================================= diff --git a/tlatools/test-model/pcal/Either3.tla b/tlatools/test-model/pcal/Either3.tla new file mode 100644 index 0000000000000000000000000000000000000000..8f1ebc0cdf5f159959ca94a9b4f61d001519142a --- /dev/null +++ b/tlatools/test-model/pcal/Either3.tla @@ -0,0 +1,74 @@ +------------------------------- MODULE Either3 ------------------------------ +EXTENDS Naturals, Sequences, TLC + +(* --algorithm Either + variables x = 0 ; y = 0 ; z = 0 ; + begin a: either x := 1 ; + b: x := x + 1; + or y := 1 ; c: y := y + 1; + or z := 100 + end either ; + d: either when x = 0 ; z := z + 1 ; + or when x = 2 ; z := z + 3 ; + end either ; + assert (x+y = 2) \/ ((z = 101) /\ (x+y=0)); + assert (z < 100) => (z = x + 1) ; + end algorithm +*) + +\* BEGIN TRANSLATION +VARIABLES x, y, z, pc + +vars == << x, y, z, pc >> + +Init == (* Global variables *) + /\ x = 0 + /\ y = 0 + /\ z = 0 + /\ pc = "a" + +a == /\ pc = "a" + /\ \/ /\ x' = 1 + /\ pc' = "b" + /\ UNCHANGED <<y, z>> + \/ /\ y' = 1 + /\ pc' = "c" + /\ UNCHANGED <<x, z>> + \/ /\ z' = 100 + /\ pc' = "d" + /\ UNCHANGED <<x, y>> + +b == /\ pc = "b" + /\ x' = x + 1 + /\ pc' = "d" + /\ UNCHANGED << y, z >> + +c == /\ pc = "c" + /\ y' = y + 1 + /\ pc' = "d" + /\ UNCHANGED << x, z >> + +d == /\ pc = "d" + /\ \/ /\ x = 0 + /\ z' = z + 1 + \/ /\ x = 2 + /\ z' = z + 3 + /\ Assert((x+y = 2) \/ ((z' = 101) /\ (x+y=0)), + "Failure of assertion at line 14, column 16.") + /\ Assert((z' < 100) => (z' = x + 1), + "Failure of assertion at line 15, column 16.") + /\ pc' = "Done" + /\ UNCHANGED << x, y >> + +Next == a \/ b \/ c \/ d + \/ (* Disjunct to prevent deadlock on termination *) + (pc = "Done" /\ UNCHANGED vars) + +Spec == /\ Init /\ [][Next]_vars + /\ WF_vars(Next) + +Termination == <>(pc = "Done") + +\* END TRANSLATION + +============================================================================= diff --git a/tlatools/test-model/pcal/Either4.tla b/tlatools/test-model/pcal/Either4.tla new file mode 100644 index 0000000000000000000000000000000000000000..e0253f5d57af24a393ae3bf2f32468abc7d65e35 --- /dev/null +++ b/tlatools/test-model/pcal/Either4.tla @@ -0,0 +1,80 @@ +------------------------------- MODULE Either4 ------------------------------ +EXTENDS Naturals, Sequences, TLC + +(* --algorithm Either + process Foo \in {1, 2} + variables x = 0 ; y = 0 ; z = 0 ; + begin a: either x := 1 ; + b: x := x + 1; + or y := 1 ; c: y := y + 1; + or z := 100 + end either ; + d: either when x = 0 ; z := z + 1 ; + or when x = 2 ; z := z + 3 ; + end either ; + assert (x+y = 2) \/ ((z = 101) /\ (x+y=0)); + assert (z < 100) => (z = x + 1) ; + end process + end algorithm +*) + +\* BEGIN TRANSLATION +VARIABLES pc, x, y, z + +vars == << pc, x, y, z >> + +ProcSet == ({1, 2}) + +Init == (* Process Foo *) + /\ x = [self \in {1, 2} |-> 0] + /\ y = [self \in {1, 2} |-> 0] + /\ z = [self \in {1, 2} |-> 0] + /\ pc = [self \in ProcSet |-> "a"] + +a(self) == /\ pc[self] = "a" + /\ \/ /\ x' = [x EXCEPT ![self] = 1] + /\ pc' = [pc EXCEPT ![self] = "b"] + /\ UNCHANGED <<y, z>> + \/ /\ y' = [y EXCEPT ![self] = 1] + /\ pc' = [pc EXCEPT ![self] = "c"] + /\ UNCHANGED <<x, z>> + \/ /\ z' = [z EXCEPT ![self] = 100] + /\ pc' = [pc EXCEPT ![self] = "d"] + /\ UNCHANGED <<x, y>> + +b(self) == /\ pc[self] = "b" + /\ x' = [x EXCEPT ![self] = x[self] + 1] + /\ pc' = [pc EXCEPT ![self] = "d"] + /\ UNCHANGED << y, z >> + +c(self) == /\ pc[self] = "c" + /\ y' = [y EXCEPT ![self] = y[self] + 1] + /\ pc' = [pc EXCEPT ![self] = "d"] + /\ UNCHANGED << x, z >> + +d(self) == /\ pc[self] = "d" + /\ \/ /\ x[self] = 0 + /\ z' = [z EXCEPT ![self] = z[self] + 1] + \/ /\ x[self] = 2 + /\ z' = [z EXCEPT ![self] = z[self] + 3] + /\ Assert((x[self]+y[self] = 2) \/ ((z'[self] = 101) /\ (x[self]+y[self]=0)), + "Failure of assertion at line 15, column 16.") + /\ Assert((z'[self] < 100) => (z'[self] = x[self] + 1), + "Failure of assertion at line 16, column 16.") + /\ pc' = [pc EXCEPT ![self] = "Done"] + /\ UNCHANGED << x, y >> + +Foo(self) == a(self) \/ b(self) \/ c(self) \/ d(self) + +Next == (\E self \in {1, 2}: Foo(self)) + \/ (* Disjunct to prevent deadlock on termination *) + ((\A self \in ProcSet: pc[self] = "Done") /\ UNCHANGED vars) + +Spec == /\ Init /\ [][Next]_vars + /\ \A self \in {1, 2} : WF_vars(Foo(self)) + +Termination == <>(\A self \in ProcSet: pc[self] = "Done") + +\* END TRANSLATION + +============================================================================= diff --git a/tlatools/test-model/pcal/Either5.tla b/tlatools/test-model/pcal/Either5.tla new file mode 100644 index 0000000000000000000000000000000000000000..62ed5708362e30d6bfea4a51154784d4224cc062 --- /dev/null +++ b/tlatools/test-model/pcal/Either5.tla @@ -0,0 +1,82 @@ +------------------------------- MODULE Either5 ------------------------------ +EXTENDS Naturals, Sequences, TLC + +(* --algorithm Either + variables x = 0 ; y = 0 ; z = 0 ; + procedure Foo(a) + begin c: x := x + a ; + return + end procedure; + begin a: either x := 1 ; y := 0 ; + or y := 1 ; + or call Foo(1) ; + b: assert x = 1 ; + end either ; + d: assert x+y = 1 ; + end algorithm +*) + +\* BEGIN TRANSLATION +\* Label a at line 10 col 16 changed to a_ +CONSTANT defaultInitValue +VARIABLES x, y, z, pc, stack, a + +vars == << x, y, z, pc, stack, a >> + +Init == (* Global variables *) + /\ x = 0 + /\ y = 0 + /\ z = 0 + (* Procedure Foo *) + /\ a = defaultInitValue + /\ stack = << >> + /\ pc = "a_" + +c == /\ pc = "c" + /\ x' = x + a + /\ pc' = Head(stack).pc + /\ a' = Head(stack).a + /\ stack' = Tail(stack) + /\ UNCHANGED << y, z >> + +Foo == c + +a_ == /\ pc = "a_" + /\ \/ /\ x' = 1 + /\ y' = 0 + /\ pc' = "d" + /\ UNCHANGED <<stack, a>> + \/ /\ y' = 1 + /\ pc' = "d" + /\ UNCHANGED <<x, stack, a>> + \/ /\ /\ a' = 1 + /\ stack' = << [ procedure |-> "Foo", + pc |-> "b", + a |-> a ] >> + \o stack + /\ pc' = "c" + /\ UNCHANGED <<x, y>> + /\ z' = z + +b == /\ pc = "b" + /\ Assert(x = 1, "Failure of assertion at line 13, column 25.") + /\ pc' = "d" + /\ UNCHANGED << x, y, z, stack, a >> + +d == /\ pc = "d" + /\ Assert(x+y = 1, "Failure of assertion at line 15, column 18.") + /\ pc' = "Done" + /\ UNCHANGED << x, y, z, stack, a >> + +Next == Foo \/ a_ \/ b \/ d + \/ (* Disjunct to prevent deadlock on termination *) + (pc = "Done" /\ UNCHANGED vars) + +Spec == /\ Init /\ [][Next]_vars + /\ WF_vars(Next) + +Termination == <>(pc = "Done") + +\* END TRANSLATION + +============================================================================= diff --git a/tlatools/test-model/pcal/Euclid.cfg b/tlatools/test-model/pcal/Euclid.cfg new file mode 100644 index 0000000000000000000000000000000000000000..886249f10a49afefccd3318c4856c04098d202a5 --- /dev/null +++ b/tlatools/test-model/pcal/Euclid.cfg @@ -0,0 +1,4 @@ +SPECIFICATION Spec +PROPERTY Termination +\* Add statements after this line. +INVARIANT Invariant diff --git a/tlatools/test-model/pcal/Euclid.tla b/tlatools/test-model/pcal/Euclid.tla new file mode 100644 index 0000000000000000000000000000000000000000..90b4c0b7503592a512bb3e766dd48b4e60c4ade2 --- /dev/null +++ b/tlatools/test-model/pcal/Euclid.tla @@ -0,0 +1,91 @@ +-------------------------------- MODULE Euclid ------------------------------- +(***************************************************************************) +(* Euclid's algorithm. *) +(***************************************************************************) + +EXTENDS Naturals, TLC + +\*CONSTANT MaxNum +MaxNum == 20 + +ASSUME MaxNum > 0 + +ASSUME /\ Print(<<"Testing Euclid's algorithm on all numbers between 1 and ", + MaxNum>>, TRUE) + /\ Print("Most time spent evaluating naive definition of GCD for test", + TRUE) + +(****** +Adapted from page 8 of the 2nd edition of Robert Sedgewick's "Algorithms". + +--algorithm Euclid + variables u_ini \in 1 .. MaxNum ; + v_ini \in 1 .. MaxNum ; + u = u_ini ; v = v_ini ; + begin a : while u # 0 + do if u < v then u := v || v := u ; end if ; + b: u := u - v; + end while ; + assert v = GCD(u_ini, v_ini) ; + \* print <<"gcd of ", u_ini, v_ini, " equals ", v >> ; + end algorithm + +*) + +GCD(x, y) == CHOOSE i \in (1..x) \cap (1..y) : + /\ x % i = 0 + /\ y % i = 0 + /\ \A j \in (1..x) \cap (1..y) : + /\ x % j = 0 + /\ y % j = 0 + => i \geq j + + + +(***** BEGIN TRANSLATION ***) +VARIABLES u_ini, v_ini, u, v, pc + +vars == << u_ini, v_ini, u, v, pc >> + +Init == (* Global variables *) + /\ u_ini \in 1 .. MaxNum + /\ v_ini \in 1 .. MaxNum + /\ u = u_ini + /\ v = v_ini + /\ pc = "a" + +a == /\ pc = "a" + /\ IF u # 0 + THEN /\ IF u < v + THEN /\ /\ u' = v + /\ v' = u + ELSE /\ TRUE + /\ UNCHANGED << u, v >> + /\ pc' = "b" + ELSE /\ Assert(v = GCD(u_ini, v_ini), + "Failure of assertion at line 29, column 13.") + /\ pc' = "Done" + /\ UNCHANGED << u, v >> + /\ UNCHANGED << u_ini, v_ini >> + +b == /\ pc = "b" + /\ u' = u - v + /\ pc' = "a" + /\ UNCHANGED << u_ini, v_ini, v >> + +Next == a \/ b + \/ (* Disjunct to prevent deadlock on termination *) + (pc = "Done" /\ UNCHANGED vars) + +Spec == /\ Init /\ [][Next]_vars + /\ WF_vars(Next) + +Termination == <>(pc = "Done") + +(***** END TRANSLATION ***) + + +Invariant == + (pc = "Done") => (v = GCD(u_ini, v_ini)) + +============================================================================= diff --git a/tlatools/test-model/pcal/Euclid2.tla b/tlatools/test-model/pcal/Euclid2.tla new file mode 100644 index 0000000000000000000000000000000000000000..b3d0b032e98f392b881d0b09587ccde1198076bb --- /dev/null +++ b/tlatools/test-model/pcal/Euclid2.tla @@ -0,0 +1,66 @@ +--algorithm EuclidAlg +variables u = 24 ; v \in 1 .. N ; v_ini = v ; +begin +lp: while u # 0 do + if u < v then u := v || v := u ; + end if ; + a: u := u - v; + end while ; + assert v = GCD(24, v_ini) ; +end algorithm + +-------------------------------- MODULE Euclid2 ------------------------------ +EXTENDS Naturals, TLC +\*CONSTANT N +N == 500 + +GCD(x, y) == CHOOSE i \in (1..x) \cap (1..y) : + /\ x % i = 0 + /\ y % i = 0 + /\ \A j \in (1..x) \cap (1..y) : + /\ x % j = 0 + /\ y % j = 0 + => i \geq j + +(***** BEGIN TRANSLATION ***) +VARIABLES u, v, v_ini, pc + +vars == << u, v, v_ini, pc >> + +Init == (* Global variables *) + /\ u = 24 + /\ v \in 1 .. N + /\ v_ini = v + /\ pc = "lp" + +lp == /\ pc = "lp" + /\ IF u # 0 + THEN /\ IF u < v + THEN /\ /\ u' = v + /\ v' = u + ELSE /\ TRUE + /\ UNCHANGED << u, v >> + /\ pc' = "a" + ELSE /\ Assert(v = GCD(24, v_ini), + "Failure of assertion at line 9, column 5.") + /\ pc' = "Done" + /\ UNCHANGED << u, v >> + /\ v_ini' = v_ini + +a == /\ pc = "a" + /\ u' = u - v + /\ pc' = "lp" + /\ UNCHANGED << v, v_ini >> + +Next == lp \/ a + \/ (* Disjunct to prevent deadlock on termination *) + (pc = "Done" /\ UNCHANGED vars) + +Spec == /\ Init /\ [][Next]_vars + /\ WF_vars(Next) + +Termination == <>(pc = "Done") + +(***** END TRANSLATION ***) + +============================================================================= diff --git a/tlatools/test-model/pcal/Euclid3.cfg b/tlatools/test-model/pcal/Euclid3.cfg new file mode 100644 index 0000000000000000000000000000000000000000..43cbbfdb66aba9787c37060889f665f2257ba25b --- /dev/null +++ b/tlatools/test-model/pcal/Euclid3.cfg @@ -0,0 +1,4 @@ +SPECIFICATION Spec +PROPERTY Termination +\* Add statements after this line. +CONSTANT N = 3 diff --git a/tlatools/test-model/pcal/Euclid3.tla b/tlatools/test-model/pcal/Euclid3.tla new file mode 100644 index 0000000000000000000000000000000000000000..f652ff2864201c011df915bc5ab0efa9149e741f --- /dev/null +++ b/tlatools/test-model/pcal/Euclid3.tla @@ -0,0 +1,64 @@ +--algorithm EuclidAlg +variables u = 24 ; v \in 1 .. N ; v_ini = v ; +begin +lp: while u # 0 do + if u < v then u := v || v := u ; + end if ; + a: u := u - v; + end while ; + print <<v, "= GCD of 24 and ", v_ini>> ; +end algorithm + +-------------------------------- MODULE Euclid3 ------------------------------ +EXTENDS Naturals, TLC +CONSTANT N + +GCD(x, y) == CHOOSE i \in (1..x) \cap (1..y) : + /\ x % i = 0 + /\ y % i = 0 + /\ \A j \in (1..x) \cap (1..y) : + /\ x % j = 0 + /\ y % j = 0 + => i \geq j + +(***** BEGIN TRANSLATION ***) +VARIABLES u, v, v_ini, pc + +vars == << u, v, v_ini, pc >> + +Init == (* Global variables *) + /\ u = 24 + /\ v \in 1 .. N + /\ v_ini = v + /\ pc = "lp" + +lp == /\ pc = "lp" + /\ IF u # 0 + THEN /\ IF u < v + THEN /\ /\ u' = v + /\ v' = u + ELSE /\ TRUE + /\ UNCHANGED << u, v >> + /\ pc' = "a" + ELSE /\ PrintT(<<v, "= GCD of 24 and ", v_ini>>) + /\ pc' = "Done" + /\ UNCHANGED << u, v >> + /\ v_ini' = v_ini + +a == /\ pc = "a" + /\ u' = u - v + /\ pc' = "lp" + /\ UNCHANGED << v, v_ini >> + +Next == lp \/ a + \/ (* Disjunct to prevent deadlock on termination *) + (pc = "Done" /\ UNCHANGED vars) + +Spec == /\ Init /\ [][Next]_vars + /\ WF_vars(Next) + +Termination == <>(pc = "Done") + +(***** END TRANSLATION ***) + +============================================================================= diff --git a/tlatools/test-model/pcal/EvenOdd.cfg b/tlatools/test-model/pcal/EvenOdd.cfg new file mode 100644 index 0000000000000000000000000000000000000000..88725dab9155d12e1fbca4531e4f30063b7dc81e --- /dev/null +++ b/tlatools/test-model/pcal/EvenOdd.cfg @@ -0,0 +1,5 @@ +SPECIFICATION Spec +PROPERTY Termination +\* Add statements after this line. +CONSTANT N = 6 + diff --git a/tlatools/test-model/pcal/EvenOdd.tla b/tlatools/test-model/pcal/EvenOdd.tla new file mode 100644 index 0000000000000000000000000000000000000000..d44ad522c275a705e2a2d41d4c228c01a177200b --- /dev/null +++ b/tlatools/test-model/pcal/EvenOdd.tla @@ -0,0 +1,114 @@ +--algorithm EvenOdd +variable result = FALSE; +procedure Even (xEven = 0) +begin + Even1: if xEven = 0 then + result := TRUE; + return; + else + call Odd(xEven - 1); + return; + end if; + end procedure +procedure Odd (xOdd = 0) +begin + Odd1: if xOdd = 0 then result := FALSE; + else call Even(xOdd - 1); + end if; + Odd2: return; + end procedure +begin + a1: call Even(N); + a2: print result; +end algorithm + +--------------- MODULE EvenOdd --------------- + +EXTENDS Naturals, Sequences, TLC + +CONSTANT N + +---------------------------------------------- + + +\* BEGIN TRANSLATION +VARIABLES result, pc, stack, xEven, xOdd + +vars == << result, pc, stack, xEven, xOdd >> + +Init == (* Global variables *) + /\ result = FALSE + (* Procedure Even *) + /\ xEven = 0 + (* Procedure Odd *) + /\ xOdd = 0 + /\ stack = << >> + /\ pc = "a1" + +Even1 == /\ pc = "Even1" + /\ IF xEven = 0 + THEN /\ result' = TRUE + /\ pc' = Head(stack).pc + /\ xEven' = Head(stack).xEven + /\ stack' = Tail(stack) + /\ xOdd' = xOdd + ELSE /\ /\ stack' = << [ procedure |-> "Odd", + pc |-> Head(stack).pc, + xOdd |-> xOdd ] >> + \o Tail(stack) + /\ xOdd' = xEven - 1 + /\ pc' = "Odd1" + /\ UNCHANGED << result, xEven >> + +Even == Even1 + +Odd1 == /\ pc = "Odd1" + /\ IF xOdd = 0 + THEN /\ result' = FALSE + /\ pc' = "Odd2" + /\ UNCHANGED << stack, xEven >> + ELSE /\ /\ stack' = << [ procedure |-> "Even", + pc |-> "Odd2", + xEven |-> xEven ] >> + \o stack + /\ xEven' = xOdd - 1 + /\ pc' = "Even1" + /\ UNCHANGED result + /\ xOdd' = xOdd + +Odd2 == /\ pc = "Odd2" + /\ pc' = Head(stack).pc + /\ xOdd' = Head(stack).xOdd + /\ stack' = Tail(stack) + /\ UNCHANGED << result, xEven >> + +Odd == Odd1 \/ Odd2 + +a1 == /\ pc = "a1" + /\ /\ stack' = << [ procedure |-> "Even", + pc |-> "a2", + xEven |-> xEven ] >> + \o stack + /\ xEven' = N + /\ pc' = "Even1" + /\ UNCHANGED << result, xOdd >> + +a2 == /\ pc = "a2" + /\ PrintT(result) + /\ pc' = "Done" + /\ UNCHANGED << result, stack, xEven, xOdd >> + +Next == Even \/ Odd \/ a1 \/ a2 + \/ (* Disjunct to prevent deadlock on termination *) + (pc = "Done" /\ UNCHANGED vars) + +Spec == /\ Init /\ [][Next]_vars + /\ WF_vars(Next) + +Termination == <>(pc = "Done") + +\* END TRANSLATION + +============================================== + + diff --git a/tlatools/test-model/pcal/EvenOddBad.tla b/tlatools/test-model/pcal/EvenOddBad.tla new file mode 100644 index 0000000000000000000000000000000000000000..78b15383a52e3bd6708c089d0116c8b27830930b --- /dev/null +++ b/tlatools/test-model/pcal/EvenOddBad.tla @@ -0,0 +1,111 @@ +---------------------------- MODULE EvenOddBad ----------------------------- + +EXTENDS Naturals, Sequences, TLC + +(* +--algorithm EvenOddBad +variable result \in { TRUE, FALSE }; +procedure Even (xEven = 0) +begin + Even1: if xEven = 0 then result := TRUE; + else call Odd(xEven - 1); + end if; + e1 : return; + end procedure; +procedure Odd (xOdd = 0) +begin + Odd1: if xOdd = 0 then result := FALSE; + else call Even(xOdd - 1); + end if; + o1 : return; + end procedure +begin + a1: call Even(2); + a2: print result; +end algorithm +*) + +\* BEGIN TRANSLATION +VARIABLES result, pc, stack, xEven, xOdd + +vars == << result, pc, stack, xEven, xOdd >> + +Init == (* Global variables *) + /\ result \in { TRUE, FALSE } + (* Procedure Even *) + /\ xEven = 0 + (* Procedure Odd *) + /\ xOdd = 0 + /\ stack = << >> + /\ pc = "a1" + +Even1 == /\ pc = "Even1" + /\ IF xEven = 0 + THEN /\ result' = TRUE + /\ pc' = "e1" + /\ UNCHANGED << stack, xOdd >> + ELSE /\ /\ stack' = << [ procedure |-> "Odd", + pc |-> "e1", + xOdd |-> xOdd ] >> + \o stack + /\ xOdd' = xEven - 1 + /\ pc' = "Odd1" + /\ UNCHANGED result + /\ xEven' = xEven + +e1 == /\ pc = "e1" + /\ pc' = Head(stack).pc + /\ xEven' = Head(stack).xEven + /\ stack' = Tail(stack) + /\ UNCHANGED << result, xOdd >> + +Even == Even1 \/ e1 + +Odd1 == /\ pc = "Odd1" + /\ IF xOdd = 0 + THEN /\ result' = FALSE + /\ pc' = "o1" + /\ UNCHANGED << stack, xEven >> + ELSE /\ /\ stack' = << [ procedure |-> "Even", + pc |-> "o1", + xEven |-> xEven ] >> + \o stack + /\ xEven' = xOdd - 1 + /\ pc' = "Even1" + /\ UNCHANGED result + /\ xOdd' = xOdd + +o1 == /\ pc = "o1" + /\ pc' = Head(stack).pc + /\ xOdd' = Head(stack).xOdd + /\ stack' = Tail(stack) + /\ UNCHANGED << result, xEven >> + +Odd == Odd1 \/ o1 + +a1 == /\ pc = "a1" + /\ /\ stack' = << [ procedure |-> "Even", + pc |-> "a2", + xEven |-> xEven ] >> + \o stack + /\ xEven' = 2 + /\ pc' = "Even1" + /\ UNCHANGED << result, xOdd >> + +a2 == /\ pc = "a2" + /\ PrintT(result) + /\ pc' = "Done" + /\ UNCHANGED << result, stack, xEven, xOdd >> + +Next == Even \/ Odd \/ a1 \/ a2 + \/ (* Disjunct to prevent deadlock on termination *) + (pc = "Done" /\ UNCHANGED vars) + +Spec == /\ Init /\ [][Next]_vars + /\ WF_vars(Next) + +Termination == <>(pc = "Done") + +\* END TRANSLATION + +============================================================================= diff --git a/tlatools/test-model/pcal/Factorial.tla b/tlatools/test-model/pcal/Factorial.tla new file mode 100644 index 0000000000000000000000000000000000000000..2ddd42494740a85450d25194d2eccb555ccfd39f --- /dev/null +++ b/tlatools/test-model/pcal/Factorial.tla @@ -0,0 +1,81 @@ +------------------------------ MODULE Factorial ----------------------------- +EXTENDS Naturals, Sequences, TLC + +(*************************************************************************** +--algorithm Factorial + variable result = 1; \* are comments ok? + procedure FactProc(arg1 = 0) (* are comments ok? *) + (* what about (* nested multi-line *) + comments? *) + variable u = 1 ; + begin p1 : if arg1 = 0 + then return; \* HERE IS A + else result := result * arg1; + call FactProc ( arg1 - 1 ) ; + return; + end if; + end procedure + begin + a1 : call FactProc( 5 ) ; + a2 : assert result = 120 ; + end algorithm +***************************************************************************) + +(************** BEGIN TRANSLATION ********************) +VARIABLES result, pc, stack, arg1, u + +vars == << result, pc, stack, arg1, u >> + +Init == (* Global variables *) + /\ result = 1 + (* Procedure FactProc *) + /\ arg1 = 0 + /\ u = 1 + /\ stack = << >> + /\ pc = "a1" + +p1 == /\ pc = "p1" + /\ IF arg1 = 0 + THEN /\ pc' = Head(stack).pc + /\ u' = Head(stack).u + /\ arg1' = Head(stack).arg1 + /\ stack' = Tail(stack) + /\ UNCHANGED result + ELSE /\ result' = result * arg1 + /\ arg1' = arg1 - 1 + /\ u' = 1 + /\ pc' = "p1" + /\ stack' = stack + +FactProc == p1 + +a1 == /\ pc = "a1" + /\ /\ arg1' = 5 + /\ stack' = << [ procedure |-> "FactProc", + pc |-> "a2", + u |-> u, + arg1 |-> arg1 ] >> + \o stack + /\ u' = 1 + /\ pc' = "p1" + /\ UNCHANGED result + +a2 == /\ pc = "a2" + /\ Assert(result = 120, "Failure of assertion at line 20, column 10.") + /\ pc' = "Done" + /\ UNCHANGED << result, stack, arg1, u >> + +Next == FactProc \/ a1 \/ a2 + \/ (* Disjunct to prevent deadlock on termination *) + (pc = "Done" /\ UNCHANGED vars) + +Spec == /\ Init /\ [][Next]_vars + /\ WF_vars(Next) + +Termination == <>(pc = "Done") + +(************* END TRANSLATION ********************) + + +Invariant == result \in Nat +============================================================================= diff --git a/tlatools/test-model/pcal/Factorial2.tla b/tlatools/test-model/pcal/Factorial2.tla new file mode 100644 index 0000000000000000000000000000000000000000..bbb268db0be042960a1a9dd3153b7e591760c151 --- /dev/null +++ b/tlatools/test-model/pcal/Factorial2.tla @@ -0,0 +1,130 @@ +---------------------------- MODULE Factorial2 --------------------------- +EXTENDS Naturals, Sequences, TLC + +(*************************************************************************** +Factorial Algorithm with 2 procedures + +--algorithm Factorial + variable result = 1; + procedure FactProc(arg1 = 0 ) + variable u = 1 ; + begin p1 : if arg1 = 0 + then return; + else result := result * arg1; + call FactProc2 ( arg1 - 1 ) ; + b: return; + end if; + end procedure + procedure FactProc2(arg2 = 0) + variable u2 = 1 ; + begin p12 : if arg2 = 0 + then return; + else result := result * arg2; + call FactProc ( arg2 - 1 ) ; + return; + end if; + end procedure + begin + a1 : call FactProc( 5 ) ; + a2 : if result = 120 then print <<"Correct =", 120>>; + else print <<"Error = ", result>> ; + end if; + end algorithm +***************************************************************************) + +(************** BEGIN TRANSLATION ********************) +VARIABLES result, pc, stack, arg1, u, arg2, u2 + +vars == << result, pc, stack, arg1, u, arg2, u2 >> + +Init == (* Global variables *) + /\ result = 1 + (* Procedure FactProc *) + /\ arg1 = 0 + /\ u = 1 + (* Procedure FactProc2 *) + /\ arg2 = 0 + /\ u2 = 1 + /\ stack = << >> + /\ pc = "a1" + +p1 == /\ pc = "p1" + /\ IF arg1 = 0 + THEN /\ pc' = Head(stack).pc + /\ u' = Head(stack).u + /\ arg1' = Head(stack).arg1 + /\ stack' = Tail(stack) + /\ UNCHANGED << result, arg2, u2 >> + ELSE /\ result' = result * arg1 + /\ /\ arg2' = arg1 - 1 + /\ stack' = << [ procedure |-> "FactProc2", + pc |-> "b", + u2 |-> u2, + arg2 |-> arg2 ] >> + \o stack + /\ u2' = 1 + /\ pc' = "p12" + /\ UNCHANGED << arg1, u >> + +b == /\ pc = "b" + /\ pc' = Head(stack).pc + /\ u' = Head(stack).u + /\ arg1' = Head(stack).arg1 + /\ stack' = Tail(stack) + /\ UNCHANGED << result, arg2, u2 >> + +FactProc == p1 \/ b + +p12 == /\ pc = "p12" + /\ IF arg2 = 0 + THEN /\ pc' = Head(stack).pc + /\ u2' = Head(stack).u2 + /\ arg2' = Head(stack).arg2 + /\ stack' = Tail(stack) + /\ UNCHANGED << result, arg1, u >> + ELSE /\ result' = result * arg2 + /\ /\ arg1' = arg2 - 1 + /\ stack' = << [ procedure |-> "FactProc", + pc |-> Head(stack).pc, + u |-> u, + arg1 |-> arg1 ] >> + \o Tail(stack) + /\ u2' = Head(stack).u2 + /\ u' = 1 + /\ pc' = "p1" + /\ arg2' = arg2 + +FactProc2 == p12 + +a1 == /\ pc = "a1" + /\ /\ arg1' = 5 + /\ stack' = << [ procedure |-> "FactProc", + pc |-> "a2", + u |-> u, + arg1 |-> arg1 ] >> + \o stack + /\ u' = 1 + /\ pc' = "p1" + /\ UNCHANGED << result, arg2, u2 >> + +a2 == /\ pc = "a2" + /\ IF result = 120 + THEN /\ PrintT(<<"Correct =", 120>>) + ELSE /\ PrintT(<<"Error = ", result>>) + /\ pc' = "Done" + /\ UNCHANGED << result, stack, arg1, u, arg2, u2 >> + +Next == FactProc \/ FactProc2 \/ a1 \/ a2 + \/ (* Disjunct to prevent deadlock on termination *) + (pc = "Done" /\ UNCHANGED vars) + +Spec == /\ Init /\ [][Next]_vars + /\ WF_vars(Next) + +Termination == <>(pc = "Done") + +(************* END TRANSLATION ********************) + + +Invariant == result \in Nat +============================================================================= diff --git a/tlatools/test-model/pcal/FairSeq.cfg b/tlatools/test-model/pcal/FairSeq.cfg new file mode 100644 index 0000000000000000000000000000000000000000..eef01cc22c6ccc68e3ccebb6338999b0382ecbbc --- /dev/null +++ b/tlatools/test-model/pcal/FairSeq.cfg @@ -0,0 +1,4 @@ +SPECIFICATION Spec +PROPERTY Termination +\* Add statements after this line. +PROPERTY Termination diff --git a/tlatools/test-model/pcal/FairSeq.tla b/tlatools/test-model/pcal/FairSeq.tla new file mode 100644 index 0000000000000000000000000000000000000000..e79e6792c514252e31ceb06d38fc93beddfc443a --- /dev/null +++ b/tlatools/test-model/pcal/FairSeq.tla @@ -0,0 +1,42 @@ +------------------------------ MODULE FairSeq ------------------------------ +EXTENDS Integers +(*************************************************************************** +PlusCal options (version 1.5) +--algorithm FairSeq { + variable x = 0 ; + fair { while (x < 10) { + x := x+1; + } + } +} + ***************************************************************************) +\* BEGIN TRANSLATION +VARIABLES x, pc + +vars == << x, pc >> + +Init == (* Global variables *) + /\ x = 0 + /\ pc = "Lbl_1" + +Lbl_1 == /\ pc = "Lbl_1" + /\ IF x < 10 + THEN /\ x' = x+1 + /\ pc' = "Lbl_1" + ELSE /\ pc' = "Done" + /\ x' = x + +Next == Lbl_1 + \/ (* Disjunct to prevent deadlock on termination *) + (pc = "Done" /\ UNCHANGED vars) + +Spec == /\ Init /\ [][Next]_vars + /\ WF_vars(Next) + +Termination == <>(pc = "Done") + +\* END TRANSLATION +============================================================================= +\* Modification History +\* Last modified Sun Mar 20 10:13:11 PDT 2011 by lamport +\* Created Sun Mar 20 10:10:54 PDT 2011 by lamport diff --git a/tlatools/test-model/pcal/FairSeq2.tla b/tlatools/test-model/pcal/FairSeq2.tla new file mode 100644 index 0000000000000000000000000000000000000000..3cea3c950d94c8671ce985754aae9505883d92f4 --- /dev/null +++ b/tlatools/test-model/pcal/FairSeq2.tla @@ -0,0 +1,42 @@ +------------------------------ MODULE FairSeq2 ------------------------------ +EXTENDS Integers +(*************************************************************************** +PlusCal options (version 1.5) +--fair algorithm FairSeq { + variable x = 0 ; + fair { while (x < 10) { + x := x+1; + } + } +} + ***************************************************************************) +\* BEGIN TRANSLATION +VARIABLES x, pc + +vars == << x, pc >> + +Init == (* Global variables *) + /\ x = 0 + /\ pc = "Lbl_1" + +Lbl_1 == /\ pc = "Lbl_1" + /\ IF x < 10 + THEN /\ x' = x+1 + /\ pc' = "Lbl_1" + ELSE /\ pc' = "Done" + /\ x' = x + +Next == Lbl_1 + \/ (* Disjunct to prevent deadlock on termination *) + (pc = "Done" /\ UNCHANGED vars) + +Spec == /\ Init /\ [][Next]_vars + /\ WF_vars(Next) + +Termination == <>(pc = "Done") + +\* END TRANSLATION +============================================================================= +\* Modification History +\* Last modified Sun Mar 20 10:13:11 PDT 2011 by lamport +\* Created Sun Mar 20 10:10:54 PDT 2011 by lamport diff --git a/tlatools/test-model/pcal/FastMutex.cfg b/tlatools/test-model/pcal/FastMutex.cfg new file mode 100644 index 0000000000000000000000000000000000000000..0e9b97c14b32cf64a2bec7b2ab69133ff609a772 --- /dev/null +++ b/tlatools/test-model/pcal/FastMutex.cfg @@ -0,0 +1,6 @@ +SPECIFICATION Spec +CONSTANT defaultInitValue = defaultInitValue +\* Add statements after this line. +CONSTANT N = 2 +INVARIANT Invariant +PROPERTY Liveness diff --git a/tlatools/test-model/pcal/FastMutex.tla b/tlatools/test-model/pcal/FastMutex.tla new file mode 100644 index 0000000000000000000000000000000000000000..cc83c392029882ba000d68c722d57efd45b7d1de --- /dev/null +++ b/tlatools/test-model/pcal/FastMutex.tla @@ -0,0 +1,167 @@ +------------------------------ MODULE FastMutex ----------------------------- + +EXTENDS Naturals + +CONSTANT N + +ASSUME N \in Nat + +(********************** +--algorithm FastMutex + variables x ; y = 0 ; b = [i \in 1..N |-> FALSE] ; +process Proc \in 1..N +variables j = 0 ; failed = FALSE ; +begin +start : while TRUE + do l1 : b[self] := TRUE ; + l2 : x := self ; + l3 : if y # 0 + then l4 : b[self] := FALSE ; + l5 : when y = 0 ; skip ; + else l6 : y := self ; + l7 : if x # self + then l8 : b[self] := FALSE ; + j := 1 ; + l9 : while (j \leq N) + do when ~b[j] ; + j := j+1 ; + end while ; + l10 : if y # self + then when y = 0 ; + failed := TRUE ; + end if; + end if ; + cs : if ~ failed + then skip ; \* the critical section + l11 : y := 0 ; + l12 : b[self] := FALSE ; + else failed := FALSE ; + end if ; + end if ; + end while ; +end process +end algorithm + +***********************) + +(**************** BEGIN TRANSLATION *******************************) +CONSTANT defaultInitValue +VARIABLES x, y, b, pc, j, failed + +vars == << x, y, b, pc, j, failed >> + +ProcSet == (1..N) + +Init == (* Global variables *) + /\ x = defaultInitValue + /\ y = 0 + /\ b = [i \in 1..N |-> FALSE] + (* Process Proc *) + /\ j = [self \in 1..N |-> 0] + /\ failed = [self \in 1..N |-> FALSE] + /\ pc = [self \in ProcSet |-> "start"] + +start(self) == /\ pc[self] = "start" + /\ pc' = [pc EXCEPT ![self] = "l1"] + /\ UNCHANGED << x, y, b, j, failed >> + +l1(self) == /\ pc[self] = "l1" + /\ b' = [b EXCEPT ![self] = TRUE] + /\ pc' = [pc EXCEPT ![self] = "l2"] + /\ UNCHANGED << x, y, j, failed >> + +l2(self) == /\ pc[self] = "l2" + /\ x' = self + /\ pc' = [pc EXCEPT ![self] = "l3"] + /\ UNCHANGED << y, b, j, failed >> + +l3(self) == /\ pc[self] = "l3" + /\ IF y # 0 + THEN /\ pc' = [pc EXCEPT ![self] = "l4"] + ELSE /\ pc' = [pc EXCEPT ![self] = "l6"] + /\ UNCHANGED << x, y, b, j, failed >> + +l4(self) == /\ pc[self] = "l4" + /\ b' = [b EXCEPT ![self] = FALSE] + /\ pc' = [pc EXCEPT ![self] = "l5"] + /\ UNCHANGED << x, y, j, failed >> + +l5(self) == /\ pc[self] = "l5" + /\ y = 0 + /\ TRUE + /\ pc' = [pc EXCEPT ![self] = "start"] + /\ UNCHANGED << x, y, b, j, failed >> + +l6(self) == /\ pc[self] = "l6" + /\ y' = self + /\ pc' = [pc EXCEPT ![self] = "l7"] + /\ UNCHANGED << x, b, j, failed >> + +l7(self) == /\ pc[self] = "l7" + /\ IF x # self + THEN /\ pc' = [pc EXCEPT ![self] = "l8"] + ELSE /\ pc' = [pc EXCEPT ![self] = "cs"] + /\ UNCHANGED << x, y, b, j, failed >> + +l8(self) == /\ pc[self] = "l8" + /\ b' = [b EXCEPT ![self] = FALSE] + /\ j' = [j EXCEPT ![self] = 1] + /\ pc' = [pc EXCEPT ![self] = "l9"] + /\ UNCHANGED << x, y, failed >> + +l9(self) == /\ pc[self] = "l9" + /\ IF (j[self] \leq N) + THEN /\ ~b[j[self]] + /\ j' = [j EXCEPT ![self] = j[self]+1] + /\ pc' = [pc EXCEPT ![self] = "l9"] + ELSE /\ pc' = [pc EXCEPT ![self] = "l10"] + /\ j' = j + /\ UNCHANGED << x, y, b, failed >> + +l10(self) == /\ pc[self] = "l10" + /\ IF y # self + THEN /\ y = 0 + /\ failed' = [failed EXCEPT ![self] = TRUE] + ELSE /\ TRUE + /\ UNCHANGED failed + /\ pc' = [pc EXCEPT ![self] = "cs"] + /\ UNCHANGED << x, y, b, j >> + +cs(self) == /\ pc[self] = "cs" + /\ IF ~ failed[self] + THEN /\ TRUE + /\ pc' = [pc EXCEPT ![self] = "l11"] + /\ UNCHANGED failed + ELSE /\ failed' = [failed EXCEPT ![self] = FALSE] + /\ pc' = [pc EXCEPT ![self] = "start"] + /\ UNCHANGED << x, y, b, j >> + +l11(self) == /\ pc[self] = "l11" + /\ y' = 0 + /\ pc' = [pc EXCEPT ![self] = "l12"] + /\ UNCHANGED << x, b, j, failed >> + +l12(self) == /\ pc[self] = "l12" + /\ b' = [b EXCEPT ![self] = FALSE] + /\ pc' = [pc EXCEPT ![self] = "start"] + /\ UNCHANGED << x, y, j, failed >> + +Proc(self) == start(self) \/ l1(self) \/ l2(self) \/ l3(self) \/ l4(self) + \/ l5(self) \/ l6(self) \/ l7(self) \/ l8(self) + \/ l9(self) \/ l10(self) \/ cs(self) \/ l11(self) + \/ l12(self) + +Next == (\E self \in 1..N: Proc(self)) + +Spec == /\ Init /\ [][Next]_vars + /\ \A self \in 1..N : WF_vars(Proc(self)) + +(**************** END TRANSLATION *******************************) + +inCS(i) == (pc[i] = "cs") /\ (~failed[i]) + +Invariant == \A i, k \in 1..N : (i # k) => ~ (inCS(i) /\ inCS(k)) + + +Liveness == []<> \E i \in 1..N : inCS(i) +============================================================================= diff --git a/tlatools/test-model/pcal/FastMutex2.cfg b/tlatools/test-model/pcal/FastMutex2.cfg new file mode 100644 index 0000000000000000000000000000000000000000..d8d7506fe9585e7c018adb246dc9ae7229148ea6 --- /dev/null +++ b/tlatools/test-model/pcal/FastMutex2.cfg @@ -0,0 +1,5 @@ +SPECIFICATION Spec +\* Add statements after this line. +CONSTANT N = 2 M = 1 +INVARIANT Invariant +PROPERTY Liveness diff --git a/tlatools/test-model/pcal/FastMutex2.tla b/tlatools/test-model/pcal/FastMutex2.tla new file mode 100644 index 0000000000000000000000000000000000000000..18fc2fde3074a3420caabe37571d29f4a23de3ef --- /dev/null +++ b/tlatools/test-model/pcal/FastMutex2.tla @@ -0,0 +1,297 @@ +----------------------------- MODULE FastMutex2 ----------------------------- + +\* This tests the translation when there are two different processes + +EXTENDS Naturals, TLC + +CONSTANT N, M + +ASSUME (N \in Nat) /\ (M \in Nat) + +(********************** +--algorithm FastMutex + variables x = 0 ; y = 0 ; b = [i \in 1..N |-> FALSE] ; +process Proc1 \in 1..M +variables j = 0 ; failed = FALSE ; +begin +start : while TRUE + do l1 : b[self] := TRUE ; + l2 : x := self ; + l3 : if y # 0 + then l4 : b[self] := FALSE ; + l5 : when y = 0 ; skip ; + else l6 : y := self ; + l7 : if x # self + then l8 : b[self] := FALSE ; + j := 1 ; + l9 : while (j \leq N) + do when ~b[j] ; + j := j+1 ; + end while ; + l10 : if y # self + then when y = 0 ; + failed := TRUE ; + end if; + end if ; + cs : if ~ failed + then skip ; \* the critical section + l11 : y := 0 ; + l12 : b[self] := FALSE ; + else failed := FALSE ; + end if ; + end if ; + end while ; +end process +process Proc2 \in (M+1)..N +variables j2 = 0 ; failed2 = FALSE ; +begin +2start : while TRUE + do 2l1 : b[self] := TRUE ; + 2l2 : x := self ; + 2l3 : if y # 0 + then 2l4 : b[self] := FALSE ; + 2l5 : when y = 0 ; skip ; + else 2l6 : y := self ; + 2l7 : if x # self + then 2l8 : b[self] := FALSE ; + j2 := 1 ; + 2l9 : while (j2 \leq N) + do when ~b[j2] ; + j2 := j2+1 ; + end while ; + 2l10 : if y # self + then when y = 0 ; + failed2 := TRUE ; + end if; + end if ; + 2cs : if ~ failed2 + then skip ; \* the critical section + 2l11 : y := 0 ; + 2l12 : b[self] := FALSE ; + else failed2 := FALSE ; + end if ; + end if ; + end while ; +end process +end algorithm + +***********************) + +(**************** BEGIN TRANSLATION *******************************) +VARIABLES x, y, b, pc, j, failed, j2, failed2 + +vars == << x, y, b, pc, j, failed, j2, failed2 >> + +ProcSet == (1..M) \cup ((M+1)..N) + +Init == (* Global variables *) + /\ x = 0 + /\ y = 0 + /\ b = [i \in 1..N |-> FALSE] + (* Process Proc1 *) + /\ j = [self \in 1..M |-> 0] + /\ failed = [self \in 1..M |-> FALSE] + (* Process Proc2 *) + /\ j2 = [self \in (M+1)..N |-> 0] + /\ failed2 = [self \in (M+1)..N |-> FALSE] + /\ pc = [self \in ProcSet |-> CASE self \in 1..M -> "start" + [] self \in (M+1)..N -> "2start"] + +start(self) == /\ pc[self] = "start" + /\ pc' = [pc EXCEPT ![self] = "l1"] + /\ UNCHANGED << x, y, b, j, failed, j2, failed2 >> + +l1(self) == /\ pc[self] = "l1" + /\ b' = [b EXCEPT ![self] = TRUE] + /\ pc' = [pc EXCEPT ![self] = "l2"] + /\ UNCHANGED << x, y, j, failed, j2, failed2 >> + +l2(self) == /\ pc[self] = "l2" + /\ x' = self + /\ pc' = [pc EXCEPT ![self] = "l3"] + /\ UNCHANGED << y, b, j, failed, j2, failed2 >> + +l3(self) == /\ pc[self] = "l3" + /\ IF y # 0 + THEN /\ pc' = [pc EXCEPT ![self] = "l4"] + ELSE /\ pc' = [pc EXCEPT ![self] = "l6"] + /\ UNCHANGED << x, y, b, j, failed, j2, failed2 >> + +l4(self) == /\ pc[self] = "l4" + /\ b' = [b EXCEPT ![self] = FALSE] + /\ pc' = [pc EXCEPT ![self] = "l5"] + /\ UNCHANGED << x, y, j, failed, j2, failed2 >> + +l5(self) == /\ pc[self] = "l5" + /\ y = 0 + /\ TRUE + /\ pc' = [pc EXCEPT ![self] = "start"] + /\ UNCHANGED << x, y, b, j, failed, j2, failed2 >> + +l6(self) == /\ pc[self] = "l6" + /\ y' = self + /\ pc' = [pc EXCEPT ![self] = "l7"] + /\ UNCHANGED << x, b, j, failed, j2, failed2 >> + +l7(self) == /\ pc[self] = "l7" + /\ IF x # self + THEN /\ pc' = [pc EXCEPT ![self] = "l8"] + ELSE /\ pc' = [pc EXCEPT ![self] = "cs"] + /\ UNCHANGED << x, y, b, j, failed, j2, failed2 >> + +l8(self) == /\ pc[self] = "l8" + /\ b' = [b EXCEPT ![self] = FALSE] + /\ j' = [j EXCEPT ![self] = 1] + /\ pc' = [pc EXCEPT ![self] = "l9"] + /\ UNCHANGED << x, y, failed, j2, failed2 >> + +l9(self) == /\ pc[self] = "l9" + /\ IF (j[self] \leq N) + THEN /\ ~b[j[self]] + /\ j' = [j EXCEPT ![self] = j[self]+1] + /\ pc' = [pc EXCEPT ![self] = "l9"] + ELSE /\ pc' = [pc EXCEPT ![self] = "l10"] + /\ j' = j + /\ UNCHANGED << x, y, b, failed, j2, failed2 >> + +l10(self) == /\ pc[self] = "l10" + /\ IF y # self + THEN /\ y = 0 + /\ failed' = [failed EXCEPT ![self] = TRUE] + ELSE /\ TRUE + /\ UNCHANGED failed + /\ pc' = [pc EXCEPT ![self] = "cs"] + /\ UNCHANGED << x, y, b, j, j2, failed2 >> + +cs(self) == /\ pc[self] = "cs" + /\ IF ~ failed[self] + THEN /\ TRUE + /\ pc' = [pc EXCEPT ![self] = "l11"] + /\ UNCHANGED failed + ELSE /\ failed' = [failed EXCEPT ![self] = FALSE] + /\ pc' = [pc EXCEPT ![self] = "start"] + /\ UNCHANGED << x, y, b, j, j2, failed2 >> + +l11(self) == /\ pc[self] = "l11" + /\ y' = 0 + /\ pc' = [pc EXCEPT ![self] = "l12"] + /\ UNCHANGED << x, b, j, failed, j2, failed2 >> + +l12(self) == /\ pc[self] = "l12" + /\ b' = [b EXCEPT ![self] = FALSE] + /\ pc' = [pc EXCEPT ![self] = "start"] + /\ UNCHANGED << x, y, j, failed, j2, failed2 >> + +Proc1(self) == start(self) \/ l1(self) \/ l2(self) \/ l3(self) \/ l4(self) + \/ l5(self) \/ l6(self) \/ l7(self) \/ l8(self) + \/ l9(self) \/ l10(self) \/ cs(self) \/ l11(self) + \/ l12(self) + +2start(self) == /\ pc[self] = "2start" + /\ pc' = [pc EXCEPT ![self] = "2l1"] + /\ UNCHANGED << x, y, b, j, failed, j2, failed2 >> + +2l1(self) == /\ pc[self] = "2l1" + /\ b' = [b EXCEPT ![self] = TRUE] + /\ pc' = [pc EXCEPT ![self] = "2l2"] + /\ UNCHANGED << x, y, j, failed, j2, failed2 >> + +2l2(self) == /\ pc[self] = "2l2" + /\ x' = self + /\ pc' = [pc EXCEPT ![self] = "2l3"] + /\ UNCHANGED << y, b, j, failed, j2, failed2 >> + +2l3(self) == /\ pc[self] = "2l3" + /\ IF y # 0 + THEN /\ pc' = [pc EXCEPT ![self] = "2l4"] + ELSE /\ pc' = [pc EXCEPT ![self] = "2l6"] + /\ UNCHANGED << x, y, b, j, failed, j2, failed2 >> + +2l4(self) == /\ pc[self] = "2l4" + /\ b' = [b EXCEPT ![self] = FALSE] + /\ pc' = [pc EXCEPT ![self] = "2l5"] + /\ UNCHANGED << x, y, j, failed, j2, failed2 >> + +2l5(self) == /\ pc[self] = "2l5" + /\ y = 0 + /\ TRUE + /\ pc' = [pc EXCEPT ![self] = "2start"] + /\ UNCHANGED << x, y, b, j, failed, j2, failed2 >> + +2l6(self) == /\ pc[self] = "2l6" + /\ y' = self + /\ pc' = [pc EXCEPT ![self] = "2l7"] + /\ UNCHANGED << x, b, j, failed, j2, failed2 >> + +2l7(self) == /\ pc[self] = "2l7" + /\ IF x # self + THEN /\ pc' = [pc EXCEPT ![self] = "2l8"] + ELSE /\ pc' = [pc EXCEPT ![self] = "2cs"] + /\ UNCHANGED << x, y, b, j, failed, j2, failed2 >> + +2l8(self) == /\ pc[self] = "2l8" + /\ b' = [b EXCEPT ![self] = FALSE] + /\ j2' = [j2 EXCEPT ![self] = 1] + /\ pc' = [pc EXCEPT ![self] = "2l9"] + /\ UNCHANGED << x, y, j, failed, failed2 >> + +2l9(self) == /\ pc[self] = "2l9" + /\ IF (j2[self] \leq N) + THEN /\ ~b[j2[self]] + /\ j2' = [j2 EXCEPT ![self] = j2[self]+1] + /\ pc' = [pc EXCEPT ![self] = "2l9"] + ELSE /\ pc' = [pc EXCEPT ![self] = "2l10"] + /\ j2' = j2 + /\ UNCHANGED << x, y, b, j, failed, failed2 >> + +2l10(self) == /\ pc[self] = "2l10" + /\ IF y # self + THEN /\ y = 0 + /\ failed2' = [failed2 EXCEPT ![self] = TRUE] + ELSE /\ TRUE + /\ UNCHANGED failed2 + /\ pc' = [pc EXCEPT ![self] = "2cs"] + /\ UNCHANGED << x, y, b, j, failed, j2 >> + +2cs(self) == /\ pc[self] = "2cs" + /\ IF ~ failed2[self] + THEN /\ TRUE + /\ pc' = [pc EXCEPT ![self] = "2l11"] + /\ UNCHANGED failed2 + ELSE /\ failed2' = [failed2 EXCEPT ![self] = FALSE] + /\ pc' = [pc EXCEPT ![self] = "2start"] + /\ UNCHANGED << x, y, b, j, failed, j2 >> + +2l11(self) == /\ pc[self] = "2l11" + /\ y' = 0 + /\ pc' = [pc EXCEPT ![self] = "2l12"] + /\ UNCHANGED << x, b, j, failed, j2, failed2 >> + +2l12(self) == /\ pc[self] = "2l12" + /\ b' = [b EXCEPT ![self] = FALSE] + /\ pc' = [pc EXCEPT ![self] = "2start"] + /\ UNCHANGED << x, y, j, failed, j2, failed2 >> + +Proc2(self) == 2start(self) \/ 2l1(self) \/ 2l2(self) \/ 2l3(self) + \/ 2l4(self) \/ 2l5(self) \/ 2l6(self) \/ 2l7(self) + \/ 2l8(self) \/ 2l9(self) \/ 2l10(self) \/ 2cs(self) + \/ 2l11(self) \/ 2l12(self) + +Next == (\E self \in 1..M: Proc1(self)) + \/ (\E self \in (M+1)..N: Proc2(self)) + +Spec == /\ Init /\ [][Next]_vars + /\ \A self \in 1..M : WF_vars(Proc1(self)) + /\ \A self \in (M+1)..N : WF_vars(Proc2(self)) + +(**************** END TRANSLATION *******************************) + +ASSUME Print(<<"ProcSet =" , ProcSet>>, TRUE) +inCS(i) == IF i \in 1..M + THEN (pc[i] = "cs") /\ (~failed[i]) + ELSE (pc[i] = "2cs") /\ (~failed2[i]) + +Invariant == \A i, k \in 1..N : (i # k) => ~ (inCS(i) /\ inCS(k)) + +Liveness == []<> \E i \in 1..N : inCS(i) +============================================================================= diff --git a/tlatools/test-model/pcal/FastMutex3.cfg b/tlatools/test-model/pcal/FastMutex3.cfg new file mode 100644 index 0000000000000000000000000000000000000000..06b6866abd1c5a3c865f733fc2dc62af47317824 --- /dev/null +++ b/tlatools/test-model/pcal/FastMutex3.cfg @@ -0,0 +1,5 @@ +SPECIFICATION Spec +\* Add statements after this line. +CONSTANT N = 2 +INVARIANT Invariant +PROPERTY Liveness diff --git a/tlatools/test-model/pcal/FastMutex3.tla b/tlatools/test-model/pcal/FastMutex3.tla new file mode 100644 index 0000000000000000000000000000000000000000..0cd07db1865b89c7f9003a24f58b14234b82b339 --- /dev/null +++ b/tlatools/test-model/pcal/FastMutex3.tla @@ -0,0 +1,293 @@ +----------------------------- MODULE FastMutex3 ----------------------------- + +\* This tests the translation when there are two different processes + +EXTENDS Naturals, TLC + +CONSTANT N + +ASSUME (N \in Nat) + +(********************** +--algorithm FastMutex + variables x = 0 ; y = 0 ; b = [i \in 1..N |-> FALSE] ; +process Proc1 = 1 +variables j = 0 ; failed = FALSE ; +begin +start : while TRUE + do l1 : b[1] := TRUE ; + l2 : x := 1 ; + l3 : if y # 0 + then l4 : b[1] := FALSE ; + l5 : when y = 0 ; skip ; + else l6 : y := 1 ; + l7 : if x # 1 + then l8 : b[1] := FALSE ; + j := 1 ; + l9 : while (j \leq N) + do when ~b[j] ; + j := j+1 ; + end while ; + l10 : if y # 1 + then when y = 0 ; + failed := TRUE ; + end if; + end if ; + cs : if ~ failed + then skip ; \* the critical section + l11 : y := 0 ; + l12 : b[1] := FALSE ; + else failed := FALSE ; + end if ; + end if ; + end while ; +end process +process Proc2 \in 2..N +variables j2 = 0 ; failed2 = FALSE ; +begin +2start : while TRUE + do 2l1 : b[self] := TRUE ; + 2l2 : x := self ; + 2l3 : if y # 0 + then 2l4 : b[self] := FALSE ; + 2l5 : when y = 0 ; skip ; + else 2l6 : y := self ; + 2l7 : if x # self + then 2l8 : b[self] := FALSE ; + j2 := 1 ; + 2l9 : while (j2 \leq N) + do when ~b[j2] ; + j2 := j2+1 ; + end while ; + 2l10 : if y # self + then when y = 0 ; + failed2 := TRUE ; + end if; + end if ; + 2cs : if ~ failed2 + then skip ; \* the critical section + 2l11 : y := 0 ; + 2l12 : b[self] := FALSE ; + else failed2 := FALSE ; + end if ; + end if ; + end while ; +end process +end algorithm + +***********************) + +(**************** BEGIN TRANSLATION *******************************) +VARIABLES x, y, b, pc, j, failed, j2, failed2 + +vars == << x, y, b, pc, j, failed, j2, failed2 >> + +ProcSet == {1} \cup (2..N) + +Init == (* Global variables *) + /\ x = 0 + /\ y = 0 + /\ b = [i \in 1..N |-> FALSE] + (* Process Proc1 *) + /\ j = 0 + /\ failed = FALSE + (* Process Proc2 *) + /\ j2 = [self \in 2..N |-> 0] + /\ failed2 = [self \in 2..N |-> FALSE] + /\ pc = [self \in ProcSet |-> CASE self = 1 -> "start" + [] self \in 2..N -> "2start"] + +start == /\ pc[1] = "start" + /\ pc' = [pc EXCEPT ![1] = "l1"] + /\ UNCHANGED << x, y, b, j, failed, j2, failed2 >> + +l1 == /\ pc[1] = "l1" + /\ b' = [b EXCEPT ![1] = TRUE] + /\ pc' = [pc EXCEPT ![1] = "l2"] + /\ UNCHANGED << x, y, j, failed, j2, failed2 >> + +l2 == /\ pc[1] = "l2" + /\ x' = 1 + /\ pc' = [pc EXCEPT ![1] = "l3"] + /\ UNCHANGED << y, b, j, failed, j2, failed2 >> + +l3 == /\ pc[1] = "l3" + /\ IF y # 0 + THEN /\ pc' = [pc EXCEPT ![1] = "l4"] + ELSE /\ pc' = [pc EXCEPT ![1] = "l6"] + /\ UNCHANGED << x, y, b, j, failed, j2, failed2 >> + +l4 == /\ pc[1] = "l4" + /\ b' = [b EXCEPT ![1] = FALSE] + /\ pc' = [pc EXCEPT ![1] = "l5"] + /\ UNCHANGED << x, y, j, failed, j2, failed2 >> + +l5 == /\ pc[1] = "l5" + /\ y = 0 + /\ TRUE + /\ pc' = [pc EXCEPT ![1] = "start"] + /\ UNCHANGED << x, y, b, j, failed, j2, failed2 >> + +l6 == /\ pc[1] = "l6" + /\ y' = 1 + /\ pc' = [pc EXCEPT ![1] = "l7"] + /\ UNCHANGED << x, b, j, failed, j2, failed2 >> + +l7 == /\ pc[1] = "l7" + /\ IF x # 1 + THEN /\ pc' = [pc EXCEPT ![1] = "l8"] + ELSE /\ pc' = [pc EXCEPT ![1] = "cs"] + /\ UNCHANGED << x, y, b, j, failed, j2, failed2 >> + +l8 == /\ pc[1] = "l8" + /\ b' = [b EXCEPT ![1] = FALSE] + /\ j' = 1 + /\ pc' = [pc EXCEPT ![1] = "l9"] + /\ UNCHANGED << x, y, failed, j2, failed2 >> + +l9 == /\ pc[1] = "l9" + /\ IF (j \leq N) + THEN /\ ~b[j] + /\ j' = j+1 + /\ pc' = [pc EXCEPT ![1] = "l9"] + ELSE /\ pc' = [pc EXCEPT ![1] = "l10"] + /\ j' = j + /\ UNCHANGED << x, y, b, failed, j2, failed2 >> + +l10 == /\ pc[1] = "l10" + /\ IF y # 1 + THEN /\ y = 0 + /\ failed' = TRUE + ELSE /\ TRUE + /\ UNCHANGED failed + /\ pc' = [pc EXCEPT ![1] = "cs"] + /\ UNCHANGED << x, y, b, j, j2, failed2 >> + +cs == /\ pc[1] = "cs" + /\ IF ~ failed + THEN /\ TRUE + /\ pc' = [pc EXCEPT ![1] = "l11"] + /\ UNCHANGED failed + ELSE /\ failed' = FALSE + /\ pc' = [pc EXCEPT ![1] = "start"] + /\ UNCHANGED << x, y, b, j, j2, failed2 >> + +l11 == /\ pc[1] = "l11" + /\ y' = 0 + /\ pc' = [pc EXCEPT ![1] = "l12"] + /\ UNCHANGED << x, b, j, failed, j2, failed2 >> + +l12 == /\ pc[1] = "l12" + /\ b' = [b EXCEPT ![1] = FALSE] + /\ pc' = [pc EXCEPT ![1] = "start"] + /\ UNCHANGED << x, y, j, failed, j2, failed2 >> + +Proc1 == start \/ l1 \/ l2 \/ l3 \/ l4 \/ l5 \/ l6 \/ l7 \/ l8 \/ l9 \/ l10 + \/ cs \/ l11 \/ l12 + +2start(self) == /\ pc[self] = "2start" + /\ pc' = [pc EXCEPT ![self] = "2l1"] + /\ UNCHANGED << x, y, b, j, failed, j2, failed2 >> + +2l1(self) == /\ pc[self] = "2l1" + /\ b' = [b EXCEPT ![self] = TRUE] + /\ pc' = [pc EXCEPT ![self] = "2l2"] + /\ UNCHANGED << x, y, j, failed, j2, failed2 >> + +2l2(self) == /\ pc[self] = "2l2" + /\ x' = self + /\ pc' = [pc EXCEPT ![self] = "2l3"] + /\ UNCHANGED << y, b, j, failed, j2, failed2 >> + +2l3(self) == /\ pc[self] = "2l3" + /\ IF y # 0 + THEN /\ pc' = [pc EXCEPT ![self] = "2l4"] + ELSE /\ pc' = [pc EXCEPT ![self] = "2l6"] + /\ UNCHANGED << x, y, b, j, failed, j2, failed2 >> + +2l4(self) == /\ pc[self] = "2l4" + /\ b' = [b EXCEPT ![self] = FALSE] + /\ pc' = [pc EXCEPT ![self] = "2l5"] + /\ UNCHANGED << x, y, j, failed, j2, failed2 >> + +2l5(self) == /\ pc[self] = "2l5" + /\ y = 0 + /\ TRUE + /\ pc' = [pc EXCEPT ![self] = "2start"] + /\ UNCHANGED << x, y, b, j, failed, j2, failed2 >> + +2l6(self) == /\ pc[self] = "2l6" + /\ y' = self + /\ pc' = [pc EXCEPT ![self] = "2l7"] + /\ UNCHANGED << x, b, j, failed, j2, failed2 >> + +2l7(self) == /\ pc[self] = "2l7" + /\ IF x # self + THEN /\ pc' = [pc EXCEPT ![self] = "2l8"] + ELSE /\ pc' = [pc EXCEPT ![self] = "2cs"] + /\ UNCHANGED << x, y, b, j, failed, j2, failed2 >> + +2l8(self) == /\ pc[self] = "2l8" + /\ b' = [b EXCEPT ![self] = FALSE] + /\ j2' = [j2 EXCEPT ![self] = 1] + /\ pc' = [pc EXCEPT ![self] = "2l9"] + /\ UNCHANGED << x, y, j, failed, failed2 >> + +2l9(self) == /\ pc[self] = "2l9" + /\ IF (j2[self] \leq N) + THEN /\ ~b[j2[self]] + /\ j2' = [j2 EXCEPT ![self] = j2[self]+1] + /\ pc' = [pc EXCEPT ![self] = "2l9"] + ELSE /\ pc' = [pc EXCEPT ![self] = "2l10"] + /\ j2' = j2 + /\ UNCHANGED << x, y, b, j, failed, failed2 >> + +2l10(self) == /\ pc[self] = "2l10" + /\ IF y # self + THEN /\ y = 0 + /\ failed2' = [failed2 EXCEPT ![self] = TRUE] + ELSE /\ TRUE + /\ UNCHANGED failed2 + /\ pc' = [pc EXCEPT ![self] = "2cs"] + /\ UNCHANGED << x, y, b, j, failed, j2 >> + +2cs(self) == /\ pc[self] = "2cs" + /\ IF ~ failed2[self] + THEN /\ TRUE + /\ pc' = [pc EXCEPT ![self] = "2l11"] + /\ UNCHANGED failed2 + ELSE /\ failed2' = [failed2 EXCEPT ![self] = FALSE] + /\ pc' = [pc EXCEPT ![self] = "2start"] + /\ UNCHANGED << x, y, b, j, failed, j2 >> + +2l11(self) == /\ pc[self] = "2l11" + /\ y' = 0 + /\ pc' = [pc EXCEPT ![self] = "2l12"] + /\ UNCHANGED << x, b, j, failed, j2, failed2 >> + +2l12(self) == /\ pc[self] = "2l12" + /\ b' = [b EXCEPT ![self] = FALSE] + /\ pc' = [pc EXCEPT ![self] = "2start"] + /\ UNCHANGED << x, y, j, failed, j2, failed2 >> + +Proc2(self) == 2start(self) \/ 2l1(self) \/ 2l2(self) \/ 2l3(self) + \/ 2l4(self) \/ 2l5(self) \/ 2l6(self) \/ 2l7(self) + \/ 2l8(self) \/ 2l9(self) \/ 2l10(self) \/ 2cs(self) + \/ 2l11(self) \/ 2l12(self) + +Next == Proc1 + \/ (\E self \in 2..N: Proc2(self)) + +Spec == /\ Init /\ [][Next]_vars + /\ WF_vars(Proc1) + /\ \A self \in 2..N : WF_vars(Proc2(self)) + +(**************** END TRANSLATION *******************************) + +ASSUME Print(<<"ProcSet =" , ProcSet>>, TRUE) +inCS(i) == IF i = 1 THEN (pc[i] = "cs") /\ (~failed) + ELSE (pc[i] = "2cs") /\ (~failed2[i]) +Invariant == \A i, k \in 1..N : (i # k) => ~ (inCS(i) /\ inCS(k)) + +Liveness == []<> \E i \in 1..N : inCS(i) +============================================================================= diff --git a/tlatools/test-model/pcal/FastMutexWithGoto.cfg b/tlatools/test-model/pcal/FastMutexWithGoto.cfg new file mode 100644 index 0000000000000000000000000000000000000000..cd016e674cbb13c109259f05e6e587fb82d6a4ae --- /dev/null +++ b/tlatools/test-model/pcal/FastMutexWithGoto.cfg @@ -0,0 +1,5 @@ +\* Add statements after this line. +CONSTANT N = 2 +INVARIANT Invariant +PROPERTY CondLiveness +SPECIFICATION FairSpec diff --git a/tlatools/test-model/pcal/FastMutexWithGoto.tla b/tlatools/test-model/pcal/FastMutexWithGoto.tla new file mode 100644 index 0000000000000000000000000000000000000000..45c12e33c46346073827d1b5124c9367ebb03e95 --- /dev/null +++ b/tlatools/test-model/pcal/FastMutexWithGoto.tla @@ -0,0 +1,179 @@ +------------------------- MODULE FastMutexWithGoto -------------------------- + +EXTENDS Naturals + +CONSTANT N + +ASSUME N \in Nat + +(********************** +--algorithm FastMutex +variables x = 0 ; y = 0 ; b = [i \in 1..N |-> FALSE] ; + +process Proc \in 1..N + variables j = 0 ; + begin + ncs: while TRUE do + skip ; \* Noncritical section. + start: b[self] := TRUE ; + l1: x := self ; + l2: if y # 0 + then l3: b[self] := FALSE ; + l4: when y = 0 ; + goto start ; + end if ; + l5: y := self ; + l6: if x # self + then l7: b[self] := FALSE ; + j := 1 ; + l8: while j \leq N do + when ~b[j] ; + j := j+1 ; + end while ; + l9: if y # self then l10: when y = 0 ; + goto start ; + end if ; + end if; + cs: skip ; \* the critical section + l11: y := 0 ; + l12: b[self] := FALSE ; + end while ; +end process + +end algorithm + +***********************) + +(**************** BEGIN TRANSLATION *******************************) +VARIABLES x, y, b, pc, j + +vars == << x, y, b, pc, j >> + +ProcSet == (1..N) + +Init == (* Global variables *) + /\ x = 0 + /\ y = 0 + /\ b = [i \in 1..N |-> FALSE] + (* Process Proc *) + /\ j = [self \in 1..N |-> 0] + /\ pc = [self \in ProcSet |-> "ncs"] + +ncs(self) == /\ pc[self] = "ncs" + /\ TRUE + /\ pc' = [pc EXCEPT ![self] = "start"] + /\ UNCHANGED << x, y, b, j >> + +start(self) == /\ pc[self] = "start" + /\ b' = [b EXCEPT ![self] = TRUE] + /\ pc' = [pc EXCEPT ![self] = "l1"] + /\ UNCHANGED << x, y, j >> + +l1(self) == /\ pc[self] = "l1" + /\ x' = self + /\ pc' = [pc EXCEPT ![self] = "l2"] + /\ UNCHANGED << y, b, j >> + +l2(self) == /\ pc[self] = "l2" + /\ IF y # 0 + THEN /\ pc' = [pc EXCEPT ![self] = "l3"] + ELSE /\ pc' = [pc EXCEPT ![self] = "l5"] + /\ UNCHANGED << x, y, b, j >> + +l3(self) == /\ pc[self] = "l3" + /\ b' = [b EXCEPT ![self] = FALSE] + /\ pc' = [pc EXCEPT ![self] = "l4"] + /\ UNCHANGED << x, y, j >> + +l4(self) == /\ pc[self] = "l4" + /\ y = 0 + /\ pc' = [pc EXCEPT ![self] = "start"] + /\ UNCHANGED << x, y, b, j >> + +l5(self) == /\ pc[self] = "l5" + /\ y' = self + /\ pc' = [pc EXCEPT ![self] = "l6"] + /\ UNCHANGED << x, b, j >> + +l6(self) == /\ pc[self] = "l6" + /\ IF x # self + THEN /\ pc' = [pc EXCEPT ![self] = "l7"] + ELSE /\ pc' = [pc EXCEPT ![self] = "cs"] + /\ UNCHANGED << x, y, b, j >> + +l7(self) == /\ pc[self] = "l7" + /\ b' = [b EXCEPT ![self] = FALSE] + /\ j' = [j EXCEPT ![self] = 1] + /\ pc' = [pc EXCEPT ![self] = "l8"] + /\ UNCHANGED << x, y >> + +l8(self) == /\ pc[self] = "l8" + /\ IF j[self] \leq N + THEN /\ ~b[j[self]] + /\ j' = [j EXCEPT ![self] = j[self]+1] + /\ pc' = [pc EXCEPT ![self] = "l8"] + ELSE /\ pc' = [pc EXCEPT ![self] = "l9"] + /\ j' = j + /\ UNCHANGED << x, y, b >> + +l9(self) == /\ pc[self] = "l9" + /\ IF y # self + THEN /\ pc' = [pc EXCEPT ![self] = "l10"] + ELSE /\ pc' = [pc EXCEPT ![self] = "cs"] + /\ UNCHANGED << x, y, b, j >> + +l10(self) == /\ pc[self] = "l10" + /\ y = 0 + /\ pc' = [pc EXCEPT ![self] = "start"] + /\ UNCHANGED << x, y, b, j >> + +cs(self) == /\ pc[self] = "cs" + /\ TRUE + /\ pc' = [pc EXCEPT ![self] = "l11"] + /\ UNCHANGED << x, y, b, j >> + +l11(self) == /\ pc[self] = "l11" + /\ y' = 0 + /\ pc' = [pc EXCEPT ![self] = "l12"] + /\ UNCHANGED << x, b, j >> + +l12(self) == /\ pc[self] = "l12" + /\ b' = [b EXCEPT ![self] = FALSE] + /\ pc' = [pc EXCEPT ![self] = "ncs"] + /\ UNCHANGED << x, y, j >> + +Proc(self) == ncs(self) \/ start(self) \/ l1(self) \/ l2(self) \/ l3(self) + \/ l4(self) \/ l5(self) \/ l6(self) \/ l7(self) + \/ l8(self) \/ l9(self) \/ l10(self) \/ cs(self) + \/ l11(self) \/ l12(self) + +Next == (\E self \in 1..N: Proc(self)) + +Spec == Init /\ [][Next]_vars + +(**************** END TRANSLATION *******************************) + +inCS(i) == (pc[i] = "cs") + +Invariant == \A i, k \in 1..N: (i # k) => ~ (inCS(i) /\ inCS(k)) + +Liveness == []<> \E i \in 1..N: inCS(i) + +CondLiveness == ([]<> \E i \in 1..N : pc[i] # "ncs") => Liveness + +Fairness == \A i \in 1..N : + /\ WF_vars(start(i)) + /\ WF_vars(l1(i)) + /\ WF_vars(l2(i)) + /\ WF_vars(l3(i)) + /\ WF_vars(l4(i)) + /\ WF_vars(l5(i)) + /\ WF_vars(l6(i)) + /\ WF_vars(l7(i)) + /\ WF_vars(l8(i)) + /\ WF_vars(l9(i)) + /\ WF_vars(l10(i)) + /\ WF_vars(l11(i)) + /\ WF_vars(l12(i)) +FairSpec == Spec /\ Fairness +============================================================================= diff --git a/tlatools/test-model/pcal/FastMutexWithGoto2.cfg b/tlatools/test-model/pcal/FastMutexWithGoto2.cfg new file mode 100644 index 0000000000000000000000000000000000000000..de1000468b848d4daa608674a58a8b347b759671 --- /dev/null +++ b/tlatools/test-model/pcal/FastMutexWithGoto2.cfg @@ -0,0 +1,5 @@ +SPECIFICATION Spec +\* Add statements after this line. +CONSTANT N = 3 +INVARIANT Invariant +PROPERTY Liveness diff --git a/tlatools/test-model/pcal/FastMutexWithGoto2.tla b/tlatools/test-model/pcal/FastMutexWithGoto2.tla new file mode 100644 index 0000000000000000000000000000000000000000..ed71caf8a3d726ff8a69351b12d05d2c702dd931 --- /dev/null +++ b/tlatools/test-model/pcal/FastMutexWithGoto2.tla @@ -0,0 +1,161 @@ +------------------------ MODULE FastMutexWithGoto2 -------------------------- + +EXTENDS Naturals + +CONSTANT N + +ASSUME N \in Nat + +(********************** +--algorithm FastMutex + variables x = 0 ; y = 0 ; b = [i \in 1..N |-> FALSE] ; +process Proc \in 1..N +variables S = {} ; +begin +start : while TRUE + do l1 : b[self] := TRUE ; + l2 : x := self ; + l3 : if y # 0 + then l4 : b[self] := FALSE ; + l5 : when y = 0 ; + goto start ; + end if ; + l6 : y := self ; + l7 : if x # self + then l8 : b[self] := FALSE ; + S := 1..N \ {self} ; + l9 : while S # {} do + with j \in S do when ~b[j] ; + S := S \ {j} + end with ; + end while ; + l10 : if y # self then l11 : when y = 0 ; + goto start ; + end if ; + end if; + cs : skip ; \* the critical section + l12 : y := 0 ; + l13 : b[self] := FALSE ; + end while ; +end process +end algorithm + +***********************) + +(**************** BEGIN TRANSLATION *******************************) +VARIABLES x, y, b, pc, S + +vars == << x, y, b, pc, S >> + +ProcSet == (1..N) + +Init == (* Global variables *) + /\ x = 0 + /\ y = 0 + /\ b = [i \in 1..N |-> FALSE] + (* Process Proc *) + /\ S = [self \in 1..N |-> {}] + /\ pc = [self \in ProcSet |-> "start"] + +start(self) == /\ pc[self] = "start" + /\ pc' = [pc EXCEPT ![self] = "l1"] + /\ UNCHANGED << x, y, b, S >> + +l1(self) == /\ pc[self] = "l1" + /\ b' = [b EXCEPT ![self] = TRUE] + /\ pc' = [pc EXCEPT ![self] = "l2"] + /\ UNCHANGED << x, y, S >> + +l2(self) == /\ pc[self] = "l2" + /\ x' = self + /\ pc' = [pc EXCEPT ![self] = "l3"] + /\ UNCHANGED << y, b, S >> + +l3(self) == /\ pc[self] = "l3" + /\ IF y # 0 + THEN /\ pc' = [pc EXCEPT ![self] = "l4"] + ELSE /\ pc' = [pc EXCEPT ![self] = "l6"] + /\ UNCHANGED << x, y, b, S >> + +l4(self) == /\ pc[self] = "l4" + /\ b' = [b EXCEPT ![self] = FALSE] + /\ pc' = [pc EXCEPT ![self] = "l5"] + /\ UNCHANGED << x, y, S >> + +l5(self) == /\ pc[self] = "l5" + /\ y = 0 + /\ pc' = [pc EXCEPT ![self] = "start"] + /\ UNCHANGED << x, y, b, S >> + +l6(self) == /\ pc[self] = "l6" + /\ y' = self + /\ pc' = [pc EXCEPT ![self] = "l7"] + /\ UNCHANGED << x, b, S >> + +l7(self) == /\ pc[self] = "l7" + /\ IF x # self + THEN /\ pc' = [pc EXCEPT ![self] = "l8"] + ELSE /\ pc' = [pc EXCEPT ![self] = "cs"] + /\ UNCHANGED << x, y, b, S >> + +l8(self) == /\ pc[self] = "l8" + /\ b' = [b EXCEPT ![self] = FALSE] + /\ S' = [S EXCEPT ![self] = 1..N \ {self}] + /\ pc' = [pc EXCEPT ![self] = "l9"] + /\ UNCHANGED << x, y >> + +l9(self) == /\ pc[self] = "l9" + /\ IF S[self] # {} + THEN /\ \E j \in S[self]: + /\ ~b[j] + /\ S' = [S EXCEPT ![self] = S[self] \ {j}] + /\ pc' = [pc EXCEPT ![self] = "l9"] + ELSE /\ pc' = [pc EXCEPT ![self] = "l10"] + /\ S' = S + /\ UNCHANGED << x, y, b >> + +l10(self) == /\ pc[self] = "l10" + /\ IF y # self + THEN /\ pc' = [pc EXCEPT ![self] = "l11"] + ELSE /\ pc' = [pc EXCEPT ![self] = "cs"] + /\ UNCHANGED << x, y, b, S >> + +l11(self) == /\ pc[self] = "l11" + /\ y = 0 + /\ pc' = [pc EXCEPT ![self] = "start"] + /\ UNCHANGED << x, y, b, S >> + +cs(self) == /\ pc[self] = "cs" + /\ TRUE + /\ pc' = [pc EXCEPT ![self] = "l12"] + /\ UNCHANGED << x, y, b, S >> + +l12(self) == /\ pc[self] = "l12" + /\ y' = 0 + /\ pc' = [pc EXCEPT ![self] = "l13"] + /\ UNCHANGED << x, b, S >> + +l13(self) == /\ pc[self] = "l13" + /\ b' = [b EXCEPT ![self] = FALSE] + /\ pc' = [pc EXCEPT ![self] = "start"] + /\ UNCHANGED << x, y, S >> + +Proc(self) == start(self) \/ l1(self) \/ l2(self) \/ l3(self) \/ l4(self) + \/ l5(self) \/ l6(self) \/ l7(self) \/ l8(self) + \/ l9(self) \/ l10(self) \/ l11(self) \/ cs(self) + \/ l12(self) \/ l13(self) + +Next == (\E self \in 1..N: Proc(self)) + +Spec == /\ Init /\ [][Next]_vars + /\ WF_vars(Next) + +(**************** END TRANSLATION *******************************) + +inCS(i) == (pc[i] = "cs") + +Invariant == \A i, k \in 1..N : (i # k) => ~ (inCS(i) /\ inCS(k)) + + +Liveness == []<> \E i \in 1..N : inCS(i) +============================================================================= diff --git a/tlatools/test-model/pcal/Fischer.cfg b/tlatools/test-model/pcal/Fischer.cfg new file mode 100644 index 0000000000000000000000000000000000000000..699094a9583bbdf24c5155731fce87e5d9a56b92 --- /dev/null +++ b/tlatools/test-model/pcal/Fischer.cfg @@ -0,0 +1,5 @@ +SPECIFICATION Spec +\* Add statements after this line. +CONSTANT N = 3 Epsilon = 3 Delta = 2 +INVARIANT Invariant +PROPERTY Liveness diff --git a/tlatools/test-model/pcal/Fischer.tla b/tlatools/test-model/pcal/Fischer.tla new file mode 100644 index 0000000000000000000000000000000000000000..e781d3c25669fb2dc8623a6459d4d0105e0fe68c --- /dev/null +++ b/tlatools/test-model/pcal/Fischer.tla @@ -0,0 +1,137 @@ +Plus Cal options (-wf -spec PlusCal2) +----------------------------- MODULE Fischer ----------------------------- +EXTENDS Naturals, TLC +\* what's up +CONSTANT Delta, Epsilon \* The timing delays +CONSTANT N \* The number of synchronizing processes +\* CONSTANT defaultInitValue + +ASSUME /\ Print("Testing Fischer's Mutual Exclusion Algorithm", TRUE) + /\ Print(<<" Number of processes = ", N>>, TRUE) + /\ Print(<<" Delta = ", Delta>>, TRUE) + /\ Print(<<" Epsilon = ", Epsilon>>, TRUE) + /\ Print("Should find a bug if N > 1 and Delta >= Epsilon", TRUE) + + +Infinity == 9999999 + +(********************** +--algorithm Fischer + variables x = 0 ; timer = [i \in 1..N |-> Infinity] ; + process Proc \in 1..N + variable firstTime = TRUE ; + begin a : while TRUE + (**********************************************************************) + (* Note that the +cal syntax requires that both while statements be *) + (* labeled, adding a useless atomic action. The only ways I see to *) + (* eliminate that would be by adding a "goto" statement that could be *) + (* used to encode the inner "while" loop. *) + (**********************************************************************) + do b : while x # self + (***************************************************) + (* x can't equal i the first time through the loop *) + (***************************************************) + do c : when x = 0 ; + timer[self] := Delta ; + d : x := self ; + timer[self] := Epsilon ; + e : when timer[self] = 0 ; + timer[self] := Infinity ; + end while ; + cs : skip ; \* critical section + f : x := 0 ; + end while ; + end process + process Tick = 0 + begin t1 : while TRUE + do when \A i \in 1..N : timer[i] > 0 ; + timer := [i \in 1..N |-> IF timer[i] < Infinity + THEN timer[i] - 1 + ELSE timer[i] ] ; + end while ; + end process +end algorithm + +***********************) + +(**************** BEGIN TRANSLATION *******************************) +VARIABLES x, timer, pc, firstTime + +vars == << x, timer, pc, firstTime >> + +ProcSet == (1..N) \cup {0} + +Init == (* Global variables *) + /\ x = 0 + /\ timer = [i \in 1..N |-> Infinity] + (* Process Proc *) + /\ firstTime = [self \in 1..N |-> TRUE] + /\ pc = [self \in ProcSet |-> CASE self \in 1..N -> "a" + [] self = 0 -> "t1"] + +a(self) == /\ pc[self] = "a" + /\ pc' = [pc EXCEPT ![self] = "b"] + /\ UNCHANGED << x, timer, firstTime >> + +b(self) == /\ pc[self] = "b" + /\ IF x # self + THEN /\ pc' = [pc EXCEPT ![self] = "c"] + ELSE /\ pc' = [pc EXCEPT ![self] = "cs"] + /\ UNCHANGED << x, timer, firstTime >> + +c(self) == /\ pc[self] = "c" + /\ x = 0 + /\ timer' = [timer EXCEPT ![self] = Delta] + /\ pc' = [pc EXCEPT ![self] = "d"] + /\ UNCHANGED << x, firstTime >> + +d(self) == /\ pc[self] = "d" + /\ x' = self + /\ timer' = [timer EXCEPT ![self] = Epsilon] + /\ pc' = [pc EXCEPT ![self] = "e"] + /\ UNCHANGED firstTime + +e(self) == /\ pc[self] = "e" + /\ timer[self] = 0 + /\ timer' = [timer EXCEPT ![self] = Infinity] + /\ pc' = [pc EXCEPT ![self] = "b"] + /\ UNCHANGED << x, firstTime >> + +cs(self) == /\ pc[self] = "cs" + /\ TRUE + /\ pc' = [pc EXCEPT ![self] = "f"] + /\ UNCHANGED << x, timer, firstTime >> + +f(self) == /\ pc[self] = "f" + /\ x' = 0 + /\ pc' = [pc EXCEPT ![self] = "a"] + /\ UNCHANGED << timer, firstTime >> + +Proc(self) == a(self) \/ b(self) \/ c(self) \/ d(self) \/ e(self) + \/ cs(self) \/ f(self) + +t1 == /\ pc[0] = "t1" + /\ \A i \in 1..N : timer[i] > 0 + /\ timer' = [i \in 1..N |-> IF timer[i] < Infinity + THEN timer[i] - 1 + ELSE timer[i] ] + /\ pc' = [pc EXCEPT ![0] = "t1"] + /\ UNCHANGED << x, firstTime >> + +Tick == t1 + +Next == Tick + \/ (\E self \in 1..N: Proc(self)) + +Spec == /\ Init /\ [][Next]_vars + /\ \A self \in 1..N : WF_vars(Proc(self)) + /\ WF_vars(Tick) + +(**************** END TRANSLATION *******************************) + +inCS(i) == pc[i] = "cs" + +Invariant == \A i, k \in 1..N : (i # k) => ~ (inCS(i) /\ inCS(k)) + +Liveness == []<> \E i \in 1..N : inCS(i) +============================================================================= diff --git a/tlatools/test-model/pcal/InnerLabeledIf.tla b/tlatools/test-model/pcal/InnerLabeledIf.tla new file mode 100644 index 0000000000000000000000000000000000000000..b38129570c5a89818e978d719bf061974613811d --- /dev/null +++ b/tlatools/test-model/pcal/InnerLabeledIf.tla @@ -0,0 +1,81 @@ +--------------------------- MODULE InnerLabeledIf ---------------------------- +EXTENDS Sequences, Naturals, TLC + +(* + --algorithm InnerLabeledIf + variable x \in 1..4 ; + begin a : if (x < 3) + then if (x = 1) + then skip ; + b : assert x = 1 + else c : assert x = 2 + end if ; + else if (x = 3) + then skip ; + d : assert x = 3 + else e : assert x = 4 ; + end if ; + end if ; + f : print("made it to end") ; + end algorithm +*) + +(***** BEGIN TRANSLATION ***) +VARIABLES x, pc + +vars == << x, pc >> + +Init == (* Global variables *) + /\ x \in 1..4 + /\ pc = "a" + +a == /\ pc = "a" + /\ IF (x < 3) + THEN /\ IF (x = 1) + THEN /\ TRUE + /\ pc' = "b" + ELSE /\ pc' = "c" + ELSE /\ IF (x = 3) + THEN /\ TRUE + /\ pc' = "d" + ELSE /\ pc' = "e" + /\ x' = x + +b == /\ pc = "b" + /\ Assert(x = 1, "Failure of assertion at line 10, column 33.") + /\ pc' = "f" + /\ x' = x + +c == /\ pc = "c" + /\ Assert(x = 2, "Failure of assertion at line 11, column 33.") + /\ pc' = "f" + /\ x' = x + +d == /\ pc = "d" + /\ Assert(x = 3, "Failure of assertion at line 15, column 33.") + /\ pc' = "f" + /\ x' = x + +e == /\ pc = "e" + /\ Assert(x = 4, "Failure of assertion at line 16, column 33.") + /\ pc' = "f" + /\ x' = x + +f == /\ pc = "f" + /\ PrintT(("made it to end")) + /\ pc' = "Done" + /\ x' = x + +Next == a \/ b \/ c \/ d \/ e \/ f + \/ (* Disjunct to prevent deadlock on termination *) + (pc = "Done" /\ UNCHANGED vars) + +Spec == /\ Init /\ [][Next]_vars + /\ WF_vars(Next) + +Termination == <>(pc = "Done") + +(***** END TRANSLATION ***) + + +============================================================================= diff --git a/tlatools/test-model/pcal/MPFactorial.tla b/tlatools/test-model/pcal/MPFactorial.tla new file mode 100644 index 0000000000000000000000000000000000000000..b95fa09e851356b52d8b2543bb31203243aa134e --- /dev/null +++ b/tlatools/test-model/pcal/MPFactorial.tla @@ -0,0 +1,117 @@ +----------------------------- MODULE MPFactorial ----------------------------- +EXTENDS Naturals, Sequences, TLC + +(*************************************************************************** +--algorithm Factorial + variable result = [i \in 1..3 |-> 1]; \* are comments ok? + procedure FactProc(arg1 (* = 0 *) ) (* are comments ok? *) + (* what about (* nested multi-line *) + comments? *) + variable u = 1 ; + begin p1 : if arg1 = 0 + then return; \* HERE IS A + else result[self] := result[self] * arg1; + call FactProc ( arg1 - 1) ; + return; + end if; + end procedure + process Main \in 1..2 + begin + a1 : call FactProc( 5 ) ; + a2 : assert result[self] = 120 ; + end process + process Minor = 3 + begin + b1 : call FactProc( 5 ) ; + b2 : assert result[3] = 120 ; + end process + end algorithm +***************************************************************************) + +(************** BEGIN TRANSLATION ********************) +CONSTANT defaultInitValue +VARIABLES result, pc, stack, arg1, u + +vars == << result, pc, stack, arg1, u >> + +ProcSet == (1..2) \cup {3} + +Init == (* Global variables *) + /\ result = [i \in 1..3 |-> 1] + (* Procedure FactProc *) + /\ arg1 = [ self \in ProcSet |-> defaultInitValue] + /\ u = [ self \in ProcSet |-> 1] + /\ stack = [self \in ProcSet |-> << >>] + /\ pc = [self \in ProcSet |-> CASE self \in 1..2 -> "a1" + [] self = 3 -> "b1"] + +p1(self) == /\ pc[self] = "p1" + /\ IF arg1[self] = 0 + THEN /\ pc' = [pc EXCEPT ![self] = Head(stack[self]).pc] + /\ u' = [u EXCEPT ![self] = Head(stack[self]).u] + /\ arg1' = [arg1 EXCEPT ![self] = Head(stack[self]).arg1] + /\ stack' = [stack EXCEPT ![self] = Tail(stack[self])] + /\ UNCHANGED result + ELSE /\ result' = [result EXCEPT ![self] = result[self] * arg1[self]] + /\ arg1' = [arg1 EXCEPT ![self] = arg1[self] - 1] + /\ u' = [u EXCEPT ![self] = 1] + /\ pc' = [pc EXCEPT ![self] = "p1"] + /\ stack' = stack + +FactProc(self) == p1(self) + +a1(self) == /\ pc[self] = "a1" + /\ /\ arg1' = [arg1 EXCEPT ![self] = 5] + /\ stack' = [stack EXCEPT ![self] = << [ procedure |-> "FactProc", + pc |-> "a2", + u |-> u[self], + arg1 |-> arg1[self] ] >> + \o stack[self]] + /\ u' = [u EXCEPT ![self] = 1] + /\ pc' = [pc EXCEPT ![self] = "p1"] + /\ UNCHANGED result + +a2(self) == /\ pc[self] = "a2" + /\ Assert(result[self] = 120, + "Failure of assertion at line 21, column 10.") + /\ pc' = [pc EXCEPT ![self] = "Done"] + /\ UNCHANGED << result, stack, arg1, u >> + +Main(self) == a1(self) \/ a2(self) + +b1 == /\ pc[3] = "b1" + /\ /\ arg1' = [arg1 EXCEPT ![3] = 5] + /\ stack' = [stack EXCEPT ![3] = << [ procedure |-> "FactProc", + pc |-> "b2", + u |-> u[3], + arg1 |-> arg1[3] ] >> + \o stack[3]] + /\ u' = [u EXCEPT ![3] = 1] + /\ pc' = [pc EXCEPT ![3] = "p1"] + /\ UNCHANGED result + +b2 == /\ pc[3] = "b2" + /\ Assert(result[3] = 120, + "Failure of assertion at line 26, column 10.") + /\ pc' = [pc EXCEPT ![3] = "Done"] + /\ UNCHANGED << result, stack, arg1, u >> + +Minor == b1 \/ b2 + +Next == Minor + \/ (\E self \in ProcSet: FactProc(self)) + \/ (\E self \in 1..2: Main(self)) + \/ (* Disjunct to prevent deadlock on termination *) + ((\A self \in ProcSet: pc[self] = "Done") /\ UNCHANGED vars) + +Spec == /\ Init /\ [][Next]_vars + /\ \A self \in 1..2 : WF_vars(Main(self)) /\ WF_vars(FactProc(self)) + /\ WF_vars(Minor) /\ WF_vars(FactProc(3)) + +Termination == <>(\A self \in ProcSet: pc[self] = "Done") + +(************* END TRANSLATION ********************) + + +Invariant == result \in Nat +============================================================================= diff --git a/tlatools/test-model/pcal/MPFactorial2.tla b/tlatools/test-model/pcal/MPFactorial2.tla new file mode 100644 index 0000000000000000000000000000000000000000..a5eb7fbcaa594551651ffda9da94c38e46df30db --- /dev/null +++ b/tlatools/test-model/pcal/MPFactorial2.tla @@ -0,0 +1,161 @@ +----------------------------- MODULE MPFactorial2 ---------------------------- +EXTENDS Naturals, Sequences, TLC + +(*************************************************************************** +Factorial Algorithm with 2 procedures + +--algorithm Factorial + variable result = [i \in 1..3 |-> 1]; + procedure FactProc(arg1 = 0 ) + variable u = 1 ; + begin p1 : if arg1 = 0 + then return; + else result[self] := result[self] * arg1; + call FactProc2 ( arg1 - 1 ) ; + b: return; + end if; + end procedure + procedure FactProc2(arg2 = 0) + variable u2 = 1 ; + begin p12 : if arg2 = 0 + then return; + else result[self] := result[self] * arg2; + call FactProc ( arg2 - 1 ) ; + return; + end if; + end procedure + process Main \in 1..2 + begin + a1 : call FactProc( 5 ) ; + a2 : assert result[self] = 120 + end process + process Minor = 3 + begin + b1 : call FactProc( 5 ) ; + b2 : assert result[3] = 120 + end process + end algorithm +***************************************************************************) + +(************** BEGIN TRANSLATION ********************) +VARIABLES result, pc, stack, arg1, u, arg2, u2 + +vars == << result, pc, stack, arg1, u, arg2, u2 >> + +ProcSet == (1..2) \cup {3} + +Init == (* Global variables *) + /\ result = [i \in 1..3 |-> 1] + (* Procedure FactProc *) + /\ arg1 = [ self \in ProcSet |-> 0] + /\ u = [ self \in ProcSet |-> 1] + (* Procedure FactProc2 *) + /\ arg2 = [ self \in ProcSet |-> 0] + /\ u2 = [ self \in ProcSet |-> 1] + /\ stack = [self \in ProcSet |-> << >>] + /\ pc = [self \in ProcSet |-> CASE self \in 1..2 -> "a1" + [] self = 3 -> "b1"] + +p1(self) == /\ pc[self] = "p1" + /\ IF arg1[self] = 0 + THEN /\ pc' = [pc EXCEPT ![self] = Head(stack[self]).pc] + /\ u' = [u EXCEPT ![self] = Head(stack[self]).u] + /\ arg1' = [arg1 EXCEPT ![self] = Head(stack[self]).arg1] + /\ stack' = [stack EXCEPT ![self] = Tail(stack[self])] + /\ UNCHANGED << result, arg2, u2 >> + ELSE /\ result' = [result EXCEPT ![self] = result[self] * arg1[self]] + /\ /\ arg2' = [arg2 EXCEPT ![self] = arg1[self] - 1] + /\ stack' = [stack EXCEPT ![self] = << [ procedure |-> "FactProc2", + pc |-> "b", + u2 |-> u2[self], + arg2 |-> arg2[self] ] >> + \o stack[self]] + /\ u2' = [u2 EXCEPT ![self] = 1] + /\ pc' = [pc EXCEPT ![self] = "p12"] + /\ UNCHANGED << arg1, u >> + +b(self) == /\ pc[self] = "b" + /\ pc' = [pc EXCEPT ![self] = Head(stack[self]).pc] + /\ u' = [u EXCEPT ![self] = Head(stack[self]).u] + /\ arg1' = [arg1 EXCEPT ![self] = Head(stack[self]).arg1] + /\ stack' = [stack EXCEPT ![self] = Tail(stack[self])] + /\ UNCHANGED << result, arg2, u2 >> + +FactProc(self) == p1(self) \/ b(self) + +p12(self) == /\ pc[self] = "p12" + /\ IF arg2[self] = 0 + THEN /\ pc' = [pc EXCEPT ![self] = Head(stack[self]).pc] + /\ u2' = [u2 EXCEPT ![self] = Head(stack[self]).u2] + /\ arg2' = [arg2 EXCEPT ![self] = Head(stack[self]).arg2] + /\ stack' = [stack EXCEPT ![self] = Tail(stack[self])] + /\ UNCHANGED << result, arg1, u >> + ELSE /\ result' = [result EXCEPT ![self] = result[self] * arg2[self]] + /\ /\ arg1' = [arg1 EXCEPT ![self] = arg2[self] - 1] + /\ stack' = [stack EXCEPT ![self] = << [ procedure |-> "FactProc", + pc |-> Head(stack[self]).pc, + u |-> u[self], + arg1 |-> arg1[self] ] >> + \o Tail(stack[self])] + /\ u2' = [u2 EXCEPT ![self] = Head(stack[self]).u2] + /\ u' = [u EXCEPT ![self] = 1] + /\ pc' = [pc EXCEPT ![self] = "p1"] + /\ arg2' = arg2 + +FactProc2(self) == p12(self) + +a1(self) == /\ pc[self] = "a1" + /\ /\ arg1' = [arg1 EXCEPT ![self] = 5] + /\ stack' = [stack EXCEPT ![self] = << [ procedure |-> "FactProc", + pc |-> "a2", + u |-> u[self], + arg1 |-> arg1[self] ] >> + \o stack[self]] + /\ u' = [u EXCEPT ![self] = 1] + /\ pc' = [pc EXCEPT ![self] = "p1"] + /\ UNCHANGED << result, arg2, u2 >> + +a2(self) == /\ pc[self] = "a2" + /\ Assert(result[self] = 120, + "Failure of assertion at line 30, column 10.") + /\ pc' = [pc EXCEPT ![self] = "Done"] + /\ UNCHANGED << result, stack, arg1, u, arg2, u2 >> + +Main(self) == a1(self) \/ a2(self) + +b1 == /\ pc[3] = "b1" + /\ /\ arg1' = [arg1 EXCEPT ![3] = 5] + /\ stack' = [stack EXCEPT ![3] = << [ procedure |-> "FactProc", + pc |-> "b2", + u |-> u[3], + arg1 |-> arg1[3] ] >> + \o stack[3]] + /\ u' = [u EXCEPT ![3] = 1] + /\ pc' = [pc EXCEPT ![3] = "p1"] + /\ UNCHANGED << result, arg2, u2 >> + +b2 == /\ pc[3] = "b2" + /\ Assert(result[3] = 120, + "Failure of assertion at line 35, column 10.") + /\ pc' = [pc EXCEPT ![3] = "Done"] + /\ UNCHANGED << result, stack, arg1, u, arg2, u2 >> + +Minor == b1 \/ b2 + +Next == Minor + \/ (\E self \in ProcSet: FactProc(self) \/ FactProc2(self)) + \/ (\E self \in 1..2: Main(self)) + \/ (* Disjunct to prevent deadlock on termination *) + ((\A self \in ProcSet: pc[self] = "Done") /\ UNCHANGED vars) + +Spec == /\ Init /\ [][Next]_vars + /\ \A self \in 1..2 : WF_vars(Main(self)) /\ WF_vars(FactProc(self)) /\ WF_vars(FactProc2(self)) + /\ WF_vars(Minor) /\ WF_vars(FactProc(3)) /\ WF_vars(FactProc2(3)) + +Termination == <>(\A self \in ProcSet: pc[self] = "Done") + +(************* END TRANSLATION ********************) + + +Invariant == result \in Nat +============================================================================= diff --git a/tlatools/test-model/pcal/MPNoParams.tla b/tlatools/test-model/pcal/MPNoParams.tla new file mode 100644 index 0000000000000000000000000000000000000000..4fa53d1b3f5929e5a841383d6a8b6282243e9015 --- /dev/null +++ b/tlatools/test-model/pcal/MPNoParams.tla @@ -0,0 +1,89 @@ +----------------------------- MODULE MPNoParams ------------------------------ +EXTENDS Sequences, Naturals, TLC + +(* +--algorithm MPNoParams + variables sum = 0; + + procedure Sum () + begin s1: sum := sum + 1; + return; + end procedure; + process P1 = 1 + begin p1 : call Sum(); + p2 : when sum = 4 ; + end process + process P2 \in 2..4 + begin + q1 : call Sum(); + q2 : when sum = 4 ; + end process + end algorithm + + +*) + +(***** BEGIN TRANSLATION ***) +VARIABLES sum, pc, stack + +vars == << sum, pc, stack >> + +ProcSet == {1} \cup (2..4) + +Init == (* Global variables *) + /\ sum = 0 + /\ stack = [self \in ProcSet |-> << >>] + /\ pc = [self \in ProcSet |-> CASE self = 1 -> "p1" + [] self \in 2..4 -> "q1"] + +s1(self) == /\ pc[self] = "s1" + /\ sum' = sum + 1 + /\ pc' = [pc EXCEPT ![self] = Head(stack[self]).pc] + /\ stack' = [stack EXCEPT ![self] = Tail(stack[self])] + +Sum(self) == s1(self) + +p1 == /\ pc[1] = "p1" + /\ stack' = [stack EXCEPT ![1] = << [ procedure |-> "Sum", + pc |-> "p2" ] >> + \o stack[1]] + /\ pc' = [pc EXCEPT ![1] = "s1"] + /\ sum' = sum + +p2 == /\ pc[1] = "p2" + /\ sum = 4 + /\ pc' = [pc EXCEPT ![1] = "Done"] + /\ UNCHANGED << sum, stack >> + +P1 == p1 \/ p2 + +q1(self) == /\ pc[self] = "q1" + /\ stack' = [stack EXCEPT ![self] = << [ procedure |-> "Sum", + pc |-> "q2" ] >> + \o stack[self]] + /\ pc' = [pc EXCEPT ![self] = "s1"] + /\ sum' = sum + +q2(self) == /\ pc[self] = "q2" + /\ sum = 4 + /\ pc' = [pc EXCEPT ![self] = "Done"] + /\ UNCHANGED << sum, stack >> + +P2(self) == q1(self) \/ q2(self) + +Next == P1 + \/ (\E self \in ProcSet: Sum(self)) + \/ (\E self \in 2..4: P2(self)) + \/ (* Disjunct to prevent deadlock on termination *) + ((\A self \in ProcSet: pc[self] = "Done") /\ UNCHANGED vars) + +Spec == /\ Init /\ [][Next]_vars + /\ WF_vars(P1) /\ WF_vars(Sum(1)) + /\ \A self \in 2..4 : WF_vars(P2(self)) /\ WF_vars(Sum(self)) + +Termination == <>(\A self \in ProcSet: pc[self] = "Done") + +(***** END TRANSLATION ***) + + +============================================================================= diff --git a/tlatools/test-model/pcal/MacroQuicksort.cfg b/tlatools/test-model/pcal/MacroQuicksort.cfg new file mode 100644 index 0000000000000000000000000000000000000000..a662e03b0eb6080164b084439f2edc97a0050a0d --- /dev/null +++ b/tlatools/test-model/pcal/MacroQuicksort.cfg @@ -0,0 +1,4 @@ +SPECIFICATION Spec +PROPERTY Termination +\* Add statements after this line. +CONSTANT ArrayLen = 4 diff --git a/tlatools/test-model/pcal/MacroQuicksort.tla b/tlatools/test-model/pcal/MacroQuicksort.tla new file mode 100644 index 0000000000000000000000000000000000000000..c6a92ae665f45712c7709e1cbaa7a026c2f2c8b3 --- /dev/null +++ b/tlatools/test-model/pcal/MacroQuicksort.tla @@ -0,0 +1,146 @@ +---------------------------- MODULE MacroQuicksort --------------------------- +EXTENDS Naturals, Sequences, TLC + +CONSTANT ArrayLen + +ASSUME ArrayLen \in Nat + +PermsOf(Arr) == + LET Automorphism(S) == { f \in [S -> S] : + \A y \in S : \E x \in S : f[x] = y } + f ** g == [x \in DOMAIN g |-> f[g[x]]] + IN { Arr ** f : f \in Automorphism(DOMAIN Arr) } + +(* +--algorithm Quicksort + variables Ainit \in [1..ArrayLen -> 1..ArrayLen]; A = Ainit; + macro Partition(pivot, lo, hi) + begin with piv \in lo..(hi-1) + do pivot := piv ; + with Ap \in + {AA \in PermsOf(A) : + (\A i \in 1..(lo-1) : AA[i] = A[i]) + /\ (\A i \in (hi+1)..Len(A) : AA[i] = A[i]) + /\ (\A i \in lo..piv, j \in (piv+1)..hi : + AA[i] \leq AA[j])} + do A := Ap; + end with ; + end with; + end macro + procedure QS(qlo = 1, qhi = 1) + variable pivot = 1 ; + begin qs1 : if qlo < qhi + then Partition(pivot, qlo, qhi) ; + qs2 : call QS(qlo, pivot) ; + qs3 : call QS(pivot +1,qhi) ; + end if; + qs4 : return ; + end procedure + begin main : call QS(1, Len(A)) ; + test : assert A \in PermsOf(Ainit) + /\ \A i, j \in 1..ArrayLen : + (i < j) => A[i] \leq A[j] + end algorithm +*) + +(***** BEGIN TRANSLATION ***) +VARIABLES Ainit, A, pc, stack, qlo, qhi, pivot + +vars == << Ainit, A, pc, stack, qlo, qhi, pivot >> + +Init == (* Global variables *) + /\ Ainit \in [1..ArrayLen -> 1..ArrayLen] + /\ A = Ainit + (* Procedure QS *) + /\ qlo = 1 + /\ qhi = 1 + /\ pivot = 1 + /\ stack = << >> + /\ pc = "main" + +qs1 == /\ pc = "qs1" + /\ IF qlo < qhi + THEN /\ \E piv \in qlo..(qhi-1): + /\ pivot' = piv + /\ \E Ap \in {AA \in PermsOf(A) : + (\A i \in 1..(qlo-1) : AA[i] = A[i]) + /\ (\A i \in (qhi+1)..Len(A) : AA[i] = A[i]) + /\ (\A i \in qlo..piv, j \in (piv+1)..qhi : + AA[i] \leq AA[j])}: + A' = Ap + /\ pc' = "qs2" + ELSE /\ pc' = "qs4" + /\ UNCHANGED << A, pivot >> + /\ UNCHANGED << Ainit, stack, qlo, qhi >> + +qs2 == /\ pc = "qs2" + /\ /\ qhi' = pivot + /\ qlo' = qlo + /\ stack' = << [ procedure |-> "QS", + pc |-> "qs3", + pivot |-> pivot, + qlo |-> qlo, + qhi |-> qhi ] >> + \o stack + /\ pivot' = 1 + /\ pc' = "qs1" + /\ UNCHANGED << Ainit, A >> + +qs3 == /\ pc = "qs3" + /\ /\ qhi' = qhi + /\ qlo' = pivot +1 + /\ stack' = << [ procedure |-> "QS", + pc |-> "qs4", + pivot |-> pivot, + qlo |-> qlo, + qhi |-> qhi ] >> + \o stack + /\ pivot' = 1 + /\ pc' = "qs1" + /\ UNCHANGED << Ainit, A >> + +qs4 == /\ pc = "qs4" + /\ pc' = Head(stack).pc + /\ pivot' = Head(stack).pivot + /\ qlo' = Head(stack).qlo + /\ qhi' = Head(stack).qhi + /\ stack' = Tail(stack) + /\ UNCHANGED << Ainit, A >> + +QS == qs1 \/ qs2 \/ qs3 \/ qs4 + +main == /\ pc = "main" + /\ /\ qhi' = Len(A) + /\ qlo' = 1 + /\ stack' = << [ procedure |-> "QS", + pc |-> "test", + pivot |-> pivot, + qlo |-> qlo, + qhi |-> qhi ] >> + \o stack + /\ pivot' = 1 + /\ pc' = "qs1" + /\ UNCHANGED << Ainit, A >> + +test == /\ pc = "test" + /\ Assert( A \in PermsOf(Ainit) + /\ \A i, j \in 1..ArrayLen : + (i < j) => A[i] \leq A[j], + "Failure of assertion at line 40, column 17.") + /\ pc' = "Done" + /\ UNCHANGED << Ainit, A, stack, qlo, qhi, pivot >> + +Next == QS \/ main \/ test + \/ (* Disjunct to prevent deadlock on termination *) + (pc = "Done" /\ UNCHANGED vars) + +Spec == /\ Init /\ [][Next]_vars + /\ WF_vars(Next) + +Termination == <>(pc = "Done") + +(***** END TRANSLATION ***) +============================================================================= +Checked without termination on svc-lamport-2 with 2 workers: + arrayLen = 4 in 15 sec, 32280 states, depth 22 + arrayLen = 5 in 138min 17 sec 1529005 states, depth 28 diff --git a/tlatools/test-model/pcal/MacroRealQuicksort.cfg b/tlatools/test-model/pcal/MacroRealQuicksort.cfg new file mode 100644 index 0000000000000000000000000000000000000000..672c5ec21152f6c0135cca7850d5415e163e2259 --- /dev/null +++ b/tlatools/test-model/pcal/MacroRealQuicksort.cfg @@ -0,0 +1,4 @@ +SPECIFICATION Spec +PROPERTY Termination +\* Add statements after this line. +CONSTANT N = 4 diff --git a/tlatools/test-model/pcal/MacroRealQuicksort.tla b/tlatools/test-model/pcal/MacroRealQuicksort.tla new file mode 100644 index 0000000000000000000000000000000000000000..eb45df5a589cf35fc75dbd55113961f2d554cc48 --- /dev/null +++ b/tlatools/test-model/pcal/MacroRealQuicksort.tla @@ -0,0 +1,90 @@ +-------------------------- MODULE MacroRealQuicksort ------------------------- +EXTENDS Naturals, Sequences, TLC + +CONSTANT N + +ASSUME N \in Nat + +PermsOf(Arr) == + LET Automorphism(S) == { f \in [S -> S] : + \A y \in S : \E x \in S : f[x] = y } + f ** g == [x \in DOMAIN g |-> f[g[x]]] + IN { Arr ** f : f \in Automorphism(DOMAIN Arr) } + +(* +--algorithm Quicksort + variables Ainit \in [1..N -> 1..N]; A = Ainit; + S = {<<1,N>>} ; pivot = 1 ; + macro Partition(pivot, lo, hi) + begin with piv \in lo..(hi-1) + do pivot := piv ; + with Ap \in + {AA \in PermsOf(A) : + (\A i \in 1..(lo-1) : AA[i] = A[i]) + /\ (\A i \in (hi+1)..Len(A) : AA[i] = A[i]) + /\ (\A i \in lo..piv, j \in (piv+1)..hi : + AA[i] \leq AA[j])} + do A := Ap; + end with ; + end with; + end macro + begin qs1 : while S # {} + do with I \in S + do if I[1] < I[2] + then Partition(pivot, I[1], I[2]) ; + S := (S \ {I}) + \cup {<<I[1], pivot>>, <<pivot+1, I[2]>>} + else S := (S \ {I}) + end if + end with + end while + end algorithm +*) + +(***** BEGIN TRANSLATION ***) +VARIABLES Ainit, A, S, pivot, pc + +vars == << Ainit, A, S, pivot, pc >> + +Init == (* Global variables *) + /\ Ainit \in [1..N -> 1..N] + /\ A = Ainit + /\ S = {<<1,N>>} + /\ pivot = 1 + /\ pc = "qs1" + +qs1 == /\ pc = "qs1" + /\ IF S # {} + THEN /\ \E I \in S: + IF I[1] < I[2] + THEN /\ \E piv \in (I[1])..((I[2])-1): + /\ pivot' = piv + /\ \E Ap \in {AA \in PermsOf(A) : + (\A i \in 1..((I[1])-1) : AA[i] = A[i]) + /\ (\A i \in ((I[2])+1)..Len(A) : AA[i] = A[i]) + /\ (\A i \in (I[1])..piv, j \in (piv+1)..(I[2]) : + AA[i] \leq AA[j])}: + A' = Ap + /\ S' = (S \ {I}) + \cup {<<I[1], pivot'>>, <<pivot'+1, I[2]>>} + ELSE /\ S' = (S \ {I}) + /\ UNCHANGED << A, pivot >> + /\ pc' = "qs1" + ELSE /\ pc' = "Done" + /\ UNCHANGED << A, S, pivot >> + /\ Ainit' = Ainit + +Next == qs1 + \/ (* Disjunct to prevent deadlock on termination *) + (pc = "Done" /\ UNCHANGED vars) + +Spec == /\ Init /\ [][Next]_vars + /\ WF_vars(Next) + +Termination == <>(pc = "Done") + +(***** END TRANSLATION ***) +============================================================================= +Checked without termination on svc-lamport-2 with 2 workers: + arrayLen = 4 in 15 sec, 32280 states, depth 22 + arrayLen = 5 in 138min 17 sec 1529005 states, depth 28 diff --git a/tlatools/test-model/pcal/MergeSort.cfg b/tlatools/test-model/pcal/MergeSort.cfg new file mode 100644 index 0000000000000000000000000000000000000000..fef7332dcd82181639a8ebe35c5a84e7458712e0 --- /dev/null +++ b/tlatools/test-model/pcal/MergeSort.cfg @@ -0,0 +1,6 @@ +SPECIFICATION Spec +PROPERTY Termination +CONSTANT defaultInitValue = defaultInitValue +\* Add statements after this line. +CONSTANTS ArrayLen = 2 +INVARIANT Invariant diff --git a/tlatools/test-model/pcal/MergeSort.tla b/tlatools/test-model/pcal/MergeSort.tla new file mode 100644 index 0000000000000000000000000000000000000000..e544b07c05841c78198bc8c8ab1a240cd27a7b89 --- /dev/null +++ b/tlatools/test-model/pcal/MergeSort.tla @@ -0,0 +1,246 @@ +------------------------------- MODULE MergeSort ----------------------------- +EXTENDS Naturals, Sequences, TLC + +CONSTANT ArrayLen + +ASSUME ArrayLen \in Nat + +ASSUME Print(<<"Testing Mergesort on all arrays of length <= ", ArrayLen>>, + TRUE) + +PermsOf(Arr) == + LET Automorphism(S) == { f \in [S -> S] : + \A y \in S : \E x \in S : f[x] = y } + f ** g == [x \in DOMAIN g |-> f[g[x]]] + IN { Arr ** f : f \in Automorphism(DOMAIN Arr) } + +(* + +Copied from page 166 of the 2nd edition of Robert Sedgewick's "Algorithms". + +--algorithm Mergesort + variables a \in UNION {[1..N -> 1..N] : N \in 0..ArrayLen} ; + b = [x \in DOMAIN a |-> 99] \* ; + procedure mergesort(l, r) + variables i ; j ; k ; m \* ; + begin l1: if r - l > 0 + then m := (r + l) \div 2 ; + l2 : call mergesort(l, m) ; + l3 : call mergesort(m+1, r) ; + l4 : i := m ; + l5 : while i \geq l + do b[i] := a[i]; + i := i - 1 \* ; + end while ; + (*************************************************) + (* I don't know what the Pascal statement *) + (* *) + (* for i := m downto l ... *) + (* *) + (* is supposed to set i to if m < l, so the *) + (* algorithm reports an error and stops in this *) + (*************************************************) + if m \geq l + then i := l ; + else print "not sure of semantics of Pascal" ; + i := CHOOSE x \in {} : FALSE ; + end if ; + j := m + 1 ; + l6 : while j \leq r + do b[r + m + 1 - j] := a[j] ; + j := j + 1 ; + end while ; + (*************************************************) + (* I don't know what the Pascal statement *) + (* *) + (* for j := m+1 to r ... *) + (* *) + (* is supposed to set j to if m+1 < r, so the *) + (* algorithm reports an error and stops in this *) + (*************************************************) + if m+1 \leq r + then j := r ; + else print "not sure of semantics of Pascal" ; + i := CHOOSE x \in {} : FALSE ; + end if ; + k := l ; + l7 : while k \leq r + do if b[i] < b[j] + then a[k] := b[i] ; + i := i + 1 ; + else a[k] := b[j] ; + j := j - 1 ; + end if ; + k := k + 1 ; + end while ; + end if ; + l8: return ; + end procedure + begin main : call mergesort (1, Len(a)) ; + end algorithm +*) + +(***** BEGIN TRANSLATION ***) +CONSTANT defaultInitValue +VARIABLES a, b, pc, stack, l, r, i, j, k, m + +vars == << a, b, pc, stack, l, r, i, j, k, m >> + +Init == (* Global variables *) + /\ a \in UNION {[1..N -> 1..N] : N \in 0..ArrayLen} + /\ b = [x \in DOMAIN a |-> 99] + (* Procedure mergesort *) + /\ l = defaultInitValue + /\ r = defaultInitValue + /\ i = defaultInitValue + /\ j = defaultInitValue + /\ k = defaultInitValue + /\ m = defaultInitValue + /\ stack = << >> + /\ pc = "main" + +l1 == /\ pc = "l1" + /\ IF r - l > 0 + THEN /\ m' = ((r + l) \div 2) + /\ pc' = "l2" + ELSE /\ pc' = "l8" + /\ m' = m + /\ UNCHANGED << a, b, stack, l, r, i, j, k >> + +l2 == /\ pc = "l2" + /\ /\ l' = l + /\ r' = m + /\ stack' = << [ procedure |-> "mergesort", + pc |-> "l3", + i |-> i, + j |-> j, + k |-> k, + m |-> m, + l |-> l, + r |-> r ] >> + \o stack + /\ i' = defaultInitValue + /\ j' = defaultInitValue + /\ k' = defaultInitValue + /\ m' = defaultInitValue + /\ pc' = "l1" + /\ UNCHANGED << a, b >> + +l3 == /\ pc = "l3" + /\ /\ l' = m+1 + /\ r' = r + /\ stack' = << [ procedure |-> "mergesort", + pc |-> "l4", + i |-> i, + j |-> j, + k |-> k, + m |-> m, + l |-> l, + r |-> r ] >> + \o stack + /\ i' = defaultInitValue + /\ j' = defaultInitValue + /\ k' = defaultInitValue + /\ m' = defaultInitValue + /\ pc' = "l1" + /\ UNCHANGED << a, b >> + +l4 == /\ pc = "l4" + /\ i' = m + /\ pc' = "l5" + /\ UNCHANGED << a, b, stack, l, r, j, k, m >> + +l5 == /\ pc = "l5" + /\ IF i \geq l + THEN /\ b' = [b EXCEPT ![i] = a[i]] + /\ i' = i - 1 + /\ pc' = "l5" + /\ j' = j + ELSE /\ IF m \geq l + THEN /\ i' = l + ELSE /\ PrintT("not sure of semantics of Pascal") + /\ i' = (CHOOSE x \in {} : FALSE) + /\ j' = m + 1 + /\ pc' = "l6" + /\ b' = b + /\ UNCHANGED << a, stack, l, r, k, m >> + +l6 == /\ pc = "l6" + /\ IF j \leq r + THEN /\ b' = [b EXCEPT ![r + m + 1 - j] = a[j]] + /\ j' = j + 1 + /\ pc' = "l6" + /\ UNCHANGED << i, k >> + ELSE /\ IF m+1 \leq r + THEN /\ j' = r + /\ i' = i + ELSE /\ PrintT("not sure of semantics of Pascal") + /\ i' = (CHOOSE x \in {} : FALSE) + /\ j' = j + /\ k' = l + /\ pc' = "l7" + /\ b' = b + /\ UNCHANGED << a, stack, l, r, m >> + +l7 == /\ pc = "l7" + /\ IF k \leq r + THEN /\ IF b[i] < b[j] + THEN /\ a' = [a EXCEPT ![k] = b[i]] + /\ i' = i + 1 + /\ j' = j + ELSE /\ a' = [a EXCEPT ![k] = b[j]] + /\ j' = j - 1 + /\ i' = i + /\ k' = k + 1 + /\ pc' = "l7" + ELSE /\ pc' = "l8" + /\ UNCHANGED << a, i, j, k >> + /\ UNCHANGED << b, stack, l, r, m >> + +l8 == /\ pc = "l8" + /\ pc' = Head(stack).pc + /\ i' = Head(stack).i + /\ j' = Head(stack).j + /\ k' = Head(stack).k + /\ m' = Head(stack).m + /\ l' = Head(stack).l + /\ r' = Head(stack).r + /\ stack' = Tail(stack) + /\ UNCHANGED << a, b >> + +mergesort == l1 \/ l2 \/ l3 \/ l4 \/ l5 \/ l6 \/ l7 \/ l8 + +main == /\ pc = "main" + /\ /\ l' = 1 + /\ r' = Len(a) + /\ stack' = << [ procedure |-> "mergesort", + pc |-> "Done", + i |-> i, + j |-> j, + k |-> k, + m |-> m, + l |-> l, + r |-> r ] >> + \o stack + /\ i' = defaultInitValue + /\ j' = defaultInitValue + /\ k' = defaultInitValue + /\ m' = defaultInitValue + /\ pc' = "l1" + /\ UNCHANGED << a, b >> + +Next == mergesort \/ main + \/ (* Disjunct to prevent deadlock on termination *) + (pc = "Done" /\ UNCHANGED vars) + +Spec == /\ Init /\ [][Next]_vars + /\ WF_vars(Next) + +Termination == <>(pc = "Done") + +(***** END TRANSLATION ***) + +Invariant == + (pc = "Done") => \A x, y \in DOMAIN a : + (x < y) => a[x] \leq a[y] +============================================================================= diff --git a/tlatools/test-model/pcal/MultiAssignment.tla b/tlatools/test-model/pcal/MultiAssignment.tla new file mode 100644 index 0000000000000000000000000000000000000000..942b10abf062f9b7454ca6b408ffc546f4fdde32 --- /dev/null +++ b/tlatools/test-model/pcal/MultiAssignment.tla @@ -0,0 +1,62 @@ +--------------------------- MODULE MultiAssignment -------------------------- +(***************************************************************************) +(* A test of multi-assignment statements with arrays. *) +(***************************************************************************) + +EXTENDS Naturals, TLC + + + +(***** + + +--algorithm MultiAssignment + process Proc \in 1..3 + variables A = [i \in 1..5 |-> i] ; x = 0 ; + begin a : A[1] := A[3] || x := 7 || A[3] := A[1] ; + assert <<3 , 1>> = <<A[1], A[3]>> ; + b : assert <<3 , 1>> = <<A[1], A[3]>> ; + end process + end algorithm + +****) + +(***** BEGIN TRANSLATION ***) +VARIABLES pc, A, x + +vars == << pc, A, x >> + +ProcSet == (1..3) + +Init == (* Process Proc *) + /\ A = [self \in 1..3 |-> [i \in 1..5 |-> i]] + /\ x = [self \in 1..3 |-> 0] + /\ pc = [self \in ProcSet |-> "a"] + +a(self) == /\ pc[self] = "a" + /\ /\ A' = [A EXCEPT ![self][1] = A[self][3], + ![self][3] = A[self][1]] + /\ x' = [x EXCEPT ![self] = 7] + /\ Assert(<<3 , 1>> = <<A'[self][1], A'[self][3]>>, + "Failure of assertion at line 17, column 13.") + /\ pc' = [pc EXCEPT ![self] = "b"] + +b(self) == /\ pc[self] = "b" + /\ Assert(<<3 , 1>> = <<A[self][1], A[self][3]>>, + "Failure of assertion at line 18, column 13.") + /\ pc' = [pc EXCEPT ![self] = "Done"] + /\ UNCHANGED << A, x >> + +Proc(self) == a(self) \/ b(self) + +Next == (\E self \in 1..3: Proc(self)) + \/ (* Disjunct to prevent deadlock on termination *) + ((\A self \in ProcSet: pc[self] = "Done") /\ UNCHANGED vars) + +Spec == /\ Init /\ [][Next]_vars + /\ \A self \in 1..3 : WF_vars(Proc(self)) + +Termination == <>(\A self \in ProcSet: pc[self] = "Done") + +(***** END TRANSLATION ***) +============================================================================= diff --git a/tlatools/test-model/pcal/MultiProc2.tla b/tlatools/test-model/pcal/MultiProc2.tla new file mode 100644 index 0000000000000000000000000000000000000000..514fee77feceadf98c1e4be8bd975833e2a15e1c --- /dev/null +++ b/tlatools/test-model/pcal/MultiProc2.tla @@ -0,0 +1,128 @@ +----------------------------- MODULE MultiProc2 ---------------------------- +EXTENDS Sequences, Naturals, TLC + +(* + + --algorithm MultiProc2 + variables + x = [i \in ProcSet |-> CASE i = 41 -> 1 [] + i = 42 -> 2 [] + i = 43 -> 3]; + sum = 0 ; + done = {}; + procedure Sum(arg = 0) + variable u = 1 ; + begin p1 : u := u + arg ; + p2 : sum := sum + u; + return; + end procedure + process ProcA = 41 + variable y = 0 ; + begin a1 : call Sum( x [ 41 ] + y ) ; + a2 : done := done \cup { 41 } ; + a3 : when done = { 41, 42, 43 } ; + when Print ( sum , TRUE ) ; + end process + process ProcB \in {42, 43} + variable z \in {2, 3} ; + begin b1 : call Sum ( x [ self ] + z ) ; + b2 : done := done \cup { self } ; + end process + end algorithm +*) + +(***** BEGIN TRANSLATION ***) +VARIABLES x, sum, done, pc, stack, arg, u, y, z + +vars == << x, sum, done, pc, stack, arg, u, y, z >> + +ProcSet == {41} \cup ({42, 43}) + +Init == (* Global variables *) + /\ x = [i \in ProcSet |-> CASE i = 41 -> 1 [] + i = 42 -> 2 [] + i = 43 -> 3] + /\ sum = 0 + /\ done = {} + (* Procedure Sum *) + /\ arg = [ self \in ProcSet |-> 0] + /\ u = [ self \in ProcSet |-> 1] + (* Process ProcA *) + /\ y = 0 + (* Process ProcB *) + /\ z \in [{42, 43} -> {2, 3}] + /\ stack = [self \in ProcSet |-> << >>] + /\ pc = [self \in ProcSet |-> CASE self = 41 -> "a1" + [] self \in {42, 43} -> "b1"] + +p1(self) == /\ pc[self] = "p1" + /\ u' = [u EXCEPT ![self] = u[self] + arg[self]] + /\ pc' = [pc EXCEPT ![self] = "p2"] + /\ UNCHANGED << x, sum, done, stack, arg, y, z >> + +p2(self) == /\ pc[self] = "p2" + /\ sum' = sum + u[self] + /\ pc' = [pc EXCEPT ![self] = Head(stack[self]).pc] + /\ u' = [u EXCEPT ![self] = Head(stack[self]).u] + /\ arg' = [arg EXCEPT ![self] = Head(stack[self]).arg] + /\ stack' = [stack EXCEPT ![self] = Tail(stack[self])] + /\ UNCHANGED << x, done, y, z >> + +Sum(self) == p1(self) \/ p2(self) + +a1 == /\ pc[41] = "a1" + /\ /\ arg' = [arg EXCEPT ![41] = x [ 41 ] + y] + /\ stack' = [stack EXCEPT ![41] = << [ procedure |-> "Sum", + pc |-> "a2", + u |-> u[41], + arg |-> arg[41] ] >> + \o stack[41]] + /\ u' = [u EXCEPT ![41] = 1] + /\ pc' = [pc EXCEPT ![41] = "p1"] + /\ UNCHANGED << x, sum, done, y, z >> + +a2 == /\ pc[41] = "a2" + /\ done' = (done \cup { 41 }) + /\ pc' = [pc EXCEPT ![41] = "a3"] + /\ UNCHANGED << x, sum, stack, arg, u, y, z >> + +a3 == /\ pc[41] = "a3" + /\ done = { 41, 42, 43 } + /\ Print ( sum , TRUE ) + /\ pc' = [pc EXCEPT ![41] = "Done"] + /\ UNCHANGED << x, sum, done, stack, arg, u, y, z >> + +ProcA == a1 \/ a2 \/ a3 + +b1(self) == /\ pc[self] = "b1" + /\ /\ arg' = [arg EXCEPT ![self] = x [ self ] + z[self]] + /\ stack' = [stack EXCEPT ![self] = << [ procedure |-> "Sum", + pc |-> "b2", + u |-> u[self], + arg |-> arg[self] ] >> + \o stack[self]] + /\ u' = [u EXCEPT ![self] = 1] + /\ pc' = [pc EXCEPT ![self] = "p1"] + /\ UNCHANGED << x, sum, done, y, z >> + +b2(self) == /\ pc[self] = "b2" + /\ done' = (done \cup { self }) + /\ pc' = [pc EXCEPT ![self] = "Done"] + /\ UNCHANGED << x, sum, stack, arg, u, y, z >> + +ProcB(self) == b1(self) \/ b2(self) + +Next == ProcA + \/ (\E self \in ProcSet: Sum(self)) + \/ (\E self \in {42, 43}: ProcB(self)) + \/ (* Disjunct to prevent deadlock on termination *) + ((\A self \in ProcSet: pc[self] = "Done") /\ UNCHANGED vars) + +Spec == /\ Init /\ [][Next]_vars + /\ WF_vars(ProcA) /\ WF_vars(Sum(41)) + /\ \A self \in {42, 43} : WF_vars(ProcB(self)) /\ WF_vars(Sum(self)) + +Termination == <>(\A self \in ProcSet: pc[self] = "Done") + +(***** END TRANSLATION ***) +============================================================================= diff --git a/tlatools/test-model/pcal/MultiprocDefine.tla b/tlatools/test-model/pcal/MultiprocDefine.tla new file mode 100644 index 0000000000000000000000000000000000000000..46de90cefd81be8be7c75518e13fe925df234754 --- /dev/null +++ b/tlatools/test-model/pcal/MultiprocDefine.tla @@ -0,0 +1,56 @@ +---------------------------- MODULE MultiprocDefine -------------------------- +EXTENDS Naturals, Sequences, TLC + +(* +--algorithm MultiprocDefine + variables n = 0 ; + define nplus1 == n + 1 + nplus2 == nplus1 + 1 + end define ; + process Proc \in {1, 2, 3} + variables i ; + begin main : i := nplus2 ; + assert i = 2 ; + end process + end algorithm +*) + +(***** BEGIN TRANSLATION ***) +CONSTANT defaultInitValue +VARIABLES n, pc + +(* define statement *) +nplus1 == n + 1 +nplus2 == nplus1 + 1 + +VARIABLE i + +vars == << n, pc, i >> + +ProcSet == ({1, 2, 3}) + +Init == (* Global variables *) + /\ n = 0 + (* Process Proc *) + /\ i = [self \in {1, 2, 3} |-> defaultInitValue] + /\ pc = [self \in ProcSet |-> "main"] + +main(self) == /\ pc[self] = "main" + /\ i' = [i EXCEPT ![self] = nplus2] + /\ Assert(i'[self] = 2, + "Failure of assertion at line 13, column 17.") + /\ pc' = [pc EXCEPT ![self] = "Done"] + /\ n' = n + +Proc(self) == main(self) + +Next == (\E self \in {1, 2, 3}: Proc(self)) + \/ (* Disjunct to prevent deadlock on termination *) + ((\A self \in ProcSet: pc[self] = "Done") /\ UNCHANGED vars) + +Spec == Init /\ [][Next]_vars + +Termination == <>(\A self \in ProcSet: pc[self] = "Done") + +(***** END TRANSLATION ***) +============================================================================= diff --git a/tlatools/test-model/pcal/NestedMacros.tla b/tlatools/test-model/pcal/NestedMacros.tla new file mode 100644 index 0000000000000000000000000000000000000000..499a2fbe6e6cdc48dfcb528b31fe0a7da00c0def --- /dev/null +++ b/tlatools/test-model/pcal/NestedMacros.tla @@ -0,0 +1,69 @@ +----------------------------- MODULE NestedMacros --------------------------- +EXTENDS Naturals, TLC + +\* PlusCal options(label) +(*************************************************************************** +--algorithm Test { + variables x, y ; + + macro ff(a, b) { + a := b + } + macro foo(a) { + ff(z,a); + y := a + } + + macro bar(b) { + x := b; + foo(22) + } + process (foob \in {1,2}) + variable z ; + { l1 : z := 0 ; + l2 : bar(42); + assert z = 22 /\ x = 42 + } +} + ***************************************************************************) +\* BEGIN TRANSLATION +CONSTANT defaultInitValue +VARIABLES x, y, pc, z + +vars == << x, y, pc, z >> + +ProcSet == ({1,2}) + +Init == (* Global variables *) + /\ x = defaultInitValue + /\ y = defaultInitValue + (* Process foob *) + /\ z = [self \in {1,2} |-> defaultInitValue] + /\ pc = [self \in ProcSet |-> "l1"] + +l1(self) == /\ pc[self] = "l1" + /\ z' = [z EXCEPT ![self] = 0] + /\ pc' = [pc EXCEPT ![self] = "l2"] + /\ UNCHANGED << x, y >> + +l2(self) == /\ pc[self] = "l2" + /\ x' = 42 + /\ z' = [z EXCEPT ![self] = 22] + /\ y' = 22 + /\ Assert(z'[self] = 22 /\ x' = 42, + "Failure of assertion at line 25, column 11.") + /\ pc' = [pc EXCEPT ![self] = "Done"] + +foob(self) == l1(self) \/ l2(self) + +Next == (\E self \in {1,2}: foob(self)) + \/ (* Disjunct to prevent deadlock on termination *) + ((\A self \in ProcSet: pc[self] = "Done") /\ UNCHANGED vars) + +Spec == /\ Init /\ [][Next]_vars + /\ \A self \in {1,2} : WF_vars(foob(self)) + +Termination == <>(\A self \in ProcSet: pc[self] = "Done") + +\* END TRANSLATION +============================================================================= diff --git a/tlatools/test-model/pcal/NoLoop.tla b/tlatools/test-model/pcal/NoLoop.tla new file mode 100644 index 0000000000000000000000000000000000000000..474a4aaf720278e74a3758a1460e33a434267417 --- /dev/null +++ b/tlatools/test-model/pcal/NoLoop.tla @@ -0,0 +1,54 @@ +------------------------------- MODULE NoLoop ------------------------------- +EXTENDS Sequences, Naturals, TLC + +(* + --algorithm NoLoop + variable x = 0; y = 0 ; + begin a : with i = 3 do x := i ; end with; + b : with j \in { 1 , 2 } do y := j ; x := x + y ; end with ; + c : if y = 1 then x := x + 1 ; else x := x + y; end if; + when Print ( x , TRUE ); + end algorithm +*) + +(***** BEGIN TRANSLATION ***) +VARIABLES x, y, pc + +vars == << x, y, pc >> + +Init == (* Global variables *) + /\ x = 0 + /\ y = 0 + /\ pc = "a" + +a == /\ pc = "a" + /\ LET i == 3 IN + x' = i + /\ pc' = "b" + /\ y' = y + +b == /\ pc = "b" + /\ \E j \in { 1 , 2 }: + /\ y' = j + /\ x' = x + y' + /\ pc' = "c" + +c == /\ pc = "c" + /\ IF y = 1 + THEN /\ x' = x + 1 + ELSE /\ x' = x + y + /\ Print ( x' , TRUE ) + /\ pc' = "Done" + /\ y' = y + +Next == a \/ b \/ c + \/ (* Disjunct to prevent deadlock on termination *) + (pc = "Done" /\ UNCHANGED vars) + +Spec == /\ Init /\ [][Next]_vars + /\ WF_vars(Next) + +Termination == <>(pc = "Done") + +(***** END TRANSLATION ***) +============================================================================= diff --git a/tlatools/test-model/pcal/NoLoop2.tla b/tlatools/test-model/pcal/NoLoop2.tla new file mode 100644 index 0000000000000000000000000000000000000000..fd12a280b201947166c524a354d51fcf781ab535 --- /dev/null +++ b/tlatools/test-model/pcal/NoLoop2.tla @@ -0,0 +1,68 @@ +------------------------------- MODULE NoLoop2 ------------------------------- +EXTENDS Naturals, TLC + +(* + + --algorithm NoLoop2 + variable x = 0; y = 0 ; + begin a : with i = 3 do x := i ; end with; + b : with j \in { 1 , 2 } do y := j ; x := x + y ; end with; + c : if y = 1 then x := x + 1 ; d : x := 2 * x ; + else x := x + y ; end if; + e : when Print ( x , TRUE ); + end algorithm + \* should print out 10 or 7 + +*) + +(***** BEGIN TRANSLATION ***) +VARIABLES x, y, pc + +vars == << x, y, pc >> + +Init == (* Global variables *) + /\ x = 0 + /\ y = 0 + /\ pc = "a" + +a == /\ pc = "a" + /\ LET i == 3 IN + x' = i + /\ pc' = "b" + /\ y' = y + +b == /\ pc = "b" + /\ \E j \in { 1 , 2 }: + /\ y' = j + /\ x' = x + y' + /\ pc' = "c" + +c == /\ pc = "c" + /\ IF y = 1 + THEN /\ x' = x + 1 + /\ pc' = "d" + ELSE /\ x' = x + y + /\ pc' = "e" + /\ y' = y + +d == /\ pc = "d" + /\ x' = 2 * x + /\ pc' = "e" + /\ y' = y + +e == /\ pc = "e" + /\ Print ( x , TRUE ) + /\ pc' = "Done" + /\ UNCHANGED << x, y >> + +Next == a \/ b \/ c \/ d \/ e + \/ (* Disjunct to prevent deadlock on termination *) + (pc = "Done" /\ UNCHANGED vars) + +Spec == /\ Init /\ [][Next]_vars + /\ WF_vars(Next) + +Termination == <>(pc = "Done") + +(***** END TRANSLATION ***) +============================================================================= diff --git a/tlatools/test-model/pcal/NoParams.tla b/tlatools/test-model/pcal/NoParams.tla new file mode 100644 index 0000000000000000000000000000000000000000..6711b4eb7ff2734445c24b23042248c894a581e4 --- /dev/null +++ b/tlatools/test-model/pcal/NoParams.tla @@ -0,0 +1,67 @@ +----------------------------- MODULE NoParams ------------------------------ +EXTENDS Sequences, Naturals, TLC + +(* + +--algorithm NoParams + variables sum = 0 ; + procedure Sum() + begin s1: sum := sum + 1; + return; + end procedure; + begin m1 : call Sum(); + m2 : call Sum(); + m3 : when Print(sum, TRUE) ; + end algorithm + + +*) + +(***** BEGIN TRANSLATION ***) +VARIABLES sum, pc, stack + +vars == << sum, pc, stack >> + +Init == (* Global variables *) + /\ sum = 0 + /\ stack = << >> + /\ pc = "m1" + +s1 == /\ pc = "s1" + /\ sum' = sum + 1 + /\ pc' = Head(stack).pc + /\ stack' = Tail(stack) + +Sum == s1 + +m1 == /\ pc = "m1" + /\ stack' = << [ procedure |-> "Sum", + pc |-> "m2" ] >> + \o stack + /\ pc' = "s1" + /\ sum' = sum + +m2 == /\ pc = "m2" + /\ stack' = << [ procedure |-> "Sum", + pc |-> "m3" ] >> + \o stack + /\ pc' = "s1" + /\ sum' = sum + +m3 == /\ pc = "m3" + /\ Print(sum, TRUE) + /\ pc' = "Done" + /\ UNCHANGED << sum, stack >> + +Next == Sum \/ m1 \/ m2 \/ m3 + \/ (* Disjunct to prevent deadlock on termination *) + (pc = "Done" /\ UNCHANGED vars) + +Spec == /\ Init /\ [][Next]_vars + /\ WF_vars(Next) + +Termination == <>(pc = "Done") + +(***** END TRANSLATION ***) + +============================================================================= diff --git a/tlatools/test-model/pcal/NotSoSimpleLoop.tla b/tlatools/test-model/pcal/NotSoSimpleLoop.tla new file mode 100644 index 0000000000000000000000000000000000000000..cea3b0486ebdf13131ba7360e3f81e6c0e81aec7 --- /dev/null +++ b/tlatools/test-model/pcal/NotSoSimpleLoop.tla @@ -0,0 +1,53 @@ +--------------------------- MODULE NotSoSimpleLoop -------------------------- +EXTENDS Naturals, TLC + +(* --algorithm NotSoSimpleLoop + variable x = 0; + begin a : while x < 10 + do x := x+1 ; + skip ; + assert x \in 1..10 + end while ; + x := 4*x ; + assert x = 40 ; + b : assert 2 * x = 80; + end algorithm *) + + +(****** BEGIN TRANSLATION ****) +VARIABLES x, pc + +vars == << x, pc >> + +Init == (* Global variables *) + /\ x = 0 + /\ pc = "a" + +a == /\ pc = "a" + /\ IF x < 10 + THEN /\ x' = x+1 + /\ TRUE + /\ Assert(x' \in 1..10, + "Failure of assertion at line 9, column 21.") + /\ pc' = "a" + ELSE /\ x' = 4*x + /\ Assert(x' = 40, + "Failure of assertion at line 12, column 16.") + /\ pc' = "b" + +b == /\ pc = "b" + /\ Assert(2 * x = 80, "Failure of assertion at line 13, column 16.") + /\ pc' = "Done" + /\ x' = x + +Next == a \/ b + \/ (* Disjunct to prevent deadlock on termination *) + (pc = "Done" /\ UNCHANGED vars) + +Spec == /\ Init /\ [][Next]_vars + /\ WF_vars(Next) + +Termination == <>(pc = "Done") + +(****** END TRANSLATION ****) +============================================================================= diff --git a/tlatools/test-model/pcal/PcalPaxos.cfg b/tlatools/test-model/pcal/PcalPaxos.cfg new file mode 100644 index 0000000000000000000000000000000000000000..8537dc757c18205aadb1e072561098ec298d10b1 --- /dev/null +++ b/tlatools/test-model/pcal/PcalPaxos.cfg @@ -0,0 +1,19 @@ +SPECIFICATION Spec +\* Add statements after this line. + +CONSTANTS + MaxBallot = 2 + Acceptor <- MCAcceptor + Leader <- MCLeader + Learner <- MCLearner + Ballot <- MCBallot + LeaderOf <- MCLeaderOf + Command <- MCCommand + Majority <- MCMajority + a1 = a1 a2 = a2 a3 = a3 + ldr1 = ldr1 ldr2 = ldr2 + lrn1 = lrn1 lrn2 = lrn2 + cmd1 = cmd1 cmd2 = cmd2 + NotACmd = NotACmd + +INVARIANTS TypeOK Safety diff --git a/tlatools/test-model/pcal/PcalPaxos.tla b/tlatools/test-model/pcal/PcalPaxos.tla new file mode 100644 index 0000000000000000000000000000000000000000..186785d1610d36369582ae765e04cfdf9c3dfccf --- /dev/null +++ b/tlatools/test-model/pcal/PcalPaxos.tla @@ -0,0 +1,220 @@ +------------------------------ MODULE PcalPaxos ----------------------------- +EXTENDS Integers, TLC, FiniteSets + +CONSTANTS Acceptor, Leader, Learner, Ballot, LeaderOf, Command, Majority + +ASSUME /\ LeaderOf \in [Ballot -> Leader] + /\ Ballot \subseteq Nat + /\ 0 \in Ballot + /\ Majority \subseteq SUBSET Acceptor + /\ \A M1, M2 \in Majority : M1 \cap M2 # {} + +NotACmd == CHOOSE c : c \notin Command + +BallotsOf(ldr) == {b \in Ballot : LeaderOf[b] = ldr} + +Message == [type : {"1a"}, bal : Ballot] \cup + [type : {"1b"}, bal : Ballot, acc : Acceptor, + mbal : Ballot \cup {-1}, mcmd : Command \cup {NotACmd}] + \cup + [type : {"2a"}, bal : Ballot, cmd : Command] \cup + [type : {"2b"}, bal : Ballot, cmd : Command, acc : Acceptor] + +(* +--algorithm Paxos + variables msgs = {}; + macro Send(m) + begin msgs := msgs \cup {m} + end macro + + process Ldr \in Leader + variables ldrBal = -1 ; + ldrPhs = 2 + begin L: + while TRUE do + with b \in {bb \in Ballot : LeaderOf[bb] = self} + do either when ldrBal < b; + ldrBal := b ; + ldrPhs := 1 ; + Send([type |-> "1a", bal |-> b]) + + or when (ldrBal = b) /\ (ldrPhs = 1) ; + with M = {m \in msgs : (m.type = "1b") /\ (m.bal = b)}; + A = {m.acc : m \in M} ; + mmsg \in {m \in M : + \A m2 \in M : m.mbal \geq m2.mbal} + do when A \in Majority ; + if mmsg.mbal > -1 + then Send([type |-> "2a", bal |-> b, + cmd |-> mmsg.mcmd]) + else with c \in Command + do Send([type |-> "2a", bal |-> b, + cmd |-> c]) + end with + end if ; + end with ; + ldrPhs := 2 + end either + end with + end while + end process + + process Acc \in Acceptor + variables bal = -1 ; mbal = -1 ; mcmd = NotACmd + begin A: + while TRUE do + with m \in msgs + do either when (m.type = "1a") /\ (m.bal > bal) ; + bal := m.bal ; + Send([type |-> "1b", bal |-> m.bal, acc |-> self, + mbal |-> mbal, mcmd |-> mcmd]) + or when (m.type = "2a") + /\ (m.bal \geq bal) + /\ (m.bal > mbal); + bal := m.bal ; + mbal := m.bal ; + mcmd := m.cmd ; + Send([type |-> "2b", bal |-> m.bal, acc |-> self, + cmd |-> m.cmd]) + end either + end with + end while + end process + + + process Lrn \in Learner + variable learned = NotACmd + begin N: with b \in Ballot ; + 2bMsgs = {m \in msgs : (m.type = "2b") /\ (m.bal = b)} + do when {m.acc : m \in 2bMsgs} \in Majority ; + with m \in 2bMsgs + do learned := m.cmd + end with + end with ; + end process +end algorithm +*) + +\* BEGIN TRANSLATION +VARIABLES msgs, pc, ldrBal, ldrPhs, bal, mbal, mcmd, learned + +vars == << msgs, pc, ldrBal, ldrPhs, bal, mbal, mcmd, learned >> + +ProcSet == (Leader) \cup (Acceptor) \cup (Learner) + +Init == (* Global variables *) + /\ msgs = {} + (* Process Ldr *) + /\ ldrBal = [self \in Leader |-> -1] + /\ ldrPhs = [self \in Leader |-> 2] + (* Process Acc *) + /\ bal = [self \in Acceptor |-> -1] + /\ mbal = [self \in Acceptor |-> -1] + /\ mcmd = [self \in Acceptor |-> NotACmd] + (* Process Lrn *) + /\ learned = [self \in Learner |-> NotACmd] + /\ pc = [self \in ProcSet |-> CASE self \in Leader -> "L" + [] self \in Acceptor -> "A" + [] self \in Learner -> "N"] + +L(self) == /\ pc[self] = "L" + /\ \E b \in {bb \in Ballot : LeaderOf[bb] = self}: + \/ /\ ldrBal[self] < b + /\ ldrBal' = [ldrBal EXCEPT ![self] = b] + /\ ldrPhs' = [ldrPhs EXCEPT ![self] = 1] + /\ msgs' = (msgs \cup {([type |-> "1a", bal |-> b])}) + \/ /\ (ldrBal[self] = b) /\ (ldrPhs[self] = 1) + /\ LET M == {m \in msgs : (m.type = "1b") /\ (m.bal = b)} IN + LET A == {m.acc : m \in M} IN + \E mmsg \in {m \in M : + \A m2 \in M : m.mbal \geq m2.mbal}: + /\ A \in Majority + /\ IF mmsg.mbal > -1 + THEN /\ msgs' = (msgs \cup {([type |-> "2a", bal |-> b, + cmd |-> mmsg.mcmd])}) + ELSE /\ \E c \in Command: + msgs' = (msgs \cup {([type |-> "2a", bal |-> b, + cmd |-> c])}) + /\ ldrPhs' = [ldrPhs EXCEPT ![self] = 2] + /\ UNCHANGED ldrBal + /\ pc' = [pc EXCEPT ![self] = "L"] + /\ UNCHANGED << bal, mbal, mcmd, learned >> + +Ldr(self) == L(self) + +A(self) == /\ pc[self] = "A" + /\ \E m \in msgs: + \/ /\ (m.type = "1a") /\ (m.bal > bal[self]) + /\ bal' = [bal EXCEPT ![self] = m.bal] + /\ msgs' = (msgs \cup {([type |-> "1b", bal |-> m.bal, acc |-> self, + mbal |-> mbal[self], mcmd |-> mcmd[self]])}) + /\ UNCHANGED <<mbal, mcmd>> + \/ /\ (m.type = "2a") + /\ (m.bal \geq bal[self]) + /\ (m.bal > mbal[self]) + /\ bal' = [bal EXCEPT ![self] = m.bal] + /\ mbal' = [mbal EXCEPT ![self] = m.bal] + /\ mcmd' = [mcmd EXCEPT ![self] = m.cmd] + /\ msgs' = (msgs \cup {([type |-> "2b", bal |-> m.bal, acc |-> self, + cmd |-> m.cmd])}) + /\ pc' = [pc EXCEPT ![self] = "A"] + /\ UNCHANGED << ldrBal, ldrPhs, learned >> + +Acc(self) == A(self) + +N(self) == /\ pc[self] = "N" + /\ \E b \in Ballot: + LET 2bMsgs == {m \in msgs : (m.type = "2b") /\ (m.bal = b)} IN + /\ {m.acc : m \in 2bMsgs} \in Majority + /\ \E m \in 2bMsgs: + learned' = [learned EXCEPT ![self] = m.cmd] + /\ pc' = [pc EXCEPT ![self] = "Done"] + /\ UNCHANGED << msgs, ldrBal, ldrPhs, bal, mbal, mcmd >> + +Lrn(self) == N(self) + +Next == (\E self \in Leader: Ldr(self)) + \/ (\E self \in Acceptor: Acc(self)) + \/ (\E self \in Learner: Lrn(self)) + +Spec == Init /\ [][Next]_vars + +\* END TRANSLATION + +TypeOK == /\ msgs \subseteq Message + /\ learned \in [Learner -> Command \cup {NotACmd}] + /\ ldrBal \in [Leader -> Ballot \cup {-1}] + /\ ldrPhs \in [Leader -> {1, 2}] + /\ bal \in [Acceptor -> Ballot \cup {-1}] + /\ mbal \in [Acceptor -> Ballot \cup {-1}] + /\ mcmd \in [Acceptor -> Command \cup {NotACmd}] +\* /\ \A b \in Ballot : +\* Cardinality({m \in msgs : (m.type = "1b") /\ (m.bal = b)}) +\* < 2 + +Safety == \A l1, l2 \in Learner : + \/ learned[l2] = NotACmd + \/ learned[l1] \in {learned[l2], NotACmd} + +CONSTANTS MaxBallot, a1, a2, a3, ldr1, ldr2, lrn1, lrn2, cmd1, cmd2 + +MCAcceptor == {a1, a2, a3} \* {a1} +MCLeader == {ldr1} +MCLearner == {lrn1, lrn2} \* {lrn1} +MCLeaderOf == [i \in Ballot |-> ldr1] +MCCommand == {cmd1, cmd2} +MCMajority == {{a1, a3}, {a1, a2}, {a2, a3}} \* {{a1}} + +MCBallot == 0..MaxBallot +============================================================================= +With + MaxBallot = 2 + MCAcceptor == {a1, a2, a3} + MCLeader == {ldr1} + MCLearner == {lrn1, lrn2} + MCLeaderOf == [i \in Ballot |-> ldr1] + MCCommand == {cmd1, cmd2} + MCMajority == {{a1, a3}, {a1, a2}, {a2, a3}} + +592889 distinct states found in Paxos and PcalPaxos + diff --git a/tlatools/test-model/pcal/Peterson.cfg b/tlatools/test-model/pcal/Peterson.cfg new file mode 100644 index 0000000000000000000000000000000000000000..a99527de5a0215e987814884692dda8c78004f27 --- /dev/null +++ b/tlatools/test-model/pcal/Peterson.cfg @@ -0,0 +1,9 @@ +\* Add statements after this line. + +SPECIFICATION Spec +INVARIANT Inv +\** INVARIANT MutualExclusion +\** PROPERTY InfinitelyOftenInCS + +\* SPECIFICATION ISpec +\* INVARIANT MutualExclusion Inv diff --git a/tlatools/test-model/pcal/Peterson.tla b/tlatools/test-model/pcal/Peterson.tla new file mode 100644 index 0000000000000000000000000000000000000000..651f6c64c2abd213446bb7371cbe99143868e429 --- /dev/null +++ b/tlatools/test-model/pcal/Peterson.tla @@ -0,0 +1,191 @@ +------------------------------ MODULE Peterson ------------------------------ + +(***************************************************************************) +(* This specification describes Peterson's algorithm. It is a modification *) +(* modification of one found on Wikipedia, written in terms of a single *) +(* parameterized process, instantiated with parameter self = 0 and 1. *) +(***************************************************************************) + +(***************************************************************************) +(* We define Not(i) to be the process number other than i, so Not(0) = 1 *) +(* and Not(1) = 0. *) +(***************************************************************************) +Not(i) == IF i = 0 THEN 1 ELSE 0 + +(************************************************************************* +Here is the algorithm in +Cal (using the C syntax): + +--algorithm Peterson { + variables flag = [i \in {0, 1} |-> FALSE], turn = 0; + process (proc \in {0,1}) { + a0: while (TRUE) { + a1: flag[self] := TRUE; + a2: turn := Not(self); + a3: while (flag[Not(self)] /\ turn = Not(self)) { + skip }; + cs: skip; \* critical section + a4: flag[self] := FALSE; + } \* end while + } \* end process + } +************************************************************************) + +(***************************************************************************) +(* Here is the TLA+ translation of the +Cal code, obtained by running pcal *) +(* with the -wf option, which defines Spec to be a specification that *) +(* assumes weak fairness of the next-state actions of both processes. *) +(* This fairness assumption is discussed below. *) +(***************************************************************************) +\* BEGIN TRANSLATION +VARIABLES flag, turn, pc + +vars == << flag, turn, pc >> + +ProcSet == ({0,1}) + +Init == (* Global variables *) + /\ flag = [i \in {0, 1} |-> FALSE] + /\ turn = 0 + /\ pc = [self \in ProcSet |-> "a0"] + +a0(self) == /\ pc[self] = "a0" + /\ pc' = [pc EXCEPT ![self] = "a1"] + /\ UNCHANGED << flag, turn >> + +a1(self) == /\ pc[self] = "a1" + /\ flag' = [flag EXCEPT ![self] = TRUE] + /\ pc' = [pc EXCEPT ![self] = "a2"] + /\ turn' = turn + +a2(self) == /\ pc[self] = "a2" + /\ turn' = Not(self) + /\ pc' = [pc EXCEPT ![self] = "a3"] + /\ flag' = flag + +a3(self) == /\ pc[self] = "a3" + /\ IF flag[Not(self)] /\ turn = Not(self) + THEN /\ TRUE + /\ pc' = [pc EXCEPT ![self] = "a3"] + ELSE /\ pc' = [pc EXCEPT ![self] = "cs"] + /\ UNCHANGED << flag, turn >> + +cs(self) == /\ pc[self] = "cs" + /\ TRUE + /\ pc' = [pc EXCEPT ![self] = "a4"] + /\ UNCHANGED << flag, turn >> + +a4(self) == /\ pc[self] = "a4" + /\ flag' = [flag EXCEPT ![self] = FALSE] + /\ pc' = [pc EXCEPT ![self] = "a0"] + /\ turn' = turn + +proc(self) == a0(self) \/ a1(self) \/ a2(self) \/ a3(self) \/ cs(self) + \/ a4(self) + +Next == (\E self \in {0,1}: proc(self)) + +Spec == Init /\ [][Next]_vars + +\* END TRANSLATION + +(***************************************************************************) +(* Here is the invariant property that the algorithm should satisfy. It *) +(* asserts that at least one process is not in its critical section., *) +(***************************************************************************) +MutualExclusion == \E i \in {0, 1} : pc[i] # "cs" + +(***************************************************************************) +(* It's a good idea to check an algorithm for liveness, to make sure that *) +(* safety isn't ensured by an error that prevents anything interesting *) +(* from happening. Peterson's algorithm is supposed to be starvation *) +(* free. The easiest and best way to check that no process is ever *) +(* starved is to assume that both processes keep trying to enter their *) +(* critical sections and check that both of them do enter it infinitely *) +(* often. This is done by assuming weak fairness of both processes next *) +(* state actions and checking that the following formula is satisfied. *) +(***************************************************************************) +InfinitelyOftenInCS == \A i \in {0, 1} : []<>(pc[i] = "cs") + +(***************************************************************************) +(* The spec of a starvation free mutual exclusion algorithm asserts that, *) +(* if any process wants to enter its critical section, then it eventually *) +(* does. A process indicates that it wants to enter by leaving its *) +(* noncritical section. In this representation of the algorithm, process *) +(* i is in its noncritical section iff pc[i] = "a0". It leaves the *) +(* noncritical section by executing an a0(i) step. that sets pc[i] to *) +(* "a1". So we assume weak fairness of the action proc(i) /\ pc[i] # *) +(* "a0", the next-state action of process i when it is not in its *) +(* noncritical section, for each i. This gives us the spec. *) +(***************************************************************************) +FairSpec == /\ Init + /\ [][Next]_vars + /\ \A self \in {0,1}: WF_vars(proc(self) /\ (pc[self] # "a0")) + +(***************************************************************************) +(* We check that this spec satisfies the following condition, which *) +(* asserts that whenever a process i leaves the noncritical section (by *) +(* setting pc[i] to "a1"), it eventually enters its critical section. *) +(***************************************************************************) +DeadlockFree == \A i \in {0,1} : (pc[i] = "a1") ~> (pc[i] = "cs") + +----------------------------------------------------------------------------- +(***************************************************************************) +(* To prove mutual exclusion, we find an inductive invariant Inv that is *) +(* true initially and implies mutual exclusion. In other words, we must *) +(* find an Inv that satisfies *) +(* *) +(* THEOREM /\ Init => Inv *) +(* /\ Inv /\ [Next]_vars => Inv' *) +(* /\ Inv => MutualExclusion *) +(* *) +(* The inductive invariant Inv will have the form TypeOK /\ I *) +(* where TypeOK just asserts type-correctness and I is the interesting *) +(* part. For Peterson's algorithm, TypeOK is: *) +(***************************************************************************) +TypeOK == /\ pc \in [{0,1} -> {"a0", "a1", "a2", "a3", "cs", "a4"}] + /\ turn \in {0, 1} + /\ flag \in [{0,1} -> BOOLEAN] + +(***************************************************************************) +(* It turns out that we can use the following I. (I explain below how I *) +(* found I.) *) +(***************************************************************************) +I == \A i \in {0, 1} : + /\ (pc[i] \in {"a2", "a3", "cs", "a4"} ) => flag[i] + /\ (pc[i] \in {"cs", "a4"}) => /\ pc[Not(i)] \notin {"cs", "a4"} + /\ (pc[Not(i)] = "a3") => (turn = i) + +(***************************************************************************) +(* so we have: *) +(***************************************************************************) +Inv == TypeOK /\ I + +(***************************************************************************) +(* We can easily use TLC to check Init => Inv by checking that Inv is an *) +(* invariant of the specification. We can check that Inv satisfies *) +(* *) +(* Inv /\ [Next]_vars => Inv' *) +(* *) +(* by checking that Inv is an invariant of the following specification. *) +(***************************************************************************) +ISpec == Inv /\ [][Next]_vars + +(***************************************************************************) +(* This works only because Inv is written as the conjunction TypeOK and *) +(* something else, where TypeOK has the form it does. (Otherwise, TLC *) +(* would not be able to handle Inv as an initial predicate.) Moreover, to *) +(* compute the initial states, TLC must calculate all states that satisfy *) +(* the type-correctness invariant. For most specs, this is an enormous *) +(* number of states except perhaps for the tiniest of models, so this *) +(* seldom works. However, Peterson's algorithm is so simple that it works *) +(* fine. In fact, I discovered the invariant I by trial and error, using *) +(* TLC to discover the problems with I that did not make Inv an invariant *) +(* of ISpec. *) +(* *) +(* Finally, we can check *) +(* *) +(* Inv => MutualExclusion *) +(* *) +(* by having TLC check that MutualExclusion is an invariant of ISpec. *) +(***************************************************************************) +============================================================================= diff --git a/tlatools/test-model/pcal/Quicksort.cfg b/tlatools/test-model/pcal/Quicksort.cfg new file mode 100644 index 0000000000000000000000000000000000000000..bf53fd99fa028a25cae0ad8e91dd46cac959359e --- /dev/null +++ b/tlatools/test-model/pcal/Quicksort.cfg @@ -0,0 +1,5 @@ +SPECIFICATION Spec +PROPERTY Termination +CONSTANT defaultInitValue = defaultInitValue +\* Add statements after this line. +CONSTANTS ArrayLen = 3 diff --git a/tlatools/test-model/pcal/Quicksort.tla b/tlatools/test-model/pcal/Quicksort.tla new file mode 100644 index 0000000000000000000000000000000000000000..c50fe77f188732881cb9c80c92637b41bb238af3 --- /dev/null +++ b/tlatools/test-model/pcal/Quicksort.tla @@ -0,0 +1,167 @@ +------------------------------- MODULE Quicksort ----------------------------- +EXTENDS Naturals, Sequences, TLC + +CONSTANT ArrayLen + +ASSUME ArrayLen \in Nat + +PermsOf(Arr) == + LET Automorphism(S) == { f \in [S -> S] : + \A y \in S : \E x \in S : f[x] = y } + f ** g == [x \in DOMAIN g |-> f[g[x]]] + IN { Arr ** f : f \in Automorphism(DOMAIN Arr) } + +(* +--algorithm Quicksort + variables Ainit \in [1..ArrayLen -> 1..ArrayLen]; A = Ainit; + returnVal = 1 + procedure Partition(lo, hi ) + begin pt1 : with piv \in lo..(hi-1) + do returnVal := piv ; + with Ap \in + {AA \in PermsOf(A) : + (\A i \in 1..(lo-1) : AA[i] = A[i]) + /\ (\A i \in (hi+1)..Len(A) : AA[i] = A[i]) + /\ (\A i \in lo..piv, j \in (piv+1)..hi : + AA[i] \leq AA[j])} + do A := Ap; + return ; + end with ; + end with; + end procedure + procedure QS(qlo, qhi ) + variable pivot ; + begin qs1 : if qlo < qhi + then call Partition(qlo, qhi) ; + qs2 : pivot := returnVal ; + qs3 : call QS(qlo, pivot) ; + qs4 : call QS(pivot +1,qhi) ; + return ; + else return; + end if; + end procedure + begin main : call QS(1, Len(A)) ; + test : assert A \in PermsOf(Ainit) + /\ \A i, j \in 1..ArrayLen : + (i < j) => A[i] \leq A[j] + end algorithm +*) + +(***** BEGIN TRANSLATION ***) +CONSTANT defaultInitValue +VARIABLES Ainit, A, returnVal, pc, stack, lo, hi, qlo, qhi, pivot + +vars == << Ainit, A, returnVal, pc, stack, lo, hi, qlo, qhi, pivot >> + +Init == (* Global variables *) + /\ Ainit \in [1..ArrayLen -> 1..ArrayLen] + /\ A = Ainit + /\ returnVal = 1 + (* Procedure Partition *) + /\ lo = defaultInitValue + /\ hi = defaultInitValue + (* Procedure QS *) + /\ qlo = defaultInitValue + /\ qhi = defaultInitValue + /\ pivot = defaultInitValue + /\ stack = << >> + /\ pc = "main" + +pt1 == /\ pc = "pt1" + /\ \E piv \in lo..(hi-1): + /\ returnVal' = piv + /\ \E Ap \in {AA \in PermsOf(A) : + (\A i \in 1..(lo-1) : AA[i] = A[i]) + /\ (\A i \in (hi+1)..Len(A) : AA[i] = A[i]) + /\ (\A i \in lo..piv, j \in (piv+1)..hi : + AA[i] \leq AA[j])}: + /\ A' = Ap + /\ pc' = Head(stack).pc + /\ lo' = Head(stack).lo + /\ hi' = Head(stack).hi + /\ stack' = Tail(stack) + /\ UNCHANGED << Ainit, qlo, qhi, pivot >> + +Partition == pt1 + +qs1 == /\ pc = "qs1" + /\ IF qlo < qhi + THEN /\ /\ hi' = qhi + /\ lo' = qlo + /\ stack' = << [ procedure |-> "Partition", + pc |-> "qs2", + lo |-> lo, + hi |-> hi ] >> + \o stack + /\ pc' = "pt1" + /\ UNCHANGED << qlo, qhi, pivot >> + ELSE /\ pc' = Head(stack).pc + /\ pivot' = Head(stack).pivot + /\ qlo' = Head(stack).qlo + /\ qhi' = Head(stack).qhi + /\ stack' = Tail(stack) + /\ UNCHANGED << lo, hi >> + /\ UNCHANGED << Ainit, A, returnVal >> + +qs2 == /\ pc = "qs2" + /\ pivot' = returnVal + /\ pc' = "qs3" + /\ UNCHANGED << Ainit, A, returnVal, stack, lo, hi, qlo, qhi >> + +qs3 == /\ pc = "qs3" + /\ /\ qhi' = pivot + /\ qlo' = qlo + /\ stack' = << [ procedure |-> "QS", + pc |-> "qs4", + pivot |-> pivot, + qlo |-> qlo, + qhi |-> qhi ] >> + \o stack + /\ pivot' = defaultInitValue + /\ pc' = "qs1" + /\ UNCHANGED << Ainit, A, returnVal, lo, hi >> + +qs4 == /\ pc = "qs4" + /\ /\ qhi' = qhi + /\ qlo' = pivot +1 + /\ pivot' = defaultInitValue + /\ pc' = "qs1" + /\ UNCHANGED << Ainit, A, returnVal, stack, lo, hi >> + +QS == qs1 \/ qs2 \/ qs3 \/ qs4 + +main == /\ pc = "main" + /\ /\ qhi' = Len(A) + /\ qlo' = 1 + /\ stack' = << [ procedure |-> "QS", + pc |-> "test", + pivot |-> pivot, + qlo |-> qlo, + qhi |-> qhi ] >> + \o stack + /\ pivot' = defaultInitValue + /\ pc' = "qs1" + /\ UNCHANGED << Ainit, A, returnVal, lo, hi >> + +test == /\ pc = "test" + /\ Assert( A \in PermsOf(Ainit) + /\ \A i, j \in 1..ArrayLen : + (i < j) => A[i] \leq A[j], + "Failure of assertion at line 44, column 17.") + /\ pc' = "Done" + /\ UNCHANGED << Ainit, A, returnVal, stack, lo, hi, qlo, qhi, pivot >> + +Next == Partition \/ QS \/ main \/ test + \/ (* Disjunct to prevent deadlock on termination *) + (pc = "Done" /\ UNCHANGED vars) + +Spec == /\ Init /\ [][Next]_vars + /\ WF_vars(Next) + +Termination == <>(pc = "Done") + +(***** END TRANSLATION ***) +============================================================================= +Checked without termination on svc-lamport-2 with 2 workers: + arrayLen = 4 in 15 sec, 32280 states, depth 22 + arrayLen = 5 in 138min 17 sec 1529005 states, depth 28 diff --git a/tlatools/test-model/pcal/Quicksort2Procs.cfg b/tlatools/test-model/pcal/Quicksort2Procs.cfg new file mode 100644 index 0000000000000000000000000000000000000000..8e5945333cd1398dc09ad5bbbab24c46e8121b21 --- /dev/null +++ b/tlatools/test-model/pcal/Quicksort2Procs.cfg @@ -0,0 +1,6 @@ +SPECIFICATION Spec +PROPERTY Termination +\* Add statements after this line. +CONSTANTS ArrayLen = 3 +INVARIANT Invariant + diff --git a/tlatools/test-model/pcal/Quicksort2Procs.tla b/tlatools/test-model/pcal/Quicksort2Procs.tla new file mode 100644 index 0000000000000000000000000000000000000000..592eb74ef76e959e632e8a30e3d5066253d03fba --- /dev/null +++ b/tlatools/test-model/pcal/Quicksort2Procs.tla @@ -0,0 +1,241 @@ +--------------------------- MODULE Quicksort2Procs --------------------------- +EXTENDS Naturals, Sequences + +CONSTANT ArrayLen + +ASSUME ArrayLen \in Nat + +PermsOf(Arr) == + LET Automorphism(S) == { f \in [S -> S] : + \A y \in S : \E x \in S : f[x] = y } + f ** g == [x \in DOMAIN g |-> f[g[x]]] + IN { Arr ** f : f \in Automorphism(DOMAIN Arr) } + +(* This algorithm uses two different copies of the QS procedure + to test whether tail recursion works when calling a different + procedure. + +--algorithm Quicksort + variables A \in [1..ArrayLen -> 1..ArrayLen]; + returnVal = 99; + procedure Partition(lo = 99, hi = 99) + begin pt1 : with piv \in lo..(hi-1) + do returnVal := piv ; + with Ap \in + {AA \in PermsOf(A) : + (\A i \in 1..(lo-1) : AA[i] = A[i]) + /\ (\A i \in (hi+1)..Len(A) : AA[i] = A[i]) + /\ (\A i \in lo..piv, j \in (piv+1)..hi : + AA[i] \leq AA[j])} + do A := Ap; + return ; + end with ; + end with; + end procedure + procedure QS(qlo = 99, qhi = 99) + variable pivot = 99 ; + begin qs1 : if qlo < qhi + then call Partition(qlo, qhi) ; + qs2 : pivot := returnVal ; + qs3 : call QS2(qlo, pivot) ; + qs4 : call QS2(pivot +1,qhi) ; + return ; + else return; + end if; + end procedure + procedure QS2(qlo2 = 99, qhi2 = 99) + variable pivot2 = 99 ; + begin 2qs1 : if qlo2 < qhi2 + then call Partition(qlo2, qhi2) ; + 2qs2 : pivot2 := returnVal ; + 2qs3 : call QS(qlo2, pivot2) ; + 2qs4 : call QS(pivot2 +1,qhi2) ; + return ; + else return; + end if; + end procedure + begin main : call QS(1, Len(A)) ; + end algorithm +*) + +(***** BEGIN TRANSLATION ***) +VARIABLES A, returnVal, pc, stack, lo, hi, qlo, qhi, pivot, qlo2, qhi2, + pivot2 + +vars == << A, returnVal, pc, stack, lo, hi, qlo, qhi, pivot, qlo2, qhi2, + pivot2 >> + +Init == (* Global variables *) + /\ A \in [1..ArrayLen -> 1..ArrayLen] + /\ returnVal = 99 + (* Procedure Partition *) + /\ lo = 99 + /\ hi = 99 + (* Procedure QS *) + /\ qlo = 99 + /\ qhi = 99 + /\ pivot = 99 + (* Procedure QS2 *) + /\ qlo2 = 99 + /\ qhi2 = 99 + /\ pivot2 = 99 + /\ stack = << >> + /\ pc = "main" + +pt1 == /\ pc = "pt1" + /\ \E piv \in lo..(hi-1): + /\ returnVal' = piv + /\ \E Ap \in {AA \in PermsOf(A) : + (\A i \in 1..(lo-1) : AA[i] = A[i]) + /\ (\A i \in (hi+1)..Len(A) : AA[i] = A[i]) + /\ (\A i \in lo..piv, j \in (piv+1)..hi : + AA[i] \leq AA[j])}: + /\ A' = Ap + /\ pc' = Head(stack).pc + /\ lo' = Head(stack).lo + /\ hi' = Head(stack).hi + /\ stack' = Tail(stack) + /\ UNCHANGED << qlo, qhi, pivot, qlo2, qhi2, pivot2 >> + +Partition == pt1 + +qs1 == /\ pc = "qs1" + /\ IF qlo < qhi + THEN /\ /\ hi' = qhi + /\ lo' = qlo + /\ stack' = << [ procedure |-> "Partition", + pc |-> "qs2", + lo |-> lo, + hi |-> hi ] >> + \o stack + /\ pc' = "pt1" + /\ UNCHANGED << qlo, qhi, pivot >> + ELSE /\ pc' = Head(stack).pc + /\ pivot' = Head(stack).pivot + /\ qlo' = Head(stack).qlo + /\ qhi' = Head(stack).qhi + /\ stack' = Tail(stack) + /\ UNCHANGED << lo, hi >> + /\ UNCHANGED << A, returnVal, qlo2, qhi2, pivot2 >> + +qs2 == /\ pc = "qs2" + /\ pivot' = returnVal + /\ pc' = "qs3" + /\ UNCHANGED << A, returnVal, stack, lo, hi, qlo, qhi, qlo2, qhi2, + pivot2 >> + +qs3 == /\ pc = "qs3" + /\ /\ qhi2' = pivot + /\ qlo2' = qlo + /\ stack' = << [ procedure |-> "QS2", + pc |-> "qs4", + pivot2 |-> pivot2, + qlo2 |-> qlo2, + qhi2 |-> qhi2 ] >> + \o stack + /\ pivot2' = 99 + /\ pc' = "2qs1" + /\ UNCHANGED << A, returnVal, lo, hi, qlo, qhi, pivot >> + +qs4 == /\ pc = "qs4" + /\ /\ pivot' = Head(stack).pivot + /\ qhi2' = qhi + /\ qlo2' = pivot +1 + /\ stack' = << [ procedure |-> "QS2", + pc |-> Head(stack).pc, + pivot2 |-> pivot2, + qlo2 |-> qlo2, + qhi2 |-> qhi2 ] >> + \o Tail(stack) + /\ pivot2' = 99 + /\ pc' = "2qs1" + /\ UNCHANGED << A, returnVal, lo, hi, qlo, qhi >> + +QS == qs1 \/ qs2 \/ qs3 \/ qs4 + +2qs1 == /\ pc = "2qs1" + /\ IF qlo2 < qhi2 + THEN /\ /\ hi' = qhi2 + /\ lo' = qlo2 + /\ stack' = << [ procedure |-> "Partition", + pc |-> "2qs2", + lo |-> lo, + hi |-> hi ] >> + \o stack + /\ pc' = "pt1" + /\ UNCHANGED << qlo2, qhi2, pivot2 >> + ELSE /\ pc' = Head(stack).pc + /\ pivot2' = Head(stack).pivot2 + /\ qlo2' = Head(stack).qlo2 + /\ qhi2' = Head(stack).qhi2 + /\ stack' = Tail(stack) + /\ UNCHANGED << lo, hi >> + /\ UNCHANGED << A, returnVal, qlo, qhi, pivot >> + +2qs2 == /\ pc = "2qs2" + /\ pivot2' = returnVal + /\ pc' = "2qs3" + /\ UNCHANGED << A, returnVal, stack, lo, hi, qlo, qhi, pivot, qlo2, + qhi2 >> + +2qs3 == /\ pc = "2qs3" + /\ /\ qhi' = pivot2 + /\ qlo' = qlo2 + /\ stack' = << [ procedure |-> "QS", + pc |-> "2qs4", + pivot |-> pivot, + qlo |-> qlo, + qhi |-> qhi ] >> + \o stack + /\ pivot' = 99 + /\ pc' = "qs1" + /\ UNCHANGED << A, returnVal, lo, hi, qlo2, qhi2, pivot2 >> + +2qs4 == /\ pc = "2qs4" + /\ /\ pivot2' = Head(stack).pivot2 + /\ qhi' = qhi2 + /\ qlo' = pivot2 +1 + /\ stack' = << [ procedure |-> "QS", + pc |-> Head(stack).pc, + pivot |-> pivot, + qlo |-> qlo, + qhi |-> qhi ] >> + \o Tail(stack) + /\ pivot' = 99 + /\ pc' = "qs1" + /\ UNCHANGED << A, returnVal, lo, hi, qlo2, qhi2 >> + +QS2 == 2qs1 \/ 2qs2 \/ 2qs3 \/ 2qs4 + +main == /\ pc = "main" + /\ /\ qhi' = Len(A) + /\ qlo' = 1 + /\ stack' = << [ procedure |-> "QS", + pc |-> "Done", + pivot |-> pivot, + qlo |-> qlo, + qhi |-> qhi ] >> + \o stack + /\ pivot' = 99 + /\ pc' = "qs1" + /\ UNCHANGED << A, returnVal, lo, hi, qlo2, qhi2, pivot2 >> + +Next == Partition \/ QS \/ QS2 \/ main + \/ (* Disjunct to prevent deadlock on termination *) + (pc = "Done" /\ UNCHANGED vars) + +Spec == /\ Init /\ [][Next]_vars + /\ WF_vars(Next) + +Termination == <>(pc = "Done") + +(***** END TRANSLATION ***) + +Invariant == + (pc = "Done") => \A i, j \in 1..ArrayLen : + (i < j) => A[i] \leq A[j] + +\* Tested on 28 June 2005 with arrayLen = 5 in +\* 2 hours 9 min 6.5 seconds on SVC-Lamport-3 + +============================================================================= diff --git a/tlatools/test-model/pcal/QuicksortMacro.cfg b/tlatools/test-model/pcal/QuicksortMacro.cfg new file mode 100644 index 0000000000000000000000000000000000000000..0ebf8fe12d66c62cbd54cf80207efc9dda94587b --- /dev/null +++ b/tlatools/test-model/pcal/QuicksortMacro.cfg @@ -0,0 +1,5 @@ +SPECIFICATION Spec +PROPERTY Termination +\* Add statements after this line. +CONSTANTS ArrayLen = 3 +INVARIANT Invariant diff --git a/tlatools/test-model/pcal/QuicksortMacro.tla b/tlatools/test-model/pcal/QuicksortMacro.tla new file mode 100644 index 0000000000000000000000000000000000000000..68abac3d107331073642b2e6b68cc6e9cbcd1c4c --- /dev/null +++ b/tlatools/test-model/pcal/QuicksortMacro.tla @@ -0,0 +1,136 @@ +---------------------------- MODULE QuicksortMacro --------------------------- +EXTENDS Naturals, Sequences + +CONSTANT ArrayLen + +ASSUME ArrayLen \in Nat + +PermsOf(Arr) == + LET Automorphism(S) == { f \in [S -> S] : + \A y \in S : \E x \in S : f[x] = y } + f ** g == [x \in DOMAIN g |-> f[g[x]]] + IN { Arr ** f : f \in Automorphism(DOMAIN Arr) } + +(* +--algorithm QuicksortMacro + variables A \in [1..ArrayLen -> 1..ArrayLen]; + returnVal = 1; + macro Partition(lo, hi) + begin with piv \in lo..(hi-1) + do returnVal := piv ; + with Ap \in + {AA \in PermsOf(A) : + (\A i \in 1..(lo-1) : AA[i] = A[i]) + /\ (\A i \in (hi+1)..Len(A) : AA[i] = A[i]) + /\ (\A i \in lo..piv, j \in (piv+1)..hi : + AA[i] \leq AA[j])} + do A := Ap; + end with ; + end with; + end macro + procedure QS(qlo = 1, qhi = 1) + variable pivot = 1 ; + begin qs1 : if qlo < qhi + then Partition(qlo, qhi) ; + qs2 : pivot := returnVal ; + qs3 : call QS(qlo, pivot) ; + qs4 : call QS(pivot +1,qhi) ; + return ; + else return; + end if; + end procedure + begin main : call QS(1, Len(A)) ; + end algorithm +*) + +(***** BEGIN TRANSLATION ***) +VARIABLES A, returnVal, pc, stack, qlo, qhi, pivot + +vars == << A, returnVal, pc, stack, qlo, qhi, pivot >> + +Init == (* Global variables *) + /\ A \in [1..ArrayLen -> 1..ArrayLen] + /\ returnVal = 1 + (* Procedure QS *) + /\ qlo = 1 + /\ qhi = 1 + /\ pivot = 1 + /\ stack = << >> + /\ pc = "main" + +qs1 == /\ pc = "qs1" + /\ IF qlo < qhi + THEN /\ \E piv \in qlo..(qhi-1): + /\ returnVal' = piv + /\ \E Ap \in {AA \in PermsOf(A) : + (\A i \in 1..(qlo-1) : AA[i] = A[i]) + /\ (\A i \in (qhi+1)..Len(A) : AA[i] = A[i]) + /\ (\A i \in qlo..piv, j \in (piv+1)..qhi : + AA[i] \leq AA[j])}: + A' = Ap + /\ pc' = "qs2" + /\ UNCHANGED << stack, qlo, qhi, pivot >> + ELSE /\ pc' = Head(stack).pc + /\ pivot' = Head(stack).pivot + /\ qlo' = Head(stack).qlo + /\ qhi' = Head(stack).qhi + /\ stack' = Tail(stack) + /\ UNCHANGED << A, returnVal >> + +qs2 == /\ pc = "qs2" + /\ pivot' = returnVal + /\ pc' = "qs3" + /\ UNCHANGED << A, returnVal, stack, qlo, qhi >> + +qs3 == /\ pc = "qs3" + /\ /\ qhi' = pivot + /\ qlo' = qlo + /\ stack' = << [ procedure |-> "QS", + pc |-> "qs4", + pivot |-> pivot, + qlo |-> qlo, + qhi |-> qhi ] >> + \o stack + /\ pivot' = 1 + /\ pc' = "qs1" + /\ UNCHANGED << A, returnVal >> + +qs4 == /\ pc = "qs4" + /\ /\ qhi' = qhi + /\ qlo' = pivot +1 + /\ pivot' = 1 + /\ pc' = "qs1" + /\ UNCHANGED << A, returnVal, stack >> + +QS == qs1 \/ qs2 \/ qs3 \/ qs4 + +main == /\ pc = "main" + /\ /\ qhi' = Len(A) + /\ qlo' = 1 + /\ stack' = << [ procedure |-> "QS", + pc |-> "Done", + pivot |-> pivot, + qlo |-> qlo, + qhi |-> qhi ] >> + \o stack + /\ pivot' = 1 + /\ pc' = "qs1" + /\ UNCHANGED << A, returnVal >> + +Next == QS \/ main + \/ (* Disjunct to prevent deadlock on termination *) + (pc = "Done" /\ UNCHANGED vars) + +Spec == /\ Init /\ [][Next]_vars + /\ WF_vars(Next) + +Termination == <>(pc = "Done") + +(***** END TRANSLATION ***) + +Invariant == + (pc = "Done") => \A i, j \in 1..ArrayLen : + (i < j) => A[i] \leq A[j] + + +============================================================================= diff --git a/tlatools/test-model/pcal/RAB.cfg b/tlatools/test-model/pcal/RAB.cfg new file mode 100644 index 0000000000000000000000000000000000000000..31078b2505852cc4c10f20c6b1643aef28d53a24 --- /dev/null +++ b/tlatools/test-model/pcal/RAB.cfg @@ -0,0 +1,5 @@ +SPECIFICATION Spec +\* Add statements after this line. +CONSTANT Pid = { p0, p1 } +INVARIANT Consistency + diff --git a/tlatools/test-model/pcal/RAB.tla b/tlatools/test-model/pcal/RAB.tla new file mode 100644 index 0000000000000000000000000000000000000000..b21b1bd7d5c2db8ec0e20f2ace7ff8e20bae60bb --- /dev/null +++ b/tlatools/test-model/pcal/RAB.tla @@ -0,0 +1,208 @@ +------------------------------- MODULE RAB ------------------------------- + +EXTENDS Naturals, Sequences, TLC + + +(**************************************************************************) +(* The Remoting Attributes bug. *) +(* *) +(* *) +(* Simplified version of the c program (comment in the original): *) +(* *) +(* *) +(* class Attributes { *) +(* int flags = 0; *) +(* *) +(* boolean CalcA () { ... } *) +(* boolean CalcB () { ... } *) +(* *) +(* // We are not protecting against a race. *) +(* // If there is a race while setting flags we *) +(* // will have to compute the result again, but *) +(* // we will always return the correct result. *) +(* *) +(* boolean isA () { *) +(* if ((flags & 0x02) == 0) { *) +(* int temp = (CalcA() ? 0x03 : 0x02); *) +(* flags |= temp; *) +(* } *) +(* return (flags & 0x01) != 0; *) +(* } *) +(* *) +(* boolean isB () { *) +(* if ((flags & 0x20) == 0) { *) +(* int temp = (CalcB() ? 0x30 : 0x20); *) +(* flags |= temp; *) +(* } *) +(* return (flags & 0x10) != 0; *) +(* } *) +(* } *) +(* *) +(* *) +(* CalcA and CalcB are assumed to be functions that each always returns *) +(* the same value; we just do not know what value that is. We model this *) +(* using an "oracle" global variable named calc. *) +(* *) +(* We model the environment as a set of processes Pid. Each process runs *) +(* in a loop, selecting a random attribute ("A" or "B") to access on each *) +(* iteration. *) +(* *) +(**************************************************************************) + +CONSTANT Pid \* set of process ids + +Attr == { "A", "B" } \* what are the attributes +Boolean == { FALSE, TRUE } + +Flags == [ Attr -> [ valid: Boolean, value: Boolean ]] + + + +(**************************************************************************) +(* How to compute the "bitwise or" of two Flags. *) +(**************************************************************************) +f | g == [ a \in DOMAIN f |-> [ n \in DOMAIN f[a] |-> f[a][n] \/ g[a][n] ]] + + + + + + + +(*--algorithm rab + + variables + (****************************************************************) + (* Global variable containing flags for all attributes. The *) + (* initial state has all valid and value bits as FALSE. *) + (****************************************************************) + flags = [ a \in Attr |-> [ valid |-> FALSE, value |-> FALSE ]]; + + + (****************************************************************) + (* Oracle that says what the value is for each attribute. *) + (* Technically this is a variable, but we never change it. *) + (****************************************************************) + calc \in [ Attr -> { FALSE, TRUE } ]; + + + + + process work \in Pid + variables + (************************************************************) + (* Arbitrary initial values of the correct type. *) + (************************************************************) + temp = CHOOSE f \in Flags : TRUE; + myattr = CHOOSE a \in Attr : TRUE; + begin + Loop: + while TRUE do + (************************************************************) + (* Choose an attribute to access. *) + (************************************************************) + with attr \in Attr do myattr := attr; end with; + + if \lnot flags[myattr].valid then + (********************************************************) + (* My component of the global flags variable is not *) + (* valid. Compute the temporary. *) + (********************************************************) + temp := + [ a \in Attr |-> + IF a = myattr + THEN [ valid |-> TRUE, value |-> calc[myattr] ] + ELSE [ valid |-> FALSE, value |-> FALSE ] + ]; + + FetchFlags: + (********************************************************) + (* Fetch the global flags variable and "bitwise or" it *) + (* into the temporary. *) + (********************************************************) + temp := flags | temp; + + StoreFlags: + (********************************************************) + (* Store the temporary back into the global flags *) + (* variable. *) + (********************************************************) + + flags := temp; + end if; + + ReadFlags: + (************************************************************) + (* Read my component of the global flags variable. It is *) + (* supposed to be consistent with the oracle. *) + (************************************************************) + \* assert flags[myattr].value = calc[myattr]; + skip; + end while; + end process; +end algorithm + +*) + + +(* BEGIN TRANSLATION *) +VARIABLES flags, calc, pc, temp, myattr + +vars == << flags, calc, pc, temp, myattr >> + +ProcSet == (Pid) + +Init == (* Global variables *) + /\ flags = [ a \in Attr |-> [ valid |-> FALSE, value |-> FALSE ]] + /\ calc \in [ Attr -> { FALSE, TRUE } ] + (* Process work *) + /\ temp = [self \in Pid |-> CHOOSE f \in Flags : TRUE] + /\ myattr = [self \in Pid |-> CHOOSE a \in Attr : TRUE] + /\ pc = [self \in ProcSet |-> "Loop"] + +Loop(self) == /\ pc[self] = "Loop" + /\ \E attr \in Attr: + myattr' = [myattr EXCEPT ![self] = attr] + /\ IF \lnot flags[myattr'[self]].valid + THEN /\ temp' = [temp EXCEPT ![self] = [ a \in Attr |-> + IF a = myattr'[self] + THEN [ valid |-> TRUE, value |-> calc[myattr'[self]] ] + ELSE [ valid |-> FALSE, value |-> FALSE ] + ]] + /\ pc' = [pc EXCEPT ![self] = "FetchFlags"] + ELSE /\ pc' = [pc EXCEPT ![self] = "ReadFlags"] + /\ temp' = temp + /\ UNCHANGED << flags, calc >> + +ReadFlags(self) == /\ pc[self] = "ReadFlags" + /\ TRUE + /\ pc' = [pc EXCEPT ![self] = "Loop"] + /\ UNCHANGED << flags, calc, temp, myattr >> + +FetchFlags(self) == /\ pc[self] = "FetchFlags" + /\ temp' = [temp EXCEPT ![self] = flags | temp[self]] + /\ pc' = [pc EXCEPT ![self] = "StoreFlags"] + /\ UNCHANGED << flags, calc, myattr >> + +StoreFlags(self) == /\ pc[self] = "StoreFlags" + /\ flags' = temp[self] + /\ pc' = [pc EXCEPT ![self] = "ReadFlags"] + /\ UNCHANGED << calc, temp, myattr >> + +work(self) == Loop(self) \/ ReadFlags(self) \/ FetchFlags(self) + \/ StoreFlags(self) + +Next == (\E self \in Pid: work(self)) + +Spec == Init /\ [][Next]_vars + +(* END TRANSLATION *) + + +Consistency == + \A self \in ProcSet : + pc[self] = "ReadFlags" => + flags[myattr[self]].value = calc[myattr[self]] + + +============================================================================ diff --git a/tlatools/test-model/pcal/RealQuicksort.cfg b/tlatools/test-model/pcal/RealQuicksort.cfg new file mode 100644 index 0000000000000000000000000000000000000000..105b80b88f83103a719c8d296f999f4d9a8c580a --- /dev/null +++ b/tlatools/test-model/pcal/RealQuicksort.cfg @@ -0,0 +1,7 @@ +SPECIFICATION Spec +PROPERTY Termination +CONSTANT defaultInitValue = defaultInitValue +\* Add statements after this line. +CONSTANTS MaxLen = 3 +INVARIANT Invariant + diff --git a/tlatools/test-model/pcal/RealQuicksort.tla b/tlatools/test-model/pcal/RealQuicksort.tla new file mode 100644 index 0000000000000000000000000000000000000000..2f0caf8fd7d363d9dccdb39676da01b2275d7754 --- /dev/null +++ b/tlatools/test-model/pcal/RealQuicksort.tla @@ -0,0 +1,122 @@ +----------------------------- MODULE RealQuicksort --------------------------- +EXTENDS Naturals, Sequences, FiniteSets + +CONSTANT MaxLen + +ASSUME MaxLen \in Nat + +PermsOf(Arr) == + LET Automorphism(S) == { f \in [S -> S] : + \A y \in S : \E x \in S : f[x] = y } + f ** g == [x \in DOMAIN g |-> f[g[x]]] + IN { Arr ** f : f \in Automorphism(DOMAIN Arr) } + +Min(S) == CHOOSE i \in S : \A j \in S : i \leq j +Max(S) == CHOOSE i \in S : \A j \in S : i \geq j + +(* + +--algorithm RealQuicksort + variables A \in UNION {[1..N -> 1..N] : N \in 0..MaxLen}; + Uns = {1..Len(A)} ; + new = {} ; + procedure Part(parg) + begin pt1 : with new1 \in + {Min(parg)..piv : piv \in parg \ {Max(parg)}} do + with new2 = parg \ new1 do + new := {new1, new2} ; + with Ap \in + {AA \in PermsOf(A) : + (\A i \in 1..Len(A) \ parg : AA[i] = A[i]) + /\ (\A i \in new1, j \in new2 : + AA[i] \leq AA[j])} do + A := Ap; + return ; + end with ; + end with ; + end with; + end procedure + begin rqs : while Uns # {} + do with next \in Uns + do Uns := Uns \ {next}; + if Cardinality(next) > 1 + then call Part(next) ; + else new := {} ; + end if ; + end with ; + rqs2 : Uns := Uns \cup new ; + end while; + end algorithm + +*) + +(***** BEGIN TRANSLATION ***) +CONSTANT defaultInitValue +VARIABLES A, Uns, new, pc, stack, parg + +vars == << A, Uns, new, pc, stack, parg >> + +Init == (* Global variables *) + /\ A \in UNION {[1..N -> 1..N] : N \in 0..MaxLen} + /\ Uns = {1..Len(A)} + /\ new = {} + (* Procedure Part *) + /\ parg = defaultInitValue + /\ stack = << >> + /\ pc = "rqs" + +pt1 == /\ pc = "pt1" + /\ \E new1 \in {Min(parg)..piv : piv \in parg \ {Max(parg)}}: + LET new2 == parg \ new1 IN + /\ new' = {new1, new2} + /\ \E Ap \in {AA \in PermsOf(A) : + (\A i \in 1..Len(A) \ parg : AA[i] = A[i]) + /\ (\A i \in new1, j \in new2 : + AA[i] \leq AA[j])}: + /\ A' = Ap + /\ pc' = Head(stack).pc + /\ parg' = Head(stack).parg + /\ stack' = Tail(stack) + /\ Uns' = Uns + +Part == pt1 + +rqs == /\ pc = "rqs" + /\ IF Uns # {} + THEN /\ \E next \in Uns: + /\ Uns' = Uns \ {next} + /\ IF Cardinality(next) > 1 + THEN /\ /\ parg' = next + /\ stack' = << [ procedure |-> "Part", + pc |-> "rqs2", + parg |-> parg ] >> + \o stack + /\ pc' = "pt1" + /\ new' = new + ELSE /\ new' = {} + /\ pc' = "rqs2" + /\ UNCHANGED << stack, parg >> + ELSE /\ pc' = "Done" + /\ UNCHANGED << Uns, new, stack, parg >> + /\ A' = A + +rqs2 == /\ pc = "rqs2" + /\ Uns' = (Uns \cup new) + /\ pc' = "rqs" + /\ UNCHANGED << A, new, stack, parg >> + +Next == Part \/ rqs \/ rqs2 + \/ (* Disjunct to prevent deadlock on termination *) + (pc = "Done" /\ UNCHANGED vars) + +Spec == /\ Init /\ [][Next]_vars + /\ WF_vars(Next) + +Termination == <>(pc = "Done") + +(***** END TRANSLATION ***) + +Invariant == + (pc = "Done") => \A i, j \in 1..Len(A) : + (i < j) => A[i] \leq A[j] +============================================================================= diff --git a/tlatools/test-model/pcal/RealQuicksort2.cfg b/tlatools/test-model/pcal/RealQuicksort2.cfg new file mode 100644 index 0000000000000000000000000000000000000000..11946ee160e9c567089c7a04b4e059fdf484a7a1 --- /dev/null +++ b/tlatools/test-model/pcal/RealQuicksort2.cfg @@ -0,0 +1,6 @@ +SPECIFICATION Spec +PROPERTY Termination +CONSTANT defaultInitValue = defaultInitValue +\* Add statements after this line. +CONSTANTS MaxLen = 3 +INVARIANT Invariant diff --git a/tlatools/test-model/pcal/RealQuicksort2.tla b/tlatools/test-model/pcal/RealQuicksort2.tla new file mode 100644 index 0000000000000000000000000000000000000000..86f8975d839dc88c5b09d6a88123912e09192b59 --- /dev/null +++ b/tlatools/test-model/pcal/RealQuicksort2.tla @@ -0,0 +1,122 @@ +---------------------------- MODULE RealQuicksort2 -------------------------- +EXTENDS Naturals, Sequences, FiniteSets + +CONSTANT MaxLen + +ASSUME MaxLen \in Nat + +PermsOf(Arr) == + LET Automorphism(S) == { f \in [S -> S] : + \A y \in S : \E x \in S : f[x] = y } + f ** g == [x \in DOMAIN g |-> f[g[x]]] + IN { Arr ** f : f \in Automorphism(DOMAIN Arr) } + +Min(S) == CHOOSE i \in S : \A j \in S : i \leq j +Max(S) == CHOOSE i \in S : \A j \in S : i \geq j + +(* + +--algorithm RealQuicksort2 + variables A \in UNION {[1..N -> 1..N] : N \in 0..MaxLen}; + Uns = {1..Len(A)} ; + new = {} ; + next = {} ; + procedure Part(parg) + begin pt1 : with new1 \in + {Min(parg)..piv : piv \in parg \ {Max(parg)}} do + with new2 = parg \ new1 do + new := {new1, new2} ; + with Ap \in + {AA \in PermsOf(A) : + (\A i \in 1..Len(A) \ parg : AA[i] = A[i]) + /\ (\A i \in new1, j \in new2 : + AA[i] \leq AA[j])} do + A := Ap; + return ; + end with ; + end with ; + end with; + end procedure; + begin rqs : while Uns # {} + do with nxt \in Uns do next := nxt ; + end with ; + Uns := Uns \ {next}; + if Cardinality(next) > 1 + then call Part(next) ; + rqs2 : Uns := Uns \cup new ; + end if ; + end while; + end algorithm + +*) + +(***** BEGIN TRANSLATION ***) +CONSTANT defaultInitValue +VARIABLES A, Uns, new, next, pc, stack, parg + +vars == << A, Uns, new, next, pc, stack, parg >> + +Init == (* Global variables *) + /\ A \in UNION {[1..N -> 1..N] : N \in 0..MaxLen} + /\ Uns = {1..Len(A)} + /\ new = {} + /\ next = {} + (* Procedure Part *) + /\ parg = defaultInitValue + /\ stack = << >> + /\ pc = "rqs" + +pt1 == /\ pc = "pt1" + /\ \E new1 \in {Min(parg)..piv : piv \in parg \ {Max(parg)}}: + LET new2 == parg \ new1 IN + /\ new' = {new1, new2} + /\ \E Ap \in {AA \in PermsOf(A) : + (\A i \in 1..Len(A) \ parg : AA[i] = A[i]) + /\ (\A i \in new1, j \in new2 : + AA[i] \leq AA[j])}: + /\ A' = Ap + /\ pc' = Head(stack).pc + /\ parg' = Head(stack).parg + /\ stack' = Tail(stack) + /\ UNCHANGED << Uns, next >> + +Part == pt1 + +rqs == /\ pc = "rqs" + /\ IF Uns # {} + THEN /\ \E nxt \in Uns: + next' = nxt + /\ Uns' = Uns \ {next'} + /\ IF Cardinality(next') > 1 + THEN /\ /\ parg' = next' + /\ stack' = << [ procedure |-> "Part", + pc |-> "rqs2", + parg |-> parg ] >> + \o stack + /\ pc' = "pt1" + ELSE /\ pc' = "rqs" + /\ UNCHANGED << stack, parg >> + ELSE /\ pc' = "Done" + /\ UNCHANGED << Uns, next, stack, parg >> + /\ UNCHANGED << A, new >> + +rqs2 == /\ pc = "rqs2" + /\ Uns' = (Uns \cup new) + /\ pc' = "rqs" + /\ UNCHANGED << A, new, next, stack, parg >> + +Next == Part \/ rqs \/ rqs2 + \/ (* Disjunct to prevent deadlock on termination *) + (pc = "Done" /\ UNCHANGED vars) + +Spec == /\ Init /\ [][Next]_vars + /\ WF_vars(Next) + +Termination == <>(pc = "Done") + +(***** END TRANSLATION ***) + +Invariant == + (pc = "Done") => \A i, j \in 1..Len(A) : + (i < j) => A[i] \leq A[j] +============================================================================= diff --git a/tlatools/test-model/pcal/ReallySimpleMultiProc.tla b/tlatools/test-model/pcal/ReallySimpleMultiProc.tla new file mode 100644 index 0000000000000000000000000000000000000000..20536ba20e7b0743df2fdf955c7e8d47e3633558 --- /dev/null +++ b/tlatools/test-model/pcal/ReallySimpleMultiProc.tla @@ -0,0 +1,86 @@ +--------------------------- MODULE ReallySimpleMultiProc -------------------------- +EXTENDS Naturals, TLC + +(* +--algorithm SimpleMultiProc + variables + x = [i \in ProcSet |-> CASE i = 41 -> 1 [] + i = 42 -> 2 [] + i = 43 -> 3]; + sum = 0 ; + done = {}; + process ProcA = 41 + variable y = 0; + begin a1 : sum := sum + y + x [ 41 ] || + done := done \cup { 41 } ; + a2 : when done = { 41, 42, 43 } ; + when Print ( sum , TRUE ) ; + end process + process ProcB \in {42, 43} + variable z \in {2, 3} ; + begin b1 : sum := sum + z + x [ self ] ; + b2 : done := done \cup { self } ; + end process + end algorithm + +*) + +(***** BEGIN TRANSLATION ***) +VARIABLES x, sum, done, pc, y, z + +vars == << x, sum, done, pc, y, z >> + +ProcSet == {41} \cup ({42, 43}) + +Init == (* Global variables *) + /\ x = [i \in ProcSet |-> CASE i = 41 -> 1 [] + i = 42 -> 2 [] + i = 43 -> 3] + /\ sum = 0 + /\ done = {} + (* Process ProcA *) + /\ y = 0 + (* Process ProcB *) + /\ z \in [{42, 43} -> {2, 3}] + /\ pc = [self \in ProcSet |-> CASE self = 41 -> "a1" + [] self \in {42, 43} -> "b1"] + +a1 == /\ pc[41] = "a1" + /\ /\ done' = (done \cup { 41 }) + /\ sum' = sum + y + x [ 41 ] + /\ pc' = [pc EXCEPT ![41] = "a2"] + /\ UNCHANGED << x, y, z >> + +a2 == /\ pc[41] = "a2" + /\ done = { 41, 42, 43 } + /\ Print ( sum , TRUE ) + /\ pc' = [pc EXCEPT ![41] = "Done"] + /\ UNCHANGED << x, sum, done, y, z >> + +ProcA == a1 \/ a2 + +b1(self) == /\ pc[self] = "b1" + /\ sum' = sum + z[self] + x [ self ] + /\ pc' = [pc EXCEPT ![self] = "b2"] + /\ UNCHANGED << x, done, y, z >> + +b2(self) == /\ pc[self] = "b2" + /\ done' = (done \cup { self }) + /\ pc' = [pc EXCEPT ![self] = "Done"] + /\ UNCHANGED << x, sum, y, z >> + +ProcB(self) == b1(self) \/ b2(self) + +Next == ProcA + \/ (\E self \in {42, 43}: ProcB(self)) + \/ (* Disjunct to prevent deadlock on termination *) + ((\A self \in ProcSet: pc[self] = "Done") /\ UNCHANGED vars) + +Spec == /\ Init /\ [][Next]_vars + /\ WF_vars(ProcA) + /\ \A self \in {42, 43} : WF_vars(ProcB(self)) + +Termination == <>(\A self \in ProcSet: pc[self] = "Done") + +(***** END TRANSLATION ***) +============================================================================= diff --git a/tlatools/test-model/pcal/SBB.cfg b/tlatools/test-model/pcal/SBB.cfg new file mode 100644 index 0000000000000000000000000000000000000000..9acb2839f67c4a2f76f25b5185c0309d20896a7a --- /dev/null +++ b/tlatools/test-model/pcal/SBB.cfg @@ -0,0 +1,11 @@ +SPECIFICATION Spec +\* Add statements after this line. +CONSTANT Pid = { p0, p1 } +CONSTANT NoPid = NoPid + +CONSTANT Buf = { b0, b1, b2, b3 } +CONSTANT NoBuf = NoBuf + +INVARIANT Immutability + +CONSTRAINT Constraint diff --git a/tlatools/test-model/pcal/SBB.tla b/tlatools/test-model/pcal/SBB.tla new file mode 100644 index 0000000000000000000000000000000000000000..44d5fb23dc2aae646e37fd8975dae866f713485e --- /dev/null +++ b/tlatools/test-model/pcal/SBB.tla @@ -0,0 +1,154 @@ +------------------------------- MODULE SBB ------------------------------- + +EXTENDS Naturals, Sequences, TLC + + +(**************************************************************************) +(* The StringBuilder bug. *) +(**************************************************************************) + +CONSTANT Pid \* set of process ids +NoPid == CHOOSE p : p \notin Pid + +CONSTANT Buf \* set of buffers +NoBuf == CHOOSE b : b \notin Buf + + + +(*--algorithm sbb + + variables + sb = [ owner |-> NoPid, buf |-> CHOOSE b \in Buf : TRUE ]; + availablebuffers = Buf \ {sb.buf}; + publishedbuffers = {}; + + + process work \in Pid + variable + buf = NoBuf; + op = {}; + begin + Loop: + while TRUE do + with lop \in { "Publish", "Modify" } do + op := lop; + end with; + + if (op = "Publish") then + buf := sb.buf; + Publish1: + if sb.owner # self /\ sb.owner # NoPid then + buf := CHOOSE b \in availablebuffers : TRUE; + availablebuffers := availablebuffers \ {buf}; + else + Publish2: + sb.owner := NoPid; + end if; + Publish3: + publishedbuffers := publishedbuffers \cup {buf}; + + + else + buf := sb.buf; + Modify1: + if sb.owner # self then + buf := CHOOSE b \in availablebuffers : TRUE; + availablebuffers := availablebuffers \ {buf}; + end if; + Modify2: + \* assert buf \notin publishedbuffers; + sb.owner := self; + Modify3: + sb.buf := buf; + end if + end while; + end process; +end algorithm + +*) + + +(* BEGIN TRANSLATION *) +VARIABLES sb, availablebuffers, publishedbuffers, pc, buf, op + +vars == << sb, availablebuffers, publishedbuffers, pc, buf, op >> + +ProcSet == (Pid) + +Init == (* Global variables *) + /\ sb = [ owner |-> NoPid, buf |-> CHOOSE b \in Buf : TRUE ] + /\ availablebuffers = Buf \ {sb.buf} + /\ publishedbuffers = {} + (* Process work *) + /\ buf = [self \in Pid |-> NoBuf] + /\ op = [self \in Pid |-> {}] + /\ pc = [self \in ProcSet |-> "Loop"] + +Loop(self) == /\ pc[self] = "Loop" + /\ \E lop \in { "Publish", "Modify" }: + op' = [op EXCEPT ![self] = lop] + /\ IF (op'[self] = "Publish") + THEN /\ buf' = [buf EXCEPT ![self] = sb.buf] + /\ pc' = [pc EXCEPT ![self] = "Publish1"] + ELSE /\ buf' = [buf EXCEPT ![self] = sb.buf] + /\ pc' = [pc EXCEPT ![self] = "Modify1"] + /\ UNCHANGED << sb, availablebuffers, publishedbuffers >> + +Publish1(self) == /\ pc[self] = "Publish1" + /\ IF sb.owner # self /\ sb.owner # NoPid + THEN /\ buf' = [buf EXCEPT ![self] = CHOOSE b \in availablebuffers : TRUE] + /\ availablebuffers' = availablebuffers \ {buf'[self]} + /\ pc' = [pc EXCEPT ![self] = "Publish3"] + ELSE /\ pc' = [pc EXCEPT ![self] = "Publish2"] + /\ UNCHANGED << availablebuffers, buf >> + /\ UNCHANGED << sb, publishedbuffers, op >> + +Publish2(self) == /\ pc[self] = "Publish2" + /\ sb' = [sb EXCEPT !.owner = NoPid] + /\ pc' = [pc EXCEPT ![self] = "Publish3"] + /\ UNCHANGED << availablebuffers, publishedbuffers, buf, op >> + +Publish3(self) == /\ pc[self] = "Publish3" + /\ publishedbuffers' = (publishedbuffers \cup {buf[self]}) + /\ pc' = [pc EXCEPT ![self] = "Loop"] + /\ UNCHANGED << sb, availablebuffers, buf, op >> + +Modify1(self) == /\ pc[self] = "Modify1" + /\ IF sb.owner # self + THEN /\ buf' = [buf EXCEPT ![self] = CHOOSE b \in availablebuffers : TRUE] + /\ availablebuffers' = availablebuffers \ {buf'[self]} + ELSE /\ TRUE + /\ UNCHANGED << availablebuffers, buf >> + /\ pc' = [pc EXCEPT ![self] = "Modify2"] + /\ UNCHANGED << sb, publishedbuffers, op >> + +Modify2(self) == /\ pc[self] = "Modify2" + /\ sb' = [sb EXCEPT !.owner = self] + /\ pc' = [pc EXCEPT ![self] = "Modify3"] + /\ UNCHANGED << availablebuffers, publishedbuffers, buf, op >> + +Modify3(self) == /\ pc[self] = "Modify3" + /\ sb' = [sb EXCEPT !.buf = buf[self]] + /\ pc' = [pc EXCEPT ![self] = "Loop"] + /\ UNCHANGED << availablebuffers, publishedbuffers, buf, op >> + +work(self) == Loop(self) \/ Publish1(self) \/ Publish2(self) + \/ Publish3(self) \/ Modify1(self) \/ Modify2(self) + \/ Modify3(self) + +Next == (\E self \in Pid: work(self)) + +Spec == Init /\ [][Next]_vars + +(* END TRANSLATION *) + + +Immutability == + \A self \in ProcSet : + pc[self] = "Modify2" => buf[self] \notin publishedbuffers + +Constraint == + availablebuffers # {} + + +============================================================================ diff --git a/tlatools/test-model/pcal/SemaphoreMutex.cfg b/tlatools/test-model/pcal/SemaphoreMutex.cfg new file mode 100644 index 0000000000000000000000000000000000000000..de1000468b848d4daa608674a58a8b347b759671 --- /dev/null +++ b/tlatools/test-model/pcal/SemaphoreMutex.cfg @@ -0,0 +1,5 @@ +SPECIFICATION Spec +\* Add statements after this line. +CONSTANT N = 3 +INVARIANT Invariant +PROPERTY Liveness diff --git a/tlatools/test-model/pcal/SemaphoreMutex.tla b/tlatools/test-model/pcal/SemaphoreMutex.tla new file mode 100644 index 0000000000000000000000000000000000000000..c79eb9e7b9373ffd98d6c17bdba7a027d44953e7 --- /dev/null +++ b/tlatools/test-model/pcal/SemaphoreMutex.tla @@ -0,0 +1,75 @@ +---------------------------- MODULE SemaphoreMutex -------------------------- + +EXTENDS Naturals + +CONSTANT N + +ASSUME N \in Nat + +(********************** +--algorithm SemaphoreMutex +variables sem = 1 ; +macro P(s) begin when s > 0 ; + s := s - 1 ; +end macro + +macro V(s) begin s := s + 1 ; +end macro + +process Proc \in 1..N +begin +start : while TRUE + do enter : P(sem) ; + cs : skip ; + exit : V(sem) ; + end while ; +end process +end algorithm + + +***********************) + +(**************** BEGIN TRANSLATION *******************************) +VARIABLES sem, pc + +vars == << sem, pc >> + +ProcSet == (1..N) + +Init == (* Global variables *) + /\ sem = 1 + /\ pc = [self \in ProcSet |-> "start"] + +start(self) == /\ pc[self] = "start" + /\ pc' = [pc EXCEPT ![self] = "enter"] + /\ sem' = sem + +enter(self) == /\ pc[self] = "enter" + /\ sem > 0 + /\ sem' = sem - 1 + /\ pc' = [pc EXCEPT ![self] = "cs"] + +cs(self) == /\ pc[self] = "cs" + /\ TRUE + /\ pc' = [pc EXCEPT ![self] = "exit"] + /\ sem' = sem + +exit(self) == /\ pc[self] = "exit" + /\ sem' = sem + 1 + /\ pc' = [pc EXCEPT ![self] = "start"] + +Proc(self) == start(self) \/ enter(self) \/ cs(self) \/ exit(self) + +Next == (\E self \in 1..N: Proc(self)) + +Spec == /\ Init /\ [][Next]_vars + /\ \A self \in 1..N : SF_vars(Proc(self)) + +(**************** END TRANSLATION *******************************) + +inCS(i) == (pc[i] = "cs") + +Invariant == \A i, k \in 1..N : (i # k) => ~ (inCS(i) /\ inCS(k)) + +Liveness == \A i \in 1..N : []<> inCS(i) +============================================================================= diff --git a/tlatools/test-model/pcal/SimpleLoop.tla b/tlatools/test-model/pcal/SimpleLoop.tla new file mode 100644 index 0000000000000000000000000000000000000000..4b20698f62b1158ed31a822eb2ee2aa48d40f61a --- /dev/null +++ b/tlatools/test-model/pcal/SimpleLoop.tla @@ -0,0 +1,44 @@ +----------------------------- MODULE SimpleLoop ----------------------------- +EXTENDS Naturals, TLC +(* + + --algorithm SimpleLoop + variable x = 0; + begin a : while x < 10 + do x := x+1 ; + skip ; + assert x \in 1..10; + end while ; + end algorithm +*) + +(******* BEGIN TRANSLATION *****) +VARIABLES x, pc + +vars == << x, pc >> + +Init == (* Global variables *) + /\ x = 0 + /\ pc = "a" + +a == /\ pc = "a" + /\ IF x < 10 + THEN /\ x' = x+1 + /\ TRUE + /\ Assert(x' \in 1..10, + "Failure of assertion at line 10, column 21.") + /\ pc' = "a" + ELSE /\ pc' = "Done" + /\ x' = x + +Next == a + \/ (* Disjunct to prevent deadlock on termination *) + (pc = "Done" /\ UNCHANGED vars) + +Spec == /\ Init /\ [][Next]_vars + /\ WF_vars(Next) + +Termination == <>(pc = "Done") + +(******* END TRANSLATION *****) +============================================================================= diff --git a/tlatools/test-model/pcal/SimpleLoopWithProcedure.tla b/tlatools/test-model/pcal/SimpleLoopWithProcedure.tla new file mode 100644 index 0000000000000000000000000000000000000000..a0b46cf46dca2a500e72f05bd5023615e198dade --- /dev/null +++ b/tlatools/test-model/pcal/SimpleLoopWithProcedure.tla @@ -0,0 +1,79 @@ +---------------------- MODULE SimpleLoopWithProcedure ---------------------- +EXTENDS Naturals, Sequences, TLC + +(* + +--algorithm SimpleLoopWithProcedure + variable x = 0; y \in {1, 2}; n = 0; i = 0; + procedure Incr(incr = 0) + variable z = 2; + begin i1 : x := incr + z + x; + i2 : return; + end procedure + begin a : while i < 10 + do when Print(x, TRUE); + i := i + 1 ; + call Incr(y) ; + end while ; + end algorithm + +*) + + +(***** BEGIN TRANSLATION ***) +VARIABLES x, y, n, i, pc, stack, incr, z + +vars == << x, y, n, i, pc, stack, incr, z >> + +Init == (* Global variables *) + /\ x = 0 + /\ y \in {1, 2} + /\ n = 0 + /\ i = 0 + (* Procedure Incr *) + /\ incr = 0 + /\ z = 2 + /\ stack = << >> + /\ pc = "a" + +i1 == /\ pc = "i1" + /\ x' = incr + z + x + /\ pc' = "i2" + /\ UNCHANGED << y, n, i, stack, incr, z >> + +i2 == /\ pc = "i2" + /\ pc' = Head(stack).pc + /\ z' = Head(stack).z + /\ incr' = Head(stack).incr + /\ stack' = Tail(stack) + /\ UNCHANGED << x, y, n, i >> + +Incr == i1 \/ i2 + +a == /\ pc = "a" + /\ IF i < 10 + THEN /\ Print(x, TRUE) + /\ i' = i + 1 + /\ /\ incr' = y + /\ stack' = << [ procedure |-> "Incr", + pc |-> "a", + z |-> z, + incr |-> incr ] >> + \o stack + /\ z' = 2 + /\ pc' = "i1" + ELSE /\ pc' = "Done" + /\ UNCHANGED << i, stack, incr, z >> + /\ UNCHANGED << x, y, n >> + +Next == Incr \/ a + \/ (* Disjunct to prevent deadlock on termination *) + (pc = "Done" /\ UNCHANGED vars) + +Spec == /\ Init /\ [][Next]_vars + /\ WF_vars(Next) + +Termination == <>(pc = "Done") + +(***** END TRANSLATION ***) +============================================================================= diff --git a/tlatools/test-model/pcal/SimpleMultiProc.tla b/tlatools/test-model/pcal/SimpleMultiProc.tla new file mode 100644 index 0000000000000000000000000000000000000000..f90f6591fbaf46fab631bc5d54a352390e275f72 --- /dev/null +++ b/tlatools/test-model/pcal/SimpleMultiProc.tla @@ -0,0 +1,162 @@ +--------------------------- MODULE SimpleMultiProc -------------------------- +EXTENDS Naturals, Sequences, TLC + +(* +--algorithm SimpleMultiProc + variables + x = [i \in ProcSet |-> CASE i = 41 -> 1 [] + i = 42 -> 2 [] + i = 43 -> 3 [] + i = 44 -> 4 [] + i = 45 -> 5]; + sum = 0 ; + done = {}; + procedure AddMe(me = 0) + variable y = 0; + begin am: done := done \cup { me } ; + return ; + end procedure + process ProcA = 41 + variable y = 0; + begin a1 : sum := sum + y + x [ 41 ] || + y := sum ; + a2 : call AddMe(41) ; + a3 : when done = { 41, 42, 43, 44, 45 } ; + end process + process ProcB \in 42 .. 43 + variable z \in {2, 3} ; + begin b1 : sum := sum + z + x [ self ] ; + b2 : call AddMe(self); + end process + process ProcC \in { 44, + 45 } + variable z \in {4, 5} ; + begin c1 : sum := sum + z + x [ self ] ; + c2 : call AddMe(self) ; + end process + end algorithm + +*) + +(***** BEGIN TRANSLATION ***) +\* Process variable y of process ProcA at line 20 col 17 changed to y_ +\* Process variable z of process ProcB at line 27 col 17 changed to z_ +VARIABLES x, sum, done, pc, stack, me, y, y_, z_, z + +vars == << x, sum, done, pc, stack, me, y, y_, z_, z >> + +ProcSet == {41} \cup (42 .. 43) \cup ({ 44, + 45 }) + +Init == (* Global variables *) + /\ x = [i \in ProcSet |-> CASE i = 41 -> 1 [] + i = 42 -> 2 [] + i = 43 -> 3 [] + i = 44 -> 4 [] + i = 45 -> 5] + /\ sum = 0 + /\ done = {} + (* Procedure AddMe *) + /\ me = [ self \in ProcSet |-> 0] + /\ y = [ self \in ProcSet |-> 0] + (* Process ProcA *) + /\ y_ = 0 + (* Process ProcB *) + /\ z_ \in [42 .. 43 -> {2, 3}] + (* Process ProcC *) + /\ z \in [{ 44, + 45 } -> {4, 5}] + /\ stack = [self \in ProcSet |-> << >>] + /\ pc = [self \in ProcSet |-> CASE self = 41 -> "a1" + [] self \in 42 .. 43 -> "b1" + [] self \in { 44, + 45 } -> "c1"] + +am(self) == /\ pc[self] = "am" + /\ done' = (done \cup { me[self] }) + /\ pc' = [pc EXCEPT ![self] = Head(stack[self]).pc] + /\ y' = [y EXCEPT ![self] = Head(stack[self]).y] + /\ me' = [me EXCEPT ![self] = Head(stack[self]).me] + /\ stack' = [stack EXCEPT ![self] = Tail(stack[self])] + /\ UNCHANGED << x, sum, y_, z_, z >> + +AddMe(self) == am(self) + +a1 == /\ pc[41] = "a1" + /\ /\ sum' = sum + y_ + x [ 41 ] + /\ y_' = sum + /\ pc' = [pc EXCEPT ![41] = "a2"] + /\ UNCHANGED << x, done, stack, me, y, z_, z >> + +a2 == /\ pc[41] = "a2" + /\ /\ me' = [me EXCEPT ![41] = 41] + /\ stack' = [stack EXCEPT ![41] = << [ procedure |-> "AddMe", + pc |-> "a3", + y |-> y[41], + me |-> me[41] ] >> + \o stack[41]] + /\ y' = [y EXCEPT ![41] = 0] + /\ pc' = [pc EXCEPT ![41] = "am"] + /\ UNCHANGED << x, sum, done, y_, z_, z >> + +a3 == /\ pc[41] = "a3" + /\ done = { 41, 42, 43, 44, 45 } + /\ pc' = [pc EXCEPT ![41] = "Done"] + /\ UNCHANGED << x, sum, done, stack, me, y, y_, z_, z >> + +ProcA == a1 \/ a2 \/ a3 + +b1(self) == /\ pc[self] = "b1" + /\ sum' = sum + z_[self] + x [ self ] + /\ pc' = [pc EXCEPT ![self] = "b2"] + /\ UNCHANGED << x, done, stack, me, y, y_, z_, z >> + +b2(self) == /\ pc[self] = "b2" + /\ /\ me' = [me EXCEPT ![self] = self] + /\ stack' = [stack EXCEPT ![self] = << [ procedure |-> "AddMe", + pc |-> "Done", + y |-> y[self], + me |-> me[self] ] >> + \o stack[self]] + /\ y' = [y EXCEPT ![self] = 0] + /\ pc' = [pc EXCEPT ![self] = "am"] + /\ UNCHANGED << x, sum, done, y_, z_, z >> + +ProcB(self) == b1(self) \/ b2(self) + +c1(self) == /\ pc[self] = "c1" + /\ sum' = sum + z[self] + x [ self ] + /\ pc' = [pc EXCEPT ![self] = "c2"] + /\ UNCHANGED << x, done, stack, me, y, y_, z_, z >> + +c2(self) == /\ pc[self] = "c2" + /\ /\ me' = [me EXCEPT ![self] = self] + /\ stack' = [stack EXCEPT ![self] = << [ procedure |-> "AddMe", + pc |-> "Done", + y |-> y[self], + me |-> me[self] ] >> + \o stack[self]] + /\ y' = [y EXCEPT ![self] = 0] + /\ pc' = [pc EXCEPT ![self] = "am"] + /\ UNCHANGED << x, sum, done, y_, z_, z >> + +ProcC(self) == c1(self) \/ c2(self) + +Next == ProcA + \/ (\E self \in ProcSet: AddMe(self)) + \/ (\E self \in 42 .. 43: ProcB(self)) + \/ (\E self \in { 44, + 45 }: ProcC(self)) + \/ (* Disjunct to prevent deadlock on termination *) + ((\A self \in ProcSet: pc[self] = "Done") /\ UNCHANGED vars) + +Spec == /\ Init /\ [][Next]_vars + /\ WF_vars(ProcA) /\ WF_vars(AddMe(41)) + /\ \A self \in 42 .. 43 : WF_vars(ProcB(self)) /\ WF_vars(AddMe(self)) + /\ \A self \in { 44, + 45 } : WF_vars(ProcC(self)) /\ WF_vars(AddMe(self)) + +Termination == <>(\A self \in ProcSet: pc[self] = "Done") + +(***** END TRANSLATION ***) +============================================================================= diff --git a/tlatools/test-model/pcal/StackTest.tla b/tlatools/test-model/pcal/StackTest.tla new file mode 100644 index 0000000000000000000000000000000000000000..85250e43848213aa4222f403709e0cea9370df27 --- /dev/null +++ b/tlatools/test-model/pcal/StackTest.tla @@ -0,0 +1,73 @@ +Bug: Currently putting an extra `self' subscript in assignment to + `stack'. + + + +----------- MODULE StackTest ----------- +EXTENDS Sequences, Naturals, TLC + +(*************************************************************************** +--algorithm StackAndPCTest + procedure P(a=42) + begin P1: stack[self][1].a := stack[self][1].a + 1; + assert Head(stack[self]).a = 43 ; + assert pc[self] = "P1" ; + P2: return + end procedure + process Q \in 0..2 + begin Q1: assert \A i \in ProcSet : pc[i] \in {"P1", "P2", "Q1", "Done"}; + call P(22) ; + end process; + end algorithm + ***************************************************************************) +\* BEGIN TRANSLATION +VARIABLES pc, stack, a + +vars == << pc, stack, a >> + +ProcSet == (0..2) + +Init == (* Procedure P *) + /\ a = [ self \in ProcSet |-> 42] + /\ stack = [self \in ProcSet |-> << >>] + /\ pc = [self \in ProcSet |-> "Q1"] + +P1(self) == /\ pc[self] = "P1" + /\ stack' = [stack EXCEPT ![self][self][1].a = stack[self][1].a + 1] + /\ Assert(Head(stack'[self]).a = 43, + "Failure of assertion at line 13, column 17.") + /\ Assert(pc[self] = "P1", + "Failure of assertion at line 14, column 17.") + /\ pc' = [pc EXCEPT ![self] = "P2"] + /\ a' = a + +P2(self) == /\ pc[self] = "P2" + /\ pc' = [pc EXCEPT ![self] = Head(stack[self]).pc] + /\ a' = [a EXCEPT ![self] = Head(stack[self]).a] + /\ stack' = [stack EXCEPT ![self] = Tail(stack[self])] + +P(self) == P1(self) \/ P2(self) + +Q1(self) == /\ pc[self] = "Q1" + /\ Assert(\A i \in ProcSet : pc[i] \in {"P1", "P2", "Q1", "Done"}, + "Failure of assertion at line 18, column 16.") + /\ /\ a' = [a EXCEPT ![self] = 22] + /\ stack' = [stack EXCEPT ![self] = << [ procedure |-> "P", + pc |-> "Done", + a |-> a[self] ] >> + \o stack[self]] + /\ pc' = [pc EXCEPT ![self] = "P1"] + +Q(self) == Q1(self) + +Next == (\E self \in ProcSet: P(self)) + \/ (\E self \in 0..2: Q(self)) + \/ (* Disjunct to prevent deadlock on termination *) + ((\A self \in ProcSet: pc[self] = "Done") /\ UNCHANGED vars) + +Spec == Init /\ [][Next]_vars + +Termination == <>(\A self \in ProcSet: pc[self] = "Done") + +\* END TRANSLATION +======================================== diff --git a/tlatools/test-model/pcal/StarkMutex.cfg b/tlatools/test-model/pcal/StarkMutex.cfg new file mode 100644 index 0000000000000000000000000000000000000000..8459e52f22b00841a0b8d2bdaff8bd8581e93e04 --- /dev/null +++ b/tlatools/test-model/pcal/StarkMutex.cfg @@ -0,0 +1,5 @@ +\* Add statements after this line. +CONSTANT N = 3 +SPECIFICATION StarkSpec \* A comment +INVARIANT Mutex +PROPERTY StarvationFree diff --git a/tlatools/test-model/pcal/StarkMutex.tla b/tlatools/test-model/pcal/StarkMutex.tla new file mode 100644 index 0000000000000000000000000000000000000000..09087d4ff76786afa174bc584157f49325f587be --- /dev/null +++ b/tlatools/test-model/pcal/StarkMutex.tla @@ -0,0 +1,208 @@ +--algorithm StarkMutex + variables flag = [i \in 1..N |-> FALSE]; + next = 1; + empty = TRUE; + mutex = 1; + weakSem = [i \in 1..N |-> 0]; + process i \in 1..N + variables first = FALSE; + j = 1; + begin + in1: while (TRUE) do + flag[self] := TRUE; + first := FALSE; + in2: when mutex = 1; mutex := 0; + in3: if empty then + in4: empty := FALSE; + first := TRUE; + end if; + in5: mutex := 1; + in6: if ~ first then + when weakSem[self] = 1; weakSem[self] := 0; + end if; + cs: skip; + ex1: flag[self] := FALSE; + ex2: when mutex = 1; mutex := 0; + ex3: j := 1; + empty := TRUE; + ex4: while j \leq N do + if flag[IF next + j > N THEN next + j - N ELSE next + j] then + ex5: with n = IF next + j > N THEN next + j - N ELSE next + j do + next := n; + weakSem[n] := 1; + j := N + 1; + end with; + ex6: empty := FALSE; + else + ex7: j := j + 1; + end if; + end while; + ex8: mutex := 1; + nc: skip; + end while; + end process + end algorithm + + + +------------------ MODULE StarkMutex ------------------ + +EXTENDS Naturals, Sequences +CONSTANT N + +------------------------------------------------------- + + + +\* BEGIN TRANSLATION +VARIABLES flag, next, empty, mutex, weakSem, pc, first, j + +vars == << flag, next, empty, mutex, weakSem, pc, first, j >> + +ProcSet == (1..N) + +Init == (* Global variables *) + /\ flag = [i \in 1..N |-> FALSE] + /\ next = 1 + /\ empty = TRUE + /\ mutex = 1 + /\ weakSem = [i \in 1..N |-> 0] + (* Process i *) + /\ first = [self \in 1..N |-> FALSE] + /\ j = [self \in 1..N |-> 1] + /\ pc = [self \in ProcSet |-> "in1"] + +in1(self) == /\ pc[self] = "in1" + /\ flag' = [flag EXCEPT ![self] = TRUE] + /\ first' = [first EXCEPT ![self] = FALSE] + /\ pc' = [pc EXCEPT ![self] = "in2"] + /\ UNCHANGED << next, empty, mutex, weakSem, j >> + +in2(self) == /\ pc[self] = "in2" + /\ mutex = 1 + /\ mutex' = 0 + /\ pc' = [pc EXCEPT ![self] = "in3"] + /\ UNCHANGED << flag, next, empty, weakSem, first, j >> + +in3(self) == /\ pc[self] = "in3" + /\ IF empty + THEN /\ pc' = [pc EXCEPT ![self] = "in4"] + ELSE /\ pc' = [pc EXCEPT ![self] = "in5"] + /\ UNCHANGED << flag, next, empty, mutex, weakSem, first, j >> + +in4(self) == /\ pc[self] = "in4" + /\ empty' = FALSE + /\ first' = [first EXCEPT ![self] = TRUE] + /\ pc' = [pc EXCEPT ![self] = "in5"] + /\ UNCHANGED << flag, next, mutex, weakSem, j >> + +in5(self) == /\ pc[self] = "in5" + /\ mutex' = 1 + /\ pc' = [pc EXCEPT ![self] = "in6"] + /\ UNCHANGED << flag, next, empty, weakSem, first, j >> + +in6(self) == /\ pc[self] = "in6" + /\ IF ~ first[self] + THEN /\ weakSem[self] = 1 + /\ weakSem' = [weakSem EXCEPT ![self] = 0] + ELSE /\ TRUE + /\ UNCHANGED weakSem + /\ pc' = [pc EXCEPT ![self] = "cs"] + /\ UNCHANGED << flag, next, empty, mutex, first, j >> + +cs(self) == /\ pc[self] = "cs" + /\ TRUE + /\ pc' = [pc EXCEPT ![self] = "ex1"] + /\ UNCHANGED << flag, next, empty, mutex, weakSem, first, j >> + +ex1(self) == /\ pc[self] = "ex1" + /\ flag' = [flag EXCEPT ![self] = FALSE] + /\ pc' = [pc EXCEPT ![self] = "ex2"] + /\ UNCHANGED << next, empty, mutex, weakSem, first, j >> + +ex2(self) == /\ pc[self] = "ex2" + /\ mutex = 1 + /\ mutex' = 0 + /\ pc' = [pc EXCEPT ![self] = "ex3"] + /\ UNCHANGED << flag, next, empty, weakSem, first, j >> + +ex3(self) == /\ pc[self] = "ex3" + /\ j' = [j EXCEPT ![self] = 1] + /\ empty' = TRUE + /\ pc' = [pc EXCEPT ![self] = "ex4"] + /\ UNCHANGED << flag, next, mutex, weakSem, first >> + +ex4(self) == /\ pc[self] = "ex4" + /\ IF j[self] \leq N + THEN /\ IF flag[IF next + j[self] > N THEN next + j[self] - N ELSE next + j[self]] + THEN /\ pc' = [pc EXCEPT ![self] = "ex5"] + ELSE /\ pc' = [pc EXCEPT ![self] = "ex7"] + ELSE /\ pc' = [pc EXCEPT ![self] = "ex8"] + /\ UNCHANGED << flag, next, empty, mutex, weakSem, first, j >> + +ex5(self) == /\ pc[self] = "ex5" + /\ LET n == IF next + j[self] > N THEN next + j[self] - N ELSE next + j[self] IN + /\ next' = n + /\ weakSem' = [weakSem EXCEPT ![n] = 1] + /\ j' = [j EXCEPT ![self] = N + 1] + /\ pc' = [pc EXCEPT ![self] = "ex6"] + /\ UNCHANGED << flag, empty, mutex, first >> + +ex6(self) == /\ pc[self] = "ex6" + /\ empty' = FALSE + /\ pc' = [pc EXCEPT ![self] = "ex4"] + /\ UNCHANGED << flag, next, mutex, weakSem, first, j >> + +ex7(self) == /\ pc[self] = "ex7" + /\ j' = [j EXCEPT ![self] = j[self] + 1] + /\ pc' = [pc EXCEPT ![self] = "ex4"] + /\ UNCHANGED << flag, next, empty, mutex, weakSem, first >> + +ex8(self) == /\ pc[self] = "ex8" + /\ mutex' = 1 + /\ pc' = [pc EXCEPT ![self] = "nc"] + /\ UNCHANGED << flag, next, empty, weakSem, first, j >> + +nc(self) == /\ pc[self] = "nc" + /\ TRUE + /\ pc' = [pc EXCEPT ![self] = "in1"] + /\ UNCHANGED << flag, next, empty, mutex, weakSem, first, j >> + +i(self) == in1(self) \/ in2(self) \/ in3(self) \/ in4(self) \/ in5(self) + \/ in6(self) \/ cs(self) \/ ex1(self) \/ ex2(self) + \/ ex3(self) \/ ex4(self) \/ ex5(self) \/ ex6(self) + \/ ex7(self) \/ ex8(self) \/ nc(self) + +Next == (\E self \in 1..N: i(self)) + \/ (* Disjunct to prevent deadlock on termination *) + ((\A self \in ProcSet: pc[self] = "Done") /\ UNCHANGED vars) + +Spec == Init /\ [][Next]_vars + +Termination == <>(\A self \in ProcSet: pc[self] = "Done") + +\* END TRANSLATION + +StarkSpec == /\ Spec + /\ \A self \in ProcSet: + /\ WF_vars(in1(self)) + /\ WF_vars(in2(self)) + /\ WF_vars(in3(self)) + /\ WF_vars(in4(self)) + /\ WF_vars(in5(self)) + /\ WF_vars(in6(self)) + /\ WF_vars(ex1(self)) + /\ WF_vars(ex2(self)) + /\ WF_vars(ex3(self)) + /\ WF_vars(ex4(self)) + /\ WF_vars(ex5(self)) + /\ WF_vars(ex6(self)) + /\ WF_vars(ex7(self)) + /\ WF_vars(ex8(self)) + /\ WF_vars(cs(self)) + +Mutex == \A p1, p2 \in ProcSet: (pc[p1] = "cs" /\ pc[p2] = "pc") => (p1 = p2) + +StarvationFree == \A p \in ProcSet: pc[p] = "in1" ~> pc[p] = "cs" +======================================================= + diff --git a/tlatools/test-model/pcal/SubSub.tla b/tlatools/test-model/pcal/SubSub.tla new file mode 100644 index 0000000000000000000000000000000000000000..9c8aca26c4b1a5a64127a5080b3022d7a88e313e --- /dev/null +++ b/tlatools/test-model/pcal/SubSub.tla @@ -0,0 +1,67 @@ +Test that "[self]" subscripts are added to expressions within subscripts. + +------------------------- MODULE SubSub ---------------------------- +EXTENDS Naturals, TLC + +ServerID == {1} +ObjectID == {1} + +-------------------------------------------------------------------------- +(********* +--algorithm SubSub + process proc \in 1..3 + variables x = [i \in {"a", "b"} |-> 0] , + y = [i \in 5..6 |-> "a"] , + z + begin + lab : z := 5 ; + y[z] := "b" ; + x[y[z]] := 1 ; + assert x[y[z]] = 1 ; + assert y[z] = "b" + end process + +end algorithm +*****) + +\******** BEGIN TRANSLATION ******** +CONSTANT defaultInitValue +VARIABLES pc, x, y, z + +vars == << pc, x, y, z >> + +ProcSet == (1..3) + +Init == (* Process proc *) + /\ x = [self \in 1..3 |-> [i \in {"a", "b"} |-> 0]] + /\ y = [self \in 1..3 |-> [i \in 5..6 |-> "a"]] + /\ z = [self \in 1..3 |-> defaultInitValue] + /\ pc = [self \in ProcSet |-> "lab"] + +lab(self) == /\ pc[self] = "lab" + /\ z' = [z EXCEPT ![self] = 5] + /\ y' = [y EXCEPT ![self][z'[self]] = "b"] + /\ x' = [x EXCEPT ![self][y'[self][z'[self]]] = 1] + /\ Assert(x'[self][y'[self][z'[self]]] = 1, + "Failure of assertion at line 20, column 12.") + /\ Assert(y'[self][z'[self]] = "b", + "Failure of assertion at line 21, column 12.") + /\ pc' = [pc EXCEPT ![self] = "Done"] + +proc(self) == lab(self) + +Next == (\E self \in 1..3: proc(self)) + \/ (* Disjunct to prevent deadlock on termination *) + ((\A self \in ProcSet: pc[self] = "Done") /\ UNCHANGED vars) + +Spec == Init /\ [][Next]_vars + +Termination == <>(\A self \in ProcSet: pc[self] = "Done") + +\******** END TRANSLATION ******** + +-------------------------------------------------------------------------- + + + +========================================================================== diff --git a/tlatools/test-model/pcal/SyncCons.cfg b/tlatools/test-model/pcal/SyncCons.cfg new file mode 100644 index 0000000000000000000000000000000000000000..a0e5c59a498af864a06c1a9b2ebc8143516de156 --- /dev/null +++ b/tlatools/test-model/pcal/SyncCons.cfg @@ -0,0 +1,8 @@ +SPECIFICATION Spec +\* Add statements after this line. +CONSTANTS N = 2 + t = 1 + Data = {0, 1} + bot = bot +INVARIANT C1 +INVARIANT C2 diff --git a/tlatools/test-model/pcal/SyncCons.tla b/tlatools/test-model/pcal/SyncCons.tla new file mode 100644 index 0000000000000000000000000000000000000000..c7c2a2ccf31d063d62c15dd62a61eebe6321d905 --- /dev/null +++ b/tlatools/test-model/pcal/SyncCons.tla @@ -0,0 +1,261 @@ +--algorithm SyncCons + variables clock = 0; + input \in Data; + round = [i \in 1..N |-> 0]; + buffer= { }; + crashed = { }; + +\***** Macros for sending and receiving messages + macro Send(i, j, msg) + begin + buffer := buffer \cup + {[from |-> i, + to |-> j, + msg |-> IF i \in crashed + THEN bot + ELSE msg]}; + end macro + + macro Receive(i, j, msg) + begin + when [from |-> i, + to |-> j, + msg |-> msg] \in buffer; + buffer := buffer + \ {[from |-> i, + to |-> j, + msg |-> msg]}; + end macro + +\***** Synchronous consensus protocol for crash failures +\***** A crashed process sends "bot" messages, which model timeouts + process Participant \in 1..N + variables output = bot; + procs = { }; + value = IF self = 1 + THEN input + ELSE bot; + recd = { }; + begin +s1: while round[self] < t + 1 do + when round[self] = clock; + procs := 1..N; +s2: while procs # { } do + with dest \in procs do + Send(self, dest, value); + procs := procs \ {dest}; + end with + end while; +s3: if self \notin crashed then + procs := 1..N; + recd := { }; +s4: while procs # { } do + with source \in Proc do + with data \in Data \cup {bot} do + Receive(source, self, data); + recd := recd \cup {data}; + procs := procs \ {source}; + end with + end with + end while; +s5: if recd \cap Data = { } + then value := bot; + else value := CHOOSE i \in Data: + i \in recd \cap Data; + end if; + end if; +s6: round[self] := round[self] + 1; + end while; + output := IF value = bot + THEN 0 + ELSE value; + end process; + +\***** Model of clock: ticks when all processes finish the current round + process Clock = N + 1 + begin +clock: while clock < t + 1 do + when \A i \in 1..N: round[i] = clock + 1; + clock := clock + 1; + end while; + end process; + +\***** Crashing processes + process Crash = N + 2 + begin +crash: while Cardinality(crashed) < t do + with x \in (1..N) \ crashed do + crashed := crashed \cup {x} + end with + end while + end process; + +end algorithm + +-------------------------------- MODULE SyncCons -------------------------------- +EXTENDS Naturals, FiniteSets, TLC + +CONSTANTS N, t, Data + +ASSUME N > t + +bot == CHOOSE v: v \notin Data + +Proc == 1..N + +\* BEGIN TRANSLATION +\* Label clock of process Clock at line 77 col 12 changed to clock_ +VARIABLES clock, input, round, buffer, crashed, pc, output, procs, value, + recd + +vars == << clock, input, round, buffer, crashed, pc, output, procs, value, + recd >> + +ProcSet == (1..N) \cup {N + 1} \cup {N + 2} + +Init == (* Global variables *) + /\ clock = 0 + /\ input \in Data + /\ round = [i \in 1..N |-> 0] + /\ buffer = { } + /\ crashed = { } + (* Process Participant *) + /\ output = [self \in 1..N |-> bot] + /\ procs = [self \in 1..N |-> { }] + /\ value = [self \in 1..N |-> IF self = 1 + THEN input + ELSE bot] + /\ recd = [self \in 1..N |-> { }] + /\ pc = [self \in ProcSet |-> CASE self \in 1..N -> "s1" + [] self = N + 1 -> "clock_" + [] self = N + 2 -> "crash"] + +s1(self) == /\ pc[self] = "s1" + /\ IF round[self] < t + 1 + THEN /\ round[self] = clock + /\ procs' = [procs EXCEPT ![self] = 1..N] + /\ pc' = [pc EXCEPT ![self] = "s2"] + /\ UNCHANGED output + ELSE /\ output' = [output EXCEPT ![self] = IF value[self] = bot + THEN 0 + ELSE value[self]] + /\ pc' = [pc EXCEPT ![self] = "Done"] + /\ procs' = procs + /\ UNCHANGED << clock, input, round, buffer, crashed, value, recd >> + +s2(self) == /\ pc[self] = "s2" + /\ IF procs[self] # { } + THEN /\ \E dest \in procs[self]: + /\ buffer' = ( buffer \cup + {[from |-> self, + to |-> dest, + msg |-> IF self \in crashed + THEN bot + ELSE value[self]]}) + /\ procs' = [procs EXCEPT ![self] = procs[self] \ {dest}] + /\ pc' = [pc EXCEPT ![self] = "s2"] + ELSE /\ pc' = [pc EXCEPT ![self] = "s3"] + /\ UNCHANGED << buffer, procs >> + /\ UNCHANGED << clock, input, round, crashed, output, value, recd >> + +s3(self) == /\ pc[self] = "s3" + /\ IF self \notin crashed + THEN /\ procs' = [procs EXCEPT ![self] = 1..N] + /\ recd' = [recd EXCEPT ![self] = { }] + /\ pc' = [pc EXCEPT ![self] = "s4"] + ELSE /\ pc' = [pc EXCEPT ![self] = "s6"] + /\ UNCHANGED << procs, recd >> + /\ UNCHANGED << clock, input, round, buffer, crashed, output, + value >> + +s4(self) == /\ pc[self] = "s4" + /\ IF procs[self] # { } + THEN /\ \E source \in Proc: + \E data \in Data \cup {bot}: + /\ [from |-> source, + to |-> self, + msg |-> data] \in buffer + /\ buffer' = buffer + \ {[from |-> source, + to |-> self, + msg |-> data]} + /\ recd' = [recd EXCEPT ![self] = recd[self] \cup {data}] + /\ procs' = [procs EXCEPT ![self] = procs[self] \ {source}] + /\ pc' = [pc EXCEPT ![self] = "s4"] + ELSE /\ pc' = [pc EXCEPT ![self] = "s5"] + /\ UNCHANGED << buffer, procs, recd >> + /\ UNCHANGED << clock, input, round, crashed, output, value >> + +s5(self) == /\ pc[self] = "s5" + /\ IF recd[self] \cap Data = { } + THEN /\ value' = [value EXCEPT ![self] = bot] + ELSE /\ value' = [value EXCEPT ![self] = CHOOSE i \in Data: + i \in recd[self] \cap Data] + /\ pc' = [pc EXCEPT ![self] = "s6"] + /\ UNCHANGED << clock, input, round, buffer, crashed, output, + procs, recd >> + +s6(self) == /\ pc[self] = "s6" + /\ round' = [round EXCEPT ![self] = round[self] + 1] + /\ pc' = [pc EXCEPT ![self] = "s1"] + /\ UNCHANGED << clock, input, buffer, crashed, output, procs, + value, recd >> + +Participant(self) == s1(self) \/ s2(self) \/ s3(self) \/ s4(self) + \/ s5(self) \/ s6(self) + +clock_ == /\ pc[N + 1] = "clock_" + /\ IF clock < t + 1 + THEN /\ \A i \in 1..N: round[i] = clock + 1 + /\ clock' = clock + 1 + /\ pc' = [pc EXCEPT ![N + 1] = "clock_"] + ELSE /\ pc' = [pc EXCEPT ![N + 1] = "Done"] + /\ clock' = clock + /\ UNCHANGED << input, round, buffer, crashed, output, procs, value, + recd >> + +Clock == clock_ + +crash == /\ pc[N + 2] = "crash" + /\ IF Cardinality(crashed) < t + THEN /\ \E x \in (1..N) \ crashed: + crashed' = (crashed \cup {x}) + /\ pc' = [pc EXCEPT ![N + 2] = "crash"] + ELSE /\ pc' = [pc EXCEPT ![N + 2] = "Done"] + /\ UNCHANGED crashed + /\ UNCHANGED << clock, input, round, buffer, output, procs, value, + recd >> + +Crash == crash + +Next == Clock \/ Crash + \/ (\E self \in 1..N: Participant(self)) + \/ (* Disjunct to prevent deadlock on termination *) + ((\A self \in ProcSet: pc[self] = "Done") /\ UNCHANGED vars) + +Spec == Init /\ [][Next]_vars + +Termination == <>(\A self \in ProcSet: pc[self] = "Done") + +\* END TRANSLATION + +C1 == \A p1, p2 \in (1..N) \ crashed: + (pc[p1] = "Done" /\ pc[p2] = "Done") => (output[p1] = output[p2]) + +C2 == \A p \in (1..N) \ crashed: + ( /\ 1 \notin crashed + /\ pc[1] = "Done" + /\ pc[p] = "Done" ) => (output[p] = input) + +THEOREM Spec => [] C1 /\ [] C2 +================================================================================= +On derosa.ucsd.edu (dual processor G5) +Model checking completed. No error has been found. + Estimates of the probability that TLC did not check all reachable states + because two distinct states had the same fingerprint: + calculated (optimistic): 8.312778857584233E-8 + based on the actual fingerprints: 8.652893187423173E-9 +3093758 states generated, 619842 distinct states found, 0 states left on queue. +The depth of the complete state graph search is 81. +181.963u 2.589s 2:47.51 110.1% 0+0k 2+119io 0pf+0w + diff --git a/tlatools/test-model/pcal/Test.tla b/tlatools/test-model/pcal/Test.tla new file mode 100644 index 0000000000000000000000000000000000000000..1b243a4e65ddbb88482c49a3af123d80698bf9cf --- /dev/null +++ b/tlatools/test-model/pcal/Test.tla @@ -0,0 +1,103 @@ + +--algorithm bug +variables x = 0 ; y = 0 ; +macro foo() + begin if TRUE then if TRUE then y := 22 ; + else y := 42 end if + else with a = 47 ; b = 77 ; do + y := 27 + end with end if + end macro +procedure Bar() + begin Q: skip ; + foo() ; + return + end procedure +begin L1 : y := 1 ; + L3 : skip ; + if x > 0 then foo() + else x := 17 end if; + L2 : assert x = 17 ; + foo() ; + assert y = 22 +end algorithm + +--------- MODULE Test ------- +(* \* xxxx *) + +\* (* *) +EXTENDS Sequences, Naturals, TLC + + +\* BEGIN TRANSLATION +VARIABLES x, y, pc, stack + +vars == << x, y, pc, stack >> + +Init == (* Global variables *) + /\ x = 0 + /\ y = 0 + /\ stack = << >> + /\ pc = "L1" + +Q == /\ pc = "Q" + /\ TRUE + /\ IF TRUE + THEN /\ IF TRUE + THEN /\ y' = 22 + ELSE /\ y' = 42 + ELSE /\ LET a == 47 IN + LET b == 77 IN + y' = 27 + /\ pc' = Head(stack).pc + /\ stack' = Tail(stack) + /\ x' = x + +Bar == Q + +L1 == /\ pc = "L1" + /\ y' = 1 + /\ pc' = "L3" + /\ UNCHANGED << x, stack >> + +L3 == /\ pc = "L3" + /\ TRUE + /\ IF x > 0 + THEN /\ IF TRUE + THEN /\ IF TRUE + THEN /\ y' = 22 + ELSE /\ y' = 42 + ELSE /\ LET a == 47 IN + LET b == 77 IN + y' = 27 + /\ x' = x + ELSE /\ x' = 17 + /\ y' = y + /\ pc' = "L2" + /\ stack' = stack + +L2 == /\ pc = "L2" + /\ Assert(x = 17, "Failure of assertion at line 20, column 13.") + /\ IF TRUE + THEN /\ IF TRUE + THEN /\ y' = 22 + ELSE /\ y' = 42 + ELSE /\ LET a == 47 IN + LET b == 77 IN + y' = 27 + /\ Assert(y' = 22, "Failure of assertion at line 22, column 13.") + /\ pc' = "Done" + /\ UNCHANGED << x, stack >> + +Next == Bar \/ L1 \/ L3 \/ L2 + \/ (* Disjunct to prevent deadlock on termination *) + (pc = "Done" /\ UNCHANGED vars) + +Spec == /\ Init /\ [][Next]_vars + /\ WF_vars(Next) + +Termination == <>(pc = "Done") + +\* END TRANSLATION + +============================================ diff --git a/tlatools/test-model/pcal/TestReplace.tla b/tlatools/test-model/pcal/TestReplace.tla new file mode 100644 index 0000000000000000000000000000000000000000..386a910f665d148779cbb6d89c26da94c4042ace --- /dev/null +++ b/tlatools/test-model/pcal/TestReplace.tla @@ -0,0 +1,249 @@ +------------------ MODULE TestReplace ----------------- +EXTENDS Naturals, TLC, Sequences + + +(********************** +--algorithm TestReplace +macro IncrementX(u) + begin X := X + u + end macro + +procedure Bar(u, v) + begin a: assert u = v; + return; + end procedure + +procedure Foo1(u, v) + variable X = 0; Y = X ; + begin + a : assert Y = X ; + b : while Y = X do + Y := Y - 1; + end while ; + assert Y = X - 1; + with id = X do assert id = 0 end with ; + if X = 0 + then c: call Bar(X, 0) + else assert FALSE + end if ; + d : print <<X, " = 0">> ; + IncrementX(X+1) ; + assert X = 1 ; + e: return +end procedure + +procedure Foo2(u, v) + variable X = 9; Z = X ; + begin + a : assert Z = X ; + b : while Z = X do + Z := Z - 1; + end while ; + assert Z = X - 1; + with id = X do assert id = 9 end with ; + if X = 9 + then c: call Bar(X, 9) + + else assert FALSE + end if ; + d : print <<X, " = 9">> ; + IncrementX(X+1) ; + assert X = 19 ; + e: return +end procedure + +begin +start : call Foo1(1, 2) ; +b : call Foo2(1, 2) ; +end algorithm + +***********************) + +\* BEGIN TRANSLATION +\* Label a of procedure Bar at line 12 col 11 changed to a_ +\* Label a of procedure Foo1 at line 19 col 6 changed to a_F +\* Label b of procedure Foo1 at line 20 col 6 changed to b_ +\* Label c of procedure Foo1 at line 26 col 17 changed to c_ +\* Label d of procedure Foo1 at line 29 col 6 changed to d_ +\* Label e of procedure Foo1 at line 32 col 6 changed to e_ +\* Label b of procedure Foo2 at line 39 col 6 changed to b_F +\* Procedure variable X of procedure Foo1 at line 17 col 11 changed to X_ +\* Parameter u of procedure Bar at line 11 col 15 changed to u_ +\* Parameter v of procedure Bar at line 11 col 18 changed to v_ +\* Parameter u of procedure Foo1 at line 16 col 16 changed to u_F +\* Parameter v of procedure Foo1 at line 16 col 19 changed to v_F +CONSTANT defaultInitValue +VARIABLES pc, stack, u_, v_, u_F, v_F, X_, Y, u, v, X, Z + +vars == << pc, stack, u_, v_, u_F, v_F, X_, Y, u, v, X, Z >> + +Init == (* Procedure Bar *) + /\ u_ = defaultInitValue + /\ v_ = defaultInitValue + (* Procedure Foo1 *) + /\ u_F = defaultInitValue + /\ v_F = defaultInitValue + /\ X_ = 0 + /\ Y = X_ + (* Procedure Foo2 *) + /\ u = defaultInitValue + /\ v = defaultInitValue + /\ X = 9 + /\ Z = X + /\ stack = << >> + /\ pc = "start" + +a_ == /\ pc = "a_" + /\ Assert(u_ = v_, "Failure of assertion at line 12, column 11.") + /\ pc' = Head(stack).pc + /\ u_' = Head(stack).u_ + /\ v_' = Head(stack).v_ + /\ stack' = Tail(stack) + /\ UNCHANGED << u_F, v_F, X_, Y, u, v, X, Z >> + +Bar == a_ + +a_F == /\ pc = "a_F" + /\ Assert(Y = X_, "Failure of assertion at line 19, column 6.") + /\ pc' = "b_" + /\ UNCHANGED << stack, u_, v_, u_F, v_F, X_, Y, u, v, X, Z >> + +b_ == /\ pc = "b_" + /\ IF Y = X_ + THEN /\ Y' = Y - 1 + /\ pc' = "b_" + ELSE /\ Assert(Y = X_ - 1, + "Failure of assertion at line 23, column 6.") + /\ LET id == X_ IN + Assert(id = 0, + "Failure of assertion at line 24, column 21.") + /\ IF X_ = 0 + THEN /\ pc' = "c_" + ELSE /\ Assert(FALSE, + "Failure of assertion at line 27, column 14.") + /\ pc' = "d_" + /\ Y' = Y + /\ UNCHANGED << stack, u_, v_, u_F, v_F, X_, u, v, X, Z >> + +c_ == /\ pc = "c_" + /\ /\ stack' = << [ procedure |-> "Bar", + pc |-> "d_", + u_ |-> u_, + v_ |-> v_ ] >> + \o stack + /\ u_' = X_ + /\ v_' = 0 + /\ pc' = "a_" + /\ UNCHANGED << u_F, v_F, X_, Y, u, v, X, Z >> + +d_ == /\ pc = "d_" + /\ PrintT(<<X_, " = 0">>) + /\ X_' = X_ + (X_+1) + /\ Assert(X_' = 1, "Failure of assertion at line 31, column 6.") + /\ pc' = "e_" + /\ UNCHANGED << stack, u_, v_, u_F, v_F, Y, u, v, X, Z >> + +e_ == /\ pc = "e_" + /\ pc' = Head(stack).pc + /\ X_' = Head(stack).X_ + /\ Y' = Head(stack).Y + /\ u_F' = Head(stack).u_F + /\ v_F' = Head(stack).v_F + /\ stack' = Tail(stack) + /\ UNCHANGED << u_, v_, u, v, X, Z >> + +Foo1 == a_F \/ b_ \/ c_ \/ d_ \/ e_ + +a == /\ pc = "a" + /\ Assert(Z = X, "Failure of assertion at line 38, column 6.") + /\ pc' = "b_F" + /\ UNCHANGED << stack, u_, v_, u_F, v_F, X_, Y, u, v, X, Z >> + +b_F == /\ pc = "b_F" + /\ IF Z = X + THEN /\ Z' = Z - 1 + /\ pc' = "b_F" + ELSE /\ Assert(Z = X - 1, + "Failure of assertion at line 42, column 6.") + /\ LET id == X IN + Assert(id = 9, + "Failure of assertion at line 43, column 21.") + /\ IF X = 9 + THEN /\ pc' = "c" + ELSE /\ Assert(FALSE, + "Failure of assertion at line 47, column 14.") + /\ pc' = "d" + /\ Z' = Z + /\ UNCHANGED << stack, u_, v_, u_F, v_F, X_, Y, u, v, X >> + +c == /\ pc = "c" + /\ /\ stack' = << [ procedure |-> "Bar", + pc |-> "d", + u_ |-> u_, + v_ |-> v_ ] >> + \o stack + /\ u_' = X + /\ v_' = 9 + /\ pc' = "a_" + /\ UNCHANGED << u_F, v_F, X_, Y, u, v, X, Z >> + +d == /\ pc = "d" + /\ PrintT(<<X, " = 9">>) + /\ X' = X + (X+1) + /\ Assert(X' = 19, "Failure of assertion at line 51, column 6.") + /\ pc' = "e" + /\ UNCHANGED << stack, u_, v_, u_F, v_F, X_, Y, u, v, Z >> + +e == /\ pc = "e" + /\ pc' = Head(stack).pc + /\ X' = Head(stack).X + /\ Z' = Head(stack).Z + /\ u' = Head(stack).u + /\ v' = Head(stack).v + /\ stack' = Tail(stack) + /\ UNCHANGED << u_, v_, u_F, v_F, X_, Y >> + +Foo2 == a \/ b_F \/ c \/ d \/ e + +start == /\ pc = "start" + /\ /\ stack' = << [ procedure |-> "Foo1", + pc |-> "b", + X_ |-> X_, + Y |-> Y, + u_F |-> u_F, + v_F |-> v_F ] >> + \o stack + /\ u_F' = 1 + /\ v_F' = 2 + /\ X_' = 0 + /\ Y' = X_' + /\ pc' = "a_F" + /\ UNCHANGED << u_, v_, u, v, X, Z >> + +b == /\ pc = "b" + /\ /\ stack' = << [ procedure |-> "Foo2", + pc |-> "Done", + X |-> X, + Z |-> Z, + u |-> u, + v |-> v ] >> + \o stack + /\ u' = 1 + /\ v' = 2 + /\ X' = 9 + /\ Z' = X' + /\ pc' = "a" + /\ UNCHANGED << u_, v_, u_F, v_F, X_, Y >> + +Next == Bar \/ Foo1 \/ Foo2 \/ start \/ b + \/ (* Disjunct to prevent deadlock on termination *) + (pc = "Done" /\ UNCHANGED vars) + +Spec == Init /\ [][Next]_vars + +Termination == <>(pc = "Done") + +\* END TRANSLATION + +================================================== + diff --git a/tlatools/test-model/pcal/TestTabs.tla b/tlatools/test-model/pcal/TestTabs.tla new file mode 100644 index 0000000000000000000000000000000000000000..08c7f1b305bdeb0b66867b9c503778a7355b544f --- /dev/null +++ b/tlatools/test-model/pcal/TestTabs.tla @@ -0,0 +1,49 @@ +------------------------------ MODULE TestTabs ------------------------------ +\* Warning: there are evil tabs in this file. +EXTENDS Naturals, TLC +(* +--algorithm TestTabs + variables x = 0 ; + begin +l: x := IF /\ \A i \in {1} : 1 + 1 = 2 + /\ \A i \in {1} : 2 + 2 = 4 + /\ \/ \A i \in {1} : + 1 = 0 + \/ \A i \in {1} : 1 = 2 + \/ \A i \in {1} : 1 = 1 + THEN 1 + ELSE 0 ; + assert x = 1 ; + end algorithm +*) +(* BEGIN TRANSLATION *) +VARIABLES x, pc + +vars == << x, pc >> + +Init == (* Global variables *) + /\ x = 0 + /\ pc = "l" + +l == /\ pc = "l" + /\ x' = (IF /\ \A i \in {1} : 1 + 1 = 2 + /\ \A i \in {1} : 2 + 2 = 4 + /\ \/ \A i \in {1} : + 1 = 0 + \/ \A i \in {1} : 1 = 2 + \/ \A i \in {1} : 1 = 1 + THEN 1 + ELSE 0) + /\ Assert(x' = 1, "Failure of assertion at line 16, column 5.") + /\ pc' = "Done" + +Next == l + \/ (* Disjunct to prevent deadlock on termination *) + (pc = "Done" /\ UNCHANGED vars) + +Spec == Init /\ [][Next]_vars + +Termination == <>(pc = "Done") + +(* END TRANSLATION *) +============================================================================= diff --git a/tlatools/test-model/pcal/TreeBarrier.cfg b/tlatools/test-model/pcal/TreeBarrier.cfg new file mode 100644 index 0000000000000000000000000000000000000000..ef9c9f9df75ac1792e7e68265b19e81d981b7b21 --- /dev/null +++ b/tlatools/test-model/pcal/TreeBarrier.cfg @@ -0,0 +1,5 @@ +SPECIFICATION Spec +\* Add statements after this line. +CONSTANT exp = 2 +INVARIANT SafeBarrier +PROPERTY LiveBarrier diff --git a/tlatools/test-model/pcal/TreeBarrier.tla b/tlatools/test-model/pcal/TreeBarrier.tla new file mode 100644 index 0000000000000000000000000000000000000000..b1f3a879a536cfa27b99ed68a91fb4f611f7f712 --- /dev/null +++ b/tlatools/test-model/pcal/TreeBarrier.tla @@ -0,0 +1,137 @@ +--algorithm TreeBarrier + variables arrived = [i \in 1..2 |-> [j \in 1..N |-> 0]]; + proceed = [i \in 1..2 |-> [j \in 1..N |-> 0]]; + process i \in 1..N + variables b = 1; + p = 0; + begin +prc: while (TRUE) do +comp: skip; +b1: if 2*self \leq N then +b2: when arrived[b][2*self] = 1; arrived[b][2*self] := 0; +b3: when arrived[b][2*self + 1] = 1; arrived[b][2*self + 1] := 0; + end if; +b4: arrived[b][self] := 1; +b5: if self = 1 then + p := 1; +b6: while (p \leq N) do +b7: proceed[b][p] := 1; + p := p + 1; + end while; + end if; +b8: when proceed[b][self] = 1; proceed[b][self] := 0; +b9: b := IF b = 1 THEN 2 ELSE 1; + end while; + end process; +end algorithm + +------------------------ MODULE TreeBarrier ------------------------ + +EXTENDS Naturals, Sequences +CONSTANT exp +N == 2^exp-1 + +-------------------------------------------------------------------- + +\* BEGIN TRANSLATION +VARIABLES arrived, proceed, pc, b, p + +vars == << arrived, proceed, pc, b, p >> + +ProcSet == (1..N) + +Init == (* Global variables *) + /\ arrived = [i \in 1..2 |-> [j \in 1..N |-> 0]] + /\ proceed = [i \in 1..2 |-> [j \in 1..N |-> 0]] + (* Process i *) + /\ b = [self \in 1..N |-> 1] + /\ p = [self \in 1..N |-> 0] + /\ pc = [self \in ProcSet |-> "prc"] + +prc(self) == /\ pc[self] = "prc" + /\ pc' = [pc EXCEPT ![self] = "comp"] + /\ UNCHANGED << arrived, proceed, b, p >> + +comp(self) == /\ pc[self] = "comp" + /\ TRUE + /\ pc' = [pc EXCEPT ![self] = "b1"] + /\ UNCHANGED << arrived, proceed, b, p >> + +b1(self) == /\ pc[self] = "b1" + /\ IF 2*self \leq N + THEN /\ pc' = [pc EXCEPT ![self] = "b2"] + ELSE /\ pc' = [pc EXCEPT ![self] = "b4"] + /\ UNCHANGED << arrived, proceed, b, p >> + +b2(self) == /\ pc[self] = "b2" + /\ arrived[b[self]][2*self] = 1 + /\ arrived' = [arrived EXCEPT ![b[self]][2*self] = 0] + /\ pc' = [pc EXCEPT ![self] = "b3"] + /\ UNCHANGED << proceed, b, p >> + +b3(self) == /\ pc[self] = "b3" + /\ arrived[b[self]][2*self + 1] = 1 + /\ arrived' = [arrived EXCEPT ![b[self]][2*self + 1] = 0] + /\ pc' = [pc EXCEPT ![self] = "b4"] + /\ UNCHANGED << proceed, b, p >> + +b4(self) == /\ pc[self] = "b4" + /\ arrived' = [arrived EXCEPT ![b[self]][self] = 1] + /\ pc' = [pc EXCEPT ![self] = "b5"] + /\ UNCHANGED << proceed, b, p >> + +b5(self) == /\ pc[self] = "b5" + /\ IF self = 1 + THEN /\ p' = [p EXCEPT ![self] = 1] + /\ pc' = [pc EXCEPT ![self] = "b6"] + ELSE /\ pc' = [pc EXCEPT ![self] = "b8"] + /\ p' = p + /\ UNCHANGED << arrived, proceed, b >> + +b6(self) == /\ pc[self] = "b6" + /\ IF (p[self] \leq N) + THEN /\ pc' = [pc EXCEPT ![self] = "b7"] + ELSE /\ pc' = [pc EXCEPT ![self] = "b8"] + /\ UNCHANGED << arrived, proceed, b, p >> + +b7(self) == /\ pc[self] = "b7" + /\ proceed' = [proceed EXCEPT ![b[self]][p[self]] = 1] + /\ p' = [p EXCEPT ![self] = p[self] + 1] + /\ pc' = [pc EXCEPT ![self] = "b6"] + /\ UNCHANGED << arrived, b >> + +b8(self) == /\ pc[self] = "b8" + /\ proceed[b[self]][self] = 1 + /\ proceed' = [proceed EXCEPT ![b[self]][self] = 0] + /\ pc' = [pc EXCEPT ![self] = "b9"] + /\ UNCHANGED << arrived, b, p >> + +b9(self) == /\ pc[self] = "b9" + /\ b' = [b EXCEPT ![self] = IF b[self] = 1 THEN 2 ELSE 1] + /\ pc' = [pc EXCEPT ![self] = "prc"] + /\ UNCHANGED << arrived, proceed, p >> + +i(self) == prc(self) \/ comp(self) \/ b1(self) \/ b2(self) \/ b3(self) + \/ b4(self) \/ b5(self) \/ b6(self) \/ b7(self) \/ b8(self) + \/ b9(self) + +Next == (\E self \in 1..N: i(self)) + \/ (* Disjunct to prevent deadlock on termination *) + ((\A self \in ProcSet: pc[self] = "Done") /\ UNCHANGED vars) + +Spec == /\ Init /\ [][Next]_vars + /\ WF_vars(Next) + +Termination == <>(\A self \in ProcSet: pc[self] = "Done") + +\* END TRANSLATION + + +SafeBarrier == \A p1, p2 \in ProcSet: + ((pc[p1] = "comp") /\ (pc[p2] = "comp")) => (b[p1] = b[p2]) + +LiveBarrier == \A p1 \in ProcSet: + /\ (b[p1] = 1) ~> (b[p1] = 2) + /\ (b[p1] = 2) ~> (b[p1] = 1) + +==================================================================== diff --git a/tlatools/test-model/pcal/ULBakery.cfg b/tlatools/test-model/pcal/ULBakery.cfg new file mode 100644 index 0000000000000000000000000000000000000000..9209a00c6288aab93977bdf9e85b204efd16702f --- /dev/null +++ b/tlatools/test-model/pcal/ULBakery.cfg @@ -0,0 +1,7 @@ +SPECIFICATION Spec +\* Add statements after this line. +CONSTANTS NumProcs = 2 + MaxNum = 3 +INVARIANT Invariant +CONSTRAINT Constraint + diff --git a/tlatools/test-model/pcal/ULCallReturn1.tla b/tlatools/test-model/pcal/ULCallReturn1.tla new file mode 100644 index 0000000000000000000000000000000000000000..b4eebdd55642ed4c2aeeae5b1b73071d8866033d --- /dev/null +++ b/tlatools/test-model/pcal/ULCallReturn1.tla @@ -0,0 +1,122 @@ +------------------------------ MODULE ULCallReturn1 ------------------------- +EXTENDS Sequences, Naturals, TLC + +(* + --algorithm CallReturn1 + procedure Proc1(arg1 = 0) + variable u = 1 ; + begin (*p1 :*) u := 2 ; + call Proc2 ( 2 * u ) ; + (*p2 :*) assert u = 2; + assert arg1 = 4 ; + call Proc2 ( 2 * u + 1 ) ; + return ; + end procedure + procedure Proc2(arg2 = 0) + variable v = 42 ; + begin (*q1 :*) assert v = 42; + assert arg2 \in {4, 5} ; + call Proc3 ( v + arg2 ) ; + return ; + end procedure + procedure Proc3(arg3 = 0) + begin (*r1 :*) assert arg3 \in {46, 47} ; + return ; + end procedure + begin + (*a1 :*) call Proc1( 4 ) ; + end algorithm + +*) + +(***** BEGIN TRANSLATION ***) +VARIABLES pc, stack, arg1, u, arg2, v, arg3 + +vars == << pc, stack, arg1, u, arg2, v, arg3 >> + +Init == (* Procedure Proc1 *) + /\ arg1 = 0 + /\ u = 1 + (* Procedure Proc2 *) + /\ arg2 = 0 + /\ v = 42 + (* Procedure Proc3 *) + /\ arg3 = 0 + /\ stack = << >> + /\ pc = "Lbl_5" + +Lbl_1 == /\ pc = "Lbl_1" + /\ u' = 2 + /\ /\ arg2' = 2 * u' + /\ stack' = << [ procedure |-> "Proc2", + pc |-> "Lbl_2", + v |-> v, + arg2 |-> arg2 ] >> + \o stack + /\ v' = 42 + /\ pc' = "Lbl_3" + /\ UNCHANGED << arg1, arg3 >> + +Lbl_2 == /\ pc = "Lbl_2" + /\ Assert(u = 2, "Failure of assertion at line 10, column 22.") + /\ Assert(arg1 = 4, "Failure of assertion at line 11, column 18.") + /\ /\ arg2' = 2 * u + 1 + /\ stack' = << [ procedure |-> "Proc2", + pc |-> Head(stack).pc, + v |-> v, + arg2 |-> arg2 ] >> + \o Tail(stack) + /\ u' = Head(stack).u + /\ v' = 42 + /\ pc' = "Lbl_3" + /\ UNCHANGED << arg1, arg3 >> + +Proc1 == Lbl_1 \/ Lbl_2 + +Lbl_3 == /\ pc = "Lbl_3" + /\ Assert(v = 42, "Failure of assertion at line 17, column 22.") + /\ Assert(arg2 \in {4, 5}, + "Failure of assertion at line 18, column 18.") + /\ /\ arg3' = v + arg2 + /\ stack' = << [ procedure |-> "Proc3", + pc |-> Head(stack).pc, + arg3 |-> arg3 ] >> + \o Tail(stack) + /\ v' = Head(stack).v + /\ pc' = "Lbl_4" + /\ UNCHANGED << arg1, u, arg2 >> + +Proc2 == Lbl_3 + +Lbl_4 == /\ pc = "Lbl_4" + /\ Assert(arg3 \in {46, 47}, + "Failure of assertion at line 23, column 22.") + /\ pc' = Head(stack).pc + /\ arg3' = Head(stack).arg3 + /\ stack' = Tail(stack) + /\ UNCHANGED << arg1, u, arg2, v >> + +Proc3 == Lbl_4 + +Lbl_5 == /\ pc = "Lbl_5" + /\ /\ arg1' = 4 + /\ stack' = << [ procedure |-> "Proc1", + pc |-> "Done", + u |-> u, + arg1 |-> arg1 ] >> + \o stack + /\ u' = 1 + /\ pc' = "Lbl_1" + /\ UNCHANGED << arg2, v, arg3 >> + +Next == Proc1 \/ Proc2 \/ Proc3 \/ Lbl_5 + \/ (* Disjunct to prevent deadlock on termination *) + (pc = "Done" /\ UNCHANGED vars) + +Spec == /\ Init /\ [][Next]_vars + /\ WF_vars(Next) + +Termination == <>(pc = "Done") + +(***** END TRANSLATION ***) +============================================================================= diff --git a/tlatools/test-model/pcal/ULEuclid.cfg b/tlatools/test-model/pcal/ULEuclid.cfg new file mode 100644 index 0000000000000000000000000000000000000000..d3f674e358ba428b8a060e8a4d4eccc010228b50 --- /dev/null +++ b/tlatools/test-model/pcal/ULEuclid.cfg @@ -0,0 +1,6 @@ +SPECIFICATION Spec +PROPERTY Termination +\* Add statements after this line. +INVARIANT Invariant +CONSTANTS MaxNum = 20 + diff --git a/tlatools/test-model/pcal/ULEuclid.tla b/tlatools/test-model/pcal/ULEuclid.tla new file mode 100644 index 0000000000000000000000000000000000000000..80c179322e6ee1a8d4e3cf47c541d3486065c9cc --- /dev/null +++ b/tlatools/test-model/pcal/ULEuclid.tla @@ -0,0 +1,90 @@ +------------------------------ MODULE ULEuclid ------------------------------- +(***************************************************************************) +(* Euclid's algorithm. *) +(***************************************************************************) + +EXTENDS Naturals, TLC + +CONSTANT MaxNum + +ASSUME MaxNum > 0 + +ASSUME /\ Print(<<"Testing Euclid's algorithm on all numbers between 1 and ", + MaxNum>>, TRUE) + /\ Print("Most time spent evaluating naive definition of GCD for test", + TRUE) + +(****** +Adapted from page 8 of the 2nd edition of Robert Sedgewick's "Algorithms". + +--algorithm Euclid + variables u_ini \in 1 .. MaxNum ; + v_ini \in 1 .. MaxNum ; + u = u_ini ; v = v_ini ; + begin (*a :*) while u # 0 + do if u < v then u := v || v := u ; end if ; + (* b: *) u := u - v; + end while ; + assert v = GCD(u_ini, v_ini) ; + \* print <<"gcd of ", u_ini, v_ini, " equals ", v >> ; + end algorithm + +*) + +GCD(x, y) == CHOOSE i \in (1..x) \cap (1..y) : + /\ x % i = 0 + /\ y % i = 0 + /\ \A j \in (1..x) \cap (1..y) : + /\ x % j = 0 + /\ y % j = 0 + => i \geq j + + + +(***** BEGIN TRANSLATION ***) +VARIABLES u_ini, v_ini, u, v, pc + +vars == << u_ini, v_ini, u, v, pc >> + +Init == (* Global variables *) + /\ u_ini \in 1 .. MaxNum + /\ v_ini \in 1 .. MaxNum + /\ u = u_ini + /\ v = v_ini + /\ pc = "Lbl_1" + +Lbl_1 == /\ pc = "Lbl_1" + /\ IF u # 0 + THEN /\ IF u < v + THEN /\ /\ u' = v + /\ v' = u + ELSE /\ TRUE + /\ UNCHANGED << u, v >> + /\ pc' = "Lbl_2" + ELSE /\ Assert(v = GCD(u_ini, v_ini), + "Failure of assertion at line 28, column 13.") + /\ pc' = "Done" + /\ UNCHANGED << u, v >> + /\ UNCHANGED << u_ini, v_ini >> + +Lbl_2 == /\ pc = "Lbl_2" + /\ u' = u - v + /\ pc' = "Lbl_1" + /\ UNCHANGED << u_ini, v_ini, v >> + +Next == Lbl_1 \/ Lbl_2 + \/ (* Disjunct to prevent deadlock on termination *) + (pc = "Done" /\ UNCHANGED vars) + +Spec == /\ Init /\ [][Next]_vars + /\ WF_vars(Next) + +Termination == <>(pc = "Done") + +(***** END TRANSLATION ***) + + +Invariant == + (pc = "Done") => (v = GCD(u_ini, v_ini)) + +============================================================================= diff --git a/tlatools/test-model/pcal/ULEvenOdd.cfg b/tlatools/test-model/pcal/ULEvenOdd.cfg new file mode 100644 index 0000000000000000000000000000000000000000..88725dab9155d12e1fbca4531e4f30063b7dc81e --- /dev/null +++ b/tlatools/test-model/pcal/ULEvenOdd.cfg @@ -0,0 +1,5 @@ +SPECIFICATION Spec +PROPERTY Termination +\* Add statements after this line. +CONSTANT N = 6 + diff --git a/tlatools/test-model/pcal/ULEvenOdd.tla b/tlatools/test-model/pcal/ULEvenOdd.tla new file mode 100644 index 0000000000000000000000000000000000000000..dc5d6733f44e18e9235b3e0321239852c5dfb085 --- /dev/null +++ b/tlatools/test-model/pcal/ULEvenOdd.tla @@ -0,0 +1,114 @@ +--algorithm EvenOdd +variable result = FALSE; +procedure Even (xEven = 0) +begin + (*Even1:*) if xEven = 0 then + result := TRUE; + return; + else + call Odd(xEven - 1); + return; + end if; + end procedure +procedure Odd (xOdd = 0) +begin + (*Odd1:*) if xOdd = 0 then result := FALSE; + else call Even(xOdd - 1); + end if; + (*Odd2:*) return; + end procedure +begin + (*a1:*) call Even(N); + (*a2:*) print result; +end algorithm + +--------------- MODULE ULEvenOdd --------------- + +EXTENDS Naturals, Sequences, TLC + +CONSTANT N + +---------------------------------------------- + + +\* BEGIN TRANSLATION +VARIABLES result, pc, stack, xEven, xOdd + +vars == << result, pc, stack, xEven, xOdd >> + +Init == (* Global variables *) + /\ result = FALSE + (* Procedure Even *) + /\ xEven = 0 + (* Procedure Odd *) + /\ xOdd = 0 + /\ stack = << >> + /\ pc = "Lbl_4" + +Lbl_1 == /\ pc = "Lbl_1" + /\ IF xEven = 0 + THEN /\ result' = TRUE + /\ pc' = Head(stack).pc + /\ xEven' = Head(stack).xEven + /\ stack' = Tail(stack) + /\ xOdd' = xOdd + ELSE /\ /\ stack' = << [ procedure |-> "Odd", + pc |-> Head(stack).pc, + xOdd |-> xOdd ] >> + \o Tail(stack) + /\ xOdd' = xEven - 1 + /\ pc' = "Lbl_2" + /\ UNCHANGED << result, xEven >> + +Even == Lbl_1 + +Lbl_2 == /\ pc = "Lbl_2" + /\ IF xOdd = 0 + THEN /\ result' = FALSE + /\ pc' = "Lbl_3" + /\ UNCHANGED << stack, xEven >> + ELSE /\ /\ stack' = << [ procedure |-> "Even", + pc |-> "Lbl_3", + xEven |-> xEven ] >> + \o stack + /\ xEven' = xOdd - 1 + /\ pc' = "Lbl_1" + /\ UNCHANGED result + /\ xOdd' = xOdd + +Lbl_3 == /\ pc = "Lbl_3" + /\ pc' = Head(stack).pc + /\ xOdd' = Head(stack).xOdd + /\ stack' = Tail(stack) + /\ UNCHANGED << result, xEven >> + +Odd == Lbl_2 \/ Lbl_3 + +Lbl_4 == /\ pc = "Lbl_4" + /\ /\ stack' = << [ procedure |-> "Even", + pc |-> "Lbl_5", + xEven |-> xEven ] >> + \o stack + /\ xEven' = N + /\ pc' = "Lbl_1" + /\ UNCHANGED << result, xOdd >> + +Lbl_5 == /\ pc = "Lbl_5" + /\ PrintT(result) + /\ pc' = "Done" + /\ UNCHANGED << result, stack, xEven, xOdd >> + +Next == Even \/ Odd \/ Lbl_4 \/ Lbl_5 + \/ (* Disjunct to prevent deadlock on termination *) + (pc = "Done" /\ UNCHANGED vars) + +Spec == /\ Init /\ [][Next]_vars + /\ WF_vars(Next) + +Termination == <>(pc = "Done") + +\* END TRANSLATION + +============================================== + + diff --git a/tlatools/test-model/pcal/ULFactorial2.tla b/tlatools/test-model/pcal/ULFactorial2.tla new file mode 100644 index 0000000000000000000000000000000000000000..f4bcb3cb3770f524109f843f57a7f6e327bb5098 --- /dev/null +++ b/tlatools/test-model/pcal/ULFactorial2.tla @@ -0,0 +1,124 @@ +-------------------------- MODULE ULFactorial2 --------------------------- +EXTENDS Naturals, Sequences, TLC + +(*************************************************************************** +Factorial Algorithm with 2 procedures + +--algorithm Factorial + variable result = 1; + procedure FactProc(arg1 = 0 ) + variable u = 1 ; + begin (*p1 :*) if arg1 = 0 + then return; + else result := result * arg1; + call FactProc2 ( arg1 - 1 ) ; + (*b:*) return; + end if; + end procedure + procedure FactProc2(arg2 = 0) + variable u2 = 1 ; + begin (*p12 :*) if arg2 = 0 + then return; + else result := result * arg2; + call FactProc ( arg2 - 1 ) ; + return; + end if; + end procedure + begin + (*a1 :*) call FactProc( 5 ) ; + (*a2 :*) if result = 120 then print <<"Correct =", 120>>; + else print <<"Error = ", result>> ; + end if; + end algorithm +***************************************************************************) + +(************** BEGIN TRANSLATION ********************) +VARIABLES result, pc, stack, arg1, u, arg2, u2 + +vars == << result, pc, stack, arg1, u, arg2, u2 >> + +Init == (* Global variables *) + /\ result = 1 + (* Procedure FactProc *) + /\ arg1 = 0 + /\ u = 1 + (* Procedure FactProc2 *) + /\ arg2 = 0 + /\ u2 = 1 + /\ stack = << >> + /\ pc = "Lbl_3" + +Lbl_1 == /\ pc = "Lbl_1" + /\ IF arg1 = 0 + THEN /\ pc' = Head(stack).pc + /\ u' = Head(stack).u + /\ arg1' = Head(stack).arg1 + /\ stack' = Tail(stack) + /\ UNCHANGED << result, arg2, u2 >> + ELSE /\ result' = result * arg1 + /\ /\ arg2' = arg1 - 1 + /\ stack' = << [ procedure |-> "FactProc2", + pc |-> Head(stack).pc, + u2 |-> u2, + arg2 |-> arg2 ] >> + \o Tail(stack) + /\ u' = Head(stack).u + /\ u2' = 1 + /\ pc' = "Lbl_2" + /\ arg1' = arg1 + +FactProc == Lbl_1 + +Lbl_2 == /\ pc = "Lbl_2" + /\ IF arg2 = 0 + THEN /\ pc' = Head(stack).pc + /\ u2' = Head(stack).u2 + /\ arg2' = Head(stack).arg2 + /\ stack' = Tail(stack) + /\ UNCHANGED << result, arg1, u >> + ELSE /\ result' = result * arg2 + /\ /\ arg1' = arg2 - 1 + /\ stack' = << [ procedure |-> "FactProc", + pc |-> Head(stack).pc, + u |-> u, + arg1 |-> arg1 ] >> + \o Tail(stack) + /\ u2' = Head(stack).u2 + /\ u' = 1 + /\ pc' = "Lbl_1" + /\ arg2' = arg2 + +FactProc2 == Lbl_2 + +Lbl_3 == /\ pc = "Lbl_3" + /\ /\ arg1' = 5 + /\ stack' = << [ procedure |-> "FactProc", + pc |-> "Lbl_4", + u |-> u, + arg1 |-> arg1 ] >> + \o stack + /\ u' = 1 + /\ pc' = "Lbl_1" + /\ UNCHANGED << result, arg2, u2 >> + +Lbl_4 == /\ pc = "Lbl_4" + /\ IF result = 120 + THEN /\ PrintT(<<"Correct =", 120>>) + ELSE /\ PrintT(<<"Error = ", result>>) + /\ pc' = "Done" + /\ UNCHANGED << result, stack, arg1, u, arg2, u2 >> + +Next == FactProc \/ FactProc2 \/ Lbl_3 \/ Lbl_4 + \/ (* Disjunct to prevent deadlock on termination *) + (pc = "Done" /\ UNCHANGED vars) + +Spec == /\ Init /\ [][Next]_vars + /\ WF_vars(Next) + +Termination == <>(pc = "Done") + +(************* END TRANSLATION ********************) + + +Invariant == result \in Nat +============================================================================= diff --git a/tlatools/test-model/pcal/ULQuicksortMacro.cfg b/tlatools/test-model/pcal/ULQuicksortMacro.cfg new file mode 100644 index 0000000000000000000000000000000000000000..0ebf8fe12d66c62cbd54cf80207efc9dda94587b --- /dev/null +++ b/tlatools/test-model/pcal/ULQuicksortMacro.cfg @@ -0,0 +1,5 @@ +SPECIFICATION Spec +PROPERTY Termination +\* Add statements after this line. +CONSTANTS ArrayLen = 3 +INVARIANT Invariant diff --git a/tlatools/test-model/pcal/ULQuicksortMacro.tla b/tlatools/test-model/pcal/ULQuicksortMacro.tla new file mode 100644 index 0000000000000000000000000000000000000000..688c7d54f5d6902009019a079baf060ad6ad2f94 --- /dev/null +++ b/tlatools/test-model/pcal/ULQuicksortMacro.tla @@ -0,0 +1,132 @@ +-------------------------- MODULE ULQuicksortMacro ------------------------- +EXTENDS Naturals, Sequences + +CONSTANT ArrayLen + +ASSUME ArrayLen \in Nat + +PermsOf(Arr) == + LET Automorphism(S) == { f \in [S -> S] : + \A y \in S : \E x \in S : f[x] = y } + f ** g == [x \in DOMAIN g |-> f[g[x]]] + IN { Arr ** f : f \in Automorphism(DOMAIN Arr) } + +(* +--algorithm QuicksortMacro + variables A \in [1..ArrayLen -> 1..ArrayLen]; + returnVal = 1; + macro Partition(lo, hi) + begin with piv \in lo..(hi-1) + do returnVal := piv ; + with Ap \in + {AA \in PermsOf(A) : + (\A i \in 1..(lo-1) : AA[i] = A[i]) + /\ (\A i \in (hi+1)..Len(A) : AA[i] = A[i]) + /\ (\A i \in lo..piv, j \in (piv+1)..hi : + AA[i] \leq AA[j])} + do A := Ap; + end with ; + end with; + end macro + procedure QS(qlo = 1, qhi = 1) + variable pivot = 1 ; + begin (*qs1 :*) if qlo < qhi + then Partition(qlo, qhi) ; + (*qs2 :*) pivot := returnVal ; + (*qs3 :*) call QS(qlo, pivot) ; + (*qs4 :*) call QS(pivot +1,qhi) ; + return ; + else return; + end if; + end procedure + begin (*main :*) call QS(1, Len(A)) ; + end algorithm +*) + +(***** BEGIN TRANSLATION ***) +VARIABLES A, returnVal, pc, stack, qlo, qhi, pivot + +vars == << A, returnVal, pc, stack, qlo, qhi, pivot >> + +Init == (* Global variables *) + /\ A \in [1..ArrayLen -> 1..ArrayLen] + /\ returnVal = 1 + (* Procedure QS *) + /\ qlo = 1 + /\ qhi = 1 + /\ pivot = 1 + /\ stack = << >> + /\ pc = "Lbl_4" + +Lbl_1 == /\ pc = "Lbl_1" + /\ IF qlo < qhi + THEN /\ \E piv \in qlo..(qhi-1): + /\ returnVal' = piv + /\ \E Ap \in {AA \in PermsOf(A) : + (\A i \in 1..(qlo-1) : AA[i] = A[i]) + /\ (\A i \in (qhi+1)..Len(A) : AA[i] = A[i]) + /\ (\A i \in qlo..piv, j \in (piv+1)..qhi : + AA[i] \leq AA[j])}: + A' = Ap + /\ pivot' = returnVal' + /\ pc' = "Lbl_2" + /\ UNCHANGED << stack, qlo, qhi >> + ELSE /\ pc' = Head(stack).pc + /\ pivot' = Head(stack).pivot + /\ qlo' = Head(stack).qlo + /\ qhi' = Head(stack).qhi + /\ stack' = Tail(stack) + /\ UNCHANGED << A, returnVal >> + +Lbl_2 == /\ pc = "Lbl_2" + /\ /\ qhi' = pivot + /\ qlo' = qlo + /\ stack' = << [ procedure |-> "QS", + pc |-> "Lbl_3", + pivot |-> pivot, + qlo |-> qlo, + qhi |-> qhi ] >> + \o stack + /\ pivot' = 1 + /\ pc' = "Lbl_1" + /\ UNCHANGED << A, returnVal >> + +Lbl_3 == /\ pc = "Lbl_3" + /\ /\ qhi' = qhi + /\ qlo' = pivot +1 + /\ pivot' = 1 + /\ pc' = "Lbl_1" + /\ UNCHANGED << A, returnVal, stack >> + +QS == Lbl_1 \/ Lbl_2 \/ Lbl_3 + +Lbl_4 == /\ pc = "Lbl_4" + /\ /\ qhi' = Len(A) + /\ qlo' = 1 + /\ stack' = << [ procedure |-> "QS", + pc |-> "Done", + pivot |-> pivot, + qlo |-> qlo, + qhi |-> qhi ] >> + \o stack + /\ pivot' = 1 + /\ pc' = "Lbl_1" + /\ UNCHANGED << A, returnVal >> + +Next == QS \/ Lbl_4 + \/ (* Disjunct to prevent deadlock on termination *) + (pc = "Done" /\ UNCHANGED vars) + +Spec == /\ Init /\ [][Next]_vars + /\ WF_vars(Next) + +Termination == <>(pc = "Done") + +(***** END TRANSLATION ***) + +Invariant == + (pc = "Done") => \A i, j \in 1..ArrayLen : + (i < j) => A[i] \leq A[j] + + +============================================================================= diff --git a/tlatools/test-model/pcal/UniprocDefine.tla b/tlatools/test-model/pcal/UniprocDefine.tla new file mode 100644 index 0000000000000000000000000000000000000000..c75d634e1fbf4263783a0777de876a57bb833796 --- /dev/null +++ b/tlatools/test-model/pcal/UniprocDefine.tla @@ -0,0 +1,74 @@ +----------------------------- MODULE UniprocDefine -------------------------- +EXTENDS Naturals, Sequences, TLC + +(* +--algorithm UniprocDefine + variables n = 0 ; + define nplus1 == n + 1 + nplus2 == nplus1 + 1 + end define ; + procedure Foo(a) + variable b = 2 ; + begin foo : n := nplus2 + a + b ; + return ; + end procedure ; + begin main : call Foo(2) ; + minor: assert n = 6 ; + end algorithm +*) + +(***** BEGIN TRANSLATION ***) +CONSTANT defaultInitValue +VARIABLES n, pc, stack + +(* define statement *) +nplus1 == n + 1 +nplus2 == nplus1 + 1 + +VARIABLES a, b + +vars == << n, pc, stack, a, b >> + +Init == (* Global variables *) + /\ n = 0 + (* Procedure Foo *) + /\ a = defaultInitValue + /\ b = 2 + /\ stack = << >> + /\ pc = "main" + +foo == /\ pc = "foo" + /\ n' = nplus2 + a + b + /\ pc' = Head(stack).pc + /\ b' = Head(stack).b + /\ a' = Head(stack).a + /\ stack' = Tail(stack) + +Foo == foo + +main == /\ pc = "main" + /\ /\ a' = 2 + /\ stack' = << [ procedure |-> "Foo", + pc |-> "minor", + b |-> b, + a |-> a ] >> + \o stack + /\ b' = 2 + /\ pc' = "foo" + /\ n' = n + +minor == /\ pc = "minor" + /\ Assert(n = 6, "Failure of assertion at line 16, column 17.") + /\ pc' = "Done" + /\ UNCHANGED << n, stack, a, b >> + +Next == Foo \/ main \/ minor + \/ (* Disjunct to prevent deadlock on termination *) + (pc = "Done" /\ UNCHANGED vars) + +Spec == Init /\ [][Next]_vars + +Termination == <>(pc = "Done") + +(***** END TRANSLATION ***) +============================================================================= diff --git a/tlatools/test-model/pcal/bug-05-12-10.tla b/tlatools/test-model/pcal/bug-05-12-10.tla new file mode 100644 index 0000000000000000000000000000000000000000..fd80b54f278e3e8d394f139e67da4d4005822f8c --- /dev/null +++ b/tlatools/test-model/pcal/bug-05-12-10.tla @@ -0,0 +1,43 @@ +CAUSES the translator to throw an exception + +last modified on Sun 11 Dec 2005 at 0:30:16 UT by lamport + +---------------------------- MODULE bug-05-12-10 ---------------------------- +EXTENDS Naturals, Sequences, FiniteSets , TLC +(* +--algorithm Pcal + procedure IsAlgorithm(alg) + variable res = FALSE ; i = 0 ; + begin IA1: assert \/ /\ alg.type = "uniprocess" + /\ DOMAIN alg = {"type", "name", "defs", + "decls", "prcds", "body"} + \/ /\ alg.type = "multiiprocess" + /\ DOMAIN alg = {"type", "name", "defs", + "decls", "prcds", "procs"}; + assert alg.name \in STRING ; + assert IsExpr(alg.defs) ; + assert IsSeq(alg.decls) ; + i := Len(alg.decls) ; + IA2: while i > 0 do call IsVarDecl(alg.decls[i]) end while ; + i := Len(alg.prcds) ; + IA3: while i > 0 do call IsProcedure(alg.prcds[i]) end while ; + if alg.type = "uniprocess" + then assert IsNonemptySeq(alg.body) ; + i := Len(alg.body) ; + IA4: while i > 0 do call IsLabeledStmt(alg.prcds[i]) + end while ; + else assert IsNonemptySeq(alg.procs) ; + i := Len(alg.procs) ; + IA5: while i > 0 do call IsLabeledStmt(alg.procs[i]) + end while ; + end if ; + IA6: return ; + end procedure + begin PC1: call IsAlgorithm(alg) ; + Pc2: print "IsAlgorithm(alg) = TRUE" + end algorithm +*) + +\* BEGIN TRANSLATION +\* END TRANSLATION +============================================================================= diff --git a/tlatools/test-model/pcal/bug_05_10_03.tla b/tlatools/test-model/pcal/bug_05_10_03.tla new file mode 100644 index 0000000000000000000000000000000000000000..deb38b272740458fe67868452d6b5915575ee055 --- /dev/null +++ b/tlatools/test-model/pcal/bug_05_10_03.tla @@ -0,0 +1,44 @@ +--algorithm showBug + +process Proc \in 1..2 +variables x=[f1 |-> 1 , f2|->self ]; + +begin +start: x.f1:=self; + assert x.f1 = self; +end process; + +end algorithm + +------------- MODULE bug_05_10_03 ------------ +EXTENDS Naturals, TLC, FiniteSets +------------------------------------------ +\* BEGIN TRANSLATION +VARIABLES pc, x + +vars == << pc, x >> + +ProcSet == (1..2) + +Init == (* Process Proc *) + /\ x = [self \in 1..2 |-> [f1 |-> 1 , f2|->self ]] + /\ pc = [self \in ProcSet |-> "start"] + +start(self) == /\ pc[self] = "start" + /\ x' = [x EXCEPT ![self].f1 = self] + /\ Assert(x'[self].f1 = self, + "Failure of assertion at line 8, column 8.") + /\ pc' = [pc EXCEPT ![self] = "Done"] + +Proc(self) == start(self) + +Next == (\E self \in 1..2: Proc(self)) + \/ (* Disjunct to prevent deadlock on termination *) + ((\A self \in ProcSet: pc[self] = "Done") /\ UNCHANGED vars) + +Spec == Init /\ [][Next]_vars + +Termination == <>(\A self \in ProcSet: pc[self] = "Done") + +\* END TRANSLATION +========================================== diff --git a/tlatools/test-model/pcal/bug_05_12_10a.tla b/tlatools/test-model/pcal/bug_05_12_10a.tla new file mode 100644 index 0000000000000000000000000000000000000000..01fbeca72e8dd09c84bf0d71c4b4a1bf32d9a94c --- /dev/null +++ b/tlatools/test-model/pcal/bug_05_12_10a.tla @@ -0,0 +1,307 @@ +last modified on Thu 2 Feb 2006 at 15:40:27 PST by lamport + +The translator was renaming i to i_ in procedure IsAlgorithm, but +it failed to rename the i in the while test of statement IA3. + +--------------------------- MODULE bug_05_12_10a --------------------------- +EXTENDS Naturals, Sequences, FiniteSets , TLC +IsSeq(x) == DOMAIN x = 1..Len(x) +IsNonemptySeq(x) == IsSeq(x) /\ (Len(x) > 0) + +alg == [type |-> "uniprocess", + name |-> "Quicksort", + decls |-> << >>, + defs |-> << >>, + prcds |-> << >>, + body |-> <<1>>] + +(* +--algorithm Pcal + procedure IsAlgorithm(A) + variable res = FALSE ; i = 0 ; + begin IA1: assert \/ /\ A.type = "uniprocess" + /\ DOMAIN A = {"type", "name", "defs", + "decls", "prcds", "body"} + \/ /\ A.type = "multiiprocess" + /\ DOMAIN A = {"type", "name", "defs", + "decls", "prcds", "procs"}; + assert A.name \in STRING ; + call IsExpr(A.defs) ; + IA2: assert IsSeq(A.decls) ; + i := Len(A.decls) ; + IA3: while i > 0 do call IsVarDecl(A.decls[i]) ; + IA3a: i := i-1 + end while ; + i := Len(A.prcds) ; + IA4: while i > 0 do call IsProcedure(A.prcds[i]) ; + IA4a: i := i-1 + end while ; + if A.type = "uniprocess" + then assert IsNonemptySeq(A.body) ; + i := Len(A.body) ; + IA5: while i > 0 do call IsLabeledStmt(A.body[i]) ; + IA5a: i := i-1 + end while ; + else assert IsNonemptySeq(A.procs) ; + i := Len(A.procs) ; + IA6: while i > 0 do call IsProcess(A.procs[i]) ; + IA6a: i := i-1 + end while ; + end if ; + IA7: return ; + end procedure + procedure IsExpr(exp) + variable i ; + begin IE1 : assert IsSeq(exp) ; + i := Len(exp) ; + IE2: while i > 0 do assert exp[i] \in STRING ; + IA5a: i := i-1 + end while ; + return + end procedure + procedure IsVarDecl(vdcl) + begin IV1 : return + end procedure + procedure IsProcedure(prcdr) + begin IP1 : return + end procedure + procedure IsLabeledStmt(lstmt) + begin IL1 : return + end procedure + procedure IsProcess(proc) + begin IPr1 : return + end procedure + begin PC1: call IsAlgorithm(alg) ; + Pc2: print "IsAlgorithm(alg) = TRUE" + end algorithm +*) + +\* BEGIN TRANSLATION +\* Label IA5a of procedure IsAlgorithm at line 43 col 38 changed to IA5a_ +\* Procedure variable i of procedure IsAlgorithm at line 21 col 28 changed to i_ +CONSTANT defaultInitValue +VARIABLES pc, stack, A, res, i_, exp, i, vdcl, prcdr, lstmt, proc + +vars == << pc, stack, A, res, i_, exp, i, vdcl, prcdr, lstmt, proc >> + +Init == (* Procedure IsAlgorithm *) + /\ A = defaultInitValue + /\ res = FALSE + /\ i_ = 0 + (* Procedure IsExpr *) + /\ exp = defaultInitValue + /\ i = defaultInitValue + (* Procedure IsVarDecl *) + /\ vdcl = defaultInitValue + (* Procedure IsProcedure *) + /\ prcdr = defaultInitValue + (* Procedure IsLabeledStmt *) + /\ lstmt = defaultInitValue + (* Procedure IsProcess *) + /\ proc = defaultInitValue + /\ stack = << >> + /\ pc = "PC1" + +IA1 == /\ pc = "IA1" + /\ Assert(\/ /\ A.type = "uniprocess" + /\ DOMAIN A = {"type", "name", "defs", + "decls", "prcds", "body"} + \/ /\ A.type = "multiiprocess" + /\ DOMAIN A = {"type", "name", "defs", + "decls", "prcds", "procs"}, + "Failure of assertion at line 22, column 16.") + /\ Assert(A.name \in STRING, + "Failure of assertion at line 28, column 16.") + /\ /\ exp' = A.defs + /\ stack' = << [ procedure |-> "IsExpr", + pc |-> "IA2", + i |-> i, + exp |-> exp ] >> + \o stack + /\ i' = defaultInitValue + /\ pc' = "IE1" + /\ UNCHANGED << A, res, i_, vdcl, prcdr, lstmt, proc >> + +IA2 == /\ pc = "IA2" + /\ Assert(IsSeq(A.decls), + "Failure of assertion at line 30, column 16.") + /\ i_' = Len(A.decls) + /\ pc' = "IA3" + /\ UNCHANGED << stack, A, res, exp, i, vdcl, prcdr, lstmt, proc >> + +IA3 == /\ pc = "IA3" + /\ IF i_ > 0 + THEN /\ /\ stack' = << [ procedure |-> "IsVarDecl", + pc |-> "IA3a", + vdcl |-> vdcl ] >> + \o stack + /\ vdcl' = A.decls[i_] + /\ pc' = "IV1" + /\ i_' = i_ + ELSE /\ i_' = Len(A.prcds) + /\ pc' = "IA4" + /\ UNCHANGED << stack, vdcl >> + /\ UNCHANGED << A, res, exp, i, prcdr, lstmt, proc >> + +IA3a == /\ pc = "IA3a" + /\ i_' = i_-1 + /\ pc' = "IA3" + /\ UNCHANGED << stack, A, res, exp, i, vdcl, prcdr, lstmt, proc >> + +IA4 == /\ pc = "IA4" + /\ IF i_ > 0 + THEN /\ /\ prcdr' = A.prcds[i_] + /\ stack' = << [ procedure |-> "IsProcedure", + pc |-> "IA4a", + prcdr |-> prcdr ] >> + \o stack + /\ pc' = "IP1" + /\ i_' = i_ + ELSE /\ IF A.type = "uniprocess" + THEN /\ Assert(IsNonemptySeq(A.body), + "Failure of assertion at line 40, column 23.") + /\ i_' = Len(A.body) + /\ pc' = "IA5" + ELSE /\ Assert(IsNonemptySeq(A.procs), + "Failure of assertion at line 45, column 23.") + /\ i_' = Len(A.procs) + /\ pc' = "IA6" + /\ UNCHANGED << stack, prcdr >> + /\ UNCHANGED << A, res, exp, i, vdcl, lstmt, proc >> + +IA4a == /\ pc = "IA4a" + /\ i_' = i_-1 + /\ pc' = "IA4" + /\ UNCHANGED << stack, A, res, exp, i, vdcl, prcdr, lstmt, proc >> + +IA5 == /\ pc = "IA5" + /\ IF i_ > 0 + THEN /\ /\ lstmt' = A.body[i_] + /\ stack' = << [ procedure |-> "IsLabeledStmt", + pc |-> "IA5a_", + lstmt |-> lstmt ] >> + \o stack + /\ pc' = "IL1" + ELSE /\ pc' = "IA7" + /\ UNCHANGED << stack, lstmt >> + /\ UNCHANGED << A, res, i_, exp, i, vdcl, prcdr, proc >> + +IA5a_ == /\ pc = "IA5a_" + /\ i_' = i_-1 + /\ pc' = "IA5" + /\ UNCHANGED << stack, A, res, exp, i, vdcl, prcdr, lstmt, proc >> + +IA6 == /\ pc = "IA6" + /\ IF i_ > 0 + THEN /\ /\ proc' = A.procs[i_] + /\ stack' = << [ procedure |-> "IsProcess", + pc |-> "IA6a", + proc |-> proc ] >> + \o stack + /\ pc' = "IPr1" + ELSE /\ pc' = "IA7" + /\ UNCHANGED << stack, proc >> + /\ UNCHANGED << A, res, i_, exp, i, vdcl, prcdr, lstmt >> + +IA6a == /\ pc = "IA6a" + /\ i_' = i_-1 + /\ pc' = "IA6" + /\ UNCHANGED << stack, A, res, exp, i, vdcl, prcdr, lstmt, proc >> + +IA7 == /\ pc = "IA7" + /\ pc' = Head(stack).pc + /\ res' = Head(stack).res + /\ i_' = Head(stack).i_ + /\ A' = Head(stack).A + /\ stack' = Tail(stack) + /\ UNCHANGED << exp, i, vdcl, prcdr, lstmt, proc >> + +IsAlgorithm == IA1 \/ IA2 \/ IA3 \/ IA3a \/ IA4 \/ IA4a \/ IA5 \/ IA5a_ + \/ IA6 \/ IA6a \/ IA7 + +IE1 == /\ pc = "IE1" + /\ Assert(IsSeq(exp), "Failure of assertion at line 55, column 17.") + /\ i' = Len(exp) + /\ pc' = "IE2" + /\ UNCHANGED << stack, A, res, i_, exp, vdcl, prcdr, lstmt, proc >> + +IE2 == /\ pc = "IE2" + /\ IF i > 0 + THEN /\ Assert(exp[i] \in STRING, + "Failure of assertion at line 57, column 31.") + /\ pc' = "IA5a" + /\ UNCHANGED << stack, exp, i >> + ELSE /\ pc' = Head(stack).pc + /\ i' = Head(stack).i + /\ exp' = Head(stack).exp + /\ stack' = Tail(stack) + /\ UNCHANGED << A, res, i_, vdcl, prcdr, lstmt, proc >> + +IA5a == /\ pc = "IA5a" + /\ i' = i-1 + /\ pc' = "IE2" + /\ UNCHANGED << stack, A, res, i_, exp, vdcl, prcdr, lstmt, proc >> + +IsExpr == IE1 \/ IE2 \/ IA5a + +IV1 == /\ pc = "IV1" + /\ pc' = Head(stack).pc + /\ vdcl' = Head(stack).vdcl + /\ stack' = Tail(stack) + /\ UNCHANGED << A, res, i_, exp, i, prcdr, lstmt, proc >> + +IsVarDecl == IV1 + +IP1 == /\ pc = "IP1" + /\ pc' = Head(stack).pc + /\ prcdr' = Head(stack).prcdr + /\ stack' = Tail(stack) + /\ UNCHANGED << A, res, i_, exp, i, vdcl, lstmt, proc >> + +IsProcedure == IP1 + +IL1 == /\ pc = "IL1" + /\ pc' = Head(stack).pc + /\ lstmt' = Head(stack).lstmt + /\ stack' = Tail(stack) + /\ UNCHANGED << A, res, i_, exp, i, vdcl, prcdr, proc >> + +IsLabeledStmt == IL1 + +IPr1 == /\ pc = "IPr1" + /\ pc' = Head(stack).pc + /\ proc' = Head(stack).proc + /\ stack' = Tail(stack) + /\ UNCHANGED << A, res, i_, exp, i, vdcl, prcdr, lstmt >> + +IsProcess == IPr1 + +PC1 == /\ pc = "PC1" + /\ /\ A' = alg + /\ stack' = << [ procedure |-> "IsAlgorithm", + pc |-> "Pc2", + res |-> res, + i_ |-> i_, + A |-> A ] >> + \o stack + /\ res' = FALSE + /\ i_' = 0 + /\ pc' = "IA1" + /\ UNCHANGED << exp, i, vdcl, prcdr, lstmt, proc >> + +Pc2 == /\ pc = "Pc2" + /\ PrintT("IsAlgorithm(alg) = TRUE") + /\ pc' = "Done" + /\ UNCHANGED << stack, A, res, i_, exp, i, vdcl, prcdr, lstmt, proc >> + +Next == IsAlgorithm \/ IsExpr \/ IsVarDecl \/ IsProcedure \/ IsLabeledStmt + \/ IsProcess \/ PC1 \/ Pc2 + \/ (* Disjunct to prevent deadlock on termination *) + (pc = "Done" /\ UNCHANGED vars) + +Spec == Init /\ [][Next]_vars + +Termination == <>(pc = "Done") + +\* END TRANSLATION +============================================================================= diff --git a/tlatools/test-model/pcal/bug_05_12_16b.tla b/tlatools/test-model/pcal/bug_05_12_16b.tla new file mode 100644 index 0000000000000000000000000000000000000000..94138bcbab932a46fc6ae8f3e2fbb9d8ff8503e1 --- /dev/null +++ b/tlatools/test-model/pcal/bug_05_12_16b.tla @@ -0,0 +1,73 @@ +--algorithm Dijkstra1 + procedure Foo(a = 1) + variable x = 42 ; y = x + begin Foo1: return ; + end procedure + process P \in 1..3 + begin + P1: assert x = y ; + skip ; + P2: call Foo(17) ; + end process; + + end algorithm + +----------- MODULE bug_05_12_16b ----------- +EXTENDS Naturals, Sequences, TLC + +\* BEGIN TRANSLATION +VARIABLES pc, stack, a, x, y + +vars == << pc, stack, a, x, y >> + +ProcSet == (1..3) + +Init == (* Procedure Foo *) + /\ a = [ self \in ProcSet |-> 1] + /\ x = [ self \in ProcSet |-> 42] + /\ y = [ self \in ProcSet |-> x[self]] + /\ stack = [self \in ProcSet |-> << >>] + /\ pc = [self \in ProcSet |-> "P1"] + +Foo1(self) == /\ pc[self] = "Foo1" + /\ pc' = [pc EXCEPT ![self] = Head(stack[self]).pc] + /\ x' = [x EXCEPT ![self] = Head(stack[self]).x] + /\ y' = [y EXCEPT ![self] = Head(stack[self]).y] + /\ a' = [a EXCEPT ![self] = Head(stack[self]).a] + /\ stack' = [stack EXCEPT ![self] = Tail(stack[self])] + +Foo(self) == Foo1(self) + +P1(self) == /\ pc[self] = "P1" + /\ Assert(x[self] = y[self], + "Failure of assertion at line 8, column 9.") + /\ TRUE + /\ pc' = [pc EXCEPT ![self] = "P2"] + /\ UNCHANGED << stack, a, x, y >> + +P2(self) == /\ pc[self] = "P2" + /\ /\ a' = [a EXCEPT ![self] = 17] + /\ stack' = [stack EXCEPT ![self] = << [ procedure |-> "Foo", + pc |-> "Done", + x |-> x[self], + y |-> y[self], + a |-> a[self] ] >> + \o stack[self]] + /\ x' = [x EXCEPT ![self] = 42] + /\ y' = [y EXCEPT ![self] = x'[self]] + /\ pc' = [pc EXCEPT ![self] = "Foo1"] + +P(self) == P1(self) \/ P2(self) + +Next == (\E self \in ProcSet: Foo(self)) + \/ (\E self \in 1..3: P(self)) + \/ (* Disjunct to prevent deadlock on termination *) + ((\A self \in ProcSet: pc[self] = "Done") /\ UNCHANGED vars) + +Spec == Init /\ [][Next]_vars + +Termination == <>(\A self \in ProcSet: pc[self] = "Done") + +\* END TRANSLATION + +======================================== diff --git a/tlatools/test-model/pcal/bug_05_12_31.tla b/tlatools/test-model/pcal/bug_05_12_31.tla new file mode 100644 index 0000000000000000000000000000000000000000..181345b88fed1e1863cb2ec0cca14adb138fde44 --- /dev/null +++ b/tlatools/test-model/pcal/bug_05_12_31.tla @@ -0,0 +1,64 @@ + +------------------------------- MODULE bug_05_12_31 ----------------------------- +EXTENDS Naturals, Sequences, TLC + + +(* +--algorithm Test + procedure P(a = 7) + variable x = a ; y = x+1 ; + begin P1: assert a = 1; + assert x = a; + assert y = a+1; + return; + end procedure + begin A: call P(1) + end algorithm +*) + +(***** BEGIN TRANSLATION ***) +VARIABLES pc, stack, a, x, y + +vars == << pc, stack, a, x, y >> + +Init == (* Procedure P *) + /\ a = 7 + /\ x = a + /\ y = x+1 + /\ stack = << >> + /\ pc = "A" + +P1 == /\ pc = "P1" + /\ Assert(a = 1, "Failure of assertion at line 10, column 17.") + /\ Assert(x = a, "Failure of assertion at line 11, column 17.") + /\ Assert(y = a+1, "Failure of assertion at line 12, column 17.") + /\ pc' = Head(stack).pc + /\ x' = Head(stack).x + /\ y' = Head(stack).y + /\ a' = Head(stack).a + /\ stack' = Tail(stack) + +P == P1 + +A == /\ pc = "A" + /\ /\ a' = 1 + /\ stack' = << [ procedure |-> "P", + pc |-> "Done", + x |-> x, + y |-> y, + a |-> a ] >> + \o stack + /\ x' = a' + /\ y' = x'+1 + /\ pc' = "P1" + +Next == P \/ A + \/ (* Disjunct to prevent deadlock on termination *) + (pc = "Done" /\ UNCHANGED vars) + +Spec == Init /\ [][Next]_vars + +Termination == <>(pc = "Done") + +(***** END TRANSLATION ***) +============================================================================= diff --git a/tlatools/test-model/pcal/bug_06_01_25.tla b/tlatools/test-model/pcal/bug_06_01_25.tla new file mode 100644 index 0000000000000000000000000000000000000000..a23cb49fff9e4eda6723cd2c94473a74bb850a01 --- /dev/null +++ b/tlatools/test-model/pcal/bug_06_01_25.tla @@ -0,0 +1,225 @@ + +--algorithm TestAlignment + variable x ; y ; z = /\ \A i \in {1} : i > 0 + /\ \A i \in {1} : i > 0 + /\ \A i \in {1} : i > 0 + define foo == /\ \A i \in {1} : i > 0 + /\ \A i \in {1} : i > 0 + /\ \A i \in {1} : i > 0 + end define; + macro Mac(a) begin x := \A i \in {1} : i > 0 ; + y := \A i \in {1} : i > 0 ; + z := \A i \in {1} : i > 0 ; + assert /\ \A i \in {1} : i > 0 + /\ \A i \in {1} : i > 0 + /\ \A i \in {1} : i > 0 ; + assert a + end macro; + + procedure P(a = /\ \A i \in {1} : i > 0 + /\ \A i \in {1} : i > 0 + /\ \A i \in {1} : i > 0) + begin P1: x := \A i \in {1} : i > 0 ; + y := \A i \in {1} : i > 0 ; + z := \A i \in {1} : i > 0 ; + return + end procedure + process Q \in {qq \in {1,2} : /\ \A i \in {1} : i > 0 + /\ \A j \in {1} : j > 0 + /\ \A k \in {1} : k > 0 } + variable w = /\ \A i \in {1} : i > 0 + /\ \A i \in {1} : i > 0 + /\ \A i \in {1} : i > 0 + begin P1: if /\ \A i \in {1} : i > 0 + /\ \A i \in {1} : i > 0 + /\ \A i \in {1} : i > 0 then x := \A i \in {1} : i > 0 ; + y := \A i \in {1} : i > 0 ; + z := \A i \in {1} : i > 0 + else x := \A i \in {1} : i > 0 ; + y := \A i \in {1} : i > 0 ; + z := \A i \in {1} : i > 0 + end if ; + P15: with k \in {kk \in {2,3} : /\ \A i \in {1} : i > 0 + /\ \A i \in {1} : i > 0 + /\ \A i \in {1} : i > 0 } do + with m = /\ \A i \in {1} : i > 0 + /\ \A i \in {1} : i > 0 + /\ \A i \in {1} : i > 0 do + x := \A i \in {1} : i > 0 ; + y := \A i \in {1} : i > 0 ; + z := \A i \in {1} : i > 0 + end with end with ; + P2: while /\ \A i \in {1} : i > 0 + /\ \A i \in {1} : i > 0 + /\ \A i \in {1} : i > 0 + /\ FALSE do + x := \A i \in {1} : i > 0 ; + y := \A i \in {1} : i > 0 ; + z := \A i \in {1} : i > 0 ; + w := /\ \A i \in {1} : i > 0 + /\ \A i \in {1} : i > 0 + /\ \A i \in {1} : i > 0 + end while ; + P3: call P(/\ \A i \in {1} : i > 0 + /\ \A i \in {1} : i > 0 + /\ \A i \in {1} : i > 0) ; + P4: assert /\ \A i \in {1} : i > 0 + /\ \A i \in {1} : i > 0 + /\ \A i \in {1} : i > 0 ; + print /\ \A i \in {1} : i > 0 + /\ \A i \in {1} : i > 0 + /\ \A i \in {1} : i > 0 ; + P5: Mac(/\ \A i \in {1} : i > 0 + /\ \A i \in {1} : i > 0 + /\ \A i \in {1} : i > 0 ) + end process + end algorithm + +----------- MODULE bug_06_01_25 ----------- +EXTENDS Sequences, Naturals, TLC + +ASSUME \forall i \in {} : i \geq 1 + +\* BEGIN TRANSLATION +\* Label P1 of procedure P at line 22 col 17 changed to P1_ +CONSTANT defaultInitValue +VARIABLES x, y, z, pc, stack + +(* define statement *) +foo == /\ \A i \in {1} : i > 0 + /\ \A i \in {1} : i > 0 + /\ \A i \in {1} : i > 0 + +VARIABLES a, w + +vars == << x, y, z, pc, stack, a, w >> + +ProcSet == ({qq \in {1,2} : /\ \A i \in {1} : i > 0 + /\ \A j \in {1} : j > 0 + /\ \A k \in {1} : k > 0 }) + +Init == (* Global variables *) + /\ x = defaultInitValue + /\ y = defaultInitValue + /\ z = (/\ \A i \in {1} : i > 0 + /\ \A i \in {1} : i > 0 + /\ \A i \in {1} : i > 0) + (* Procedure P *) + /\ a = [ self \in ProcSet |-> /\ \A i \in {1} : i > 0 + /\ \A i \in {1} : i > 0 + /\ \A i \in {1} : i > 0] + (* Process Q *) + /\ w = [self \in {qq \in {1,2} : /\ \A i \in {1} : i > 0 + /\ \A j \in {1} : j > 0 + /\ \A k \in {1} : k > 0 } |-> /\ \A i \in {1} : i > 0 + /\ \A i \in {1} : i > 0 + /\ \A i \in {1} : i > 0] + /\ stack = [self \in ProcSet |-> << >>] + /\ pc = [self \in ProcSet |-> "P1"] + +P1_(self) == /\ pc[self] = "P1_" + /\ x' = (\A i \in {1} : i > 0) + /\ y' = (\A i \in {1} : i > 0) + /\ z' = (\A i \in {1} : i > 0) + /\ pc' = [pc EXCEPT ![self] = Head(stack[self]).pc] + /\ a' = [a EXCEPT ![self] = Head(stack[self]).a] + /\ stack' = [stack EXCEPT ![self] = Tail(stack[self])] + /\ w' = w + +P(self) == P1_(self) + +P1(self) == /\ pc[self] = "P1" + /\ IF /\ \A i \in {1} : i > 0 + /\ \A i \in {1} : i > 0 + /\ \A i \in {1} : i > 0 + THEN /\ x' = (\A i \in {1} : i > 0) + /\ y' = (\A i \in {1} : i > 0) + /\ z' = (\A i \in {1} : i > 0) + ELSE /\ x' = (\A i \in {1} : i > 0) + /\ y' = (\A i \in {1} : i > 0) + /\ z' = (\A i \in {1} : i > 0) + /\ pc' = [pc EXCEPT ![self] = "P15"] + /\ UNCHANGED << stack, a, w >> + +P15(self) == /\ pc[self] = "P15" + /\ \E k \in {kk \in {2,3} : /\ \A i \in {1} : i > 0 + /\ \A i \in {1} : i > 0 + /\ \A i \in {1} : i > 0 }: + LET m == /\ \A i \in {1} : i > 0 + /\ \A i \in {1} : i > 0 + /\ \A i \in {1} : i > 0 IN + /\ x' = (\A i \in {1} : i > 0) + /\ y' = (\A i \in {1} : i > 0) + /\ z' = (\A i \in {1} : i > 0) + /\ pc' = [pc EXCEPT ![self] = "P2"] + /\ UNCHANGED << stack, a, w >> + +P2(self) == /\ pc[self] = "P2" + /\ IF /\ \A i \in {1} : i > 0 + /\ \A i \in {1} : i > 0 + /\ \A i \in {1} : i > 0 + /\ FALSE + THEN /\ x' = (\A i \in {1} : i > 0) + /\ y' = (\A i \in {1} : i > 0) + /\ z' = (\A i \in {1} : i > 0) + /\ w' = [w EXCEPT ![self] = /\ \A i \in {1} : i > 0 + /\ \A i \in {1} : i > 0 + /\ \A i \in {1} : i > 0] + /\ pc' = [pc EXCEPT ![self] = "P2"] + ELSE /\ pc' = [pc EXCEPT ![self] = "P3"] + /\ UNCHANGED << x, y, z, w >> + /\ UNCHANGED << stack, a >> + +P3(self) == /\ pc[self] = "P3" + /\ /\ a' = [a EXCEPT ![self] = /\ \A i \in {1} : i > 0 + /\ \A i \in {1} : i > 0 + /\ \A i \in {1} : i > 0] + /\ stack' = [stack EXCEPT ![self] = << [ procedure |-> "P", + pc |-> "P4", + a |-> a[self] ] >> + \o stack[self]] + /\ pc' = [pc EXCEPT ![self] = "P1_"] + /\ UNCHANGED << x, y, z, w >> + +P4(self) == /\ pc[self] = "P4" + /\ Assert(/\ \A i \in {1} : i > 0 + /\ \A i \in {1} : i > 0 + /\ \A i \in {1} : i > 0, + "Failure of assertion at line 66, column 17.") + /\ PrintT(/\ \A i \in {1} : i > 0 + /\ \A i \in {1} : i > 0 + /\ \A i \in {1} : i > 0) + /\ pc' = [pc EXCEPT ![self] = "P5"] + /\ UNCHANGED << x, y, z, stack, a, w >> + +P5(self) == /\ pc[self] = "P5" + /\ x' = (\A i \in {1} : i > 0) + /\ y' = (\A i \in {1} : i > 0) + /\ z' = (\A i \in {1} : i > 0) + /\ Assert(/\ \A i \in {1} : i > 0 + /\ \A i \in {1} : i > 0 + /\ \A i \in {1} : i > 0, + "Failure of assertion at line 13, column 23 of macro called at line 72, column 17.") + /\ Assert(/\ \A i \in {1} : i > 0 + /\ \A i \in {1} : i > 0 + /\ \A i \in {1} : i > 0, + "Failure of assertion at line 16, column 23 of macro called at line 72, column 17.") + /\ pc' = [pc EXCEPT ![self] = "Done"] + /\ UNCHANGED << stack, a, w >> + +Q(self) == P1(self) \/ P15(self) \/ P2(self) \/ P3(self) \/ P4(self) + \/ P5(self) + +Next == (\E self \in ProcSet: P(self)) + \/ (\E self \in {qq \in {1,2} : /\ \A i \in {1} : i > 0 + /\ \A j \in {1} : j > 0 + /\ \A k \in {1} : k > 0 }: Q(self)) + \/ (* Disjunct to prevent deadlock on termination *) + ((\A self \in ProcSet: pc[self] = "Done") /\ UNCHANGED vars) + +Spec == Init /\ [][Next]_vars + +Termination == <>(\A self \in ProcSet: pc[self] = "Done") + +\* END TRANSLATION +======================================== diff --git a/tlatools/test-model/simulation/NQSpec/NQSpec.tla b/tlatools/test-model/simulation/NQSpec/NQSpec.tla index 985d91f6a98ed8a9b0b7ad0ee750e1e230f058e1..df9696352aff3633975edc6a91e70401dc27feca 100644 --- a/tlatools/test-model/simulation/NQSpec/NQSpec.tla +++ b/tlatools/test-model/simulation/NQSpec/NQSpec.tla @@ -1,87 +1,87 @@ -------------------------------- MODULE NQSpec ------------------------------- -EXTENDS Integers, Sequences - -CONSTANTS EnQers, DeQers, Data, InitData, Ids, Busy, NoData - -ASSUME InitData \in Data - -Done == CHOOSE D : D \notin Data -\*Busy == CHOOSE D : D \notin Data -NotAnId == CHOOSE i : i \notin Ids -\*NoData == CHOOSE D : D \notin Data -Elements == [data : Data, id : Ids] -NotAnElement == CHOOSE E : E \notin Elements - -VARIABLES enq, deq, after, adding -vars == <<enq, deq, after, adding>> - -elts == DOMAIN after - -doneElts == elts \ {adding[e] : e \in EnQers} - -TypeOK == /\ enq \in [EnQers -> Data \cup {Done}] - /\ deq \in [DeQers -> Data \cup {Busy}] - /\ elts \in SUBSET Elements - /\ after \in [elts -> SUBSET doneElts] - /\ adding \in [EnQers -> Elements \cup {NotAnElement}] - -Init == /\ enq = [e \in EnQers |-> Done] - /\ deq = [d \in DeQers |-> InitData] - /\ after = << >> - /\ adding = [e \in EnQers |-> NotAnElement] ------------------------------------------------------------------------------ - -Assign(var, idx, val) == var' = [var EXCEPT ![idx] = val] - -IdsBeingAdded == {adding[el].id : el \in {e \in EnQers : adding[e] # NotAnElement}} - -UnusedIds == (Ids \ {el.id : el \in elts}) \ IdsBeingAdded - - -AddElt(el) == - after' = [x \in elts \cup {el} |-> - IF x = el THEN doneElts - ELSE after[x] ] - -RemoveElt(el) == - after' = [x \in elts \ {el} |-> after[x] \ {el}] - -MinimalElts(After) == {el \in DOMAIN After : After[el] = {}} -minimalElts == MinimalElts(after) - -BeginEnq(e) == /\ enq[e] = Done - /\ \E D \in Data, id \in UnusedIds : - LET el == [data |-> D, id |-> id] - IN /\ Assign(enq, e, D) - /\ AddElt(el) - /\ Assign(adding, e, el) - /\ UNCHANGED deq - -EndEnq(e) == /\ enq[e] # Done - /\ Assign(enq, e, Done) - /\ Assign(adding, e, NotAnElement) - /\ UNCHANGED <<deq, after>> - -\* enq, deq, elts, after, adding -BeginDeq(d) == /\ deq[d] # Busy - /\ Assign(deq, d, Busy) - /\ UNCHANGED <<enq, after, adding>> - -EndDeq(d) == /\ deq[d] = Busy - /\ \E el \in minimalElts : - /\ RemoveElt(el) - /\ Assign(deq, d, el.data) - /\ UNCHANGED <<enq, adding>> - -Next == \/ \E e \in EnQers : BeginEnq(e) \/ EndEnq(e) - \/ \E d \in DeQers : BeginDeq(d) \/ EndDeq(d) - -Liveness == /\ \A e \in EnQers : WF_vars(BeginEnq(e) \/ EndEnq(e)) - /\ \A d \in DeQers : WF_vars(BeginDeq(d) \/ EndDeq(d)) - -Spec == Init /\ [][Next]_vars /\ Liveness - +------------------------------- MODULE NQSpec ------------------------------- +EXTENDS Integers, Sequences + +CONSTANTS EnQers, DeQers, Data, InitData, Ids, Busy, NoData + +ASSUME InitData \in Data + +Done == CHOOSE D : D \notin Data +\*Busy == CHOOSE D : D \notin Data +NotAnId == CHOOSE i : i \notin Ids +\*NoData == CHOOSE D : D \notin Data +Elements == [data : Data, id : Ids] +NotAnElement == CHOOSE E : E \notin Elements + +VARIABLES enq, deq, after, adding +vars == <<enq, deq, after, adding>> + +elts == DOMAIN after + +doneElts == elts \ {adding[e] : e \in EnQers} + +TypeOK == /\ enq \in [EnQers -> Data \cup {Done}] + /\ deq \in [DeQers -> Data \cup {Busy}] + /\ elts \in SUBSET Elements + /\ after \in [elts -> SUBSET doneElts] + /\ adding \in [EnQers -> Elements \cup {NotAnElement}] + +Init == /\ enq = [e \in EnQers |-> Done] + /\ deq = [d \in DeQers |-> InitData] + /\ after = << >> + /\ adding = [e \in EnQers |-> NotAnElement] +----------------------------------------------------------------------------- + +Assign(var, idx, val) == var' = [var EXCEPT ![idx] = val] + +IdsBeingAdded == {adding[el].id : el \in {e \in EnQers : adding[e] # NotAnElement}} + +UnusedIds == (Ids \ {el.id : el \in elts}) \ IdsBeingAdded + + +AddElt(el) == + after' = [x \in elts \cup {el} |-> + IF x = el THEN doneElts + ELSE after[x] ] + +RemoveElt(el) == + after' = [x \in elts \ {el} |-> after[x] \ {el}] + +MinimalElts(After) == {el \in DOMAIN After : After[el] = {}} +minimalElts == MinimalElts(after) + +BeginEnq(e) == /\ enq[e] = Done + /\ \E D \in Data, id \in UnusedIds : + LET el == [data |-> D, id |-> id] + IN /\ Assign(enq, e, D) + /\ AddElt(el) + /\ Assign(adding, e, el) + /\ UNCHANGED deq + +EndEnq(e) == /\ enq[e] # Done + /\ Assign(enq, e, Done) + /\ Assign(adding, e, NotAnElement) + /\ UNCHANGED <<deq, after>> + +\* enq, deq, elts, after, adding +BeginDeq(d) == /\ deq[d] # Busy + /\ Assign(deq, d, Busy) + /\ UNCHANGED <<enq, after, adding>> + +EndDeq(d) == /\ deq[d] = Busy + /\ \E el \in minimalElts : + /\ RemoveElt(el) + /\ Assign(deq, d, el.data) + /\ UNCHANGED <<enq, adding>> + +Next == \/ \E e \in EnQers : BeginEnq(e) \/ EndEnq(e) + \/ \E d \in DeQers : BeginDeq(d) \/ EndDeq(d) + +Liveness == /\ \A e \in EnQers : WF_vars(BeginEnq(e) \/ EndEnq(e)) + /\ \A d \in DeQers : WF_vars(BeginDeq(d) \/ EndDeq(d)) + +Spec == Init /\ [][Next]_vars /\ Liveness + ============================================================================= -\* Modification History -\* Last modified Sat Nov 14 16:00:53 PST 2015 by lamport -\* Created Thu Nov 05 15:07:25 PST 2015 by lamport +\* Modification History +\* Last modified Sat Nov 14 16:00:53 PST 2015 by lamport +\* Created Thu Nov 05 15:07:25 PST 2015 by lamport diff --git a/tlatools/test-model/simulation/NQSpec/NQSpecImpliesQSpec.tla b/tlatools/test-model/simulation/NQSpec/NQSpecImpliesQSpec.tla index c7a3b125d26cafea1c77e442d42a633f05706b99..2197c3620e3a2d900ef513d986a489b4c9e52543 100644 --- a/tlatools/test-model/simulation/NQSpec/NQSpecImpliesQSpec.tla +++ b/tlatools/test-model/simulation/NQSpec/NQSpecImpliesQSpec.tla @@ -1,212 +1,212 @@ -------------------------- MODULE NQSpecImpliesQSpec ------------------------- -EXTENDS NQSpec, FiniteSets, TLC - -\*NoData == NotData -NatSetMax(S) == IF S = {} THEN 0 ELSE CHOOSE n \in S : \A m \in S : n >=m -VARIABLE p, \* The prophecy variable = sequence of next values read, - \* of length Cardinality(elts) - Q, \* The queue of QSpec, except as Elements with their Ids, - \* and except that it is changed only on the actions - \* of NQSpec. Added as a history variable. - s, - \* A stuttering variable to add the actions - \* corresponding to the DoEnq and DoDeq actions of QSpec - enqInner, deqInner - \* History variables implementing the corresponding variables - \* of QSpec, except deqInner gets set to an Element el instead - \* of el.data - -\* The order of adding the variables is: -\* s, p, Q, {queue, enqInner, deqInner} -varsI == <<vars, p, Q, s, enqInner, deqInner>> - -top == CHOOSE t : t \notin {} -bot == [EndEnq |-> TRUE, EndDeq |-> TRUE] - -TypeOKI == /\ TypeOK - /\ Q \in Seq(Elements) - /\ p \in Seq(Elements) - /\ s \in {top} - \cup [type : {"EndDeq"}, name : DeQers \X Elements, val : {FALSE, TRUE}] - \cup [type : {"EndEnq"}, name : EnQers, val : {TRUE}] - \cup [type : {"BeginEnq"}, name : EnQers, val : Seq(Elements)] - /\ enqInner \in [EnQers -> {Done, Busy}] - /\ deqInner \in [DeQers -> {NoData} \cup Elements] - -InitI == /\ Init - /\ Q = << >> - /\ enqInner = [e \in EnQers |-> Done] - /\ \E i \in Ids : deqInner = [d \in DeQers |-> [data |-> InitData, - id |-> i]] - /\ p = << >> - /\ s = top - /\ TLCSet(1, {}) - -RemoveFrom(E, After) == [x \in (DOMAIN After) \ E |-> After[x] \ E] -RECURSIVE IsConsistent(_, _) -IsConsistent(seq, After) == - IF seq = << >> - THEN TRUE - ELSE LET hd == Head(seq) - Elts == DOMAIN After - IN /\ (hd \in DOMAIN After) /\ (After[hd] = {}) - /\ IsConsistent(Tail(seq), - RemoveFrom({hd}, After)) - -IsBlocking(el, After) == LET Elts == DOMAIN After - MinElts == MinimalElts(After) - IN (el \notin MinElts) /\ (doneElts # {}) - - -AllEnabled == s = top - -PostStutterEnabled(type, name) == (s # top) /\ (s.type = type) /\ (s.name = name) -PreStutterEnabled(type, name) == (s # top) => - /\ (s.type = type) /\ (s.name = name) - /\ s.val # bot[s.type] -AfterPreStutterEnabled(type, name) == /\ s # top - /\ (s.type = type) /\ (s.name = name) - /\ s.val = bot[s.type] - -SetStutter(type, name, val) == - /\ (s # top) => Assert(s.type = type /\ s.name = name, - "SetStutter not executed by owner of stuttering variable") - /\ s' = [type |-> type, name |-> name, val |-> val] - -Prefix(n, seq) == [i \in 1..n |-> seq[i]] -Suffix(n, seq) == [i \in 1..(Len(seq)-n) |-> seq[i+n]] -SeqElts(seq) == {seq[i] : i \in 1..Len(seq)} - -PInv == /\ Cardinality(elts) = Len(p) - -QInv == /\ Cardinality(SeqElts(Q)) = Len(Q) - /\ SeqElts(Q) \subseteq elts - /\ IsConsistent(Q, after) - /\ LET n == NatSetMax({i \in 1..Len(Q) : Prefix(i, Q) = Prefix(i, p)}) - IN (n < Len(Q)) => IsBlocking(p[n+1], - RemoveFrom(SeqElts(Prefix(n, Q)), after)) - -Writer(elt) == CHOOSE e \in EnQers : adding[e] = elt - -BeginEnqI(e) == /\ AllEnabled - /\ BeginEnq(e) - /\ \E el \in Elements : p' = Append(p, el) -\* /\ TLCSet(1, {p'} \cup TLCGet(1)) -\* /\ IF (Elements \X Elements \subseteq TLCGet(1)) -\* THEN /\ PrintT(TLCGet(1)) -\* /\ Assert (FALSE, "There") -\* ELSE TRUE -\*\* /\ PrintT(<<e, p, p', after'>>) - /\ LET RECURSIVE ToAdd(_, _) - ToAdd(i, After) == - IF (i > Len(p')) \/ p'[i] \notin MinimalElts(After) - THEN << >> - ELSE <<p'[i]>> \o ToAdd(i+1, RemoveFrom({p'[i]}, After)) - TA == ToAdd(Len(Q)+1, RemoveFrom(SeqElts(Q), after')) - IN IF TA # << >> - THEN SetStutter("BeginEnq", e, TA) - ELSE s' = s - /\ Assign(enqInner, e, Busy) - /\ UNCHANGED <<Q, deqInner>> - -BeginEnqIDo(e) == /\ PostStutterEnabled("BeginEnq", e) - /\ Q' = Append(Q, Head(s.val)) - /\ Assign(enqInner, Writer(Head(s.val)), Done) - /\ IF Tail(s.val) # << >> THEN SetStutter("BeginEnq", e, Tail(s.val)) - ELSE s' = top - /\ UNCHANGED <<vars, p, deqInner>> - -DoEnqI(e) == /\ PreStutterEnabled("EndEnq", e) - /\ enq[e] # Done - /\ IF enqInner[e] # Done \* adding[e] \notin SeqElts(Q) - THEN /\ Q' = Append(Q, adding[e]) - /\ Assign(enqInner, e, Done) - ELSE UNCHANGED <<Q, enqInner>> - /\ SetStutter("EndEnq", e, TRUE) - /\ UNCHANGED <<vars, p, deqInner>> - -EndEnqI(e) == /\ AfterPreStutterEnabled("EndEnq", e) - /\ EndEnq(e) - /\ s' = top - /\ UNCHANGED << p, Q, enqInner, deqInner>> - -BeginDeqI(d) == /\ AllEnabled - /\ BeginDeq(d) - /\ Assign(deqInner, d, NoData) - /\ UNCHANGED <<p, Q, s, enqInner>> - -\* OLD DEFS: -\*DoDeqI(d) == /\ PreStutterEnabled("EndDeq", d) -\* /\ deq[d] = Busy -\* /\ minimalElts # {} -\* /\ IF s = top /\ Q = << >> -\* THEN /\ \E el \in minimalElts : -\* /\ Q' = <<el>> -\* /\ Assign(enqInner, Writer(el), Done) -\* /\ SetStutter("EndDeq", d, FALSE) -\* /\ UNCHANGED deqInner -\* ELSE /\ Q' = Tail(Q) -\* /\ SetStutter("EndDeq", d, TRUE) -\* /\ Assign(deqInner, d, Head(Q)) -\* /\ UNCHANGED enqInner -\* /\ UNCHANGED <<vars, p>> -\* -\*EndDeqI(d) == /\ AfterPreStutterEnabled("EndDeq", d) -\* /\ EndDeq(d) -\* /\ p = << >> \/ Head(p) = deqInner[d] -\* /\ p' = Tail(p) -\* /\ s' = top -\* /\ UNCHANGED <<Q, enqInner, deqInner>> -(*************************************************************************** -XEndDeq(d, el) defined so that - - EndDeq(d) == \E el \in Elements : XEndDeq(d, el) - ***************************************************************************) -XEndDeq(d, el) == /\ deq[d] = Busy - /\ el \in minimalElts - /\ RemoveElt(el) - /\ Assign(deq, d, el.data) - /\ UNCHANGED <<enq, adding>> - -DoDeqI(d, el) == /\ PreStutterEnabled("EndDeq", <<d, el>>) - /\ deq[d] = Busy - /\ el \in minimalElts - /\ \/ p = << >> /\ p' = << >> /\ Assert(FALSE, "shouldn't happen") - \/ Head(p) = el /\ p' = Tail(p) - /\ IF s = top /\ Q = << >> - THEN \* I believe this case should never occur - /\ Q' = <<el>> - /\ Assign(enqInner, Writer(el), Done) - /\ SetStutter("EndDeq", <<d, el>>, FALSE) - /\ UNCHANGED deqInner - ELSE /\ el = Head(Q) - /\ Q' = Tail(Q) - /\ SetStutter("EndDeq", <<d, el>>, TRUE) - /\ Assign(deqInner, d, Head(Q)) - /\ UNCHANGED enqInner - /\ UNCHANGED <<vars>> - -EndDeqI(d, el) == /\ AfterPreStutterEnabled("EndDeq", <<d, el>>) - /\ XEndDeq(d, el) -\* /\ p = << >> \/ Head(p) = deqInner[d] -\* /\ p' = Tail(p) - /\ s' = top - /\ UNCHANGED <<Q, enqInner, deqInner, p>> - -NextI == \/ \E e \in EnQers : BeginEnqI(e) \/ BeginEnqIDo(e) - \/ DoEnqI(e) \/ EndEnqI(e) - \/ \E d \in DeQers : \/ BeginDeqI(d) - \/ \E el \in Elements : DoDeqI(d, el) \/ EndDeqI(d, el) - -SpecI == InitI /\ [][NextI]_varsI ------------------------------------------------------------------------------ -queue == [i \in 1..Len(Q) |-> Q[i].data] - -deqInnerBar == [d \in DeQers |-> IF deqInner[d] = NoData THEN NoData - ELSE deqInner[d].data] -I == INSTANCE QSpec WITH deqInner <- deqInnerBar - +------------------------- MODULE NQSpecImpliesQSpec ------------------------- +EXTENDS NQSpec, FiniteSets, TLC + +\*NoData == NotData +NatSetMax(S) == IF S = {} THEN 0 ELSE CHOOSE n \in S : \A m \in S : n >=m +VARIABLE p, \* The prophecy variable = sequence of next values read, + \* of length Cardinality(elts) + Q, \* The queue of QSpec, except as Elements with their Ids, + \* and except that it is changed only on the actions + \* of NQSpec. Added as a history variable. + s, + \* A stuttering variable to add the actions + \* corresponding to the DoEnq and DoDeq actions of QSpec + enqInner, deqInner + \* History variables implementing the corresponding variables + \* of QSpec, except deqInner gets set to an Element el instead + \* of el.data + +\* The order of adding the variables is: +\* s, p, Q, {queue, enqInner, deqInner} +varsI == <<vars, p, Q, s, enqInner, deqInner>> + +top == CHOOSE t : t \notin {} +bot == [EndEnq |-> TRUE, EndDeq |-> TRUE] + +TypeOKI == /\ TypeOK + /\ Q \in Seq(Elements) + /\ p \in Seq(Elements) + /\ s \in {top} + \cup [type : {"EndDeq"}, name : DeQers \X Elements, val : {FALSE, TRUE}] + \cup [type : {"EndEnq"}, name : EnQers, val : {TRUE}] + \cup [type : {"BeginEnq"}, name : EnQers, val : Seq(Elements)] + /\ enqInner \in [EnQers -> {Done, Busy}] + /\ deqInner \in [DeQers -> {NoData} \cup Elements] + +InitI == /\ Init + /\ Q = << >> + /\ enqInner = [e \in EnQers |-> Done] + /\ \E i \in Ids : deqInner = [d \in DeQers |-> [data |-> InitData, + id |-> i]] + /\ p = << >> + /\ s = top + /\ TLCSet(1, {}) + +RemoveFrom(E, After) == [x \in (DOMAIN After) \ E |-> After[x] \ E] +RECURSIVE IsConsistent(_, _) +IsConsistent(seq, After) == + IF seq = << >> + THEN TRUE + ELSE LET hd == Head(seq) + Elts == DOMAIN After + IN /\ (hd \in DOMAIN After) /\ (After[hd] = {}) + /\ IsConsistent(Tail(seq), + RemoveFrom({hd}, After)) + +IsBlocking(el, After) == LET Elts == DOMAIN After + MinElts == MinimalElts(After) + IN (el \notin MinElts) /\ (doneElts # {}) + + +AllEnabled == s = top + +PostStutterEnabled(type, name) == (s # top) /\ (s.type = type) /\ (s.name = name) +PreStutterEnabled(type, name) == (s # top) => + /\ (s.type = type) /\ (s.name = name) + /\ s.val # bot[s.type] +AfterPreStutterEnabled(type, name) == /\ s # top + /\ (s.type = type) /\ (s.name = name) + /\ s.val = bot[s.type] + +SetStutter(type, name, val) == + /\ (s # top) => Assert(s.type = type /\ s.name = name, + "SetStutter not executed by owner of stuttering variable") + /\ s' = [type |-> type, name |-> name, val |-> val] + +Prefix(n, seq) == [i \in 1..n |-> seq[i]] +Suffix(n, seq) == [i \in 1..(Len(seq)-n) |-> seq[i+n]] +SeqElts(seq) == {seq[i] : i \in 1..Len(seq)} + +PInv == /\ Cardinality(elts) = Len(p) + +QInv == /\ Cardinality(SeqElts(Q)) = Len(Q) + /\ SeqElts(Q) \subseteq elts + /\ IsConsistent(Q, after) + /\ LET n == NatSetMax({i \in 1..Len(Q) : Prefix(i, Q) = Prefix(i, p)}) + IN (n < Len(Q)) => IsBlocking(p[n+1], + RemoveFrom(SeqElts(Prefix(n, Q)), after)) + +Writer(elt) == CHOOSE e \in EnQers : adding[e] = elt + +BeginEnqI(e) == /\ AllEnabled + /\ BeginEnq(e) + /\ \E el \in Elements : p' = Append(p, el) +\* /\ TLCSet(1, {p'} \cup TLCGet(1)) +\* /\ IF (Elements \X Elements \subseteq TLCGet(1)) +\* THEN /\ PrintT(TLCGet(1)) +\* /\ Assert (FALSE, "There") +\* ELSE TRUE +\*\* /\ PrintT(<<e, p, p', after'>>) + /\ LET RECURSIVE ToAdd(_, _) + ToAdd(i, After) == + IF (i > Len(p')) \/ p'[i] \notin MinimalElts(After) + THEN << >> + ELSE <<p'[i]>> \o ToAdd(i+1, RemoveFrom({p'[i]}, After)) + TA == ToAdd(Len(Q)+1, RemoveFrom(SeqElts(Q), after')) + IN IF TA # << >> + THEN SetStutter("BeginEnq", e, TA) + ELSE s' = s + /\ Assign(enqInner, e, Busy) + /\ UNCHANGED <<Q, deqInner>> + +BeginEnqIDo(e) == /\ PostStutterEnabled("BeginEnq", e) + /\ Q' = Append(Q, Head(s.val)) + /\ Assign(enqInner, Writer(Head(s.val)), Done) + /\ IF Tail(s.val) # << >> THEN SetStutter("BeginEnq", e, Tail(s.val)) + ELSE s' = top + /\ UNCHANGED <<vars, p, deqInner>> + +DoEnqI(e) == /\ PreStutterEnabled("EndEnq", e) + /\ enq[e] # Done + /\ IF enqInner[e] # Done \* adding[e] \notin SeqElts(Q) + THEN /\ Q' = Append(Q, adding[e]) + /\ Assign(enqInner, e, Done) + ELSE UNCHANGED <<Q, enqInner>> + /\ SetStutter("EndEnq", e, TRUE) + /\ UNCHANGED <<vars, p, deqInner>> + +EndEnqI(e) == /\ AfterPreStutterEnabled("EndEnq", e) + /\ EndEnq(e) + /\ s' = top + /\ UNCHANGED << p, Q, enqInner, deqInner>> + +BeginDeqI(d) == /\ AllEnabled + /\ BeginDeq(d) + /\ Assign(deqInner, d, NoData) + /\ UNCHANGED <<p, Q, s, enqInner>> + +\* OLD DEFS: +\*DoDeqI(d) == /\ PreStutterEnabled("EndDeq", d) +\* /\ deq[d] = Busy +\* /\ minimalElts # {} +\* /\ IF s = top /\ Q = << >> +\* THEN /\ \E el \in minimalElts : +\* /\ Q' = <<el>> +\* /\ Assign(enqInner, Writer(el), Done) +\* /\ SetStutter("EndDeq", d, FALSE) +\* /\ UNCHANGED deqInner +\* ELSE /\ Q' = Tail(Q) +\* /\ SetStutter("EndDeq", d, TRUE) +\* /\ Assign(deqInner, d, Head(Q)) +\* /\ UNCHANGED enqInner +\* /\ UNCHANGED <<vars, p>> +\* +\*EndDeqI(d) == /\ AfterPreStutterEnabled("EndDeq", d) +\* /\ EndDeq(d) +\* /\ p = << >> \/ Head(p) = deqInner[d] +\* /\ p' = Tail(p) +\* /\ s' = top +\* /\ UNCHANGED <<Q, enqInner, deqInner>> +(*************************************************************************** +XEndDeq(d, el) defined so that + + EndDeq(d) == \E el \in Elements : XEndDeq(d, el) + ***************************************************************************) +XEndDeq(d, el) == /\ deq[d] = Busy + /\ el \in minimalElts + /\ RemoveElt(el) + /\ Assign(deq, d, el.data) + /\ UNCHANGED <<enq, adding>> + +DoDeqI(d, el) == /\ PreStutterEnabled("EndDeq", <<d, el>>) + /\ deq[d] = Busy + /\ el \in minimalElts + /\ \/ p = << >> /\ p' = << >> /\ Assert(FALSE, "shouldn't happen") + \/ Head(p) = el /\ p' = Tail(p) + /\ IF s = top /\ Q = << >> + THEN \* I believe this case should never occur + /\ Q' = <<el>> + /\ Assign(enqInner, Writer(el), Done) + /\ SetStutter("EndDeq", <<d, el>>, FALSE) + /\ UNCHANGED deqInner + ELSE /\ el = Head(Q) + /\ Q' = Tail(Q) + /\ SetStutter("EndDeq", <<d, el>>, TRUE) + /\ Assign(deqInner, d, Head(Q)) + /\ UNCHANGED enqInner + /\ UNCHANGED <<vars>> + +EndDeqI(d, el) == /\ AfterPreStutterEnabled("EndDeq", <<d, el>>) + /\ XEndDeq(d, el) +\* /\ p = << >> \/ Head(p) = deqInner[d] +\* /\ p' = Tail(p) + /\ s' = top + /\ UNCHANGED <<Q, enqInner, deqInner, p>> + +NextI == \/ \E e \in EnQers : BeginEnqI(e) \/ BeginEnqIDo(e) + \/ DoEnqI(e) \/ EndEnqI(e) + \/ \E d \in DeQers : \/ BeginDeqI(d) + \/ \E el \in Elements : DoDeqI(d, el) \/ EndDeqI(d, el) + +SpecI == InitI /\ [][NextI]_varsI +----------------------------------------------------------------------------- +queue == [i \in 1..Len(Q) |-> Q[i].data] + +deqInnerBar == [d \in DeQers |-> IF deqInner[d] = NoData THEN NoData + ELSE deqInner[d].data] +I == INSTANCE QSpec WITH deqInner <- deqInnerBar + ============================================================================= -\* Modification History -\* Last modified Sat Nov 14 17:54:40 PST 2015 by lamport -\* Created Fri Nov 06 11:05:33 PST 2015 by lamport +\* Modification History +\* Last modified Sat Nov 14 17:54:40 PST 2015 by lamport +\* Created Fri Nov 06 11:05:33 PST 2015 by lamport diff --git a/tlatools/test-model/simulation/NQSpec/QSpec.tla b/tlatools/test-model/simulation/NQSpec/QSpec.tla index 19c85329e61bbe55f748ea4222f85398375fd9b1..ad2b1b3b8f3e06053d29ae5eeb5624781c125e67 100644 --- a/tlatools/test-model/simulation/NQSpec/QSpec.tla +++ b/tlatools/test-model/simulation/NQSpec/QSpec.tla @@ -1,66 +1,66 @@ -------------------------------- MODULE QSpec ------------------------------- -EXTENDS Integers, Sequences, TLC - -CONSTANTS EnQers, DeQers, Data, Done, Busy, NoData, InitData - -ASSUME /\ Done \notin Data - /\ Busy \notin Data - /\ NoData \notin Data - /\ InitData \in Data - -VARIABLES enq, deq, queue, enqInner, deqInner -vars == <<enq, deq, queue, enqInner, deqInner>> - -TypeOK == /\ enq \in [EnQers -> Data \cup {Done}] - /\ deq \in [DeQers -> Data \cup {Busy}] - /\ queue \in Seq(Data) - /\ enqInner \in [EnQers -> {Done, Busy}] - /\ deqInner \in [DeQers -> {NoData} \cup Data] - -Init == \* /\ PrintT("begin") - /\ enq = [e \in EnQers |-> Done] - /\ deq = [d \in DeQers |-> InitData] - /\ queue = << >> - /\ enqInner = [e \in EnQers |-> Done] \* /\ PrintT("foo") - /\ deqInner = [d \in DeQers |-> InitData] \* /\ PrintT("bar") - -BeginEnq(e) == /\ enq[e] = Done - /\ \E D \in Data : enq' = [enq EXCEPT ![e] = D] - /\ enqInner' = [enqInner EXCEPT ![e] = Busy] - /\ UNCHANGED <<deq, queue, deqInner>> - -DoEnq(e) == /\ enqInner[e] = Busy - /\ queue' = Append(queue, enq[e]) - /\ enqInner' = [enqInner EXCEPT ![e] = Done] - /\ UNCHANGED <<deq, enq, deqInner>> - -EndEnq(e) == /\ enq[e] # Done - /\ enqInner[e] = Done - /\ enq' = [enq EXCEPT ![e] = Done] - /\ UNCHANGED <<deq, queue, enqInner, deqInner>> - -BeginDeq(d) == /\ deq[d] # Busy - /\ deq' = [deq EXCEPT ![d] = Busy] - /\ deqInner' = [deqInner EXCEPT ![d] = NoData] - /\ UNCHANGED <<enq, queue, enqInner>> - -DoDeq(d) == /\ deq[d] = Busy - /\ deqInner[d] = NoData - /\ queue # << >> - /\ deqInner' = [deqInner EXCEPT ![d] = Head(queue)] - /\ queue' = Tail(queue) - /\ UNCHANGED <<enq, deq, enqInner>> - -EndDeq(d) == /\ deq[d] = Busy - /\ deqInner[d] # NoData - /\ deq' = [deq EXCEPT ![d] = deqInner[d]] - /\ UNCHANGED <<enq, queue, enqInner, deqInner>> - -Next == \/ \E e \in EnQers : BeginEnq(e) \/ DoEnq(e) \/ EndEnq(e) - \/ \E d \in DeQers : BeginDeq(d) \/ DoDeq(d) \/ EndDeq(d) - -Spec == Init /\ [][Next]_vars +------------------------------- MODULE QSpec ------------------------------- +EXTENDS Integers, Sequences, TLC + +CONSTANTS EnQers, DeQers, Data, Done, Busy, NoData, InitData + +ASSUME /\ Done \notin Data + /\ Busy \notin Data + /\ NoData \notin Data + /\ InitData \in Data + +VARIABLES enq, deq, queue, enqInner, deqInner +vars == <<enq, deq, queue, enqInner, deqInner>> + +TypeOK == /\ enq \in [EnQers -> Data \cup {Done}] + /\ deq \in [DeQers -> Data \cup {Busy}] + /\ queue \in Seq(Data) + /\ enqInner \in [EnQers -> {Done, Busy}] + /\ deqInner \in [DeQers -> {NoData} \cup Data] + +Init == \* /\ PrintT("begin") + /\ enq = [e \in EnQers |-> Done] + /\ deq = [d \in DeQers |-> InitData] + /\ queue = << >> + /\ enqInner = [e \in EnQers |-> Done] \* /\ PrintT("foo") + /\ deqInner = [d \in DeQers |-> InitData] \* /\ PrintT("bar") + +BeginEnq(e) == /\ enq[e] = Done + /\ \E D \in Data : enq' = [enq EXCEPT ![e] = D] + /\ enqInner' = [enqInner EXCEPT ![e] = Busy] + /\ UNCHANGED <<deq, queue, deqInner>> + +DoEnq(e) == /\ enqInner[e] = Busy + /\ queue' = Append(queue, enq[e]) + /\ enqInner' = [enqInner EXCEPT ![e] = Done] + /\ UNCHANGED <<deq, enq, deqInner>> + +EndEnq(e) == /\ enq[e] # Done + /\ enqInner[e] = Done + /\ enq' = [enq EXCEPT ![e] = Done] + /\ UNCHANGED <<deq, queue, enqInner, deqInner>> + +BeginDeq(d) == /\ deq[d] # Busy + /\ deq' = [deq EXCEPT ![d] = Busy] + /\ deqInner' = [deqInner EXCEPT ![d] = NoData] + /\ UNCHANGED <<enq, queue, enqInner>> + +DoDeq(d) == /\ deq[d] = Busy + /\ deqInner[d] = NoData + /\ queue # << >> + /\ deqInner' = [deqInner EXCEPT ![d] = Head(queue)] + /\ queue' = Tail(queue) + /\ UNCHANGED <<enq, deq, enqInner>> + +EndDeq(d) == /\ deq[d] = Busy + /\ deqInner[d] # NoData + /\ deq' = [deq EXCEPT ![d] = deqInner[d]] + /\ UNCHANGED <<enq, queue, enqInner, deqInner>> + +Next == \/ \E e \in EnQers : BeginEnq(e) \/ DoEnq(e) \/ EndEnq(e) + \/ \E d \in DeQers : BeginDeq(d) \/ DoDeq(d) \/ EndDeq(d) + +Spec == Init /\ [][Next]_vars ============================================================================= -\* Modification History -\* Last modified Sat Nov 14 12:56:11 PST 2015 by lamport -\* Created Wed Nov 04 15:29:04 PST 2015 by lamport +\* Modification History +\* Last modified Sat Nov 14 12:56:11 PST 2015 by lamport +\* Created Wed Nov 04 15:29:04 PST 2015 by lamport diff --git a/tlatools/test-model/suite/etest13.tla b/tlatools/test-model/suite/etest13.tla index f4f1c6f9140be499e46d413149a1338ba8d04038..e0d4e62c966367ddb93813ddb332358a98cea9e3 100644 --- a/tlatools/test-model/suite/etest13.tla +++ b/tlatools/test-model/suite/etest13.tla @@ -1,9 +1,9 @@ --------------------------- MODULE etest13 -------------------------------- -EXTENDS Naturals, TLC, FiniteSets -\* Test of error reporting when computing Cardinality of a huge set. - -ASSUME - IF Cardinality ([0..2 -> 1..2000]) = Cardinality ([2..4 -> 1..2000]) - THEN Print("Test 22 OK", TRUE) - ELSE Assert(FALSE, "Test 22 Failed") +-------------------------- MODULE etest13 -------------------------------- +EXTENDS Naturals, TLC, FiniteSets +\* Test of error reporting when computing Cardinality of a huge set. + +ASSUME + IF Cardinality ([0..2 -> 1..2000]) = Cardinality ([2..4 -> 1..2000]) + THEN Print("Test 22 OK", TRUE) + ELSE Assert(FALSE, "Test 22 Failed") ========================================================================== \ No newline at end of file diff --git a/tlatools/test-model/suite/etest14.tla b/tlatools/test-model/suite/etest14.tla index 97d71ce2b2df70fde6e5b02cbd7d19501d482843..e93ce4a819c7dc16c6c52de0b521146af97d4f8d 100644 --- a/tlatools/test-model/suite/etest14.tla +++ b/tlatools/test-model/suite/etest14.tla @@ -1,6 +1,6 @@ ----------------------- MODULE etest14 ----------------------------- - -\* Test of CHOOSEing element of empty set. -ASSUME - /\ (CHOOSE y \in {} : TRUE) = (CHOOSE y \in {} : TRUE) -===================================================================== +---------------------- MODULE etest14 ----------------------------- + +\* Test of CHOOSEing element of empty set. +ASSUME + /\ (CHOOSE y \in {} : TRUE) = (CHOOSE y \in {} : TRUE) +===================================================================== diff --git a/tlatools/test-model/suite/etest15.tla b/tlatools/test-model/suite/etest15.tla index 8835abc2a3f9fe1d6d9ac186d9f8f5b21a736796..af25c8cc9469be17cbb43b5e8a906a9aeaf2e9a8 100644 --- a/tlatools/test-model/suite/etest15.tla +++ b/tlatools/test-model/suite/etest15.tla @@ -1,10 +1,10 @@ ----------------------- MODULE etest15 ----------------------------- -\* Test that TLC distinguishes <<x>> from x in function expressions. - -EXTENDS Naturals - -S == {<<y>> : y \in {1, 2, 3, 4}} - -ASSUME [<<y>> \in S |-> y+1][2] = [<<y>> \in S |-> y+1][2] - -===================================================================== +---------------------- MODULE etest15 ----------------------------- +\* Test that TLC distinguishes <<x>> from x in function expressions. + +EXTENDS Naturals + +S == {<<y>> : y \in {1, 2, 3, 4}} + +ASSUME [<<y>> \in S |-> y+1][2] = [<<y>> \in S |-> y+1][2] + +===================================================================== diff --git a/tlatools/test-model/suite/etest16.tla b/tlatools/test-model/suite/etest16.tla index 9e3151531a9290872d53cb4480ebc949919d656d..d0d388ae3858ddef0d3abccf3e991eb0f0c0df5d 100644 --- a/tlatools/test-model/suite/etest16.tla +++ b/tlatools/test-model/suite/etest16.tla @@ -1,11 +1,11 @@ ---------------- MODULE etest16 ----------- - -\* Test of detecting duplicate record elements - -Foo == [a |-> 1, b |-> 2, a |-> 1] - -Bar == [a : {1}, b : {2}, a : {1}] -============================================================================= - - - +--------------- MODULE etest16 ----------- + +\* Test of detecting duplicate record elements + +Foo == [a |-> 1, b |-> 2, a |-> 1] + +Bar == [a : {1}, b : {2}, a : {1}] +============================================================================= + + + diff --git a/tlatools/test-model/suite/test201.tla b/tlatools/test-model/suite/test201.tla index 76c45796bcad4dd77528b773cc9d61c712fb578b..b2d3d5752a44c8ecb35d5802c3b0a7f1834cfc3f 100644 --- a/tlatools/test-model/suite/test201.tla +++ b/tlatools/test-model/suite/test201.tla @@ -1,20 +1,20 @@ --------------------- MODULE test201 ---------------- -\* Test of lambda expressions - -EXTENDS Naturals, TLC -Op(A(_)) == A(4) - -bar == Op(LAMBDA x : x^2) - -ASSUME /\ Op(LAMBDA x : {x,2} ) = {4,2} - /\ PrintT("Test1 OK") - -ASSUME /\ bar = 16 - /\ PrintT("Test2 OK") - -foo == INSTANCE test201a WITH A <- LAMBDA y : y^3, b <- 4 - -ASSUME /\ foo!def = 64 - /\ PrintT("Test201 OK") -================================================= - +-------------------- MODULE test201 ---------------- +\* Test of lambda expressions + +EXTENDS Naturals, TLC +Op(A(_)) == A(4) + +bar == Op(LAMBDA x : x^2) + +ASSUME /\ Op(LAMBDA x : {x,2} ) = {4,2} + /\ PrintT("Test1 OK") + +ASSUME /\ bar = 16 + /\ PrintT("Test2 OK") + +foo == INSTANCE test201a WITH A <- LAMBDA y : y^3, b <- 4 + +ASSUME /\ foo!def = 64 + /\ PrintT("Test201 OK") +================================================= + diff --git a/tlatools/test-model/suite/test201a.tla b/tlatools/test-model/suite/test201a.tla index 23c0983432153c439208a12c3554db7605b70fc7..1f5c21d50552d1fa1a74e50dab58a381f7acb211 100644 --- a/tlatools/test-model/suite/test201a.tla +++ b/tlatools/test-model/suite/test201a.tla @@ -1,7 +1,7 @@ --------------------- MODULE test201a ---------------- - -CONSTANT A(_), b - -def == A(b) - +-------------------- MODULE test201a ---------------- + +CONSTANT A(_), b + +def == A(b) + ============================================================================= \ No newline at end of file diff --git a/tlatools/test-model/suite/test202.tla b/tlatools/test-model/suite/test202.tla index e5ff4307de4d9e3c196b713cf054d5157a87e93f..bf779d2986e617f83e4070bf003f0cf88ea007ef 100644 --- a/tlatools/test-model/suite/test202.tla +++ b/tlatools/test-model/suite/test202.tla @@ -1,32 +1,32 @@ --------------------- MODULE test202 ---------------- -\* Test of recursion - -EXTENDS Naturals, TLC - -RECURSIVE g(_) -f(a) == IF a = 0 THEN 1 ELSE a * g(a-1) -g(a) == f(a) - - -ASSUME /\ f(0) = 1 - /\ f(4) = 24 - /\ \A i \in 1..5 : f(i) = i * f(i-1) - /\ PrintT("Test 1 OK") - -ASSUME /\ g(0) = 1 - /\ g(4) = 24 - /\ \A i \in 1..5 : g(i) = i * g(i-1) - /\ PrintT("Test 2 OK") - -RECURSIVE fact -fact1[n \in Nat] == fact[n] -fact[n \in Nat] == IF n = 0 THEN 1 ELSE n * fact1[n-1] - -ASSUME /\ fact1[3] = 6 - /\ fact[4] = 24 - /\ \A i \in 0..5 : fact[i] = g(i) - /\ PrintT("Test 3 OK") - - -================================================= - +-------------------- MODULE test202 ---------------- +\* Test of recursion + +EXTENDS Naturals, TLC + +RECURSIVE g(_) +f(a) == IF a = 0 THEN 1 ELSE a * g(a-1) +g(a) == f(a) + + +ASSUME /\ f(0) = 1 + /\ f(4) = 24 + /\ \A i \in 1..5 : f(i) = i * f(i-1) + /\ PrintT("Test 1 OK") + +ASSUME /\ g(0) = 1 + /\ g(4) = 24 + /\ \A i \in 1..5 : g(i) = i * g(i-1) + /\ PrintT("Test 2 OK") + +RECURSIVE fact +fact1[n \in Nat] == fact[n] +fact[n \in Nat] == IF n = 0 THEN 1 ELSE n * fact1[n-1] + +ASSUME /\ fact1[3] = 6 + /\ fact[4] = 24 + /\ \A i \in 0..5 : fact[i] = g(i) + /\ PrintT("Test 3 OK") + + +================================================= + diff --git a/tlatools/test-model/suite/test203.tla b/tlatools/test-model/suite/test203.tla index 62230616ae62f817fb5c88324467927e3d18b703..47ba23369b9232e869c454ec290ea756d2ee3c43 100644 --- a/tlatools/test-model/suite/test203.tla +++ b/tlatools/test-model/suite/test203.tla @@ -1,17 +1,17 @@ --------------------- MODULE test203 ---------------- -\* Test of recursion - -EXTENDS Naturals, TLC - -RECURSIVE g(_) - -foo(n) == INSTANCE test203a WITH A <- g, b <- n - -g(n) == IF n = 0 THEN 1 ELSE n * foo(n-1)!h - -ASSUME /\ g(0) = 1 - /\ g(4) = 24 - /\ \A i \in 1..5 : g(i) = i * g(i-1) - /\ PrintT("Test1 OK") -================================================= - +-------------------- MODULE test203 ---------------- +\* Test of recursion + +EXTENDS Naturals, TLC + +RECURSIVE g(_) + +foo(n) == INSTANCE test203a WITH A <- g, b <- n + +g(n) == IF n = 0 THEN 1 ELSE n * foo(n-1)!h + +ASSUME /\ g(0) = 1 + /\ g(4) = 24 + /\ \A i \in 1..5 : g(i) = i * g(i-1) + /\ PrintT("Test1 OK") +================================================= + diff --git a/tlatools/test-model/suite/test203a.tla b/tlatools/test-model/suite/test203a.tla index ad82d1eb31fbf9c5fc9986559b92782c6913ce04..4e3cc2422ced3efb13590461bf82d745063cb183 100644 --- a/tlatools/test-model/suite/test203a.tla +++ b/tlatools/test-model/suite/test203a.tla @@ -1,8 +1,8 @@ --------------------- MODULE test203a ---------------- - -CONSTANT A(_), b - -h == A(b) - - +-------------------- MODULE test203a ---------------- + +CONSTANT A(_), b + +h == A(b) + + ============================================================================= \ No newline at end of file diff --git a/tlatools/test-model/suite/test206.tla b/tlatools/test-model/suite/test206.tla index 113ba790596d68bccf659b55e7b3e4a7c8f8c39b..16f9e534db5b450cdc3242ad42bf6f9baa6848fb 100644 --- a/tlatools/test-model/suite/test206.tla +++ b/tlatools/test-model/suite/test206.tla @@ -1,238 +1,238 @@ -------------------------------- MODULE test206 ------------------------------ -\* Test of labels and their use in subexpression selectors. - -EXTENDS TLC, Integers - -CONSTANT C \* Test with C = 4 - -Op(Arg(_), p) == - \A x \in {1,2}, <<y, z>> \in {<<3, 4>>} : - lab(x,y,z) :: LET a ++ b == - Arg(a) + b + x + 2*y + 3*z - IN (Arg(1) + Arg(p) + C + - 2*x + 4*y + 6*z) = - 1 ++ ( label2 :: p ++ C) -\* IN /\label2:: PrintT("FOO") -\* /\ PrintT(Arg(1)) -\* /\ PrintT("FOO2") -\* /\ PrintT(<<p, Arg(p)>>) -\* /\ PrintT("FOO3") -\* /\ PrintT(<<p, C>>) -\* /\ PrintT("FOO3a") -\* /\ PrintT(1++2) -\* /\ PrintT(p++C) -\* /\ PrintT("FOO4") -\* /\ PrintT(<<x, y, z>>) - -Foo(u) == 2*u - -ASSUME Foo(5) = Foo(5)!: - -THEOREM Thm == ASSUME FALSE - PROVE lab:: C > 0 - -THEOREM Thm2 == lab3 :: TRUE - - -ASSUME Foo(25) = 50 - -Bar == Op(Foo, 9)!lab(1,2,3) - -ASSUME Op(Foo, 9) - -ASSUME Thm2!lab3 - -ASSUME Bar - -ASSUME Op(Foo, 9)!lab(1,2,3)!label2 = Op(Foo, 9)!lab(1,2,3)!:!++(9, 4) - -Op3(A(_,_,_), a1, a2, a3) == A(a1, a2, a3) - -Op1(a) == \A x \in {} : lab(x) :: IF TRUE - THEN LET Op1a(c) == 4 * c + a*x - IN a + Op1a(x) - ELSE 1 -SOp1(a) == a -OOp1(A(_), a) == A(a) -ASSUME OOp1(SOp1, 2) = 2 - -SOp1a(a) == {x \in {1,2} : a = x} -OOp2(A(_,_), a, b) == A(a, b) -ASSUME OOp2(SOp1a!@, 2, 2) = TRUE - -SOp1b(a) == {x + a : x \in {1,2}} -ASSUME OOp2(SOp1b!@, 2, 3) = 5 - -SOp1c(a) == {(LET c == a * x IN x + a) : x \in {1,2}} -ASSUME OOp2(SOp1c!@!c, 2, 3) = 2 * 3 - -SOp1d(a) == {(LET c(y) == (a * x) + y IN x + a) : x \in {1,2}} -OOp3(A(_,_,_), a, b, c) == A(a, b, c) -ASSUME OOp3(SOp1d!@!c, 2, 3, 4) = 2 * 3 + 4 - -OOp4(A(_,_,_,_), a, b, c, d) == A(a, b, c, d) - - -\* Foo1 == Op1(2)!(3)!2!1 -ASSUME Op1(2)!(3)!2!1 = 2 + 4*3 + 6 -ASSUME Op1(2)!(3)!2!Op1a(4) = 16 + 6 -ASSUME Op3(Op1!@!2!Op1a, 2, 3, 4) = 22 - -COp(q, p) == - CHOOSE x : lab(x) :: LET a ++ b == {a, b, q, p, x} - IN <<q, 99 ++ p >> - - -ASSUME COp(1, 2)!(3)!++(4, 5) = {2,1, 3, 4, 5} - -ASSUME COp(1, 2)!(3) = <<1, {99, 1, 2, 3} >> -ASSUME COp(1, 2)!(3)!1 = <<1, {99, 1, 2, 3} >> -ASSUME COp(1, 2)!(3)!1!>> = {99, 1, 2, 3} - -OOp5(A(_, _, _, _, _), a1, a2, a3, a4, a5) == A(a1, a2, a3, a4, a5) - -ASSUME OOp5(COp!@!++, 1, 2, 3, 4, 5) = {2,1, 3, 4, 5} -ASSUME COp(1, 2)!lab(3)!:!++(4, 5) = {2,1, 3, 4, 5} - -Inst == INSTANCE test206a WITH A5 <- COp!@!++ -ASSUME Inst!Foo(1, 2, 3, 4, 5) = {2,1, 3, 4, 5} -ASSUME Inst!Bar(3)!>> = 3 -ASSUME Inst!Bar2(3)!>> = 3 -ASSUME Inst!Bar3!>> = 2 -ASSUME Inst!Bar4(1)!(2)!<< = 2 -ASSUME Inst!Bar4(1)!(2)!>> = 1 -ASSUME Inst!Bar4(1)!lab(2)!<< = 2 -ASSUME Inst!Bar4(1)!lab(2)!>> = 1 -ASSUME OOp2(Inst!Bar4!@!<<, 1, 2) = 2 -ASSUME OOp2(Inst!Bar4!@!>>, 1, 2) = 1 -ASSUME OOp2(Inst!Bar4!lab!<<, 1, 2) = 2 -ASSUME OOp2(Inst!Bar4!lab!>>, 1, 2) = 1 -ASSUME Inst!Bar5(1)!lab(2)!:!++(3, 4) = <<1, 3, 4, 2>> -ASSUME Inst!Bar5(1)!(2)!++(3, 4) = <<1, 3, 4, 2>> -ASSUME OOp4(Inst!Bar5!lab!:!++, 1, 2, 3, 4) = <<1, 3, 4, 2>> - -Inst2(A5(_, _, _, _, _)) == INSTANCE test206a -ASSUME Inst2(COp!@!++)!Foo(1, 2, 3, 4, 5) = {2,1, 3, 4, 5} - - -COp2(q, p) == - CHOOSE x : lab(x) :: LET a ++ b == {lab(y):: y + a + b : y \in {1}} - IN <<q, 99 ++ p >> - -ASSUME COp2(1,2)!lab(3)!:!++(9,10)!lab(11) = 30 -ASSUME COp2(1,2)!(3)!++(9,10)!lab(11) = 30 -ASSUME COp2(1,2)!lab(3)!:!++(9,10)!(11) = 30 -OOp6(A(_, _, _, _, _, _), a1, a2, a3, a4, a5, a6) == A(a1, a2, a3, a4, a5, a6) -ASSUME OOp6(COp2!lab!:!++!lab, 1, 2, 3, 9, 10, 11) = 30 -ASSUME OOp6(COp2!@!++!lab, 1, 2, 3, 9, 10, 11) = 30 -ASSUME OOp6(COp2!lab!:!++!@, 1, 2, 3, 9, 10, 11) = 30 - -\* Let's test all the different kinds of operators - -Def1 == {1, 2, 3, 4} -ASSUME Def1!2 = 2 - -Def2 == {x \in {1, 2, 3} : x > 17} -ASSUME Def2!1 = {1, 2, 3} -ASSUME Def2!(14)!<< = 14 - -Def3 == {<<x, y>> : x \in {1}, y \in {2}} -ASSUME Def3!2!1 = 2 -ASSUME Def3!(1, 2)!<< = 1 - -Def4 == SUBSET UNION {{1}, {2}} -ASSUME Def4!<<!<<!2 = {2} - -Def5 == [i \in 1..10 |-> i+1][3] -ASSUME Def5!>> = 3 -ASSUME Def5!<<[4] = 5 -ASSUME Def5!<<!1!>> = 10 - -Def6 == [[i \in 1..10 |-> i+1] EXCEPT ![2] = 1, ![3] = 2] -ASSUME Def6!1[3] = 4 -\* The following two subexpression expressions are now -\* considered to be illegal because they could contain -\* a "@". -\* ASSUME Def6!2=1 -\* ASSUME Def6!3=2 - -Def7 == 3.a -ASSUME Def7!1 = 3 -ASSUME Def7!2 = "a" - -Def8 == [a |-> 1, b |-> 2] -ASSUME Def8!2 = 2 - -Def9 == [a : 1, b : 2] -ASSUME Def9!2 = 2 - -Def10 == <<1, 2, 3>> -ASSUME Def10!2 = 2 - -Def11 == {1} \X {2} \X {3} -ASSUME Def11!3!1 = 3 - -Def12 == IF 2=3 THEN 2 ELSE 3 -ASSUME /\ Def12!1!<< = 2 - /\ Def12!2 = 2 - /\ Def12!3 = 3 - -Def13 == \A x : CASE x=1 -> 1 - [] x=2 -> 2 - [] OTHER -> 3 -ASSUME /\ Def13!(42)!1!<<!<< = 42 - /\ Def13!(42)!1!>> = 1 - /\ Def13!(42)!2!>> = 2 - /\ Def13!(42)!3!>> = 3 - -Def14 == \A x \in {1} : x = 1 -ASSUME /\ Def14!(2)!<< = 2 - /\ Def14!1!1 = 1 - -Def15 == \A x \in {1}, y \in {2} : (x = 1) /\ (y = 2) -ASSUME /\ Def15!(2,3)!<<!<< = 2 - /\ Def15!(2,3)!>>!<< = 3 - /\ Def15!2!<< = 2 - -Def16 == \E x \in {1}, <<y, z>> \in {<<2,3>>} : /\ ((x = 1)) - /\ y = 2 - /\ (z=3) -ASSUME /\ Def16!(2,3,4)!1!1 = 2 - /\ Def16!(2,3,4)!2!1 = 3 - /\ Def16!2!1!<< = 2 - -Def17 == \E x , y, z : /\ ((x = 1)) - /\ y = 2 - /\ (z=3) -ASSUME /\ Def17!(2,3,4)!1!1 = 2 - /\ Def17!(2,3,4)!2!1 = 3 - -Def18 == CHOOSE x : (x=1) -ASSUME Def18!(2)!<< = 2 - -Def19 == CHOOSE x \in {42}: (x=1) -ASSUME /\ Def19!(2)!<< = 2 - /\ Def19!1!1 = 42 - -Def20 == [12]_(23) -ASSUME /\ Def20!1 = 12 - /\ Def20!>> = 23 - -Def21 == <<12>>_(23) -ASSUME /\ Def21!1 = 12 - /\ Def21!>> = 23 - -Def22 == WF_(12)(23) -ASSUME /\ Def22!1 = 12 - /\ Def22!>> = 23 - -Def23 == \EE x , y, z : /\ ((x = 1)) - /\ y = 2 - /\ (z=3) -ASSUME /\ Def23!(2,3,4)!1!1 = 2 - /\ Def23!(2,3,4)!2!1 = 3 - - -============================================================================= - +------------------------------- MODULE test206 ------------------------------ +\* Test of labels and their use in subexpression selectors. + +EXTENDS TLC, Integers + +CONSTANT C \* Test with C = 4 + +Op(Arg(_), p) == + \A x \in {1,2}, <<y, z>> \in {<<3, 4>>} : + lab(x,y,z) :: LET a ++ b == + Arg(a) + b + x + 2*y + 3*z + IN (Arg(1) + Arg(p) + C + + 2*x + 4*y + 6*z) = + 1 ++ ( label2 :: p ++ C) +\* IN /\label2:: PrintT("FOO") +\* /\ PrintT(Arg(1)) +\* /\ PrintT("FOO2") +\* /\ PrintT(<<p, Arg(p)>>) +\* /\ PrintT("FOO3") +\* /\ PrintT(<<p, C>>) +\* /\ PrintT("FOO3a") +\* /\ PrintT(1++2) +\* /\ PrintT(p++C) +\* /\ PrintT("FOO4") +\* /\ PrintT(<<x, y, z>>) + +Foo(u) == 2*u + +ASSUME Foo(5) = Foo(5)!: + +THEOREM Thm == ASSUME FALSE + PROVE lab:: C > 0 + +THEOREM Thm2 == lab3 :: TRUE + + +ASSUME Foo(25) = 50 + +Bar == Op(Foo, 9)!lab(1,2,3) + +ASSUME Op(Foo, 9) + +ASSUME Thm2!lab3 + +ASSUME Bar + +ASSUME Op(Foo, 9)!lab(1,2,3)!label2 = Op(Foo, 9)!lab(1,2,3)!:!++(9, 4) + +Op3(A(_,_,_), a1, a2, a3) == A(a1, a2, a3) + +Op1(a) == \A x \in {} : lab(x) :: IF TRUE + THEN LET Op1a(c) == 4 * c + a*x + IN a + Op1a(x) + ELSE 1 +SOp1(a) == a +OOp1(A(_), a) == A(a) +ASSUME OOp1(SOp1, 2) = 2 + +SOp1a(a) == {x \in {1,2} : a = x} +OOp2(A(_,_), a, b) == A(a, b) +ASSUME OOp2(SOp1a!@, 2, 2) = TRUE + +SOp1b(a) == {x + a : x \in {1,2}} +ASSUME OOp2(SOp1b!@, 2, 3) = 5 + +SOp1c(a) == {(LET c == a * x IN x + a) : x \in {1,2}} +ASSUME OOp2(SOp1c!@!c, 2, 3) = 2 * 3 + +SOp1d(a) == {(LET c(y) == (a * x) + y IN x + a) : x \in {1,2}} +OOp3(A(_,_,_), a, b, c) == A(a, b, c) +ASSUME OOp3(SOp1d!@!c, 2, 3, 4) = 2 * 3 + 4 + +OOp4(A(_,_,_,_), a, b, c, d) == A(a, b, c, d) + + +\* Foo1 == Op1(2)!(3)!2!1 +ASSUME Op1(2)!(3)!2!1 = 2 + 4*3 + 6 +ASSUME Op1(2)!(3)!2!Op1a(4) = 16 + 6 +ASSUME Op3(Op1!@!2!Op1a, 2, 3, 4) = 22 + +COp(q, p) == + CHOOSE x : lab(x) :: LET a ++ b == {a, b, q, p, x} + IN <<q, 99 ++ p >> + + +ASSUME COp(1, 2)!(3)!++(4, 5) = {2,1, 3, 4, 5} + +ASSUME COp(1, 2)!(3) = <<1, {99, 1, 2, 3} >> +ASSUME COp(1, 2)!(3)!1 = <<1, {99, 1, 2, 3} >> +ASSUME COp(1, 2)!(3)!1!>> = {99, 1, 2, 3} + +OOp5(A(_, _, _, _, _), a1, a2, a3, a4, a5) == A(a1, a2, a3, a4, a5) + +ASSUME OOp5(COp!@!++, 1, 2, 3, 4, 5) = {2,1, 3, 4, 5} +ASSUME COp(1, 2)!lab(3)!:!++(4, 5) = {2,1, 3, 4, 5} + +Inst == INSTANCE test206a WITH A5 <- COp!@!++ +ASSUME Inst!Foo(1, 2, 3, 4, 5) = {2,1, 3, 4, 5} +ASSUME Inst!Bar(3)!>> = 3 +ASSUME Inst!Bar2(3)!>> = 3 +ASSUME Inst!Bar3!>> = 2 +ASSUME Inst!Bar4(1)!(2)!<< = 2 +ASSUME Inst!Bar4(1)!(2)!>> = 1 +ASSUME Inst!Bar4(1)!lab(2)!<< = 2 +ASSUME Inst!Bar4(1)!lab(2)!>> = 1 +ASSUME OOp2(Inst!Bar4!@!<<, 1, 2) = 2 +ASSUME OOp2(Inst!Bar4!@!>>, 1, 2) = 1 +ASSUME OOp2(Inst!Bar4!lab!<<, 1, 2) = 2 +ASSUME OOp2(Inst!Bar4!lab!>>, 1, 2) = 1 +ASSUME Inst!Bar5(1)!lab(2)!:!++(3, 4) = <<1, 3, 4, 2>> +ASSUME Inst!Bar5(1)!(2)!++(3, 4) = <<1, 3, 4, 2>> +ASSUME OOp4(Inst!Bar5!lab!:!++, 1, 2, 3, 4) = <<1, 3, 4, 2>> + +Inst2(A5(_, _, _, _, _)) == INSTANCE test206a +ASSUME Inst2(COp!@!++)!Foo(1, 2, 3, 4, 5) = {2,1, 3, 4, 5} + + +COp2(q, p) == + CHOOSE x : lab(x) :: LET a ++ b == {lab(y):: y + a + b : y \in {1}} + IN <<q, 99 ++ p >> + +ASSUME COp2(1,2)!lab(3)!:!++(9,10)!lab(11) = 30 +ASSUME COp2(1,2)!(3)!++(9,10)!lab(11) = 30 +ASSUME COp2(1,2)!lab(3)!:!++(9,10)!(11) = 30 +OOp6(A(_, _, _, _, _, _), a1, a2, a3, a4, a5, a6) == A(a1, a2, a3, a4, a5, a6) +ASSUME OOp6(COp2!lab!:!++!lab, 1, 2, 3, 9, 10, 11) = 30 +ASSUME OOp6(COp2!@!++!lab, 1, 2, 3, 9, 10, 11) = 30 +ASSUME OOp6(COp2!lab!:!++!@, 1, 2, 3, 9, 10, 11) = 30 + +\* Let's test all the different kinds of operators + +Def1 == {1, 2, 3, 4} +ASSUME Def1!2 = 2 + +Def2 == {x \in {1, 2, 3} : x > 17} +ASSUME Def2!1 = {1, 2, 3} +ASSUME Def2!(14)!<< = 14 + +Def3 == {<<x, y>> : x \in {1}, y \in {2}} +ASSUME Def3!2!1 = 2 +ASSUME Def3!(1, 2)!<< = 1 + +Def4 == SUBSET UNION {{1}, {2}} +ASSUME Def4!<<!<<!2 = {2} + +Def5 == [i \in 1..10 |-> i+1][3] +ASSUME Def5!>> = 3 +ASSUME Def5!<<[4] = 5 +ASSUME Def5!<<!1!>> = 10 + +Def6 == [[i \in 1..10 |-> i+1] EXCEPT ![2] = 1, ![3] = 2] +ASSUME Def6!1[3] = 4 +\* The following two subexpression expressions are now +\* considered to be illegal because they could contain +\* a "@". +\* ASSUME Def6!2=1 +\* ASSUME Def6!3=2 + +Def7 == 3.a +ASSUME Def7!1 = 3 +ASSUME Def7!2 = "a" + +Def8 == [a |-> 1, b |-> 2] +ASSUME Def8!2 = 2 + +Def9 == [a : 1, b : 2] +ASSUME Def9!2 = 2 + +Def10 == <<1, 2, 3>> +ASSUME Def10!2 = 2 + +Def11 == {1} \X {2} \X {3} +ASSUME Def11!3!1 = 3 + +Def12 == IF 2=3 THEN 2 ELSE 3 +ASSUME /\ Def12!1!<< = 2 + /\ Def12!2 = 2 + /\ Def12!3 = 3 + +Def13 == \A x : CASE x=1 -> 1 + [] x=2 -> 2 + [] OTHER -> 3 +ASSUME /\ Def13!(42)!1!<<!<< = 42 + /\ Def13!(42)!1!>> = 1 + /\ Def13!(42)!2!>> = 2 + /\ Def13!(42)!3!>> = 3 + +Def14 == \A x \in {1} : x = 1 +ASSUME /\ Def14!(2)!<< = 2 + /\ Def14!1!1 = 1 + +Def15 == \A x \in {1}, y \in {2} : (x = 1) /\ (y = 2) +ASSUME /\ Def15!(2,3)!<<!<< = 2 + /\ Def15!(2,3)!>>!<< = 3 + /\ Def15!2!<< = 2 + +Def16 == \E x \in {1}, <<y, z>> \in {<<2,3>>} : /\ ((x = 1)) + /\ y = 2 + /\ (z=3) +ASSUME /\ Def16!(2,3,4)!1!1 = 2 + /\ Def16!(2,3,4)!2!1 = 3 + /\ Def16!2!1!<< = 2 + +Def17 == \E x , y, z : /\ ((x = 1)) + /\ y = 2 + /\ (z=3) +ASSUME /\ Def17!(2,3,4)!1!1 = 2 + /\ Def17!(2,3,4)!2!1 = 3 + +Def18 == CHOOSE x : (x=1) +ASSUME Def18!(2)!<< = 2 + +Def19 == CHOOSE x \in {42}: (x=1) +ASSUME /\ Def19!(2)!<< = 2 + /\ Def19!1!1 = 42 + +Def20 == [12]_(23) +ASSUME /\ Def20!1 = 12 + /\ Def20!>> = 23 + +Def21 == <<12>>_(23) +ASSUME /\ Def21!1 = 12 + /\ Def21!>> = 23 + +Def22 == WF_(12)(23) +ASSUME /\ Def22!1 = 12 + /\ Def22!>> = 23 + +Def23 == \EE x , y, z : /\ ((x = 1)) + /\ y = 2 + /\ (z=3) +ASSUME /\ Def23!(2,3,4)!1!1 = 2 + /\ Def23!(2,3,4)!2!1 = 3 + + +============================================================================= + last modified on Tue 9 March 2010 at 11:49:54 PST by lamport \ No newline at end of file diff --git a/tlatools/test-model/suite/test206a.tla b/tlatools/test-model/suite/test206a.tla index 11bb0d2d27e882f5f69ffa3d27dda492bcded99b..add74af1a0e13af6987c95283dacbef9eab2d75c 100644 --- a/tlatools/test-model/suite/test206a.tla +++ b/tlatools/test-model/suite/test206a.tla @@ -1,12 +1,12 @@ ------------------------------ MODULE test206a ----------------------------- - -CONSTANT A5(_, _, _, _, _) - -Foo(a1, a2, a3, a4, a5) == A5(a1, a2, a3, a4, a5) -Bar(a) == <<1, a>> -Bar2(a) == <<1, lab::a>> -Bar3 == <<1, 2>> -Bar4(a) == {x \in {1} : lab(x) :: <<x, a>>} -Bar5(a) == {x \in {1} : lab(x) :: LET b ++ c == <<a, b, c, x>> - IN 42 } +----------------------------- MODULE test206a ----------------------------- + +CONSTANT A5(_, _, _, _, _) + +Foo(a1, a2, a3, a4, a5) == A5(a1, a2, a3, a4, a5) +Bar(a) == <<1, a>> +Bar2(a) == <<1, lab::a>> +Bar3 == <<1, 2>> +Bar4(a) == {x \in {1} : lab(x) :: <<x, a>>} +Bar5(a) == {x \in {1} : lab(x) :: LET b ++ c == <<a, b, c, x>> + IN 42 } ============================================================================= \ No newline at end of file diff --git a/tlatools/test-model/suite/test207.cfg b/tlatools/test-model/suite/test207.cfg index d3f5a12faa99758192ecc4ed3fc22c9249232e86..8b137891791fe96927ad78e64b0aad7bded08bdc 100644 --- a/tlatools/test-model/suite/test207.cfg +++ b/tlatools/test-model/suite/test207.cfg @@ -1 +1 @@ - + diff --git a/tlatools/test-model/suite/test207.tla b/tlatools/test-model/suite/test207.tla index c1723057ef5a9ac210ab6af7095e274e8882e19b..c8b6cd6974c96fd1d3289c707bca5039404a12f5 100644 --- a/tlatools/test-model/suite/test207.tla +++ b/tlatools/test-model/suite/test207.tla @@ -1,38 +1,38 @@ -\* SANY2 test. -\* Test of scope of NEW declarations. They should be restricted -\* to the statement's proof, except for SUFFICES which should be -\* visible to the rest of the current proof. - --------------------- MODULE test207 ---------------- -EXTENDS TLC -a + b == <<a, b>> -THEOREM Thm == ASSUME NEW J PROVE lab :: TRUE -<1>1 ASSUME NEW I - PROVE Thm!lab - <2>1 I = J - <2>2 QED -<1> DEFINE I == 1 -<1>2 ASSUME NEW K - PROVE TRUE -<1>3 SUFFICES ASSUME NEW K - PROVE TRUE - <2>1. \A K : TRUE - <2>2. SUFFICES ASSUME NEW L - PROVE TRUE - <2>3. QED -<1>3a. DEFINE L == 0 -<1>4. K = 0 \* 12 June 14 Changed from <*>4 which is now illegal. - <2>1. DEFINE F == 7 - <2>4. TRUE \* 12 June 14 Changed from <*>4 which is now illegal. - <2>2. QED - BY <2>4 -<1>4a. DEFINE F == 42 -<1>5 QED - BY <1>4 -J == 0 -I == 0 -F == 1 - -ASSUME PrintT("SANY2 Test") - -============================= +\* SANY2 test. +\* Test of scope of NEW declarations. They should be restricted +\* to the statement's proof, except for SUFFICES which should be +\* visible to the rest of the current proof. + +-------------------- MODULE test207 ---------------- +EXTENDS TLC +a + b == <<a, b>> +THEOREM Thm == ASSUME NEW J PROVE lab :: TRUE +<1>1 ASSUME NEW I + PROVE Thm!lab + <2>1 I = J + <2>2 QED +<1> DEFINE I == 1 +<1>2 ASSUME NEW K + PROVE TRUE +<1>3 SUFFICES ASSUME NEW K + PROVE TRUE + <2>1. \A K : TRUE + <2>2. SUFFICES ASSUME NEW L + PROVE TRUE + <2>3. QED +<1>3a. DEFINE L == 0 +<1>4. K = 0 \* 12 June 14 Changed from <*>4 which is now illegal. + <2>1. DEFINE F == 7 + <2>4. TRUE \* 12 June 14 Changed from <*>4 which is now illegal. + <2>2. QED + BY <2>4 +<1>4a. DEFINE F == 42 +<1>5 QED + BY <1>4 +J == 0 +I == 0 +F == 1 + +ASSUME PrintT("SANY2 Test") + +============================= diff --git a/tlatools/test-model/suite/test208.cfg b/tlatools/test-model/suite/test208.cfg index d3f5a12faa99758192ecc4ed3fc22c9249232e86..8b137891791fe96927ad78e64b0aad7bded08bdc 100644 --- a/tlatools/test-model/suite/test208.cfg +++ b/tlatools/test-model/suite/test208.cfg @@ -1 +1 @@ - + diff --git a/tlatools/test-model/suite/test208.tla b/tlatools/test-model/suite/test208.tla index 08cd7dc26b470290018a33146f8654a34fdd6132..8f938c37b8b8d648da0e14862f7362d0fc60bf0a 100644 --- a/tlatools/test-model/suite/test208.tla +++ b/tlatools/test-model/suite/test208.tla @@ -1,203 +1,203 @@ -\* SANY2 test. -\* Test to make sure that all keywords are useable as record fields. - --------------------- MODULE test208 ---------------- -bar == 17 - -LEMMA TRUE -PROPOSITION TRUE -ASSUMPTION TRUE - -Foo == -/\ bar.NEW \cup [bar EXCEPT !.NEW = 0] -/\ bar.SF_ \cup [bar EXCEPT !.SF_ = 0] -/\ bar.WF_ \cup [bar EXCEPT !.WF_ = 0] -/\ bar.THEN \cup [bar EXCEPT !.THEN = 0] -/\ bar.BY \cup [bar EXCEPT !.BY = 0] \* 68 XXXXXX -/\ bar.HAVE \cup [bar EXCEPT !.HAVE = 0] -/\ bar.QED \cup [bar EXCEPT !.QED = 0] -/\ bar.TAKE \cup [bar EXCEPT !.TAKE = 0] - -/\ bar.DEF \cup [bar EXCEPT !.DEF = 0] -/\ bar.HIDE \cup [bar EXCEPT !.HIDE = 0] -/\ bar.RECURSIVE \cup [bar EXCEPT !.RECURSIVE = 0] \* XXXXX 82 -/\ bar.USE \cup [bar EXCEPT !.USE = 0] - -/\ bar.DEFINE \cup [bar EXCEPT !.DEFINE = 0] -/\ bar.PROOF \cup [bar EXCEPT !.PROOF = 0] -/\ bar.WITNESS \cup [bar EXCEPT !.WITNESS = 0] -/\ bar.PICK \cup [bar EXCEPT !.PICK = 0] - -/\ bar.DEFS \cup [bar EXCEPT !.DEFS = 0] -/\ bar.PROVE \cup [bar EXCEPT !.PROVE = 0] -/\ bar.SUFFICES \cup [bar EXCEPT !.SUFFICES = 0] -/\ bar.NEW \cup [bar EXCEPT !.NEW = 0] - -/\ bar.LAMBDA \cup [bar EXCEPT !.LAMBDA = 0] -/\ bar.LEMMA \cup [bar EXCEPT !.LEMMA = 0] -/\ bar.PROPOSITION \cup [bar EXCEPT !.PROPOSITION = 0] -/\ bar.STATE \cup [bar EXCEPT !.STATE = 0] -/\ bar.ACTION \cup [bar EXCEPT !.ACTION = 0] -/\ bar.TEMPORAL \cup [bar EXCEPT !.TEMPORAL = 0] -/\ bar.VARIABLE \cup [bar EXCEPT !.VARIABLE = 0] - -/\ bar.OBVIOUS \cup [bar EXCEPT !.OBVIOUS = 0] -/\ bar.OMITTED \cup [bar EXCEPT !.OMITTED = 0] - -/\ bar.ASSUME \cup [bar EXCEPT !.ASSUME = 0] -/\ bar.ELSE \cup [bar EXCEPT !.ELSE = 0] -/\ bar.LOCAL \cup [bar EXCEPT !.LOCAL = 0] -/\ bar.UNION \cup [bar EXCEPT !.UNION = 0] - -/\ bar.ASSUMPTION \cup [bar EXCEPT !.ASSUMPTION = 0] -/\ bar.ENABLED \cup [bar EXCEPT !.ENABLED = 0] -/\ bar.MODULE \cup [bar EXCEPT !.MODULE = 0] -/\ bar.VARIABLE \cup [bar EXCEPT !.VARIABLE = 0] - -/\ bar.AXIOM \cup [bar EXCEPT !.AXIOM = 0] -/\ bar.EXCEPT \cup [bar EXCEPT !.EXCEPT = 0] -/\ bar.OTHER \cup [bar EXCEPT !.OTHER = 0] -/\ bar.VARIABLES \cup [bar EXCEPT !.VARIABLES = 0] - -/\ bar.CASE \cup [bar EXCEPT !.CASE = 0] -/\ bar.EXTENDS \cup [bar EXCEPT !.EXTENDS = 0] -/\ bar.SF_ \cup [bar EXCEPT !.SF_ = 0] -/\ bar.WF_ \cup [bar EXCEPT !.WF_ = 0] - -/\ bar.CHOOSE \cup [bar EXCEPT !.CHOOSE = 0] -/\ bar.IF \cup [bar EXCEPT !.IF = 0] \* XXXXX -/\ bar.SUBSET \cup [bar EXCEPT !.SUBSET = 0] -/\ bar.WITH \cup [bar EXCEPT !.WITH = 0] - -/\ bar.CONSTANT \cup [bar EXCEPT !.CONSTANT = 0] -/\ bar.IN \cup [bar EXCEPT !.IN = 0] -/\ bar.THEN \cup [bar EXCEPT !.THEN = 0] \* XXXXX - -/\ bar.CONSTANTS \cup [bar EXCEPT !.CONSTANTS = 0] -/\ bar.INSTANCE \cup [bar EXCEPT !.INSTANCE = 0] -/\ bar.THEOREM \cup [bar EXCEPT !.THEOREM = 0] \* XXXXX - -/\ bar.DOMAIN \cup [bar EXCEPT !.DOMAIN = 0] -/\ bar.LET \cup [bar EXCEPT !.LET = 0] -/\ bar.UNCHANGED \cup [bar EXCEPT !.UNCHANGED = 0] -================================ - - - -THEOREM Bar == ASSUME NEW y, ASSUME TRUE PROVE FALSE - PROVE TRUE - - -THEOREM TRUE - <1>1. TAKE x \in << a:: {}, {}>> - <1>2. <1>1!a - <1>3. <1>1!1 - <1> QED - - -================================================== -a+b == <<a, b>> -THEOREM TRUE -<1>2 TRUE - <33>1 HAVE ~ TRUE - <33>2 TAKE Id, Id1 - <33>3 TAKE Id4 \in {1}, <<Id2, Id3>> \in {2} - <33>123 FooBar == <<Id, Id1, Id4, Id2, Id3>> - <33>4 WITNESS {1} - <33>5 WITNESS {1} \in {2}, {3} - <33>-... PICK x : ~ FALSE - <+>*. PICK y \in {1} : ~ FALSE - <*>* QED - <33>7 PICK y \in {1} : <33>5!1!1 + <33>3!1 - PROOF <55>1... TRUE - <*>2.... USE <33>5, <33>7!1!1, <33>7!(42)!<< DEF + - <55>2 QED - <33>7a Foo == << <33>7!(1)!<< , <33>7!>> >> - <33>8 PICK z \in {1}, <<y1, z1>> \in {2} : ~ FALSE - <33>9 PICK w, u : <<1, 2, 3>> - <34>* DEFINE A == <<x, y, z, y1, z1, w, u>> - <34>*. B == A!1 - <34> QED - <33>44 DEFINE A == <<x, y, z, y1, z1, w, u>> - <33>*. B == <33>9!(1,2)!3 - <33>. BBC(Op(_,_)) == Op(1,2) - DD == BBC(<33>9!@) - <33>22 ASSUME TRUE PROVE FALSE - <33> BBB == \A xxxx \in {} : TRUE - <33>14. INSTANCE Test1 - <*> AA == INSTANCE Test1 - <33> B3 == AA!Foo3!Def2 - <*>a ASSUME FALSE PROVE TRUE - <33>b CASE TRUE - <33>c SUFFICES TRUE - <33>. SUFFICES ASSUME FALSE PROVE TRUE - <33>2a. QED -<1>14 HAVE <<1, 2, 3>> -<1>14a havedef == <1>14!1!3 -<*> TAKE Id7 \in {1} -<*> WITNESS {1} \in {2} -<*> PICK x2 \in {1}, y2 \in {2} : ~ FALSE - <+> PICK x3, y3 : ~ FALSE - <*>*. DEFINE A2 == 1 - <*>2 B2 == 17 - <*> ASSUME FALSE PROVE TRUE - <*> CASE TRUE - <*> TRUE - <*> SUFFICES ASSUME FALSE PROVE TRUE - <2> QED -<1>... DEFINE A == 1 -<1> B == 17 -<1> INSTANCE Test1 -<1> AA == INSTANCE Test2 WITH B <- 1 -<1>3. QED - -=============================== - -\* Foo == \A x , y, z : TRUE -\* Bar == \A x \in {}, y, z \in {}, <<u, v>> \in {} : TRUE -\* Inst(a) == INSTANCE Test1 -\* Foo == Inst(7)!Bar1 -THEOREM Thm2 == TRUE - <1>2 QED - PROOF USE <1>2 - QED -==================== - PROOF -\* DEFINE Def1 == TRUE - USE Thm2!: \* DEF Thm2 , Inst!Bar2 -\* Def2 == TRUE - QED -\* PROOF USE Def1 DEFS Def2 -\* QED -================================= -THEOREM Thm3 == FALSE - PROOF DEFINE A == B - PROVE /\ TRUE - /\ 1=1 - BY Thm2 - QED -========================================================== -THEOREM 1 - PROOF QED - PROOF OBVIOUS -================================================= -============================================================================= - -BY [.] -USE DEF FALSE -HIDE -<1>abc FALSE - BY MODULE M DEF MODULE M, 2 [.] -A == B -DEFINE F == INSTANCE M -A[x \in S] == B -INSTANCE M -<1>2. QED -(******** - PROOF ASSUME TRUE PROVE FALSE - <1>1. TRUE - <1>2. QED - HAVE TRUE - QED -********) -============================================================================= +\* SANY2 test. +\* Test to make sure that all keywords are useable as record fields. + +-------------------- MODULE test208 ---------------- +bar == 17 + +LEMMA TRUE +PROPOSITION TRUE +ASSUMPTION TRUE + +Foo == +/\ bar.NEW \cup [bar EXCEPT !.NEW = 0] +/\ bar.SF_ \cup [bar EXCEPT !.SF_ = 0] +/\ bar.WF_ \cup [bar EXCEPT !.WF_ = 0] +/\ bar.THEN \cup [bar EXCEPT !.THEN = 0] +/\ bar.BY \cup [bar EXCEPT !.BY = 0] \* 68 XXXXXX +/\ bar.HAVE \cup [bar EXCEPT !.HAVE = 0] +/\ bar.QED \cup [bar EXCEPT !.QED = 0] +/\ bar.TAKE \cup [bar EXCEPT !.TAKE = 0] + +/\ bar.DEF \cup [bar EXCEPT !.DEF = 0] +/\ bar.HIDE \cup [bar EXCEPT !.HIDE = 0] +/\ bar.RECURSIVE \cup [bar EXCEPT !.RECURSIVE = 0] \* XXXXX 82 +/\ bar.USE \cup [bar EXCEPT !.USE = 0] + +/\ bar.DEFINE \cup [bar EXCEPT !.DEFINE = 0] +/\ bar.PROOF \cup [bar EXCEPT !.PROOF = 0] +/\ bar.WITNESS \cup [bar EXCEPT !.WITNESS = 0] +/\ bar.PICK \cup [bar EXCEPT !.PICK = 0] + +/\ bar.DEFS \cup [bar EXCEPT !.DEFS = 0] +/\ bar.PROVE \cup [bar EXCEPT !.PROVE = 0] +/\ bar.SUFFICES \cup [bar EXCEPT !.SUFFICES = 0] +/\ bar.NEW \cup [bar EXCEPT !.NEW = 0] + +/\ bar.LAMBDA \cup [bar EXCEPT !.LAMBDA = 0] +/\ bar.LEMMA \cup [bar EXCEPT !.LEMMA = 0] +/\ bar.PROPOSITION \cup [bar EXCEPT !.PROPOSITION = 0] +/\ bar.STATE \cup [bar EXCEPT !.STATE = 0] +/\ bar.ACTION \cup [bar EXCEPT !.ACTION = 0] +/\ bar.TEMPORAL \cup [bar EXCEPT !.TEMPORAL = 0] +/\ bar.VARIABLE \cup [bar EXCEPT !.VARIABLE = 0] + +/\ bar.OBVIOUS \cup [bar EXCEPT !.OBVIOUS = 0] +/\ bar.OMITTED \cup [bar EXCEPT !.OMITTED = 0] + +/\ bar.ASSUME \cup [bar EXCEPT !.ASSUME = 0] +/\ bar.ELSE \cup [bar EXCEPT !.ELSE = 0] +/\ bar.LOCAL \cup [bar EXCEPT !.LOCAL = 0] +/\ bar.UNION \cup [bar EXCEPT !.UNION = 0] + +/\ bar.ASSUMPTION \cup [bar EXCEPT !.ASSUMPTION = 0] +/\ bar.ENABLED \cup [bar EXCEPT !.ENABLED = 0] +/\ bar.MODULE \cup [bar EXCEPT !.MODULE = 0] +/\ bar.VARIABLE \cup [bar EXCEPT !.VARIABLE = 0] + +/\ bar.AXIOM \cup [bar EXCEPT !.AXIOM = 0] +/\ bar.EXCEPT \cup [bar EXCEPT !.EXCEPT = 0] +/\ bar.OTHER \cup [bar EXCEPT !.OTHER = 0] +/\ bar.VARIABLES \cup [bar EXCEPT !.VARIABLES = 0] + +/\ bar.CASE \cup [bar EXCEPT !.CASE = 0] +/\ bar.EXTENDS \cup [bar EXCEPT !.EXTENDS = 0] +/\ bar.SF_ \cup [bar EXCEPT !.SF_ = 0] +/\ bar.WF_ \cup [bar EXCEPT !.WF_ = 0] + +/\ bar.CHOOSE \cup [bar EXCEPT !.CHOOSE = 0] +/\ bar.IF \cup [bar EXCEPT !.IF = 0] \* XXXXX +/\ bar.SUBSET \cup [bar EXCEPT !.SUBSET = 0] +/\ bar.WITH \cup [bar EXCEPT !.WITH = 0] + +/\ bar.CONSTANT \cup [bar EXCEPT !.CONSTANT = 0] +/\ bar.IN \cup [bar EXCEPT !.IN = 0] +/\ bar.THEN \cup [bar EXCEPT !.THEN = 0] \* XXXXX + +/\ bar.CONSTANTS \cup [bar EXCEPT !.CONSTANTS = 0] +/\ bar.INSTANCE \cup [bar EXCEPT !.INSTANCE = 0] +/\ bar.THEOREM \cup [bar EXCEPT !.THEOREM = 0] \* XXXXX + +/\ bar.DOMAIN \cup [bar EXCEPT !.DOMAIN = 0] +/\ bar.LET \cup [bar EXCEPT !.LET = 0] +/\ bar.UNCHANGED \cup [bar EXCEPT !.UNCHANGED = 0] +================================ + + + +THEOREM Bar == ASSUME NEW y, ASSUME TRUE PROVE FALSE + PROVE TRUE + + +THEOREM TRUE + <1>1. TAKE x \in << a:: {}, {}>> + <1>2. <1>1!a + <1>3. <1>1!1 + <1> QED + + +================================================== +a+b == <<a, b>> +THEOREM TRUE +<1>2 TRUE + <33>1 HAVE ~ TRUE + <33>2 TAKE Id, Id1 + <33>3 TAKE Id4 \in {1}, <<Id2, Id3>> \in {2} + <33>123 FooBar == <<Id, Id1, Id4, Id2, Id3>> + <33>4 WITNESS {1} + <33>5 WITNESS {1} \in {2}, {3} + <33>-... PICK x : ~ FALSE + <+>*. PICK y \in {1} : ~ FALSE + <*>* QED + <33>7 PICK y \in {1} : <33>5!1!1 + <33>3!1 + PROOF <55>1... TRUE + <*>2.... USE <33>5, <33>7!1!1, <33>7!(42)!<< DEF + + <55>2 QED + <33>7a Foo == << <33>7!(1)!<< , <33>7!>> >> + <33>8 PICK z \in {1}, <<y1, z1>> \in {2} : ~ FALSE + <33>9 PICK w, u : <<1, 2, 3>> + <34>* DEFINE A == <<x, y, z, y1, z1, w, u>> + <34>*. B == A!1 + <34> QED + <33>44 DEFINE A == <<x, y, z, y1, z1, w, u>> + <33>*. B == <33>9!(1,2)!3 + <33>. BBC(Op(_,_)) == Op(1,2) + DD == BBC(<33>9!@) + <33>22 ASSUME TRUE PROVE FALSE + <33> BBB == \A xxxx \in {} : TRUE + <33>14. INSTANCE Test1 + <*> AA == INSTANCE Test1 + <33> B3 == AA!Foo3!Def2 + <*>a ASSUME FALSE PROVE TRUE + <33>b CASE TRUE + <33>c SUFFICES TRUE + <33>. SUFFICES ASSUME FALSE PROVE TRUE + <33>2a. QED +<1>14 HAVE <<1, 2, 3>> +<1>14a havedef == <1>14!1!3 +<*> TAKE Id7 \in {1} +<*> WITNESS {1} \in {2} +<*> PICK x2 \in {1}, y2 \in {2} : ~ FALSE + <+> PICK x3, y3 : ~ FALSE + <*>*. DEFINE A2 == 1 + <*>2 B2 == 17 + <*> ASSUME FALSE PROVE TRUE + <*> CASE TRUE + <*> TRUE + <*> SUFFICES ASSUME FALSE PROVE TRUE + <2> QED +<1>... DEFINE A == 1 +<1> B == 17 +<1> INSTANCE Test1 +<1> AA == INSTANCE Test2 WITH B <- 1 +<1>3. QED + +=============================== + +\* Foo == \A x , y, z : TRUE +\* Bar == \A x \in {}, y, z \in {}, <<u, v>> \in {} : TRUE +\* Inst(a) == INSTANCE Test1 +\* Foo == Inst(7)!Bar1 +THEOREM Thm2 == TRUE + <1>2 QED + PROOF USE <1>2 + QED +==================== + PROOF +\* DEFINE Def1 == TRUE + USE Thm2!: \* DEF Thm2 , Inst!Bar2 +\* Def2 == TRUE + QED +\* PROOF USE Def1 DEFS Def2 +\* QED +================================= +THEOREM Thm3 == FALSE + PROOF DEFINE A == B + PROVE /\ TRUE + /\ 1=1 + BY Thm2 + QED +========================================================== +THEOREM 1 + PROOF QED + PROOF OBVIOUS +================================================= +============================================================================= + +BY [.] +USE DEF FALSE +HIDE +<1>abc FALSE + BY MODULE M DEF MODULE M, 2 [.] +A == B +DEFINE F == INSTANCE M +A[x \in S] == B +INSTANCE M +<1>2. QED +(******** + PROOF ASSUME TRUE PROVE FALSE + <1>1. TRUE + <1>2. QED + HAVE TRUE + QED +********) +============================================================================= diff --git a/tlatools/test-model/suite/test209.cfg b/tlatools/test-model/suite/test209.cfg index d3f5a12faa99758192ecc4ed3fc22c9249232e86..8b137891791fe96927ad78e64b0aad7bded08bdc 100644 --- a/tlatools/test-model/suite/test209.cfg +++ b/tlatools/test-model/suite/test209.cfg @@ -1 +1 @@ - + diff --git a/tlatools/test-model/suite/test209.tla b/tlatools/test-model/suite/test209.tla index 28e824c8dbe30afb9aa1c43f4094304a6400bd29..70d8ad7998d6035eaca0e392f88c6af640c93c9e 100644 --- a/tlatools/test-model/suite/test209.tla +++ b/tlatools/test-model/suite/test209.tla @@ -1,293 +1,293 @@ -\* Test of positional subexpression naming. --------------------- MODULE test209 ---------------- -EXTENDS Naturals, Sequences - -xx == <<11, <<22,33>>, 33>> -F(a) == /\ TRUE - /\ TRUE - /\ Len(xx[a]) > 0 - /\ TRUE - -ASSUME F(2)!3 = (Len(xx[2]) > 0) -ASSUME F(2)!3!1 = Len(xx[2]) -ASSUME F(2)!3!1!1 = xx[2] -ASSUME F(2)!3!1!1!2 = 2 -ASSUME F(2)!3!1!1!1 = xx -ASSUME F(2)!3!<< = Len(xx[2]) -ASSUME F(2)!3!<<!<< = xx[2] -ASSUME F(2)!3!<<!<<!>> = 2 -ASSUME F(2)!3!<<!<<!<< = xx - -G == [xx EXCEPT ![1] = 42, ![2] = 55] -H == xx.foo -I == [fld1 |-> 1, fld2 |->2, fld3 |-> 3] -J == [fld1 : 1, fld2 :2, fld3 : 3] - -ASSUME G!1 = xx -\* Selection of EXCEPT fields disabled because of "@" problem. -\* ASSUME G!2 = 42 -\* ASSUME G!3 = 55 -ASSUME H!1 = xx -ASSUME H!2 = "foo" -\* ASSUME I!3 = "fld3" -ASSUME I!3 = 3 - -\* ASSUME J!3 = "fld3" -ASSUME J!3 = 3 - -K == IF 41 THEN 42 ELSE 43 -ASSUME K!1 = 41 -ASSUME K!2 = 42 -ASSUME K!3 = 43 - -L == CASE 1 -> 11 [] - 2 -> 22 [] - OTHER -> 33 - -ASSUME L!1!1 = 1 -ASSUME L!1!2 = 11 -ASSUME L!2!1 = 2 -ASSUME L!2!2 = 22 -ASSUME L!3!2 = 33 - -M == LET Z == 23 IN Z -Z == 44 -ASSUME M!1 = 23 - -NN == 55 -N == [44]_NN -O == <<44>>_NN -P == WF_NN(44) -Q == SF_NN(44) - -ASSUME N!1 = 44 -ASSUME N!2 = 55 -ASSUME O!1 = 44 -ASSUME O!2 = 55 -ASSUME P!1 = 55 -ASSUME P!2 = 44 -ASSUME Q!1 = 55 -ASSUME Q!2 = 44 - -R == \E x \in {1}, y \in {2} : x + y > 2 -ASSUME R!1 = {1} -ASSUME R!2 = {2} -ASSUME R!(1,2)!<< = 3 - -S == [x, y \in {1, 2}, z \in {3} |-> x+y+z] -ASSUME S!1 = {1, 2} -ASSUME S!2 = {3} -ASSUME S!(2, 3, 4) = 2+3+4 - -T(Op(_)) == Op(42) -U == /\ LET Op(x) == x+1 - IN 44 - /\ TRUE -ASSUME T(U!1!Op) = 43 -ASSUME U!1!Op(42) = 43 -ASSUME U!1!Op(42)!: = 43 -V == \A x \in {} : 2*x -ASSUME T(V!@) = 84 -ASSUME T(LAMBDA x : 2*x) = 84 - -============================================================================= - -CONSTANT bar - -LEMMA TRUE -PROPOSITION TRUE -ASSUMPTION TRUE - -Foo == -/\ bar.NEW \cup [bar EXCEPT !.NEW = 0] -/\ bar.SF_ \cup [bar EXCEPT !.SF_ = 0] -/\ bar.WF_ \cup [bar EXCEPT !.WF_ = 0] -/\ bar.THEN \cup [bar EXCEPT !.THEN = 0] -/\ bar.BY \cup [bar EXCEPT !.BY = 0] \* 68 XXXXXX -/\ bar.HAVE \cup [bar EXCEPT !.HAVE = 0] -/\ bar.QED \cup [bar EXCEPT !.QED = 0] -/\ bar.TAKE \cup [bar EXCEPT !.TAKE = 0] - -/\ bar.DEF \cup [bar EXCEPT !.DEF = 0] -/\ bar.HIDE \cup [bar EXCEPT !.HIDE = 0] -/\ bar.RECURSIVE \cup [bar EXCEPT !.RECURSIVE = 0] \* XXXXX 82 -/\ bar.USE \cup [bar EXCEPT !.USE = 0] - -/\ bar.DEFINE \cup [bar EXCEPT !.DEFINE = 0] -/\ bar.PROOF \cup [bar EXCEPT !.PROOF = 0] -/\ bar.WITNESS \cup [bar EXCEPT !.WITNESS = 0] -/\ bar.PICK \cup [bar EXCEPT !.PICK = 0] - -/\ bar.DEFS \cup [bar EXCEPT !.DEFS = 0] -/\ bar.PROVE \cup [bar EXCEPT !.PROVE = 0] -/\ bar.SUFFICES \cup [bar EXCEPT !.SUFFICES = 0] -/\ bar.NEW \cup [bar EXCEPT !.NEW = 0] - -/\ bar.LAMBDA \cup [bar EXCEPT !.LAMBDA = 0] -/\ bar.LEMMA \cup [bar EXCEPT !.LEMMA = 0] -/\ bar.PROPOSITION \cup [bar EXCEPT !.PROPOSITION = 0] -/\ bar.STATE \cup [bar EXCEPT !.STATE = 0] -/\ bar.ACTION \cup [bar EXCEPT !.ACTION = 0] -/\ bar.TEMPORAL \cup [bar EXCEPT !.TEMPORAL = 0] -/\ bar.VARIABLE \cup [bar EXCEPT !.VARIABLE = 0] - -/\ bar.OBVIOUS \cup [bar EXCEPT !.OBVIOUS = 0] -/\ bar.OMITTED \cup [bar EXCEPT !.OMITTED = 0] - -/\ bar.ASSUME \cup [bar EXCEPT !.ASSUME = 0] -/\ bar.ELSE \cup [bar EXCEPT !.ELSE = 0] -/\ bar.LOCAL \cup [bar EXCEPT !.LOCAL = 0] -/\ bar.UNION \cup [bar EXCEPT !.UNION = 0] - -/\ bar.ASSUMPTION \cup [bar EXCEPT !.ASSUMPTION = 0] -/\ bar.ENABLED \cup [bar EXCEPT !.ENABLED = 0] -/\ bar.MODULE \cup [bar EXCEPT !.MODULE = 0] -/\ bar.VARIABLE \cup [bar EXCEPT !.VARIABLE = 0] - -/\ bar.AXIOM \cup [bar EXCEPT !.AXIOM = 0] -/\ bar.EXCEPT \cup [bar EXCEPT !.EXCEPT = 0] -/\ bar.OTHER \cup [bar EXCEPT !.OTHER = 0] -/\ bar.VARIABLES \cup [bar EXCEPT !.VARIABLES = 0] - -/\ bar.CASE \cup [bar EXCEPT !.CASE = 0] -/\ bar.EXTENDS \cup [bar EXCEPT !.EXTENDS = 0] -/\ bar.SF_ \cup [bar EXCEPT !.SF_ = 0] -/\ bar.WF_ \cup [bar EXCEPT !.WF_ = 0] - -/\ bar.CHOOSE \cup [bar EXCEPT !.CHOOSE = 0] -/\ bar.IF \cup [bar EXCEPT !.IF = 0] \* XXXXX -/\ bar.SUBSET \cup [bar EXCEPT !.SUBSET = 0] -/\ bar.WITH \cup [bar EXCEPT !.WITH = 0] - -/\ bar.CONSTANT \cup [bar EXCEPT !.CONSTANT = 0] -/\ bar.IN \cup [bar EXCEPT !.IN = 0] -/\ bar.THEN \cup [bar EXCEPT !.THEN = 0] \* XXXXX - -/\ bar.CONSTANTS \cup [bar EXCEPT !.CONSTANTS = 0] -/\ bar.INSTANCE \cup [bar EXCEPT !.INSTANCE = 0] -/\ bar.THEOREM \cup [bar EXCEPT !.THEOREM = 0] \* XXXXX - -/\ bar.DOMAIN \cup [bar EXCEPT !.DOMAIN = 0] -/\ bar.LET \cup [bar EXCEPT !.LET = 0] -/\ bar.UNCHANGED \cup [bar EXCEPT !.UNCHANGED = 0] -================================ - - - -THEOREM Bar == ASSUME NEW y, ASSUME TRUE PROVE FALSE - PROVE TRUE - - -THEOREM TRUE - <1>1. TAKE x \in << a:: {}, {}>> - <1>2. <1>1!a - <1>3. <1>1!1 - <1> QED - - -================================================== -a+b == <<a, b>> -THEOREM TRUE -<1>2 TRUE - <33>1 HAVE ~ TRUE - <33>2 TAKE Id, Id1 - <33>3 TAKE Id4 \in {1}, <<Id2, Id3>> \in {2} - <33>123 FooBar == <<Id, Id1, Id4, Id2, Id3>> - <33>4 WITNESS {1} - <33>5 WITNESS {1} \in {2}, {3} - <33>-... PICK x : ~ FALSE - <+>*. PICK y \in {1} : ~ FALSE - <*>* QED - <33>7 PICK y \in {1} : <33>5!1!1 + <33>3!1 - PROOF <55>1... TRUE - <*>2.... USE <33>5, <33>7!1!1, <33>7!(42)!<< DEF + - <55>2 QED - <33>7a Foo == << <33>7!(1)!<< , <33>7!>> >> - <33>8 PICK z \in {1}, <<y1, z1>> \in {2} : ~ FALSE - <33>9 PICK w, u : <<1, 2, 3>> - <34>* DEFINE A == <<x, y, z, y1, z1, w, u>> - <34>*. B == A!1 - <34> QED - <33>44 DEFINE A == <<x, y, z, y1, z1, w, u>> - <33>*. B == <33>9!(1,2)!3 - <33>. BBC(Op(_,_)) == Op(1,2) - DD == BBC(<33>9!@) - <33>22 ASSUME TRUE PROVE FALSE - <33> BBB == \A xxxx \in {} : TRUE - <33>14. INSTANCE Test1 - <*> AA == INSTANCE Test1 - <33> B3 == AA!Foo3!Def2 - <*>a ASSUME FALSE PROVE TRUE - <33>b CASE TRUE - <33>c SUFFICES TRUE - <33>. SUFFICES ASSUME FALSE PROVE TRUE - <33>2a. QED -<1>14 HAVE <<1, 2, 3>> -<1>14a havedef == <1>14!1!3 -<*> TAKE Id7 \in {1} -<*> WITNESS {1} \in {2} -<*> PICK x2 \in {1}, y2 \in {2} : ~ FALSE - <+> PICK x3, y3 : ~ FALSE - <*>*. DEFINE A2 == 1 - <*>2 B2 == 17 - <*> ASSUME FALSE PROVE TRUE - <*> CASE TRUE - <*> TRUE - <*> SUFFICES ASSUME FALSE PROVE TRUE - <2> QED -<1>... DEFINE A == 1 -<1> B == 17 -<1> INSTANCE Test1 -<1> AA == INSTANCE Test2 WITH B <- 1 -<1>3. QED - -=============================== - -\* Foo == \A x , y, z : TRUE -\* Bar == \A x \in {}, y, z \in {}, <<u, v>> \in {} : TRUE -\* Inst(a) == INSTANCE Test1 -\* Foo == Inst(7)!Bar1 -THEOREM Thm2 == TRUE - <1>2 QED - PROOF USE <1>2 - QED -==================== - PROOF -\* DEFINE Def1 == TRUE - USE Thm2!: \* DEF Thm2 , Inst!Bar2 -\* Def2 == TRUE - QED -\* PROOF USE Def1 DEFS Def2 -\* QED -================================= -THEOREM Thm3 == FALSE - PROOF DEFINE A == B - PROVE /\ TRUE - /\ 1=1 - BY Thm2 - QED -========================================================== -THEOREM 1 - PROOF QED - PROOF OBVIOUS -================================================= -============================================================================= - -BY [.] -USE DEF FALSE -HIDE -<1>abc FALSE - BY MODULE M DEF MODULE M, 2 [.] -A == B -DEFINE F == INSTANCE M -A[x \in S] == B -INSTANCE M -<1>2. QED -(******** - PROOF ASSUME TRUE PROVE FALSE - <1>1. TRUE - <1>2. QED - HAVE TRUE - QED -********) -============================================================================= +\* Test of positional subexpression naming. +-------------------- MODULE test209 ---------------- +EXTENDS Naturals, Sequences + +xx == <<11, <<22,33>>, 33>> +F(a) == /\ TRUE + /\ TRUE + /\ Len(xx[a]) > 0 + /\ TRUE + +ASSUME F(2)!3 = (Len(xx[2]) > 0) +ASSUME F(2)!3!1 = Len(xx[2]) +ASSUME F(2)!3!1!1 = xx[2] +ASSUME F(2)!3!1!1!2 = 2 +ASSUME F(2)!3!1!1!1 = xx +ASSUME F(2)!3!<< = Len(xx[2]) +ASSUME F(2)!3!<<!<< = xx[2] +ASSUME F(2)!3!<<!<<!>> = 2 +ASSUME F(2)!3!<<!<<!<< = xx + +G == [xx EXCEPT ![1] = 42, ![2] = 55] +H == xx.foo +I == [fld1 |-> 1, fld2 |->2, fld3 |-> 3] +J == [fld1 : 1, fld2 :2, fld3 : 3] + +ASSUME G!1 = xx +\* Selection of EXCEPT fields disabled because of "@" problem. +\* ASSUME G!2 = 42 +\* ASSUME G!3 = 55 +ASSUME H!1 = xx +ASSUME H!2 = "foo" +\* ASSUME I!3 = "fld3" +ASSUME I!3 = 3 + +\* ASSUME J!3 = "fld3" +ASSUME J!3 = 3 + +K == IF 41 THEN 42 ELSE 43 +ASSUME K!1 = 41 +ASSUME K!2 = 42 +ASSUME K!3 = 43 + +L == CASE 1 -> 11 [] + 2 -> 22 [] + OTHER -> 33 + +ASSUME L!1!1 = 1 +ASSUME L!1!2 = 11 +ASSUME L!2!1 = 2 +ASSUME L!2!2 = 22 +ASSUME L!3!2 = 33 + +M == LET Z == 23 IN Z +Z == 44 +ASSUME M!1 = 23 + +NN == 55 +N == [44]_NN +O == <<44>>_NN +P == WF_NN(44) +Q == SF_NN(44) + +ASSUME N!1 = 44 +ASSUME N!2 = 55 +ASSUME O!1 = 44 +ASSUME O!2 = 55 +ASSUME P!1 = 55 +ASSUME P!2 = 44 +ASSUME Q!1 = 55 +ASSUME Q!2 = 44 + +R == \E x \in {1}, y \in {2} : x + y > 2 +ASSUME R!1 = {1} +ASSUME R!2 = {2} +ASSUME R!(1,2)!<< = 3 + +S == [x, y \in {1, 2}, z \in {3} |-> x+y+z] +ASSUME S!1 = {1, 2} +ASSUME S!2 = {3} +ASSUME S!(2, 3, 4) = 2+3+4 + +T(Op(_)) == Op(42) +U == /\ LET Op(x) == x+1 + IN 44 + /\ TRUE +ASSUME T(U!1!Op) = 43 +ASSUME U!1!Op(42) = 43 +ASSUME U!1!Op(42)!: = 43 +V == \A x \in {} : 2*x +ASSUME T(V!@) = 84 +ASSUME T(LAMBDA x : 2*x) = 84 + +============================================================================= + +CONSTANT bar + +LEMMA TRUE +PROPOSITION TRUE +ASSUMPTION TRUE + +Foo == +/\ bar.NEW \cup [bar EXCEPT !.NEW = 0] +/\ bar.SF_ \cup [bar EXCEPT !.SF_ = 0] +/\ bar.WF_ \cup [bar EXCEPT !.WF_ = 0] +/\ bar.THEN \cup [bar EXCEPT !.THEN = 0] +/\ bar.BY \cup [bar EXCEPT !.BY = 0] \* 68 XXXXXX +/\ bar.HAVE \cup [bar EXCEPT !.HAVE = 0] +/\ bar.QED \cup [bar EXCEPT !.QED = 0] +/\ bar.TAKE \cup [bar EXCEPT !.TAKE = 0] + +/\ bar.DEF \cup [bar EXCEPT !.DEF = 0] +/\ bar.HIDE \cup [bar EXCEPT !.HIDE = 0] +/\ bar.RECURSIVE \cup [bar EXCEPT !.RECURSIVE = 0] \* XXXXX 82 +/\ bar.USE \cup [bar EXCEPT !.USE = 0] + +/\ bar.DEFINE \cup [bar EXCEPT !.DEFINE = 0] +/\ bar.PROOF \cup [bar EXCEPT !.PROOF = 0] +/\ bar.WITNESS \cup [bar EXCEPT !.WITNESS = 0] +/\ bar.PICK \cup [bar EXCEPT !.PICK = 0] + +/\ bar.DEFS \cup [bar EXCEPT !.DEFS = 0] +/\ bar.PROVE \cup [bar EXCEPT !.PROVE = 0] +/\ bar.SUFFICES \cup [bar EXCEPT !.SUFFICES = 0] +/\ bar.NEW \cup [bar EXCEPT !.NEW = 0] + +/\ bar.LAMBDA \cup [bar EXCEPT !.LAMBDA = 0] +/\ bar.LEMMA \cup [bar EXCEPT !.LEMMA = 0] +/\ bar.PROPOSITION \cup [bar EXCEPT !.PROPOSITION = 0] +/\ bar.STATE \cup [bar EXCEPT !.STATE = 0] +/\ bar.ACTION \cup [bar EXCEPT !.ACTION = 0] +/\ bar.TEMPORAL \cup [bar EXCEPT !.TEMPORAL = 0] +/\ bar.VARIABLE \cup [bar EXCEPT !.VARIABLE = 0] + +/\ bar.OBVIOUS \cup [bar EXCEPT !.OBVIOUS = 0] +/\ bar.OMITTED \cup [bar EXCEPT !.OMITTED = 0] + +/\ bar.ASSUME \cup [bar EXCEPT !.ASSUME = 0] +/\ bar.ELSE \cup [bar EXCEPT !.ELSE = 0] +/\ bar.LOCAL \cup [bar EXCEPT !.LOCAL = 0] +/\ bar.UNION \cup [bar EXCEPT !.UNION = 0] + +/\ bar.ASSUMPTION \cup [bar EXCEPT !.ASSUMPTION = 0] +/\ bar.ENABLED \cup [bar EXCEPT !.ENABLED = 0] +/\ bar.MODULE \cup [bar EXCEPT !.MODULE = 0] +/\ bar.VARIABLE \cup [bar EXCEPT !.VARIABLE = 0] + +/\ bar.AXIOM \cup [bar EXCEPT !.AXIOM = 0] +/\ bar.EXCEPT \cup [bar EXCEPT !.EXCEPT = 0] +/\ bar.OTHER \cup [bar EXCEPT !.OTHER = 0] +/\ bar.VARIABLES \cup [bar EXCEPT !.VARIABLES = 0] + +/\ bar.CASE \cup [bar EXCEPT !.CASE = 0] +/\ bar.EXTENDS \cup [bar EXCEPT !.EXTENDS = 0] +/\ bar.SF_ \cup [bar EXCEPT !.SF_ = 0] +/\ bar.WF_ \cup [bar EXCEPT !.WF_ = 0] + +/\ bar.CHOOSE \cup [bar EXCEPT !.CHOOSE = 0] +/\ bar.IF \cup [bar EXCEPT !.IF = 0] \* XXXXX +/\ bar.SUBSET \cup [bar EXCEPT !.SUBSET = 0] +/\ bar.WITH \cup [bar EXCEPT !.WITH = 0] + +/\ bar.CONSTANT \cup [bar EXCEPT !.CONSTANT = 0] +/\ bar.IN \cup [bar EXCEPT !.IN = 0] +/\ bar.THEN \cup [bar EXCEPT !.THEN = 0] \* XXXXX + +/\ bar.CONSTANTS \cup [bar EXCEPT !.CONSTANTS = 0] +/\ bar.INSTANCE \cup [bar EXCEPT !.INSTANCE = 0] +/\ bar.THEOREM \cup [bar EXCEPT !.THEOREM = 0] \* XXXXX + +/\ bar.DOMAIN \cup [bar EXCEPT !.DOMAIN = 0] +/\ bar.LET \cup [bar EXCEPT !.LET = 0] +/\ bar.UNCHANGED \cup [bar EXCEPT !.UNCHANGED = 0] +================================ + + + +THEOREM Bar == ASSUME NEW y, ASSUME TRUE PROVE FALSE + PROVE TRUE + + +THEOREM TRUE + <1>1. TAKE x \in << a:: {}, {}>> + <1>2. <1>1!a + <1>3. <1>1!1 + <1> QED + + +================================================== +a+b == <<a, b>> +THEOREM TRUE +<1>2 TRUE + <33>1 HAVE ~ TRUE + <33>2 TAKE Id, Id1 + <33>3 TAKE Id4 \in {1}, <<Id2, Id3>> \in {2} + <33>123 FooBar == <<Id, Id1, Id4, Id2, Id3>> + <33>4 WITNESS {1} + <33>5 WITNESS {1} \in {2}, {3} + <33>-... PICK x : ~ FALSE + <+>*. PICK y \in {1} : ~ FALSE + <*>* QED + <33>7 PICK y \in {1} : <33>5!1!1 + <33>3!1 + PROOF <55>1... TRUE + <*>2.... USE <33>5, <33>7!1!1, <33>7!(42)!<< DEF + + <55>2 QED + <33>7a Foo == << <33>7!(1)!<< , <33>7!>> >> + <33>8 PICK z \in {1}, <<y1, z1>> \in {2} : ~ FALSE + <33>9 PICK w, u : <<1, 2, 3>> + <34>* DEFINE A == <<x, y, z, y1, z1, w, u>> + <34>*. B == A!1 + <34> QED + <33>44 DEFINE A == <<x, y, z, y1, z1, w, u>> + <33>*. B == <33>9!(1,2)!3 + <33>. BBC(Op(_,_)) == Op(1,2) + DD == BBC(<33>9!@) + <33>22 ASSUME TRUE PROVE FALSE + <33> BBB == \A xxxx \in {} : TRUE + <33>14. INSTANCE Test1 + <*> AA == INSTANCE Test1 + <33> B3 == AA!Foo3!Def2 + <*>a ASSUME FALSE PROVE TRUE + <33>b CASE TRUE + <33>c SUFFICES TRUE + <33>. SUFFICES ASSUME FALSE PROVE TRUE + <33>2a. QED +<1>14 HAVE <<1, 2, 3>> +<1>14a havedef == <1>14!1!3 +<*> TAKE Id7 \in {1} +<*> WITNESS {1} \in {2} +<*> PICK x2 \in {1}, y2 \in {2} : ~ FALSE + <+> PICK x3, y3 : ~ FALSE + <*>*. DEFINE A2 == 1 + <*>2 B2 == 17 + <*> ASSUME FALSE PROVE TRUE + <*> CASE TRUE + <*> TRUE + <*> SUFFICES ASSUME FALSE PROVE TRUE + <2> QED +<1>... DEFINE A == 1 +<1> B == 17 +<1> INSTANCE Test1 +<1> AA == INSTANCE Test2 WITH B <- 1 +<1>3. QED + +=============================== + +\* Foo == \A x , y, z : TRUE +\* Bar == \A x \in {}, y, z \in {}, <<u, v>> \in {} : TRUE +\* Inst(a) == INSTANCE Test1 +\* Foo == Inst(7)!Bar1 +THEOREM Thm2 == TRUE + <1>2 QED + PROOF USE <1>2 + QED +==================== + PROOF +\* DEFINE Def1 == TRUE + USE Thm2!: \* DEF Thm2 , Inst!Bar2 +\* Def2 == TRUE + QED +\* PROOF USE Def1 DEFS Def2 +\* QED +================================= +THEOREM Thm3 == FALSE + PROOF DEFINE A == B + PROVE /\ TRUE + /\ 1=1 + BY Thm2 + QED +========================================================== +THEOREM 1 + PROOF QED + PROOF OBVIOUS +================================================= +============================================================================= + +BY [.] +USE DEF FALSE +HIDE +<1>abc FALSE + BY MODULE M DEF MODULE M, 2 [.] +A == B +DEFINE F == INSTANCE M +A[x \in S] == B +INSTANCE M +<1>2. QED +(******** + PROOF ASSUME TRUE PROVE FALSE + <1>1. TRUE + <1>2. QED + HAVE TRUE + QED +********) +============================================================================= diff --git a/tlatools/test-model/suite/test210.tla b/tlatools/test-model/suite/test210.tla index f8f42a96480af1a5bee84755c474b6663d1c04a6..8bde6fb282f8fc24860c529ff00f3fb58f3ed1be 100644 --- a/tlatools/test-model/suite/test210.tla +++ b/tlatools/test-model/suite/test210.tla @@ -1,293 +1,293 @@ -\* This module is meant to produce parsing errors when evaluating any -\* subexpression reference ref in an expression of the form ref <=> -\* ILLEGAL and any label labeling "ILLEGAL" - - --------------------- MODULE test210 -------------- -ILLEGAL == FALSE -LEGAL == TRUE - -ASSUME assump == /\ lab :: LEGAL - /\ TRUE - -AssDef == /\ assump!lab <=> LEGAL - /\ assump!1 <=> LEGAL - -THEOREM foo == ASSUME NEW x \in labx :: LEGAL, - NEW y \in laby :: LEGAL, - labz :: LEGAL, - ASSUME TRUE PROVE labi :: LEGAL - PROVE labu :: LEGAL -<1>1. ASSUME LEGAL, - NEW q \in labx :: LEGAL, - NEW r \in laby :: LEGAL - PROVE /\ foo!3 <=> LEGAL - /\ foo!labz <=> LEGAL - /\ foo!5 <=> LEGAL - /\ foo!labu <=> LEGAL - /\ foo!labi <=> LEGAL - BY <1>1!labx <=> LEGAL, <1>1!laby <=> LEGAL, <1>1!4 <=> LEGAL, - foo!4!2 <=> LEGAL, foo!4!1 <=> LEGAL - -<1>1a. /\ <1>1!labx <=> LEGAL - /\ <1>1!laby <=> ILLEGAL - /\ <1>1!1 <=> LEGAL - /\ <1>1!4 <=> ILLEGAL - -<1>2. SUFFICES ASSUME NEW q \in labx :: LEGAL, - TRUE, - NEW r \in laby :: LEGAL, - ASSUME lab1 :: LEGAL, - NEW a \in lab2 :: LEGAL, - NEW b \in lab3 :: ILLEGAL - PROVE lab4 :: ILLEGAL - PROVE /\ foo!3 <=> LEGAL - /\ foo!labz <=> LEGAL - /\ foo!5 <=> LEGAL - /\ foo!labu <=> LEGAL - -<1>2a. /\ <1>2!laby <=> LEGAL - /\ <1>2!labx <=> LEGAL - /\ <1>2!lab1 <=> LEGAL - /\ <1>2!lab2 <=> LEGAL - /\ <1>2!1!5 <=> LEGAL - /\ <1>2!1!5!2 <=> LEGAL - /\ <1>2!2 <=> ILLEGAL - -<1>3. SUFFICES 1 = 2 - -<1>4. QED - -Bar == /\ foo!labx <=> LEGAL - /\ foo!laby <=> ILLEGAL - /\ foo!labi <=> ILLEGAL - /\ foo!labu <=> ILLEGAL - /\ foo!3 <=> ILLEGAL -================== - -CONSTANT x -THEOREM TRUE -<1>1. x = 1 -<1>4. QED -================ -<2>21 bar == 1 foobar == 2 -<2>31 foo - BY DEF <2>21 -(**** -<2>22 WITNESS TRUE -<2>32 <2>22 -<2>23 TAKE x \in {} -<2>33 <2>23 -<2>24 PICK y \in {} : TRUE -<2>34 <2>24 -<2>25 CASE TRUE -<2>35 <2>25 -*****) -<2>3 QED - <3>1 TRUE\* <2>3 - BY <2>31 - <3>2 QED -================= -VARIABLE y -Foo(x) == INSTANCE Test1 -LOCAL fcn[x \in {}] == x -USE MODULE Test, MODULE Test1 DEFS (* MODULE Test, *) MODULE Test1, Foo -Bar == Foo(1)!-(1, 2) -================================ - -THEOREM ASSUME ASSUME P PROVE - PROVE P -BY Foo \* DEFS Foo - -THEOREM foo7 == TRUE - <0>1. TRUE - <*>.... <0>1 - <007>1. TRUE - <07>2. QED - <000>3 QED - -================= -\* Foo == <1>1 -THEOREM foobar == TRUE -<*>1. TRUE -PROOF - <+>1. TRUE - <+> TRUE - <*>11. TRUE - <*>12 TRUE - <2>13. TRUE - <2>14 TRUE - <2>2a TRUE - <*>2 <2>2a - <*>3. TRUE - <*> QED - <*>2. QED -<0>4. TRUE -<0>1a <0>4 -<0>2. QED - -THEOREM foo == ASSUME CONSTANT a, - VARIABLE c, - STATE b - PROVE TRUE -PROOF -<+>1. TRUE - PROOF <+>a. TRUE - <1>3. TRUE - <*> Test == <1>a - - <1>4. QED - <+> <1>3 - <2> QED -<0>... QED - -AXIOM TRUE - -THEOREM ASSUME CONSTANT a, - CONSTANT b \in {} , - VARIABLE c, - STATE d, - ACTION e, - TEMPORAL f - PROVE e = e - -THEOREM ASSUME NEW a, - NEW CONSTANT b \in {} , - NEW VARIABLE c, - NEW STATE d, - NEW ACTION e, - NEW TEMPORAL f - PROVE TRUE - -OBVIOUS - -THEOREM TRUE -OMITTED - -THEOREM TRUE -PROOF OBVIOUS - -THEOREM TRUE -PROOF OMITTED - -a+b == <<a, b>> - -THEOREM TRUE -BY TRUE DEF + - -THEOREM TRUE -BY TRUE DEFS + - -THEOREM TRUE -PROOF BY TRUE DEFS + - - - -THEOREM TRUE -<1>ab.... TRUE - PROOF - <33>0 TRUE - BY <1>ab - <33>1 HAVE ~ (TRUE /\ <33>0) - <33>2 TAKE Id, Id1 - <33>3 TAKE Id4 \in {1}, <<Id2, Id3>> \in {2} - <33>123 FooBar == <<Id, Id1, Id4, Id2, Id3>> - <33>4 WITNESS {1} \cup <33>1!1!1!2 - <33>5 WITNESS {1} \in {2}, {3} - <33>-... PICK x : ~ FALSE - <+>*. PICK y \in {1} : ~ FALSE - <*>* QED - <33>7 PICK y \in {1} : <33>5!1!1 + <33>3!1 - PROOF <*>1... TRUE - <*>2.... USE <*>1, <33>5, <33>7!1!1, <33>7!(42)!<< DEF + - - <*>3 QED - <33>7a Foo == << <33>7!(1)!<< , <33>7!>> >> - <33>8 PICK z \in {1}, <<y1, z1>> \in {2} : ~ FALSE - <33>9 PICK w, u : <<1, 2, 3>> - <34>* DEFINE A == <<x, y, z, y1, z1>> - <34>*. B == A!1 - C == A - <34> QED - <33>44 DEFINE A == <<x, y, z, y1, z1, w, u>> - <33>*. B == <33>9!(1,2)!3 - <33>. BBC(Op(_,_)) == Op(1,2) - DD == BBC(<33>9!@) - <33>22 ASSUME TRUE PROVE FALSE - <33> BBB == \A xxxx \in {} : TRUE - <33>14. INSTANCE Test1 - <*> AA == INSTANCE Test1 - <*>a ASSUME FALSE PROVE TRUE - <33>b CASE TRUE /\ <33>22!1 - <33>c SUFFICES TRUE - <33>. SUFFICES ASSUME FALSE PROVE TRUE - <33>2a. QED -<1>14 HAVE <<1, 2, 3>> -<1>14a havedef == <1>14!1!3 -<*> TAKE Id7 \in {1} -<*> WITNESS {1} \in {2} -<*> PICK x2 \in {1}, y2 \in {2} : ~ FALSE - <+> PICK x3, y3 : ~ FALSE - <*>*. DEFINE A2 == 1 - <*>2 B2 == 17 - <*> ASSUME FALSE PROVE TRUE - <*> CASE TRUE - <*> TRUE - <*> SUFFICES ASSUME FALSE PROVE TRUE - <2> QED -<1>... DEFINE A == 1 -<1> B == 17 -<1> INSTANCE Test1 WITH x <- 27 -<1> AA == INSTANCE Test2 WITH B <- 1 -<1>3. QED - -=============================== - -\* Foo == \A x , y, z : TRUE -\* Bar == \A x \in {}, y, z \in {}, <<u, v>> \in {} : TRUE -\* Inst(a) == INSTANCE Test1 -\* Foo == Inst(7)!Bar1 -THEOREM Thm2 == TRUE - <1>2 QED - PROOF USE <1>2 - QED -==================== - PROOF -\* DEFINE Def1 == TRUE - USE Thm2!: \* DEF Thm2 , Inst!Bar2 -\* Def2 == TRUE - QED -\* PROOF USE Def1 DEFS Def2 -\* QED -================================= -THEOREM Thm3 == FALSE - PROOF DEFINE A == B - PROVE /\ TRUE - /\ 1=1 - BY Thm2 - QED -========================================================== -THEOREM 1 - PROOF QED - PROOF OBVIOUS -================================================= -============================================================================= - -BY [.] -USE DEF FALSE -HIDE -<1>abc FALSE - BY MODULE M DEF MODULE M, 2 [.] -A == B -DEFINE F == INSTANCE M -A[x \in S] == B -INSTANCE M -<1>2. QED -(******** - PROOF ASSUME TRUE PROVE FALSE - <1>1. TRUE - <1>2. QED - HAVE TRUE - QED -********) -============================================================================= +\* This module is meant to produce parsing errors when evaluating any +\* subexpression reference ref in an expression of the form ref <=> +\* ILLEGAL and any label labeling "ILLEGAL" + + +-------------------- MODULE test210 -------------- +ILLEGAL == FALSE +LEGAL == TRUE + +ASSUME assump == /\ lab :: LEGAL + /\ TRUE + +AssDef == /\ assump!lab <=> LEGAL + /\ assump!1 <=> LEGAL + +THEOREM foo == ASSUME NEW x \in labx :: LEGAL, + NEW y \in laby :: LEGAL, + labz :: LEGAL, + ASSUME TRUE PROVE labi :: LEGAL + PROVE labu :: LEGAL +<1>1. ASSUME LEGAL, + NEW q \in labx :: LEGAL, + NEW r \in laby :: LEGAL + PROVE /\ foo!3 <=> LEGAL + /\ foo!labz <=> LEGAL + /\ foo!5 <=> LEGAL + /\ foo!labu <=> LEGAL + /\ foo!labi <=> LEGAL + BY <1>1!labx <=> LEGAL, <1>1!laby <=> LEGAL, <1>1!4 <=> LEGAL, + foo!4!2 <=> LEGAL, foo!4!1 <=> LEGAL + +<1>1a. /\ <1>1!labx <=> LEGAL + /\ <1>1!laby <=> ILLEGAL + /\ <1>1!1 <=> LEGAL + /\ <1>1!4 <=> ILLEGAL + +<1>2. SUFFICES ASSUME NEW q \in labx :: LEGAL, + TRUE, + NEW r \in laby :: LEGAL, + ASSUME lab1 :: LEGAL, + NEW a \in lab2 :: LEGAL, + NEW b \in lab3 :: ILLEGAL + PROVE lab4 :: ILLEGAL + PROVE /\ foo!3 <=> LEGAL + /\ foo!labz <=> LEGAL + /\ foo!5 <=> LEGAL + /\ foo!labu <=> LEGAL + +<1>2a. /\ <1>2!laby <=> LEGAL + /\ <1>2!labx <=> LEGAL + /\ <1>2!lab1 <=> LEGAL + /\ <1>2!lab2 <=> LEGAL + /\ <1>2!1!5 <=> LEGAL + /\ <1>2!1!5!2 <=> LEGAL + /\ <1>2!2 <=> ILLEGAL + +<1>3. SUFFICES 1 = 2 + +<1>4. QED + +Bar == /\ foo!labx <=> LEGAL + /\ foo!laby <=> ILLEGAL + /\ foo!labi <=> ILLEGAL + /\ foo!labu <=> ILLEGAL + /\ foo!3 <=> ILLEGAL +================== + +CONSTANT x +THEOREM TRUE +<1>1. x = 1 +<1>4. QED +================ +<2>21 bar == 1 foobar == 2 +<2>31 foo + BY DEF <2>21 +(**** +<2>22 WITNESS TRUE +<2>32 <2>22 +<2>23 TAKE x \in {} +<2>33 <2>23 +<2>24 PICK y \in {} : TRUE +<2>34 <2>24 +<2>25 CASE TRUE +<2>35 <2>25 +*****) +<2>3 QED + <3>1 TRUE\* <2>3 + BY <2>31 + <3>2 QED +================= +VARIABLE y +Foo(x) == INSTANCE Test1 +LOCAL fcn[x \in {}] == x +USE MODULE Test, MODULE Test1 DEFS (* MODULE Test, *) MODULE Test1, Foo +Bar == Foo(1)!-(1, 2) +================================ + +THEOREM ASSUME ASSUME P PROVE + PROVE P +BY Foo \* DEFS Foo + +THEOREM foo7 == TRUE + <0>1. TRUE + <*>.... <0>1 + <007>1. TRUE + <07>2. QED + <000>3 QED + +================= +\* Foo == <1>1 +THEOREM foobar == TRUE +<*>1. TRUE +PROOF + <+>1. TRUE + <+> TRUE + <*>11. TRUE + <*>12 TRUE + <2>13. TRUE + <2>14 TRUE + <2>2a TRUE + <*>2 <2>2a + <*>3. TRUE + <*> QED + <*>2. QED +<0>4. TRUE +<0>1a <0>4 +<0>2. QED + +THEOREM foo == ASSUME CONSTANT a, + VARIABLE c, + STATE b + PROVE TRUE +PROOF +<+>1. TRUE + PROOF <+>a. TRUE + <1>3. TRUE + <*> Test == <1>a + + <1>4. QED + <+> <1>3 + <2> QED +<0>... QED + +AXIOM TRUE + +THEOREM ASSUME CONSTANT a, + CONSTANT b \in {} , + VARIABLE c, + STATE d, + ACTION e, + TEMPORAL f + PROVE e = e + +THEOREM ASSUME NEW a, + NEW CONSTANT b \in {} , + NEW VARIABLE c, + NEW STATE d, + NEW ACTION e, + NEW TEMPORAL f + PROVE TRUE + +OBVIOUS + +THEOREM TRUE +OMITTED + +THEOREM TRUE +PROOF OBVIOUS + +THEOREM TRUE +PROOF OMITTED + +a+b == <<a, b>> + +THEOREM TRUE +BY TRUE DEF + + +THEOREM TRUE +BY TRUE DEFS + + +THEOREM TRUE +PROOF BY TRUE DEFS + + + + +THEOREM TRUE +<1>ab.... TRUE + PROOF + <33>0 TRUE + BY <1>ab + <33>1 HAVE ~ (TRUE /\ <33>0) + <33>2 TAKE Id, Id1 + <33>3 TAKE Id4 \in {1}, <<Id2, Id3>> \in {2} + <33>123 FooBar == <<Id, Id1, Id4, Id2, Id3>> + <33>4 WITNESS {1} \cup <33>1!1!1!2 + <33>5 WITNESS {1} \in {2}, {3} + <33>-... PICK x : ~ FALSE + <+>*. PICK y \in {1} : ~ FALSE + <*>* QED + <33>7 PICK y \in {1} : <33>5!1!1 + <33>3!1 + PROOF <*>1... TRUE + <*>2.... USE <*>1, <33>5, <33>7!1!1, <33>7!(42)!<< DEF + + + <*>3 QED + <33>7a Foo == << <33>7!(1)!<< , <33>7!>> >> + <33>8 PICK z \in {1}, <<y1, z1>> \in {2} : ~ FALSE + <33>9 PICK w, u : <<1, 2, 3>> + <34>* DEFINE A == <<x, y, z, y1, z1>> + <34>*. B == A!1 + C == A + <34> QED + <33>44 DEFINE A == <<x, y, z, y1, z1, w, u>> + <33>*. B == <33>9!(1,2)!3 + <33>. BBC(Op(_,_)) == Op(1,2) + DD == BBC(<33>9!@) + <33>22 ASSUME TRUE PROVE FALSE + <33> BBB == \A xxxx \in {} : TRUE + <33>14. INSTANCE Test1 + <*> AA == INSTANCE Test1 + <*>a ASSUME FALSE PROVE TRUE + <33>b CASE TRUE /\ <33>22!1 + <33>c SUFFICES TRUE + <33>. SUFFICES ASSUME FALSE PROVE TRUE + <33>2a. QED +<1>14 HAVE <<1, 2, 3>> +<1>14a havedef == <1>14!1!3 +<*> TAKE Id7 \in {1} +<*> WITNESS {1} \in {2} +<*> PICK x2 \in {1}, y2 \in {2} : ~ FALSE + <+> PICK x3, y3 : ~ FALSE + <*>*. DEFINE A2 == 1 + <*>2 B2 == 17 + <*> ASSUME FALSE PROVE TRUE + <*> CASE TRUE + <*> TRUE + <*> SUFFICES ASSUME FALSE PROVE TRUE + <2> QED +<1>... DEFINE A == 1 +<1> B == 17 +<1> INSTANCE Test1 WITH x <- 27 +<1> AA == INSTANCE Test2 WITH B <- 1 +<1>3. QED + +=============================== + +\* Foo == \A x , y, z : TRUE +\* Bar == \A x \in {}, y, z \in {}, <<u, v>> \in {} : TRUE +\* Inst(a) == INSTANCE Test1 +\* Foo == Inst(7)!Bar1 +THEOREM Thm2 == TRUE + <1>2 QED + PROOF USE <1>2 + QED +==================== + PROOF +\* DEFINE Def1 == TRUE + USE Thm2!: \* DEF Thm2 , Inst!Bar2 +\* Def2 == TRUE + QED +\* PROOF USE Def1 DEFS Def2 +\* QED +================================= +THEOREM Thm3 == FALSE + PROOF DEFINE A == B + PROVE /\ TRUE + /\ 1=1 + BY Thm2 + QED +========================================================== +THEOREM 1 + PROOF QED + PROOF OBVIOUS +================================================= +============================================================================= + +BY [.] +USE DEF FALSE +HIDE +<1>abc FALSE + BY MODULE M DEF MODULE M, 2 [.] +A == B +DEFINE F == INSTANCE M +A[x \in S] == B +INSTANCE M +<1>2. QED +(******** + PROOF ASSUME TRUE PROVE FALSE + <1>1. TRUE + <1>2. QED + HAVE TRUE + QED +********) +============================================================================= diff --git a/tlatools/test-model/suite/test211.tla b/tlatools/test-model/suite/test211.tla index 71b03691f981a6143369ee1f05785cde3f21093f..2b7f396c514fdb48a5364b0ae090e590c325b0c9 100644 --- a/tlatools/test-model/suite/test211.tla +++ b/tlatools/test-model/suite/test211.tla @@ -1,1114 +1,1114 @@ -\* Test of moderately large proof. - -`. last modified on Wed 4 March 2009 at 17:55:12 PST by lamport - Major changes made 21 Sep 2007: - variable chosen renamed learned - action Choose renamed Learn - Major changes made 22 Sep 2007: - removed variable noccmd -.' - - ---------------------------------- MODULE test211 -------------------------------- -EXTENDS Integers, FiniteSets ------------------------------------------------------------------------------ -(***************************************************************************) -(* CONSTANTS *) -(* *) -(* For convenience, we take configuration numbers, instance numbers, and *) -(* ballot numbers all to be the set of naturals. However, to make the *) -(* meanings of our formulas easier to understand, we use different names *) -(* for these three equal sets. *) -(***************************************************************************) -CNum == Nat \* The set of configuration numbers. -INum == Nat \* The set of instance numbers. -BNum == Nat \* The set of ballot numbers. - -CONSTANT Acc \* The set of acceptors - -(***************************************************************************) -(* We define Config to be the set of configurations, where a configuration *) -(* is a record with a cnum field that is the configuration number field *) -(* and a quorums field that is a set of quorums, which is a set of *) -(* pairwise non-disjoint sets of acceptors. *) -(***************************************************************************) -Config == [cnum : CNum, - quorums : {C \in SUBSET SUBSET Acc : - \A P1, P2 \in C : P1 \cap P2 # {}}] - -CONSTANTS Cmd, \* The set of commands (choosable values). - - ConfigCmd(_), \* ConfigCmd(C) is the command that sets the - \* current configuration to C. - - InitConfig \* The initial configuration - -(***************************************************************************) -(* We assume that ConfigCmd(C) is a distinct command for every *) -(* configuration C, and that InitConfig is a configuration with cnum 0. *) -(***************************************************************************) -ASSUME ConstantAssumption == - /\ \A C \in Config : ConfigCmd(C) \in Cmd - /\ \A C, D \in Config : (C # D) => (ConfigCmd(C) # ConfigCmd(D)) - /\ InitConfig \in Config - /\ InitConfig.cnum = 0 - -(***************************************************************************) -(* The configuration of a configuration command. *) -(***************************************************************************) -ConfigOfCmd(c) == CHOOSE C \in Config : c = ConfigCmd(C) - - -(***************************************************************************) -(* CCmd is the set of reconfiguration commands. *) -(***************************************************************************) -CCmd == {ConfigCmd(C) : C \in Config} - -(***************************************************************************) -(* Vote is the set of votes, where a vote is a record with cnum *) -(* (configuration number) field and cmd (command) field. We define init *) -(* and `none' to be two different values a that are not votes. *) -(***************************************************************************) -Vote == [cnum : CNum, cmd : Cmd] -init == CHOOSE v : v \notin Vote -none == CHOOSE v : v \notin Vote \cup {init} ------------------------------------------------------------------------------ -(***************************************************************************) -(* VARIABLES *) -(* *) -(* The algorithm has two variables avote and `learned', where: *) -(* *) -(* - avote[a][i][b] is either the vote cast by acceptor a in instance i *) -(* for ballot b. It initially equals init from which it can be set to *) -(* a vote, to the value `none' indicating that `a' abstains in that *) -(* ballot. *) -(* *) -(* - `learned' is the set of pairs <<i, cmd>> indicating that command cmd *) -(* has been learned in instance i. *) -(***************************************************************************) -VARIABLE avote, learned - -(***************************************************************************) -(* BOUND IDENTIFIER CONVENTIONS *) -(* *) -(* We use the following conventions for the names used in quantifiers and *) -(* operator parameters: *) -(* *) -(* `a' : An acceptor *) -(* *) -(* i : An instance number. *) -(* *) -(* b : A ballot number *) -(* *) -(* C : A configuration *) -(* *) -(* c, cmd : A command *) -(* *) -(* n, cnum : A configuration number. *) -(* *) -(* Multiple identifiers of the same type are named in an obvious way--for *) -(* example b and bb, or c1 and c2. *) -(***************************************************************************) ------------------------------------------------------------------------------ -(***************************************************************************) -(* STATE PREDICATES *) -(* *) -(* The initial predicate asserts that avote[a][i][b] = init for all `a', *) -(* i, and b, and that `learned' contains the single element <<-1, c>> *) -(* where c is the command that sets the current configuration to *) -(* InitConfig. *) -(***************************************************************************) -Init == /\ avote = [a \in Acc |-> [i \in INum |-> [b \in BNum |-> init]]] - /\ learned = {<<-1, ConfigCmd(InitConfig)>>} - -(***************************************************************************) -(* The following state predicate is true iff `a' voted in instance i at *) -(* ballot b for command c with configuration number n. *) -(***************************************************************************) -Voted(a, i, b, n, c) == /\ avote[a][i][b] \in Vote - /\ avote[a][i][b] = [cnum |-> n, cmd |-> c] - -(***************************************************************************) -(* A type correctness assertion, which is an invariant of the algorithm. *) -(* It is trivial to check that this is true in the initial state and *) -(* preserved by every step of the algorithm. *) -(***************************************************************************) -TypeOK == - /\ (**********************************************************************) - (* avote is a function with the correct domain and range. *) - (**********************************************************************) - avote \in [Acc -> [INum -> [BNum -> Vote \cup {init, none}] ] ] - - /\ (**********************************************************************) - (* An acceptor votes only for a new configuration with a *) - (* configuration number 1 greater than that of the current *) - (* configuration. *) - (**********************************************************************) - \A a \in Acc, i \in INum, b \in BNum, n \in CNum, C \in Config : - Voted(a, i, b, n, ConfigCmd(C)) => (C.cnum = n+1) - - /\ (**********************************************************************) - (* `learned' is a set of elements of the proper type. *) - (**********************************************************************) - learned \subseteq (INum \cup {-1}) \X Cmd - - /\ (**********************************************************************) - (* There is exactly one element of the form <<-1, c>> \in learned, *) - (* where c is the command that sets the configuration to InitConfig. *) - (**********************************************************************) - \A c \in Cmd : (<<-1, c>> \in learned) <=> (c = ConfigCmd(InitConfig)) - - -(***************************************************************************) -(* The following state predicates are the usual ones for Paxos for a *) -(* particular instance i and a fixed configuration C. *) -(***************************************************************************) -ChosenInBal(i, b, C, cmd) == - (*************************************************************************) - (* True iff command cmd is chosen in ballot b. *) - (*************************************************************************) - \E Q \in C.quorums : - \A a \in Q : Voted(a, i, b, C.cnum, cmd) - -ChosenIn(i, C, cmd) == \E b \in BNum : ChosenInBal(i, b, C, cmd) - (*************************************************************************) - (* True iff command cmd is chosen. *) - (*************************************************************************) - -ChoosableAt(i, b, C, cmd) == - (*************************************************************************) - (* True iff command c has been chosen or could still be chosen in ballot *) - (* b. *) - (*************************************************************************) - \E Q \in C.quorums : - \A a \in Q : \/ Voted(a, i, b, C.cnum, cmd) - \/ avote[a][i][b] = init - -UnchoosableBefore(i, b, C, cmd) == - (*************************************************************************) - (* True iff it is not possible for command c ever to be chosen in any *) - (* ballot numbered less than b. *) - (*************************************************************************) - \A bb \in 0 .. (b-1): ~ ChoosableAt(i, bb, C, cmd) - -SafeAt(i, b, C, cmd) == - (*************************************************************************) - (* True iff it is safe for an acceptor to vote for command cmd in ballot *) - (* b (because no other command can be chosen with a smaller ballot *) - (* number). *) - (*************************************************************************) - \A c \in Cmd \ {cmd} : UnchoosableBefore(i, b, C, c) - - -(***************************************************************************) -(* The following state predicate asserts that it is safe to try to choose *) -(* a command in ballot b of instance i using configuration C. It assserts *) -(* that C was learned in some instance ii < i and that in every instance j *) -(* with ii < j < i, no reconfiguration command can possibly be chosen in a *) -(* ballot < b and no acceptor can vote for a reconfiguration command in *) -(* ballot b. *) -(***************************************************************************) -ConfigOKAt(i, b, C) == - \E ii \in -1 .. (i-1) : - /\ <<ii, ConfigCmd(C)>> \in learned - /\ \A j \in (ii+1)..(i-1), c \in CCmd : - /\ UnchoosableBefore(j, b, C, c) - /\ \A a \in Acc : ~Voted(a, j, b, C.cnum, c) - (***************************************************************) - (* Note: a ConfigOK formula is used as an enabling condition *) - (* in the action by which an acceptor votes. In practice, the *) - (* real enabling condition will be the stronger formula *) - (* *) - (* \A a \in Acc, n \in BNum : ~ Voted(a, j, b, n, c) *) - (* *) - (* However, my proof seems to requires the weaker formula. I *) - (* think the algorithm remains correct with the weaker *) - (* precondition. *) - (***************************************************************) ------------------------------------------------------------------------------ -(***************************************************************************) -(* ACTIONS *) -(* *) -(* The following is the action in which acceptor `a' votes in instance i *) -(* at ballot b for command cmd using configuration numbere cnum. The *) -(* first three conjuncts are enabling conditions. In an implementation, *) -(* acceptor `a' will perform this action only if it receives of a phase2a *) -(* message containing i, b, cnum, and cmd from the leader of ballot b. *) -(* It is up to the leader to ensure that the second and third conjuncts *) -(* will be satisfied when that message is received. After preforming the *) -(* action (meaning after the new value of avote[a][i][b] is written in *) -(* stable storage), acceptor `a' will send a phase2b message. The *) -(* purpose of those phase2b messages is to enable some process to learn *) -(* if command cmd has been chosen. *) -(***************************************************************************) -VoteFor(a, i, b, cnum, cmd) == - /\ (**********************************************************************) - (* `a' has not already voted or abstained in this ballot. *) - (**********************************************************************) - avote[a][i][b] = init - - /\ (**********************************************************************) - (* Any other acceptor that has voted in ballot b of instance i has *) - (* voted for cmd with configuration number cnum. *) - (**********************************************************************) - \A aa \in Acc \ {a} : - (avote[aa][i][b] \in Vote) => - (avote[aa][i][b] = [cnum |-> cnum, cmd |-> cmd]) - - /\ (**********************************************************************) - (* It is safe to try to choose a command with ballot b in instance i *) - (* for some configuration C with number cnum. Moreover, if cmd is a *) - (* reconfiguration command, then no configuration command can ever be *) - (* chosen with configuration C in any instance after i with a ballot *) - (* number < b. *) - (**********************************************************************) - \E C \in Config : - /\ C.cnum = cnum - /\ ConfigOKAt(i, b, C) - /\ SafeAt(i, b, C, cmd) - /\ \A newC \in Config : - (cmd = ConfigCmd(newC)) - => /\ newC.cnum = cnum + 1 - /\ \A ii \in INum, c \in Cmd : - (ii > i) => - /\ UnchoosableBefore(ii, b, C, c) - /\ \/ ChosenInBal(i, b, C, cmd) - \/ \A aa \in Acc : - avote[aa][ii][b] \notin Vote - (***************************************************************) - (* When the leader sends the Phase2a message for this vote, *) - (* the last disjunct will be true. However, it can send *) - (* Phase2a messages in instance ii once it knows that cmd is *) - (* chosen in ballot b. In that case, the preceding disjunct *) - (* will be true when the first Phase2a message arrives at `a'. *) - (***************************************************************) - - /\ (**********************************************************************) - (* Set avote[a][i][b] to a vote with configuration number cnum and *) - (* command cmd. *) - (**********************************************************************) - avote' = [avote EXCEPT ![a][i][b] = [cnum |-> cnum, cmd |-> cmd]] - - /\ (**********************************************************************) - (* Leave learned unchanged. *) - (**********************************************************************) - UNCHANGED learned - -(***************************************************************************) -(* The following action is one in which acceptor `a' abstains (votes *) -(* `none') for every pair <<i, b>> in the set S of instance number, ballot *) -(* number pairs in which it has not yet voted. This action is always *) -(* enabled. In an actual implementation, acceptor `a' performs this *) -(* action for the set S equal to the set of <<i, b>> with b < b0 and i any *) -(* instance number when it receives a phase1b message with ballot *) -(* number b0. It also performs the action for S the set of all <<i, b>> *) -(* with b < b0 when it receives a phase2a message for instance i with *) -(* ballot number b0 before it performs the Vote action. This action will *) -(* be a no-op (will perform a stuttering step) if `a' discards the phase1a *) -(* or phase2a message because it has already seen one with a ballow number *) -(* \geq b0. *) -(***************************************************************************) -Abstain(a, S) == - /\ avote' = [avote EXCEPT ![a] = - [i \in INum |-> [b \in BNum |-> IF /\ <<i, b>> \in S - /\ avote[a][i][b] = init - THEN none - ELSE avote[a][i][b] ] ] ] - /\ UNCHANGED learned - -(***************************************************************************) -(* The action by which a command cmd is learned in instance i at ballot b. *) -(* It occurs if cmd is chosen for that instance and ballot by a *) -(* configuration C for which it is safe to choose commands in that *) -(* instance and ballot. *) -(***************************************************************************) -Learn(i, b, cmd) == - /\ \E C \in Config : /\ ConfigOKAt(i, b, C) - /\ ChosenInBal(i, b, C, cmd) - /\ learned' = learned \cup {<<i, cmd>>} - /\ UNCHANGED avote - - -(***************************************************************************) -(* The next-state action is one that performs any of the Vote, Abstain, or *) -(* Learn steps described above. *) -(***************************************************************************) -Next == \/ \E a \in Acc: - \/ \E S \in SUBSET (INum \X BNum) : Abstain(a, S) - \/ \E i \in INum, b \in BNum, cnum \in CNum, cmd \in Cmd : - VoteFor(a, i, b, cnum, cmd) - \/ \E i \in INum, b \in BNum, cmd \in Cmd : Learn(i, b, cmd) ------------------------------------------------------------------------------ -(***************************************************************************) -(* The standard TLA+ formula that represents the complete algorithm, with *) -(* no liveness assumptions on when actions must be performed. *) -(***************************************************************************) -Spec == Init /\ [][Next]_<<avote, learned>> - -(***************************************************************************) -(* The fact that TypeOK is an invariant of the algorithm is expressed *) -(* formally by: *) -(***************************************************************************) -THEOREM Spec => []TypeOK - -(***************************************************************************) -(* The following is the invariant that expresses the desired safety *) -(* property, and the theorem asserting that it is an invariant. *) -(***************************************************************************) -SafetyInv == \A ch1, ch2 \in learned : (ch1[1] = ch2[1]) => (ch1 = ch2) -THEOREM Spec => []SafetyInv ------------------------------------------------------------------------------ - -(***************************************************************************) -(* We first prove some stability results. A predicate P is generally *) -(* called stable if it can't be made false by executing a step. When *) -(* formalized in an untyped system, this generally assumes that the *) -(* starting state is type-correct. *) -(***************************************************************************) -Stable(P) == TypeOK /\ P /\ Next => P' - -THEOREM Stability == - /\(*1*) \A i \in INum, c \in Cmd : Stable(<<i, c>> \in learned) - /\(*2*) \A a \in Acc, i \in INum, b \in BNum, n \in CNum, c \in Cmd: - /\(*2.1*) Stable( Voted(a, i, b, n, c) ) - /\(*2.2*) Stable( /\ ~Voted(a, i, b, n, c) - /\ avote[a][i][b] # init ) - /\(*3*) \A i \in INum, b \in BNum, c \in Cmd, C \in Config: - /\(*3.1*) Stable( ChosenInBal(i, b, C, c) ) - /\(*3.2*) Stable( ~ChoosableAt(i, b, C, c) ) - /\(*3.3*) Stable( UnchoosableBefore(i, b, C, c) ) - /\(*3.4*) Stable( SafeAt(i, b, C, c) ) - -(***************************************************************************) -(* Proof: 1 and 2 are obvious since no action removes an element from *) -(* `learned' and once an acceptor has voted or abstained in a ballot, it *) -(* cannot retract that decision. The proof of 3 uses 1 and 2 and the fact *) -(* that the conjunction or disjunction (and hence \A and \E) of stable *) -(* predicates are stable. The only part that takes a little work is 3.2, *) -(* which requires first rewriting ~ChoosableAt(i, b, C, c) as *) -(* *) -(* \A Q \in C.quorums : *) -(* \E a \in Q : ~Voted(a, i, b, C.cnum, c) /\ avote[a][i][b] # init *) -(* *) -(* and applying 2.1. *) -(***************************************************************************) - - -(***************************************************************************) -(* We define Max(S) to be the maximum of the set S of numbers, if S is *) -(* non-empty. *) -(***************************************************************************) -Max(S) == CHOOSE k \in S : \A j \in S : k \geq j - - -(***************************************************************************) -(* Suppose that m+1 reconfiguration commands have been chosen and they *) -(* can be numbered C_0, ... , C_m such that each C_j with j>0 was chosen *) -(* in ballot b_j of instance i_j using configuration C_(j-1) with *) -(* i_1 < i_2 < ... < i_m. Let i_0 = -1 and b_0 = 0, and let c_j be the *) -(* command that chooses new configuration C_j. Then the following *) -(* definitions define *) -(* *) -(* maxcfg = m *) -(* *) -(* cfgl[j] = <<i_j, c_j>> *) -(* *) -(* cfgi[j] = i_j *) -(* *) -(* cfgc[j] = c_j *) -(* *) -(* cfgC[j] = C_j *) -(* *) -(* cfgb[j] = b_j *) -(***************************************************************************) -learnedRcfg == { ln \in learned : ln[2] \in CCmd } -maxcfg == Cardinality(learnedRcfg) - 1 -cfgl == [j \in 0..maxcfg |-> CHOOSE ln \in learnedRcfg : ln[2].cnum = j ] -cfgi == [j \in 0..maxcfg |-> cfgl[j][1]] -cfgc == [j \in 0..maxcfg |-> cfgl[j][2]] -cfgC == [j \in 0..maxcfg |-> ConfigOfCmd(cfgc[j])] - -RECURSIVE cfgb \* This statement warns that the definition of cfgb is recursive. -cfgb == [j \in 0..maxcfg |-> - IF j = 0 THEN 0 - ELSE CHOOSE b \in BNum : - /\ ChosenInBal(cfgi[j], b, cfgC[j-1], cfgc[j]) - /\ ConfigOKAt(cfgi[j], b, cfgC[j-1]) ] - (***************************************************) - (* The choice isn't necessarily unique, but it *) - (* doesn't matter which b is chosen. *) - (***************************************************) - - -(***************************************************************************) -(* The definitions of cfgl, etc. define what they are supposed to only if *) -(* the set of chosen reconfiguration commands satisfies a certain *) -(* property. The following predicate asserts that they really do satisfy *) -(* those properties. More precisely, it asserts enough so that those *) -(* properties follow from it and the definitions. *) -(***************************************************************************) -CfgOK == - /\ cfgl \in [0..maxcfg -> learnedRcfg] - /\ cfgb \in [0..maxcfg -> BNum] - /\ cfgi[0] = -1 - /\ cfgC[0] = InitConfig - /\ cfgb[0] = 0 - /\ \A j \in 0..maxcfg : /\ <<cfgi[j], cfgc[j]>> \in learnedRcfg - /\ cfgC[j].cnum = j - /\ \A j \in 1..maxcfg : /\ ChosenInBal(cfgi[j], cfgb[j], cfgC[j-1], cfgc[j]) - /\ ConfigOKAt(cfgi[j], cfgb[j], cfgC[j-1]) - /\ \A j \in 1..maxcfg, i \in INum : - (i > cfgi[j]) => \A c \in Cmd : UnchoosableBefore(i, cfgb[j], cfgC[j-1], c) - -(***************************************************************************) -(* The following theorem asserts that the desired properties of cfgi, etc. *) -(* not explicitly stated in CfgOK follow from it and the definitions. *) -(* (This theorem isn't used explicitly, but it's probably used *) -(* implicitly.) *) -(***************************************************************************) -THEOREM TypeOK /\ CfgOK => - /\ cfgi \in [0..maxcfg -> INum \cup {-1}] - /\ cfgC \in [0..maxcfg -> Config] - /\ cfgb \in [0..maxcfg -> BNum ] - /\ \A j\in 0..maxcfg : cfgc[j] = ConfigCmd(cfgC[j]) - /\ learnedRcfg = {cfgl[j] : j \in 0..maxcfg} - PROOF OBVIOUS - -(***************************************************************************) -(* The following stability property is used in the invariance proof. *) -(***************************************************************************) -THEOREM CfgStability == - CfgOK => - \A i \in INum, b \in BNum, C \in Config : - /\ \A a \in Acc, c \in Cmd : Stable( /\ Voted(a, i, b, C.cnum, c) - /\ ConfigOKAt(i, b, C) ) - /\ \A c \in Cmd : Stable( /\ ChosenInBal(i, b, C, c) - /\ ConfigOKAt(i, b, C) ) - -<1>1 HAVE CfgOK - (*************************************************************************) - (* This statement means that we're assuming CfgOK and proving the *) - (* formula that it's supposed to imply. *) - (*************************************************************************) - -<1>2. TAKE i \in INum, b \in BNum, C \in Config - (*************************************************************************) - (* This statement means that our current goal is a formula of the form *) - (* *) - (* \A i \in INum, b \in BNum, C \in Config : P *) - (* *) - (* and we're going to prove it by introducing these new constants i, b, *) - (* and C and proving P. *) - (*************************************************************************) - - -<1>3. ASSUME CONSTANT a \in Acc, - CONSTANT c \in Cmd - PROVE Stable( /\ Voted(a, i, b, C.cnum, c) - /\ ConfigOKAt(i, b, C) ) - - <2>1. SUFFICES ASSUME Next, Voted(a, i, b, C.cnum, c), - ConfigOKAt(i, b, C) - PROVE ConfigOKAt(i, b, C)' - - (***********************************************************************) - (* Note: This statement is read "it suffices to assume ... and *) - (* prove ..." *) - (* *) - (* Proof: By definition of stability and the fact that Voted(...) is *) - (* stable. *) - (***********************************************************************) - <2>2. PICK ii \in -1 .. (i-1) : - /\ <<ii, ConfigCmd(C)>> \in learned - /\ \A j \in (ii+1)..(i-1), c4 \in CCmd : - /\ UnchoosableBefore(j, b, C, c4) - /\ \A aa \in Acc : ~ Voted(aa, j, b, C.cnum, c4) - (***********************************************************************) - (* By the assumption ConfigOKAt(...) of <2>1 and the definition of *) - (* ConfigOKAt. *) - (***********************************************************************) - - <2>3. SUFFICES ASSUME CONSTANT j \in (ii+1)..(i-1), - CONSTANT c4 \in CCmd, - CONSTANT aa \in Acc, - ~ Voted(aa, j, b, C.cnum, c4), - Voted(aa, j, b, C.cnum, c4)' - PROVE FALSE - (***********************************************************************) - (* Proof: By <2>1 we're assuming ConfigOKAt(i, b, C) and have to prove *) - (* ConfigOKAt(i, b, C)'. ConfiguOKAt(...) is the disjunction and *) - (* conjunction of formulas all of which are stable except for *) - (* *) - (* \A a \in Acc: ~ Voted(a, j, b, C.cnum, c), *) - (* *) - (* So we just have to show that ~ Voted(aa, j, b, n, c4) is stable for *) - (* every aa, j, c4, and n. The proof is by contradiction. *) - (***********************************************************************) - - <2>4. VoteFor(aa, j, b, C.cnum, c4) - (**********************************************************************) - (* Proof: By the assumptions of <2>3, because this VoteFor action is *) - (* the only subaction of Next that can make *) - (* Voted(aa, j, b, C.cnum, c) become true. *) - (**********************************************************************) - - <2>5. PICK CC \in Config : - /\ CC.cnum = C.cnum - /\ ConfigOKAt(j, b, CC) - /\ ChosenInBal(j, b, CC, c4) - (**********************************************************************) - (* Proof: The required CC exists by <2>4 and the third conjunct of *) - (* VoteFor(aa, j, b, C.cnum, c4), using the assumption c4 \in CCmd of *) - (* <2>3 and the assumption Voted(a, i, b, C.cnum, c) of <2>1, which *) - (* implies avote[a][i][b] \in Vote, so the final disjunct at the end *) - (* of that conjunct is false. *) - (**********************************************************************) - - <2>6. CC = C - (**********************************************************************) - (* This follows from ConfigOKAt(j, b, CC) (from <2>5) and *) - (* ConfigOKAt(i, b, C) (from <2>1, which imply that ConfigCmd(CC) and *) - (* ConfigCmd(C) are both learned commands. It then follows from *) - (* CC.cnum = C.cnum (from <2>5) and CfigOK (<1>1), which implies that *) - (* chosen reconfiguration commands have unique numbers, that CC = C. *) - (**********************************************************************) - - <2>7. \A a3 \in Acc : ~Voted(a3, j, b, C.cnum, c4) - (***********************************************************************) - (* Proof: By the last conjunct of <2>2, since <2>3 implies *) - (* j \in (ii+1)..(i-1) and c4 \in CCmd *) - (***********************************************************************) - - <2>8. QED - (***********************************************************************) - (* Proof: ChosenInBal(j, b, CC, c4) (from <2>5) implies Voted(aa, b, *) - (* CC.cnum, c4) aa. By <2>6 (CC = C), this contradicts <2>7. *) - (***********************************************************************) - -<1>4. ASSUME CONSTANT c1 \in Cmd \* Bug in parser prevents reuse of symbol c - PROVE Stable( /\ ChosenInBal(i, b, C, c1) - /\ ConfigOKAt(i, b, C) ) - (*************************************************************************) - (* Proof: Since ChosenInBal(i, b, C, c1) implies *) - (* Voted(a, i, b, C.cnum, c1), for some `a', this follows easily from *) - (* <1>3 and the stability of ChosenInBal(i, b, C, c1). *) - (*************************************************************************) - BY <1>4!2 + 1 - -<1>5. QED - BY <1>1, <1>2, <1>3, <1>4 ------------------------------------------------------------------------------ - -(***************************************************************************) -(* We now define the inductive invariant that is the heart of the safety *) -(* proof. *) -(***************************************************************************) -Inv == - /\(*1*) TypeOK - - /\(*2*) \A a \in Acc, i \in INum, b \in BNum, n \in CNum, c \in Cmd : - Voted(a, i, b, n, c) => - \A aa \in Acc, nn \in CNum, cc \in Cmd : - Voted(aa, i, b, nn, cc) => (<<nn, cc>> = <<n, c>>) - - /\(*3*) \A i \in INum, c \in Cmd : - (<<i, c>> \in learned) => - \E b \in BNum, C \in Config : /\ ConfigOKAt(i, b, C) - /\ ChosenInBal(i, b, C, c) - - /\(*4*) CfgOK - - /\(*5*) \A a \in Acc, i \in INum, b \in BNum, n \in CNum, c \in Cmd : - Voted(a, i, b, n, c) => - \E C \in Config : - /\ C.cnum = n - /\ ConfigOKAt(i, b, C) - /\ SafeAt(i, b, C, c) - /\ c \in CCmd => /\ ConfigOfCmd(c).cnum = n+1 - /\ \A j \in INum, cc \in Cmd : - (j > i) => UnchoosableBefore(j, b, C, cc) - /\ ChoosableAt(i, b, C, c) => - C = cfgC[ Max({j \in 0..maxcfg : cfgi[j] < i}) ] - - -(***************************************************************************) -(* We first prove that this Inv is strong enough--that is, it implies the *) -(* predicate that we want to show is invariant. *) -(***************************************************************************) -THEOREM Inv => SafetyInv - -<1>1. SUFFICES ASSUME Inv, - CONSTANT i \in INum, - CONSTANT c1 \in Cmd, - CONSTANT c2 \in Cmd, - <<i, c1>> \in learned /\ <<i, c2>> \in learned - PROVE c1 = c2 - PROOF OBVIOUS - -<1>2. PICK C1, C2 \in Config, b1, b2 \in BNum : - /\ ConfigOKAt(i, b1, C1) - /\ ChosenInBal(i, b1, C1, c1) - /\ ConfigOKAt(i, b2, C2) - /\ ChosenInBal(i, b2, C2, c2) - (*************************************************************************) - (* Proof: By <<i, c1>> and <<i, c2>> in `learned' (from <1>1) and Inv!3 *) - (* (which is assumed by <1>1). *) - (*************************************************************************) - -<1>3. PICK a1, a2 \in Acc : /\ Voted(a1, i, b1, C1.cnum, c1) - /\ Voted(a2, i, b2, C2.cnum, c2) - (*************************************************************************) - (* Proof: By <1>2, since ChosenInBal implies at least one vote. *) - (*************************************************************************) - -<1>4. PICK CC1, CC2 \in Config : - /\ CC1.cnum = C1.cnum - /\ ConfigOKAt(i, b1, CC1) - /\ ChoosableAt(i, b1, CC1, c1) => - CC1 = cfgC[Max ({j \in 0 .. maxcfg : cfgi[j] < i})] - /\ CC2.cnum = C2.cnum - /\ ConfigOKAt(i, b2, CC2) - /\ ChoosableAt(i, b2, CC2, c2) => - CC2 = cfgC[Max ({j \in 0 .. maxcfg : cfgi[j] < i})] - (*************************************************************************) - (* Proof: By <1>3 and conjunction 5 of Inv. *) - (*************************************************************************) - -<1>5. (CC1 = C1) /\ (CC2 = C2) - (*************************************************************************) - (* Proof: ConfigOKAt(i, b1, C1) (1st conjunct of <1>2) and *) - (* ConfigOKAt(i, b1, CC1) (2nd conjunct of <1>4) imply that <<i1, C1>> *) - (* and <<ii1, CC1>> are in `learned' for some i1 and ii1, and C1.cnum = *) - (* CC1.cnum (<1>4!1). By CfgOK, this implies that C1 = CC1. Similarly, *) - (* C2 = CC2. *) - (*************************************************************************) - -<1>6. C1 = C2 - (*************************************************************************) - (* Proof: We have ChosenInBal(i, b1, C1, c1) (second conjunct of <1>2), *) - (* which by definition of ChosenInBal and ChoosableAt implies *) - (* ChoosableAt(i, b1, C1, c1). By <1>5 and the 3rd conjunct of <1>4, *) - (* this shows that *) - (* *) - (* C1 = cfgC[Max ({j \in 0 .. maxcfg : cfgi[j] < i})] *) - (* *) - (* A similar argument shows that C2 equals the same expression. *) - (*************************************************************************) - -<1>7. QED - (*************************************************************************) - (* Proof: <1>6 and <1>2 imply ChosenInBal(i, b1, C, c1) and *) - (* ChosenInBal(i, b2, C, c2) for C = C1 = C2. The same simple reasoning *) - (* used in the proof of ordinary Paxos (with a fixed configuration C) *) - (* shows that this implies c1 = c2. *) - (*************************************************************************) ------------------------------------------------------------------------------ - -(***************************************************************************) -(* Here is the heart of the proof--the proof that Inv is an inductive *) -(* invariant. *) -(***************************************************************************) -THEOREM InductiveInvariance == Inv /\ Next => Inv' -<1>1. HAVE Inv /\ Next - -<1>2. Inv!1' - (*************************************************************************) - (* It is straighforward to show that TypeOK /\ Next => TypeOK'. *) - (*************************************************************************) - -\* <1> USE TypeOK -\* On 4 Mar 2009 it became illegal to use arbitrary expressions as -\* facts in a USE or HIDE--making this USE illegal - -<1>2a. TypeOK - PROOF OBVIOUS -<1> USE <1>2a - (*************************************************************************) - (* This statement means that from now on, we are free to use TypeOK *) - (* without explicitly mentioning that we're using it. In an informal *) - (* proof like this one, there are undoubtedly lots of places where we *) - (* assume other things without mentioning them. If we've been careful, *) - (* then we haven't assumed anything that we're not allowed to. *) - (*************************************************************************) - -<1>3. Inv!2' - (*************************************************************************) - (* Proof: Next and Inv!2 true and Inv!2' false implies that *) - (* VoteFor(a1, i, b, n, c) /\ Voted(a2, i, b, nn, cc) is true for some *) - (* a2 # a1 and cc # c. The second conjunct of VoteFor(a1, i, b, n, c) *) - (* implies that this is impossible. *) - (*************************************************************************) - -<1>4. Inv!3' - (*************************************************************************) - (* Proof: Next and Inv!3 true and Inv!3' false implies that there is *) - (* some i, bb, and c such that Learn(i, bb, c) is true but *) - (* *) - (* \E b \in BNum, C \in Config : /\ ConfigOKAt(i, b, C) *) - (* /\ ChosenInBal(i, b, C, c) *) - (* *) - (* is false. The definition of Learn(i, bb, c) implies that this is *) - (* impossible. *) - (*************************************************************************) - -<1>5. Inv!4' - <2>1. CASE learnedRcfg' = learnedRcfg - <3>1. maxcfg' = maxcfg /\ cfgl' = cfgl - (*********************************************************************) - (* Proof: By case assumption <2>1 becuase maxcfg is defined in terms *) - (* of learnedRcfg and cfgl is defined in terms of maxcfg and *) - (* learnedRcfg. *) - (*********************************************************************) - <3>2. cfgi' = cfgi /\ cfgc' = cfgc /\ cfgC' = cfgc /\ cfgb' = cfgb - (*********************************************************************) - (* Proof: By <3>1, since All these values are defined in terms of *) - (* cfgl and maxcfg. *) - (*********************************************************************) - <3>3. QED - (*********************************************************************) - (* Proof: CfgOK' follows by assumption <2>1, <3>1, <3>2, the *) - (* stability of *) - (* *) - (* /\ ChosenInBal(cfgi[j], cfgb[j], cfgC[j-1], cfgc[j]) *) - (* /\ ConfigOKAt(cfgi[j], cfgb[j], cfgC[j-1]) *) - (* *) - (* for all j (by <1>1 and Theorem CfgStability) and the stability of *) - (* *) - (* UnchoosableBefore(i, cfgb[j], cfgC[j-1], c) *) - (* *) - (* for all j, c (by Theorem Stability). *) - (*********************************************************************) - - <2>2. CASE learnedRcfg' # learnedRcfg - - <3>1. PICK i \in INum, b \in BNum, C \in Config : Learn(i, b, ConfigCmd(C)) - (*********************************************************************) - (* Proof: Case assumption <2>2 and the definition of Next. *) - (*********************************************************************) - <3> DEFINE c == ConfigCmd(C) - - <3>2. PICK k \in 0..maxcfg : - /\ ConfigOKAt(i, b, cfgC[k]) - /\ ChosenInBal(i, b, cfgC[k], c) - /\ learned' = learned \cup {<<i, c>>} - (*********************************************************************) - (* Proof: By <3>1, the definition of Learn, and CfgOK (Inv!4), which *) - (* implies that the configuration whose existence is implied by the *) - (* definition Learn(i, b, c) must be one of the cfgC[j]. *) - (*********************************************************************) - <3>3. i > cfgi[k] - (**********************************************************************) - (* Proof: By ChosenInBal(i, b, cfgC[k], c) (<3>2), definition of *) - (* ConfigOKAt, and CfgOK *) - (**********************************************************************) - - <3>4. k = maxcfg - <4>1. SUFFICES ASSUME k < maxcfg - PROVE FALSE - (*******************************************************************) - (* Proof by contradiction. *) - (*******************************************************************) - - <4> HAVE k < maxcfg - - <4>2. CASE i > cfgi[k+1] - <5>1. b < cfgb[k+1] - <6>1. /\ UnchoosableBefore(cfgi[k+1], b, cfgC[k], cfgc[k+1]) - /\ \A a \in Acc: ~Voted(a, cfgi[k+1], b, cfgC[k].cnum, cfgc[k+1]) - (***************************************************************) - (* Proof: By ConfigOKAt(i, b, cfgC[k]) (<3>2), case assumption *) - (* <4>2, and cfgi[k] < cfgi[k+1] (by CfgOK). *) - (***************************************************************) - <6>2. QED - (***************************************************************) - (* Proof: Since CfgOK implies *) - (* *) - (* ChosenInBal(cfgi[k+1], cfgb[k+1], cfgC[k], cfgc[k+1]) *) - (* *) - (* <6>1 implies that cfgb[k+1] cannot be \leq b. *) - (***************************************************************) - - <5>2. UnchoosableBefore(i, cfgb[k+1], cfgC[k], c) - (*****************************************************************) - (* Proof: By the last conjunct of CfgOK, substituting k+1 for j, *) - (* using case assumption <4>2. *) - (*****************************************************************) - - <5>3. QED - (*****************************************************************) - (* Proof: <5>1 and <5>2 contradict <3>2, which implies *) - (* ChosenInBal(i, b, cfgC[k], c). *) - (*****************************************************************) - - <4>3. CASE i < cfgi[k+1] - <5>1. b > cfgb[k+1] - <6>1. /\ UnchoosableBefore(i, cfgb[k+1], cfgC[k], c) - /\ \A a \in Acc : ~Voted(a, i, cfgb[k+1], cfgC[k].cnum, c) - (***************************************************************) - (* Proof: By CfgOK, which implies *) - (* ConfigOKAt(cfgi[k+1], cfgb[k+1], cfgC[k]) and the *) - (* definition of ConfigOKAt, since case assumption <4>3 and *) - (* <3>3 allows us to substitute i for j in the definition. *) - (***************************************************************) - <6>2. QED - (***************************************************************) - (* Proof: <3>2 implies ChosenInBal(i, b, cfgC[k], c), which *) - (* would contradict <6>1 if b \leq cfgb[k+1]. *) - (***************************************************************) - - <5>2. PICK a \in Acc : Voted(a, i, b, cfgC[k].cnum, c) - (*****************************************************************) - (* Proof: By ChosenInBal(i, b, cfgC[k], c) (from <3>2). *) - (*****************************************************************) - - <5>3. PICK CC \in Config : - /\ CC.cnum = cfgC[k].cnum - /\ ConfigOKAt(i, b, CC) - /\ UnchoosableBefore(cfgi[k+1], b, CC, cfgc[k+1]) - (*****************************************************************) - (* Proof: By <5>2 and the Inv!5, using case assumption <4>3 to *) - (* justify substituting cfgc[k+1] for j in the 4th conjunct of *) - (* the body of the \E C \in Config expression. *) - (*****************************************************************) - - <5>4. CC = cfgC[k] - (*****************************************************************) - (* Proof: ConfigOKAt(i, b, CC) (from <5>3) and CfgOK implies CC *) - (* equals cfgC[j] for some j, and CC.cnum = cfgC[k].cnum (from *) - (* <5>3) implies j = k. *) - (*****************************************************************) - - <5>5. QED - (*****************************************************************) - (* Proof: <5>3 and <5>4 imply *) - (* *) - (* UnchoosableBefore(cfgi[k+1], b, cfg[k], cfgc[k+1]) *) - (* *) - (* and by b > cfgb[k+1] (from <5>1) this contradicts CfgOK, *) - (* which implies *) - (* *) - (* ChosenInBal(cfgi[k+1], cfgb[k+1], cfgC[k], cfgc[k+1]) *) - (*****************************************************************) - - <4>4. CASE i = cfgi[k+1] - <5>1. ChosenInBal(i, b, cfgC[k], c) - BY <3>2 - - <5>2. ChosenInBal(cfgi[k+1], cfgb[k+1], cfgC[k], cfgc[k+1]) - BY CfgOK - - <5>3. c = cfgc[k+1] - (*****************************************************************) - (* Proof: By same simple reasoning used to prove the consistency *) - (* of ordinary Paxos (for instance i = cfgi[k+1] and the (fixed) *) - (* configuration cfgC[k]). *) - (*****************************************************************) - - <5>4. QED - (*****************************************************************) - (* Proof: CfgOK implies <<cfgi[k+1], cfgc[k+1]>> \in `learned', *) - (* so Learn(i, b, c) implies that `learned' is unchanged, *) - (* contradicting case assumption <2>2 (learnedRcfg' # *) - (* learnedRcfg). *) - (*****************************************************************) - - <4>5. QED - BY <4>2, <4>3, <4>4 - - <3>5. /\(*1*) <<i, c>> \in learned' \ {learned} - /\(*2*) C.cnum = maxcfg + 1 - /\(*3*) ChosenInBal(i, b, cfgC[maxcfg], c) - /\(*4*) ConfigOKAt(i, b, cfgC[maxcfg]) - /\(*5*) \A ii \in INum : - (ii > i) => - \A cc \in Cmd : UnchoosableBefore(ii, b, cfgC[maxcfg], cc) - <4>1. <3>5!1 - (*******************************************************************) - (* Proof: By <3>1 and case assumption <2>2. *) - (*******************************************************************) - - <4>2. <3>5!3 - BY <3>2 - - <4>3. <3>5!4 - BY <3>2 - - <4>4. /\ C.cnum = cfgC[maxcfg].cnum + 1 - /\ \A ii \in INum, cc \in Cmd : - (ii > i) => UnchoosableBefore(ii, b, cfgC[maxcfg], cc) - - <5>1. PICK a \in Acc : Voted(a, i, b, cfgC[maxcfg], c) - BY <4>2 - <5>2. PICK CC \in Config : - /\ CC.cnum = cfgC[maxcfg] - /\ ConfigOKAt(i, b, CC) - /\ C.cnum = cfgC[maxcfg].cnum + 1 - /\ \A j \in INum, cc \in Cmd : - (j > i) => UnchoosableBefore(j, b, CC, cc) - (*****************************************************************) - (* Proof: By <5>1 and Inv!5, since c \in CCmd and C = *) - (* ConfigOfCmd(c). *) - (*****************************************************************) - <5>3. CC = cfgC[maxcfg] - (*****************************************************************) - (* Proof: BY <5>2, since ConfigOKAt(i, b, CC) implies *) - (* <<j, CmdOfConfig(CC)>> in `learned', so it equals cfgC[j] for *) - (* some j, and CC.cnum = cfgC[maxcfg] implies j = maxcfg. *) - (*****************************************************************) - <5>4. QED - BY <5>2, <5>3 - - <4>5. <3>5!5 - - <4>6. QED - BY <4>1, <4>2, <4>3, <4>4, <4>5 - - <3>6. QED - (*********************************************************************) - (* Proof: <3>5!1 and <3>5!2 imply that maxcfg' = maxcfg+1 and *) - (* *) - (* cfgl' = [j \in 0..maxcfg' |-> *) - (* IF j < maxcfg THEN cfgl[j] ELSE <<i, c>>] *) - (* *) - (* from which it follows that the functions cfgi', cfgc', cfgC', *) - (* and cfgb' are the expected "extensions" of cfgi, cfgc, cfgC, and *) - (* cfgb, where <3>5!3 and <3>5!4 imply the existence of the b in *) - (* BNum satisfying the CHOOSE expression in the definition of *) - (* cfgb'[maxcfg']. This proves the first 5 conjuncts of CfgOK'. *) - (* The remaining three conjuncts are all \A j formulas. For j < *) - (* maxcfg', they follow from CfgOK. For j = maxcfg', they follow *) - (* from <3>5. *) - (*********************************************************************) - <2>3. QED - BY <2>1, <2>2 - -<1>6. Inv!5' - <2>1. TAKE a \in Acc, i \in INum, b \in BNum, n \in CNum, c \in Cmd - <2>2. HAVE Voted(a, i, b, n, c)' - <2>3. CASE Voted(a, i, b, n, c) - (***********************************************************************) - (* Proof: This case follows from the Theorems Stability and *) - (* CfgStability, which imply the stability of all the non-constant *) - (* subformuulas in the \E C \in Config expression in Inv!5. *) - (***********************************************************************) - <2>4. CASE ~Voted(a, i, b, n, c) - <3>1. VoteFor(a, i, b, n, c) - (*********************************************************************) - (* Proof: Next, <2>2 and case assumption <2>4, implies this VoteFor *) - (* action. *) - (*********************************************************************) - - <3>2. SUFFICES (* to prove *) - \E C \in Config : - /\ C.cnum = n - /\ ConfigOKAt(i, b, C) - /\ SafeAt(i, b, C, c) - /\ c \in CCmd => /\ ConfigOfCmd(c).cnum = n+1 - /\ \A j \in INum, cc \in Cmd : - (j > i) => UnchoosableBefore(j, b, C, cc) - /\ ChoosableAt(i, b, C, c) => - C = cfgC[ Max({j \in 0..maxcfg : cfgi[j] < i}) ] - (*********************************************************************) - (* Proof: For all other tuples <<aa, ii, bb, nn, cc>>, the body of *) - (* the \A of Inv!5' follows from Inv!5 and Theorems Stability and *) - (* CfgStability. *) - (*********************************************************************) - - <3>3. PICK C \in Config : - /\ C.cnum = n - /\ ConfigOKAt(i, b, C) - /\ SafeAt(i, b, C, c) - /\ c \in CCmd => /\ ConfigOfCmd(c).cnum = n+1 - /\ \A j \in INum, cc \in Cmd : - (j > i) => UnchoosableBefore(j, b, C, cc) - (*********************************************************************) - (* Proof: The existence of C follows from <3>1 and the definition of *) - (* VoteFor. *) - (*********************************************************************) - - <3>4. ASSUME ChoosableAt(i, b, C, c), - C # cfgC[ Max({j \in 0..maxcfg : cfgi[j] < i}) ] - PROVE FALSE - <4>1. PICK j \in 0..maxcfg : C = cfgC[j] - (*******************************************************************) - (* Proof: By CfgOK and ConfigOKAt(i, b, C), which imply that C is *) - (* one of the cfgC[j], and *) - (*******************************************************************) - <4>2. i > cfgi[j] - (*******************************************************************) - (* Proof: <3>3 and <4>1 imply ConfigOKAt(i, b, cfgC[j]), which *) - (* implies i > cfgi[j]. *) - (*******************************************************************) - <4>3. i > cfgi[j+1] - (*******************************************************************) - (* Proof: <4>1, <4>2, and the assumption <3>4!2. *) - (*******************************************************************) - <4>4. cfgb[j+1] > b - (*******************************************************************) - (* Proof: Since and i > cfgi[j+1] > cfgi[j] (by <4>3 and CfgOK), *) - (* ConfigOKAt(i, b, cfgC[j]) (which holds by <3>3 and <4>1) *) - (* implies UnchoosableBefore(cfgi[j+1], b, cfgC[j], cfgc[j+1]) and *) - (* ~ChosenInBal(cfgi[j+1], b, cfgC[j], cfgc[j+1]). Since CfgOK *) - (* implies ChosenInBal(cfgi[j+1], cfgb[j+1], cfgC[j], cfgc[j+1]), *) - (* we cannot have b \geq cfgb[j+1]. *) - (*******************************************************************) - <4>5. QED - (*******************************************************************) - (* Proof: The last conjunct of CfgOK implies *) - (* *) - (* UnchoosableBefore(i, cfgb[j+1], cfgC[j], c) *) - (* *) - (* By <4>4 and <4>1, this contradicts ChoosableAt(i, b, C, c), *) - (* which is assumption <3>4!1. *) - (*******************************************************************) - <3>5. QED - BY <3>2, <3>3, <3>4 - - <2>5. QED - BY <2>3, <2>4 - -<1>7. QED - BY <1>1, <1>2, <1>3, <1>4, <1>5, <1>6 - -============================================================================= - - -TLA+2 problems: - - - Can't use "!" selectors to name "c \in S" in - ASSUME CONSTANT c \in S - PARTIALLY FIXED 10 Oct 2007 to allow "CONSTANT c \in S" to - be used as a fact. - - - <i>j. PICK x ... makes x declared in the proof of <i>j, which - is wrong, since it's not legal to use it there. - FIXED 10 Oct 2007 - - - For subexpression naming, PICK is treated like a \A, even though - the variables being picked are being declared externally to the - expression. Thus, we have to write - - <3>4. PICK x : P(x) - <3>5. ... - BY <3>4!(x) \* This names P(x) - - This seems wrong, since x is declared in the scope of the use. - However, the !(x) can't be omitted if we want to refer to P inside - the proof of <3>4. Since we don't want the naming convention to - depend on where the name appears, we don't have much choice but to - let it stand as is. - - - Doesn't allow labels in numbered steps. This seems to be a bug, - since the parser allows positional naming of subexpressions of - a numbered step. FIXED 10 Oct 2007 - - - Bug: declaration of NEWs introduced in an ASSUME/PROVE step leak - out into the rest of the proof. (They should only for a - SUFFICE ASSUME/PROVE step.) FIXED 10 Oct 2007 - - - Bug: The error message for duplicate step numbers reports the position - as the entire containing proof body, not the step. This indicates - that some semantic node is being created with the entire proof body - rather than just its own part of the spec as its syntactic node. - FIXED 10 Oct 2007 -============================================================================= +\* Test of moderately large proof. + +`. last modified on Wed 4 March 2009 at 17:55:12 PST by lamport + Major changes made 21 Sep 2007: + variable chosen renamed learned + action Choose renamed Learn + Major changes made 22 Sep 2007: + removed variable noccmd +.' + + +--------------------------------- MODULE test211 -------------------------------- +EXTENDS Integers, FiniteSets +----------------------------------------------------------------------------- +(***************************************************************************) +(* CONSTANTS *) +(* *) +(* For convenience, we take configuration numbers, instance numbers, and *) +(* ballot numbers all to be the set of naturals. However, to make the *) +(* meanings of our formulas easier to understand, we use different names *) +(* for these three equal sets. *) +(***************************************************************************) +CNum == Nat \* The set of configuration numbers. +INum == Nat \* The set of instance numbers. +BNum == Nat \* The set of ballot numbers. + +CONSTANT Acc \* The set of acceptors + +(***************************************************************************) +(* We define Config to be the set of configurations, where a configuration *) +(* is a record with a cnum field that is the configuration number field *) +(* and a quorums field that is a set of quorums, which is a set of *) +(* pairwise non-disjoint sets of acceptors. *) +(***************************************************************************) +Config == [cnum : CNum, + quorums : {C \in SUBSET SUBSET Acc : + \A P1, P2 \in C : P1 \cap P2 # {}}] + +CONSTANTS Cmd, \* The set of commands (choosable values). + + ConfigCmd(_), \* ConfigCmd(C) is the command that sets the + \* current configuration to C. + + InitConfig \* The initial configuration + +(***************************************************************************) +(* We assume that ConfigCmd(C) is a distinct command for every *) +(* configuration C, and that InitConfig is a configuration with cnum 0. *) +(***************************************************************************) +ASSUME ConstantAssumption == + /\ \A C \in Config : ConfigCmd(C) \in Cmd + /\ \A C, D \in Config : (C # D) => (ConfigCmd(C) # ConfigCmd(D)) + /\ InitConfig \in Config + /\ InitConfig.cnum = 0 + +(***************************************************************************) +(* The configuration of a configuration command. *) +(***************************************************************************) +ConfigOfCmd(c) == CHOOSE C \in Config : c = ConfigCmd(C) + + +(***************************************************************************) +(* CCmd is the set of reconfiguration commands. *) +(***************************************************************************) +CCmd == {ConfigCmd(C) : C \in Config} + +(***************************************************************************) +(* Vote is the set of votes, where a vote is a record with cnum *) +(* (configuration number) field and cmd (command) field. We define init *) +(* and `none' to be two different values a that are not votes. *) +(***************************************************************************) +Vote == [cnum : CNum, cmd : Cmd] +init == CHOOSE v : v \notin Vote +none == CHOOSE v : v \notin Vote \cup {init} +----------------------------------------------------------------------------- +(***************************************************************************) +(* VARIABLES *) +(* *) +(* The algorithm has two variables avote and `learned', where: *) +(* *) +(* - avote[a][i][b] is either the vote cast by acceptor a in instance i *) +(* for ballot b. It initially equals init from which it can be set to *) +(* a vote, to the value `none' indicating that `a' abstains in that *) +(* ballot. *) +(* *) +(* - `learned' is the set of pairs <<i, cmd>> indicating that command cmd *) +(* has been learned in instance i. *) +(***************************************************************************) +VARIABLE avote, learned + +(***************************************************************************) +(* BOUND IDENTIFIER CONVENTIONS *) +(* *) +(* We use the following conventions for the names used in quantifiers and *) +(* operator parameters: *) +(* *) +(* `a' : An acceptor *) +(* *) +(* i : An instance number. *) +(* *) +(* b : A ballot number *) +(* *) +(* C : A configuration *) +(* *) +(* c, cmd : A command *) +(* *) +(* n, cnum : A configuration number. *) +(* *) +(* Multiple identifiers of the same type are named in an obvious way--for *) +(* example b and bb, or c1 and c2. *) +(***************************************************************************) +----------------------------------------------------------------------------- +(***************************************************************************) +(* STATE PREDICATES *) +(* *) +(* The initial predicate asserts that avote[a][i][b] = init for all `a', *) +(* i, and b, and that `learned' contains the single element <<-1, c>> *) +(* where c is the command that sets the current configuration to *) +(* InitConfig. *) +(***************************************************************************) +Init == /\ avote = [a \in Acc |-> [i \in INum |-> [b \in BNum |-> init]]] + /\ learned = {<<-1, ConfigCmd(InitConfig)>>} + +(***************************************************************************) +(* The following state predicate is true iff `a' voted in instance i at *) +(* ballot b for command c with configuration number n. *) +(***************************************************************************) +Voted(a, i, b, n, c) == /\ avote[a][i][b] \in Vote + /\ avote[a][i][b] = [cnum |-> n, cmd |-> c] + +(***************************************************************************) +(* A type correctness assertion, which is an invariant of the algorithm. *) +(* It is trivial to check that this is true in the initial state and *) +(* preserved by every step of the algorithm. *) +(***************************************************************************) +TypeOK == + /\ (**********************************************************************) + (* avote is a function with the correct domain and range. *) + (**********************************************************************) + avote \in [Acc -> [INum -> [BNum -> Vote \cup {init, none}] ] ] + + /\ (**********************************************************************) + (* An acceptor votes only for a new configuration with a *) + (* configuration number 1 greater than that of the current *) + (* configuration. *) + (**********************************************************************) + \A a \in Acc, i \in INum, b \in BNum, n \in CNum, C \in Config : + Voted(a, i, b, n, ConfigCmd(C)) => (C.cnum = n+1) + + /\ (**********************************************************************) + (* `learned' is a set of elements of the proper type. *) + (**********************************************************************) + learned \subseteq (INum \cup {-1}) \X Cmd + + /\ (**********************************************************************) + (* There is exactly one element of the form <<-1, c>> \in learned, *) + (* where c is the command that sets the configuration to InitConfig. *) + (**********************************************************************) + \A c \in Cmd : (<<-1, c>> \in learned) <=> (c = ConfigCmd(InitConfig)) + + +(***************************************************************************) +(* The following state predicates are the usual ones for Paxos for a *) +(* particular instance i and a fixed configuration C. *) +(***************************************************************************) +ChosenInBal(i, b, C, cmd) == + (*************************************************************************) + (* True iff command cmd is chosen in ballot b. *) + (*************************************************************************) + \E Q \in C.quorums : + \A a \in Q : Voted(a, i, b, C.cnum, cmd) + +ChosenIn(i, C, cmd) == \E b \in BNum : ChosenInBal(i, b, C, cmd) + (*************************************************************************) + (* True iff command cmd is chosen. *) + (*************************************************************************) + +ChoosableAt(i, b, C, cmd) == + (*************************************************************************) + (* True iff command c has been chosen or could still be chosen in ballot *) + (* b. *) + (*************************************************************************) + \E Q \in C.quorums : + \A a \in Q : \/ Voted(a, i, b, C.cnum, cmd) + \/ avote[a][i][b] = init + +UnchoosableBefore(i, b, C, cmd) == + (*************************************************************************) + (* True iff it is not possible for command c ever to be chosen in any *) + (* ballot numbered less than b. *) + (*************************************************************************) + \A bb \in 0 .. (b-1): ~ ChoosableAt(i, bb, C, cmd) + +SafeAt(i, b, C, cmd) == + (*************************************************************************) + (* True iff it is safe for an acceptor to vote for command cmd in ballot *) + (* b (because no other command can be chosen with a smaller ballot *) + (* number). *) + (*************************************************************************) + \A c \in Cmd \ {cmd} : UnchoosableBefore(i, b, C, c) + + +(***************************************************************************) +(* The following state predicate asserts that it is safe to try to choose *) +(* a command in ballot b of instance i using configuration C. It assserts *) +(* that C was learned in some instance ii < i and that in every instance j *) +(* with ii < j < i, no reconfiguration command can possibly be chosen in a *) +(* ballot < b and no acceptor can vote for a reconfiguration command in *) +(* ballot b. *) +(***************************************************************************) +ConfigOKAt(i, b, C) == + \E ii \in -1 .. (i-1) : + /\ <<ii, ConfigCmd(C)>> \in learned + /\ \A j \in (ii+1)..(i-1), c \in CCmd : + /\ UnchoosableBefore(j, b, C, c) + /\ \A a \in Acc : ~Voted(a, j, b, C.cnum, c) + (***************************************************************) + (* Note: a ConfigOK formula is used as an enabling condition *) + (* in the action by which an acceptor votes. In practice, the *) + (* real enabling condition will be the stronger formula *) + (* *) + (* \A a \in Acc, n \in BNum : ~ Voted(a, j, b, n, c) *) + (* *) + (* However, my proof seems to requires the weaker formula. I *) + (* think the algorithm remains correct with the weaker *) + (* precondition. *) + (***************************************************************) +----------------------------------------------------------------------------- +(***************************************************************************) +(* ACTIONS *) +(* *) +(* The following is the action in which acceptor `a' votes in instance i *) +(* at ballot b for command cmd using configuration numbere cnum. The *) +(* first three conjuncts are enabling conditions. In an implementation, *) +(* acceptor `a' will perform this action only if it receives of a phase2a *) +(* message containing i, b, cnum, and cmd from the leader of ballot b. *) +(* It is up to the leader to ensure that the second and third conjuncts *) +(* will be satisfied when that message is received. After preforming the *) +(* action (meaning after the new value of avote[a][i][b] is written in *) +(* stable storage), acceptor `a' will send a phase2b message. The *) +(* purpose of those phase2b messages is to enable some process to learn *) +(* if command cmd has been chosen. *) +(***************************************************************************) +VoteFor(a, i, b, cnum, cmd) == + /\ (**********************************************************************) + (* `a' has not already voted or abstained in this ballot. *) + (**********************************************************************) + avote[a][i][b] = init + + /\ (**********************************************************************) + (* Any other acceptor that has voted in ballot b of instance i has *) + (* voted for cmd with configuration number cnum. *) + (**********************************************************************) + \A aa \in Acc \ {a} : + (avote[aa][i][b] \in Vote) => + (avote[aa][i][b] = [cnum |-> cnum, cmd |-> cmd]) + + /\ (**********************************************************************) + (* It is safe to try to choose a command with ballot b in instance i *) + (* for some configuration C with number cnum. Moreover, if cmd is a *) + (* reconfiguration command, then no configuration command can ever be *) + (* chosen with configuration C in any instance after i with a ballot *) + (* number < b. *) + (**********************************************************************) + \E C \in Config : + /\ C.cnum = cnum + /\ ConfigOKAt(i, b, C) + /\ SafeAt(i, b, C, cmd) + /\ \A newC \in Config : + (cmd = ConfigCmd(newC)) + => /\ newC.cnum = cnum + 1 + /\ \A ii \in INum, c \in Cmd : + (ii > i) => + /\ UnchoosableBefore(ii, b, C, c) + /\ \/ ChosenInBal(i, b, C, cmd) + \/ \A aa \in Acc : + avote[aa][ii][b] \notin Vote + (***************************************************************) + (* When the leader sends the Phase2a message for this vote, *) + (* the last disjunct will be true. However, it can send *) + (* Phase2a messages in instance ii once it knows that cmd is *) + (* chosen in ballot b. In that case, the preceding disjunct *) + (* will be true when the first Phase2a message arrives at `a'. *) + (***************************************************************) + + /\ (**********************************************************************) + (* Set avote[a][i][b] to a vote with configuration number cnum and *) + (* command cmd. *) + (**********************************************************************) + avote' = [avote EXCEPT ![a][i][b] = [cnum |-> cnum, cmd |-> cmd]] + + /\ (**********************************************************************) + (* Leave learned unchanged. *) + (**********************************************************************) + UNCHANGED learned + +(***************************************************************************) +(* The following action is one in which acceptor `a' abstains (votes *) +(* `none') for every pair <<i, b>> in the set S of instance number, ballot *) +(* number pairs in which it has not yet voted. This action is always *) +(* enabled. In an actual implementation, acceptor `a' performs this *) +(* action for the set S equal to the set of <<i, b>> with b < b0 and i any *) +(* instance number when it receives a phase1b message with ballot *) +(* number b0. It also performs the action for S the set of all <<i, b>> *) +(* with b < b0 when it receives a phase2a message for instance i with *) +(* ballot number b0 before it performs the Vote action. This action will *) +(* be a no-op (will perform a stuttering step) if `a' discards the phase1a *) +(* or phase2a message because it has already seen one with a ballow number *) +(* \geq b0. *) +(***************************************************************************) +Abstain(a, S) == + /\ avote' = [avote EXCEPT ![a] = + [i \in INum |-> [b \in BNum |-> IF /\ <<i, b>> \in S + /\ avote[a][i][b] = init + THEN none + ELSE avote[a][i][b] ] ] ] + /\ UNCHANGED learned + +(***************************************************************************) +(* The action by which a command cmd is learned in instance i at ballot b. *) +(* It occurs if cmd is chosen for that instance and ballot by a *) +(* configuration C for which it is safe to choose commands in that *) +(* instance and ballot. *) +(***************************************************************************) +Learn(i, b, cmd) == + /\ \E C \in Config : /\ ConfigOKAt(i, b, C) + /\ ChosenInBal(i, b, C, cmd) + /\ learned' = learned \cup {<<i, cmd>>} + /\ UNCHANGED avote + + +(***************************************************************************) +(* The next-state action is one that performs any of the Vote, Abstain, or *) +(* Learn steps described above. *) +(***************************************************************************) +Next == \/ \E a \in Acc: + \/ \E S \in SUBSET (INum \X BNum) : Abstain(a, S) + \/ \E i \in INum, b \in BNum, cnum \in CNum, cmd \in Cmd : + VoteFor(a, i, b, cnum, cmd) + \/ \E i \in INum, b \in BNum, cmd \in Cmd : Learn(i, b, cmd) +----------------------------------------------------------------------------- +(***************************************************************************) +(* The standard TLA+ formula that represents the complete algorithm, with *) +(* no liveness assumptions on when actions must be performed. *) +(***************************************************************************) +Spec == Init /\ [][Next]_<<avote, learned>> + +(***************************************************************************) +(* The fact that TypeOK is an invariant of the algorithm is expressed *) +(* formally by: *) +(***************************************************************************) +THEOREM Spec => []TypeOK + +(***************************************************************************) +(* The following is the invariant that expresses the desired safety *) +(* property, and the theorem asserting that it is an invariant. *) +(***************************************************************************) +SafetyInv == \A ch1, ch2 \in learned : (ch1[1] = ch2[1]) => (ch1 = ch2) +THEOREM Spec => []SafetyInv +----------------------------------------------------------------------------- + +(***************************************************************************) +(* We first prove some stability results. A predicate P is generally *) +(* called stable if it can't be made false by executing a step. When *) +(* formalized in an untyped system, this generally assumes that the *) +(* starting state is type-correct. *) +(***************************************************************************) +Stable(P) == TypeOK /\ P /\ Next => P' + +THEOREM Stability == + /\(*1*) \A i \in INum, c \in Cmd : Stable(<<i, c>> \in learned) + /\(*2*) \A a \in Acc, i \in INum, b \in BNum, n \in CNum, c \in Cmd: + /\(*2.1*) Stable( Voted(a, i, b, n, c) ) + /\(*2.2*) Stable( /\ ~Voted(a, i, b, n, c) + /\ avote[a][i][b] # init ) + /\(*3*) \A i \in INum, b \in BNum, c \in Cmd, C \in Config: + /\(*3.1*) Stable( ChosenInBal(i, b, C, c) ) + /\(*3.2*) Stable( ~ChoosableAt(i, b, C, c) ) + /\(*3.3*) Stable( UnchoosableBefore(i, b, C, c) ) + /\(*3.4*) Stable( SafeAt(i, b, C, c) ) + +(***************************************************************************) +(* Proof: 1 and 2 are obvious since no action removes an element from *) +(* `learned' and once an acceptor has voted or abstained in a ballot, it *) +(* cannot retract that decision. The proof of 3 uses 1 and 2 and the fact *) +(* that the conjunction or disjunction (and hence \A and \E) of stable *) +(* predicates are stable. The only part that takes a little work is 3.2, *) +(* which requires first rewriting ~ChoosableAt(i, b, C, c) as *) +(* *) +(* \A Q \in C.quorums : *) +(* \E a \in Q : ~Voted(a, i, b, C.cnum, c) /\ avote[a][i][b] # init *) +(* *) +(* and applying 2.1. *) +(***************************************************************************) + + +(***************************************************************************) +(* We define Max(S) to be the maximum of the set S of numbers, if S is *) +(* non-empty. *) +(***************************************************************************) +Max(S) == CHOOSE k \in S : \A j \in S : k \geq j + + +(***************************************************************************) +(* Suppose that m+1 reconfiguration commands have been chosen and they *) +(* can be numbered C_0, ... , C_m such that each C_j with j>0 was chosen *) +(* in ballot b_j of instance i_j using configuration C_(j-1) with *) +(* i_1 < i_2 < ... < i_m. Let i_0 = -1 and b_0 = 0, and let c_j be the *) +(* command that chooses new configuration C_j. Then the following *) +(* definitions define *) +(* *) +(* maxcfg = m *) +(* *) +(* cfgl[j] = <<i_j, c_j>> *) +(* *) +(* cfgi[j] = i_j *) +(* *) +(* cfgc[j] = c_j *) +(* *) +(* cfgC[j] = C_j *) +(* *) +(* cfgb[j] = b_j *) +(***************************************************************************) +learnedRcfg == { ln \in learned : ln[2] \in CCmd } +maxcfg == Cardinality(learnedRcfg) - 1 +cfgl == [j \in 0..maxcfg |-> CHOOSE ln \in learnedRcfg : ln[2].cnum = j ] +cfgi == [j \in 0..maxcfg |-> cfgl[j][1]] +cfgc == [j \in 0..maxcfg |-> cfgl[j][2]] +cfgC == [j \in 0..maxcfg |-> ConfigOfCmd(cfgc[j])] + +RECURSIVE cfgb \* This statement warns that the definition of cfgb is recursive. +cfgb == [j \in 0..maxcfg |-> + IF j = 0 THEN 0 + ELSE CHOOSE b \in BNum : + /\ ChosenInBal(cfgi[j], b, cfgC[j-1], cfgc[j]) + /\ ConfigOKAt(cfgi[j], b, cfgC[j-1]) ] + (***************************************************) + (* The choice isn't necessarily unique, but it *) + (* doesn't matter which b is chosen. *) + (***************************************************) + + +(***************************************************************************) +(* The definitions of cfgl, etc. define what they are supposed to only if *) +(* the set of chosen reconfiguration commands satisfies a certain *) +(* property. The following predicate asserts that they really do satisfy *) +(* those properties. More precisely, it asserts enough so that those *) +(* properties follow from it and the definitions. *) +(***************************************************************************) +CfgOK == + /\ cfgl \in [0..maxcfg -> learnedRcfg] + /\ cfgb \in [0..maxcfg -> BNum] + /\ cfgi[0] = -1 + /\ cfgC[0] = InitConfig + /\ cfgb[0] = 0 + /\ \A j \in 0..maxcfg : /\ <<cfgi[j], cfgc[j]>> \in learnedRcfg + /\ cfgC[j].cnum = j + /\ \A j \in 1..maxcfg : /\ ChosenInBal(cfgi[j], cfgb[j], cfgC[j-1], cfgc[j]) + /\ ConfigOKAt(cfgi[j], cfgb[j], cfgC[j-1]) + /\ \A j \in 1..maxcfg, i \in INum : + (i > cfgi[j]) => \A c \in Cmd : UnchoosableBefore(i, cfgb[j], cfgC[j-1], c) + +(***************************************************************************) +(* The following theorem asserts that the desired properties of cfgi, etc. *) +(* not explicitly stated in CfgOK follow from it and the definitions. *) +(* (This theorem isn't used explicitly, but it's probably used *) +(* implicitly.) *) +(***************************************************************************) +THEOREM TypeOK /\ CfgOK => + /\ cfgi \in [0..maxcfg -> INum \cup {-1}] + /\ cfgC \in [0..maxcfg -> Config] + /\ cfgb \in [0..maxcfg -> BNum ] + /\ \A j\in 0..maxcfg : cfgc[j] = ConfigCmd(cfgC[j]) + /\ learnedRcfg = {cfgl[j] : j \in 0..maxcfg} + PROOF OBVIOUS + +(***************************************************************************) +(* The following stability property is used in the invariance proof. *) +(***************************************************************************) +THEOREM CfgStability == + CfgOK => + \A i \in INum, b \in BNum, C \in Config : + /\ \A a \in Acc, c \in Cmd : Stable( /\ Voted(a, i, b, C.cnum, c) + /\ ConfigOKAt(i, b, C) ) + /\ \A c \in Cmd : Stable( /\ ChosenInBal(i, b, C, c) + /\ ConfigOKAt(i, b, C) ) + +<1>1 HAVE CfgOK + (*************************************************************************) + (* This statement means that we're assuming CfgOK and proving the *) + (* formula that it's supposed to imply. *) + (*************************************************************************) + +<1>2. TAKE i \in INum, b \in BNum, C \in Config + (*************************************************************************) + (* This statement means that our current goal is a formula of the form *) + (* *) + (* \A i \in INum, b \in BNum, C \in Config : P *) + (* *) + (* and we're going to prove it by introducing these new constants i, b, *) + (* and C and proving P. *) + (*************************************************************************) + + +<1>3. ASSUME CONSTANT a \in Acc, + CONSTANT c \in Cmd + PROVE Stable( /\ Voted(a, i, b, C.cnum, c) + /\ ConfigOKAt(i, b, C) ) + + <2>1. SUFFICES ASSUME Next, Voted(a, i, b, C.cnum, c), + ConfigOKAt(i, b, C) + PROVE ConfigOKAt(i, b, C)' + + (***********************************************************************) + (* Note: This statement is read "it suffices to assume ... and *) + (* prove ..." *) + (* *) + (* Proof: By definition of stability and the fact that Voted(...) is *) + (* stable. *) + (***********************************************************************) + <2>2. PICK ii \in -1 .. (i-1) : + /\ <<ii, ConfigCmd(C)>> \in learned + /\ \A j \in (ii+1)..(i-1), c4 \in CCmd : + /\ UnchoosableBefore(j, b, C, c4) + /\ \A aa \in Acc : ~ Voted(aa, j, b, C.cnum, c4) + (***********************************************************************) + (* By the assumption ConfigOKAt(...) of <2>1 and the definition of *) + (* ConfigOKAt. *) + (***********************************************************************) + + <2>3. SUFFICES ASSUME CONSTANT j \in (ii+1)..(i-1), + CONSTANT c4 \in CCmd, + CONSTANT aa \in Acc, + ~ Voted(aa, j, b, C.cnum, c4), + Voted(aa, j, b, C.cnum, c4)' + PROVE FALSE + (***********************************************************************) + (* Proof: By <2>1 we're assuming ConfigOKAt(i, b, C) and have to prove *) + (* ConfigOKAt(i, b, C)'. ConfiguOKAt(...) is the disjunction and *) + (* conjunction of formulas all of which are stable except for *) + (* *) + (* \A a \in Acc: ~ Voted(a, j, b, C.cnum, c), *) + (* *) + (* So we just have to show that ~ Voted(aa, j, b, n, c4) is stable for *) + (* every aa, j, c4, and n. The proof is by contradiction. *) + (***********************************************************************) + + <2>4. VoteFor(aa, j, b, C.cnum, c4) + (**********************************************************************) + (* Proof: By the assumptions of <2>3, because this VoteFor action is *) + (* the only subaction of Next that can make *) + (* Voted(aa, j, b, C.cnum, c) become true. *) + (**********************************************************************) + + <2>5. PICK CC \in Config : + /\ CC.cnum = C.cnum + /\ ConfigOKAt(j, b, CC) + /\ ChosenInBal(j, b, CC, c4) + (**********************************************************************) + (* Proof: The required CC exists by <2>4 and the third conjunct of *) + (* VoteFor(aa, j, b, C.cnum, c4), using the assumption c4 \in CCmd of *) + (* <2>3 and the assumption Voted(a, i, b, C.cnum, c) of <2>1, which *) + (* implies avote[a][i][b] \in Vote, so the final disjunct at the end *) + (* of that conjunct is false. *) + (**********************************************************************) + + <2>6. CC = C + (**********************************************************************) + (* This follows from ConfigOKAt(j, b, CC) (from <2>5) and *) + (* ConfigOKAt(i, b, C) (from <2>1, which imply that ConfigCmd(CC) and *) + (* ConfigCmd(C) are both learned commands. It then follows from *) + (* CC.cnum = C.cnum (from <2>5) and CfigOK (<1>1), which implies that *) + (* chosen reconfiguration commands have unique numbers, that CC = C. *) + (**********************************************************************) + + <2>7. \A a3 \in Acc : ~Voted(a3, j, b, C.cnum, c4) + (***********************************************************************) + (* Proof: By the last conjunct of <2>2, since <2>3 implies *) + (* j \in (ii+1)..(i-1) and c4 \in CCmd *) + (***********************************************************************) + + <2>8. QED + (***********************************************************************) + (* Proof: ChosenInBal(j, b, CC, c4) (from <2>5) implies Voted(aa, b, *) + (* CC.cnum, c4) aa. By <2>6 (CC = C), this contradicts <2>7. *) + (***********************************************************************) + +<1>4. ASSUME CONSTANT c1 \in Cmd \* Bug in parser prevents reuse of symbol c + PROVE Stable( /\ ChosenInBal(i, b, C, c1) + /\ ConfigOKAt(i, b, C) ) + (*************************************************************************) + (* Proof: Since ChosenInBal(i, b, C, c1) implies *) + (* Voted(a, i, b, C.cnum, c1), for some `a', this follows easily from *) + (* <1>3 and the stability of ChosenInBal(i, b, C, c1). *) + (*************************************************************************) + BY <1>4!2 + 1 + +<1>5. QED + BY <1>1, <1>2, <1>3, <1>4 +----------------------------------------------------------------------------- + +(***************************************************************************) +(* We now define the inductive invariant that is the heart of the safety *) +(* proof. *) +(***************************************************************************) +Inv == + /\(*1*) TypeOK + + /\(*2*) \A a \in Acc, i \in INum, b \in BNum, n \in CNum, c \in Cmd : + Voted(a, i, b, n, c) => + \A aa \in Acc, nn \in CNum, cc \in Cmd : + Voted(aa, i, b, nn, cc) => (<<nn, cc>> = <<n, c>>) + + /\(*3*) \A i \in INum, c \in Cmd : + (<<i, c>> \in learned) => + \E b \in BNum, C \in Config : /\ ConfigOKAt(i, b, C) + /\ ChosenInBal(i, b, C, c) + + /\(*4*) CfgOK + + /\(*5*) \A a \in Acc, i \in INum, b \in BNum, n \in CNum, c \in Cmd : + Voted(a, i, b, n, c) => + \E C \in Config : + /\ C.cnum = n + /\ ConfigOKAt(i, b, C) + /\ SafeAt(i, b, C, c) + /\ c \in CCmd => /\ ConfigOfCmd(c).cnum = n+1 + /\ \A j \in INum, cc \in Cmd : + (j > i) => UnchoosableBefore(j, b, C, cc) + /\ ChoosableAt(i, b, C, c) => + C = cfgC[ Max({j \in 0..maxcfg : cfgi[j] < i}) ] + + +(***************************************************************************) +(* We first prove that this Inv is strong enough--that is, it implies the *) +(* predicate that we want to show is invariant. *) +(***************************************************************************) +THEOREM Inv => SafetyInv + +<1>1. SUFFICES ASSUME Inv, + CONSTANT i \in INum, + CONSTANT c1 \in Cmd, + CONSTANT c2 \in Cmd, + <<i, c1>> \in learned /\ <<i, c2>> \in learned + PROVE c1 = c2 + PROOF OBVIOUS + +<1>2. PICK C1, C2 \in Config, b1, b2 \in BNum : + /\ ConfigOKAt(i, b1, C1) + /\ ChosenInBal(i, b1, C1, c1) + /\ ConfigOKAt(i, b2, C2) + /\ ChosenInBal(i, b2, C2, c2) + (*************************************************************************) + (* Proof: By <<i, c1>> and <<i, c2>> in `learned' (from <1>1) and Inv!3 *) + (* (which is assumed by <1>1). *) + (*************************************************************************) + +<1>3. PICK a1, a2 \in Acc : /\ Voted(a1, i, b1, C1.cnum, c1) + /\ Voted(a2, i, b2, C2.cnum, c2) + (*************************************************************************) + (* Proof: By <1>2, since ChosenInBal implies at least one vote. *) + (*************************************************************************) + +<1>4. PICK CC1, CC2 \in Config : + /\ CC1.cnum = C1.cnum + /\ ConfigOKAt(i, b1, CC1) + /\ ChoosableAt(i, b1, CC1, c1) => + CC1 = cfgC[Max ({j \in 0 .. maxcfg : cfgi[j] < i})] + /\ CC2.cnum = C2.cnum + /\ ConfigOKAt(i, b2, CC2) + /\ ChoosableAt(i, b2, CC2, c2) => + CC2 = cfgC[Max ({j \in 0 .. maxcfg : cfgi[j] < i})] + (*************************************************************************) + (* Proof: By <1>3 and conjunction 5 of Inv. *) + (*************************************************************************) + +<1>5. (CC1 = C1) /\ (CC2 = C2) + (*************************************************************************) + (* Proof: ConfigOKAt(i, b1, C1) (1st conjunct of <1>2) and *) + (* ConfigOKAt(i, b1, CC1) (2nd conjunct of <1>4) imply that <<i1, C1>> *) + (* and <<ii1, CC1>> are in `learned' for some i1 and ii1, and C1.cnum = *) + (* CC1.cnum (<1>4!1). By CfgOK, this implies that C1 = CC1. Similarly, *) + (* C2 = CC2. *) + (*************************************************************************) + +<1>6. C1 = C2 + (*************************************************************************) + (* Proof: We have ChosenInBal(i, b1, C1, c1) (second conjunct of <1>2), *) + (* which by definition of ChosenInBal and ChoosableAt implies *) + (* ChoosableAt(i, b1, C1, c1). By <1>5 and the 3rd conjunct of <1>4, *) + (* this shows that *) + (* *) + (* C1 = cfgC[Max ({j \in 0 .. maxcfg : cfgi[j] < i})] *) + (* *) + (* A similar argument shows that C2 equals the same expression. *) + (*************************************************************************) + +<1>7. QED + (*************************************************************************) + (* Proof: <1>6 and <1>2 imply ChosenInBal(i, b1, C, c1) and *) + (* ChosenInBal(i, b2, C, c2) for C = C1 = C2. The same simple reasoning *) + (* used in the proof of ordinary Paxos (with a fixed configuration C) *) + (* shows that this implies c1 = c2. *) + (*************************************************************************) +----------------------------------------------------------------------------- + +(***************************************************************************) +(* Here is the heart of the proof--the proof that Inv is an inductive *) +(* invariant. *) +(***************************************************************************) +THEOREM InductiveInvariance == Inv /\ Next => Inv' +<1>1. HAVE Inv /\ Next + +<1>2. Inv!1' + (*************************************************************************) + (* It is straighforward to show that TypeOK /\ Next => TypeOK'. *) + (*************************************************************************) + +\* <1> USE TypeOK +\* On 4 Mar 2009 it became illegal to use arbitrary expressions as +\* facts in a USE or HIDE--making this USE illegal + +<1>2a. TypeOK + PROOF OBVIOUS +<1> USE <1>2a + (*************************************************************************) + (* This statement means that from now on, we are free to use TypeOK *) + (* without explicitly mentioning that we're using it. In an informal *) + (* proof like this one, there are undoubtedly lots of places where we *) + (* assume other things without mentioning them. If we've been careful, *) + (* then we haven't assumed anything that we're not allowed to. *) + (*************************************************************************) + +<1>3. Inv!2' + (*************************************************************************) + (* Proof: Next and Inv!2 true and Inv!2' false implies that *) + (* VoteFor(a1, i, b, n, c) /\ Voted(a2, i, b, nn, cc) is true for some *) + (* a2 # a1 and cc # c. The second conjunct of VoteFor(a1, i, b, n, c) *) + (* implies that this is impossible. *) + (*************************************************************************) + +<1>4. Inv!3' + (*************************************************************************) + (* Proof: Next and Inv!3 true and Inv!3' false implies that there is *) + (* some i, bb, and c such that Learn(i, bb, c) is true but *) + (* *) + (* \E b \in BNum, C \in Config : /\ ConfigOKAt(i, b, C) *) + (* /\ ChosenInBal(i, b, C, c) *) + (* *) + (* is false. The definition of Learn(i, bb, c) implies that this is *) + (* impossible. *) + (*************************************************************************) + +<1>5. Inv!4' + <2>1. CASE learnedRcfg' = learnedRcfg + <3>1. maxcfg' = maxcfg /\ cfgl' = cfgl + (*********************************************************************) + (* Proof: By case assumption <2>1 becuase maxcfg is defined in terms *) + (* of learnedRcfg and cfgl is defined in terms of maxcfg and *) + (* learnedRcfg. *) + (*********************************************************************) + <3>2. cfgi' = cfgi /\ cfgc' = cfgc /\ cfgC' = cfgc /\ cfgb' = cfgb + (*********************************************************************) + (* Proof: By <3>1, since All these values are defined in terms of *) + (* cfgl and maxcfg. *) + (*********************************************************************) + <3>3. QED + (*********************************************************************) + (* Proof: CfgOK' follows by assumption <2>1, <3>1, <3>2, the *) + (* stability of *) + (* *) + (* /\ ChosenInBal(cfgi[j], cfgb[j], cfgC[j-1], cfgc[j]) *) + (* /\ ConfigOKAt(cfgi[j], cfgb[j], cfgC[j-1]) *) + (* *) + (* for all j (by <1>1 and Theorem CfgStability) and the stability of *) + (* *) + (* UnchoosableBefore(i, cfgb[j], cfgC[j-1], c) *) + (* *) + (* for all j, c (by Theorem Stability). *) + (*********************************************************************) + + <2>2. CASE learnedRcfg' # learnedRcfg + + <3>1. PICK i \in INum, b \in BNum, C \in Config : Learn(i, b, ConfigCmd(C)) + (*********************************************************************) + (* Proof: Case assumption <2>2 and the definition of Next. *) + (*********************************************************************) + <3> DEFINE c == ConfigCmd(C) + + <3>2. PICK k \in 0..maxcfg : + /\ ConfigOKAt(i, b, cfgC[k]) + /\ ChosenInBal(i, b, cfgC[k], c) + /\ learned' = learned \cup {<<i, c>>} + (*********************************************************************) + (* Proof: By <3>1, the definition of Learn, and CfgOK (Inv!4), which *) + (* implies that the configuration whose existence is implied by the *) + (* definition Learn(i, b, c) must be one of the cfgC[j]. *) + (*********************************************************************) + <3>3. i > cfgi[k] + (**********************************************************************) + (* Proof: By ChosenInBal(i, b, cfgC[k], c) (<3>2), definition of *) + (* ConfigOKAt, and CfgOK *) + (**********************************************************************) + + <3>4. k = maxcfg + <4>1. SUFFICES ASSUME k < maxcfg + PROVE FALSE + (*******************************************************************) + (* Proof by contradiction. *) + (*******************************************************************) + + <4> HAVE k < maxcfg + + <4>2. CASE i > cfgi[k+1] + <5>1. b < cfgb[k+1] + <6>1. /\ UnchoosableBefore(cfgi[k+1], b, cfgC[k], cfgc[k+1]) + /\ \A a \in Acc: ~Voted(a, cfgi[k+1], b, cfgC[k].cnum, cfgc[k+1]) + (***************************************************************) + (* Proof: By ConfigOKAt(i, b, cfgC[k]) (<3>2), case assumption *) + (* <4>2, and cfgi[k] < cfgi[k+1] (by CfgOK). *) + (***************************************************************) + <6>2. QED + (***************************************************************) + (* Proof: Since CfgOK implies *) + (* *) + (* ChosenInBal(cfgi[k+1], cfgb[k+1], cfgC[k], cfgc[k+1]) *) + (* *) + (* <6>1 implies that cfgb[k+1] cannot be \leq b. *) + (***************************************************************) + + <5>2. UnchoosableBefore(i, cfgb[k+1], cfgC[k], c) + (*****************************************************************) + (* Proof: By the last conjunct of CfgOK, substituting k+1 for j, *) + (* using case assumption <4>2. *) + (*****************************************************************) + + <5>3. QED + (*****************************************************************) + (* Proof: <5>1 and <5>2 contradict <3>2, which implies *) + (* ChosenInBal(i, b, cfgC[k], c). *) + (*****************************************************************) + + <4>3. CASE i < cfgi[k+1] + <5>1. b > cfgb[k+1] + <6>1. /\ UnchoosableBefore(i, cfgb[k+1], cfgC[k], c) + /\ \A a \in Acc : ~Voted(a, i, cfgb[k+1], cfgC[k].cnum, c) + (***************************************************************) + (* Proof: By CfgOK, which implies *) + (* ConfigOKAt(cfgi[k+1], cfgb[k+1], cfgC[k]) and the *) + (* definition of ConfigOKAt, since case assumption <4>3 and *) + (* <3>3 allows us to substitute i for j in the definition. *) + (***************************************************************) + <6>2. QED + (***************************************************************) + (* Proof: <3>2 implies ChosenInBal(i, b, cfgC[k], c), which *) + (* would contradict <6>1 if b \leq cfgb[k+1]. *) + (***************************************************************) + + <5>2. PICK a \in Acc : Voted(a, i, b, cfgC[k].cnum, c) + (*****************************************************************) + (* Proof: By ChosenInBal(i, b, cfgC[k], c) (from <3>2). *) + (*****************************************************************) + + <5>3. PICK CC \in Config : + /\ CC.cnum = cfgC[k].cnum + /\ ConfigOKAt(i, b, CC) + /\ UnchoosableBefore(cfgi[k+1], b, CC, cfgc[k+1]) + (*****************************************************************) + (* Proof: By <5>2 and the Inv!5, using case assumption <4>3 to *) + (* justify substituting cfgc[k+1] for j in the 4th conjunct of *) + (* the body of the \E C \in Config expression. *) + (*****************************************************************) + + <5>4. CC = cfgC[k] + (*****************************************************************) + (* Proof: ConfigOKAt(i, b, CC) (from <5>3) and CfgOK implies CC *) + (* equals cfgC[j] for some j, and CC.cnum = cfgC[k].cnum (from *) + (* <5>3) implies j = k. *) + (*****************************************************************) + + <5>5. QED + (*****************************************************************) + (* Proof: <5>3 and <5>4 imply *) + (* *) + (* UnchoosableBefore(cfgi[k+1], b, cfg[k], cfgc[k+1]) *) + (* *) + (* and by b > cfgb[k+1] (from <5>1) this contradicts CfgOK, *) + (* which implies *) + (* *) + (* ChosenInBal(cfgi[k+1], cfgb[k+1], cfgC[k], cfgc[k+1]) *) + (*****************************************************************) + + <4>4. CASE i = cfgi[k+1] + <5>1. ChosenInBal(i, b, cfgC[k], c) + BY <3>2 + + <5>2. ChosenInBal(cfgi[k+1], cfgb[k+1], cfgC[k], cfgc[k+1]) + BY CfgOK + + <5>3. c = cfgc[k+1] + (*****************************************************************) + (* Proof: By same simple reasoning used to prove the consistency *) + (* of ordinary Paxos (for instance i = cfgi[k+1] and the (fixed) *) + (* configuration cfgC[k]). *) + (*****************************************************************) + + <5>4. QED + (*****************************************************************) + (* Proof: CfgOK implies <<cfgi[k+1], cfgc[k+1]>> \in `learned', *) + (* so Learn(i, b, c) implies that `learned' is unchanged, *) + (* contradicting case assumption <2>2 (learnedRcfg' # *) + (* learnedRcfg). *) + (*****************************************************************) + + <4>5. QED + BY <4>2, <4>3, <4>4 + + <3>5. /\(*1*) <<i, c>> \in learned' \ {learned} + /\(*2*) C.cnum = maxcfg + 1 + /\(*3*) ChosenInBal(i, b, cfgC[maxcfg], c) + /\(*4*) ConfigOKAt(i, b, cfgC[maxcfg]) + /\(*5*) \A ii \in INum : + (ii > i) => + \A cc \in Cmd : UnchoosableBefore(ii, b, cfgC[maxcfg], cc) + <4>1. <3>5!1 + (*******************************************************************) + (* Proof: By <3>1 and case assumption <2>2. *) + (*******************************************************************) + + <4>2. <3>5!3 + BY <3>2 + + <4>3. <3>5!4 + BY <3>2 + + <4>4. /\ C.cnum = cfgC[maxcfg].cnum + 1 + /\ \A ii \in INum, cc \in Cmd : + (ii > i) => UnchoosableBefore(ii, b, cfgC[maxcfg], cc) + + <5>1. PICK a \in Acc : Voted(a, i, b, cfgC[maxcfg], c) + BY <4>2 + <5>2. PICK CC \in Config : + /\ CC.cnum = cfgC[maxcfg] + /\ ConfigOKAt(i, b, CC) + /\ C.cnum = cfgC[maxcfg].cnum + 1 + /\ \A j \in INum, cc \in Cmd : + (j > i) => UnchoosableBefore(j, b, CC, cc) + (*****************************************************************) + (* Proof: By <5>1 and Inv!5, since c \in CCmd and C = *) + (* ConfigOfCmd(c). *) + (*****************************************************************) + <5>3. CC = cfgC[maxcfg] + (*****************************************************************) + (* Proof: BY <5>2, since ConfigOKAt(i, b, CC) implies *) + (* <<j, CmdOfConfig(CC)>> in `learned', so it equals cfgC[j] for *) + (* some j, and CC.cnum = cfgC[maxcfg] implies j = maxcfg. *) + (*****************************************************************) + <5>4. QED + BY <5>2, <5>3 + + <4>5. <3>5!5 + + <4>6. QED + BY <4>1, <4>2, <4>3, <4>4, <4>5 + + <3>6. QED + (*********************************************************************) + (* Proof: <3>5!1 and <3>5!2 imply that maxcfg' = maxcfg+1 and *) + (* *) + (* cfgl' = [j \in 0..maxcfg' |-> *) + (* IF j < maxcfg THEN cfgl[j] ELSE <<i, c>>] *) + (* *) + (* from which it follows that the functions cfgi', cfgc', cfgC', *) + (* and cfgb' are the expected "extensions" of cfgi, cfgc, cfgC, and *) + (* cfgb, where <3>5!3 and <3>5!4 imply the existence of the b in *) + (* BNum satisfying the CHOOSE expression in the definition of *) + (* cfgb'[maxcfg']. This proves the first 5 conjuncts of CfgOK'. *) + (* The remaining three conjuncts are all \A j formulas. For j < *) + (* maxcfg', they follow from CfgOK. For j = maxcfg', they follow *) + (* from <3>5. *) + (*********************************************************************) + <2>3. QED + BY <2>1, <2>2 + +<1>6. Inv!5' + <2>1. TAKE a \in Acc, i \in INum, b \in BNum, n \in CNum, c \in Cmd + <2>2. HAVE Voted(a, i, b, n, c)' + <2>3. CASE Voted(a, i, b, n, c) + (***********************************************************************) + (* Proof: This case follows from the Theorems Stability and *) + (* CfgStability, which imply the stability of all the non-constant *) + (* subformuulas in the \E C \in Config expression in Inv!5. *) + (***********************************************************************) + <2>4. CASE ~Voted(a, i, b, n, c) + <3>1. VoteFor(a, i, b, n, c) + (*********************************************************************) + (* Proof: Next, <2>2 and case assumption <2>4, implies this VoteFor *) + (* action. *) + (*********************************************************************) + + <3>2. SUFFICES (* to prove *) + \E C \in Config : + /\ C.cnum = n + /\ ConfigOKAt(i, b, C) + /\ SafeAt(i, b, C, c) + /\ c \in CCmd => /\ ConfigOfCmd(c).cnum = n+1 + /\ \A j \in INum, cc \in Cmd : + (j > i) => UnchoosableBefore(j, b, C, cc) + /\ ChoosableAt(i, b, C, c) => + C = cfgC[ Max({j \in 0..maxcfg : cfgi[j] < i}) ] + (*********************************************************************) + (* Proof: For all other tuples <<aa, ii, bb, nn, cc>>, the body of *) + (* the \A of Inv!5' follows from Inv!5 and Theorems Stability and *) + (* CfgStability. *) + (*********************************************************************) + + <3>3. PICK C \in Config : + /\ C.cnum = n + /\ ConfigOKAt(i, b, C) + /\ SafeAt(i, b, C, c) + /\ c \in CCmd => /\ ConfigOfCmd(c).cnum = n+1 + /\ \A j \in INum, cc \in Cmd : + (j > i) => UnchoosableBefore(j, b, C, cc) + (*********************************************************************) + (* Proof: The existence of C follows from <3>1 and the definition of *) + (* VoteFor. *) + (*********************************************************************) + + <3>4. ASSUME ChoosableAt(i, b, C, c), + C # cfgC[ Max({j \in 0..maxcfg : cfgi[j] < i}) ] + PROVE FALSE + <4>1. PICK j \in 0..maxcfg : C = cfgC[j] + (*******************************************************************) + (* Proof: By CfgOK and ConfigOKAt(i, b, C), which imply that C is *) + (* one of the cfgC[j], and *) + (*******************************************************************) + <4>2. i > cfgi[j] + (*******************************************************************) + (* Proof: <3>3 and <4>1 imply ConfigOKAt(i, b, cfgC[j]), which *) + (* implies i > cfgi[j]. *) + (*******************************************************************) + <4>3. i > cfgi[j+1] + (*******************************************************************) + (* Proof: <4>1, <4>2, and the assumption <3>4!2. *) + (*******************************************************************) + <4>4. cfgb[j+1] > b + (*******************************************************************) + (* Proof: Since and i > cfgi[j+1] > cfgi[j] (by <4>3 and CfgOK), *) + (* ConfigOKAt(i, b, cfgC[j]) (which holds by <3>3 and <4>1) *) + (* implies UnchoosableBefore(cfgi[j+1], b, cfgC[j], cfgc[j+1]) and *) + (* ~ChosenInBal(cfgi[j+1], b, cfgC[j], cfgc[j+1]). Since CfgOK *) + (* implies ChosenInBal(cfgi[j+1], cfgb[j+1], cfgC[j], cfgc[j+1]), *) + (* we cannot have b \geq cfgb[j+1]. *) + (*******************************************************************) + <4>5. QED + (*******************************************************************) + (* Proof: The last conjunct of CfgOK implies *) + (* *) + (* UnchoosableBefore(i, cfgb[j+1], cfgC[j], c) *) + (* *) + (* By <4>4 and <4>1, this contradicts ChoosableAt(i, b, C, c), *) + (* which is assumption <3>4!1. *) + (*******************************************************************) + <3>5. QED + BY <3>2, <3>3, <3>4 + + <2>5. QED + BY <2>3, <2>4 + +<1>7. QED + BY <1>1, <1>2, <1>3, <1>4, <1>5, <1>6 + +============================================================================= + + +TLA+2 problems: + + - Can't use "!" selectors to name "c \in S" in + ASSUME CONSTANT c \in S + PARTIALLY FIXED 10 Oct 2007 to allow "CONSTANT c \in S" to + be used as a fact. + + - <i>j. PICK x ... makes x declared in the proof of <i>j, which + is wrong, since it's not legal to use it there. + FIXED 10 Oct 2007 + + - For subexpression naming, PICK is treated like a \A, even though + the variables being picked are being declared externally to the + expression. Thus, we have to write + + <3>4. PICK x : P(x) + <3>5. ... + BY <3>4!(x) \* This names P(x) + + This seems wrong, since x is declared in the scope of the use. + However, the !(x) can't be omitted if we want to refer to P inside + the proof of <3>4. Since we don't want the naming convention to + depend on where the name appears, we don't have much choice but to + let it stand as is. + + - Doesn't allow labels in numbered steps. This seems to be a bug, + since the parser allows positional naming of subexpressions of + a numbered step. FIXED 10 Oct 2007 + + - Bug: declaration of NEWs introduced in an ASSUME/PROVE step leak + out into the rest of the proof. (They should only for a + SUFFICE ASSUME/PROVE step.) FIXED 10 Oct 2007 + + - Bug: The error message for duplicate step numbers reports the position + as the entire containing proof body, not the step. This indicates + that some semantic node is being created with the entire proof body + rather than just its own part of the spec as its syntactic node. + FIXED 10 Oct 2007 +============================================================================= diff --git a/tlatools/test-model/suite/test212.tla b/tlatools/test-model/suite/test212.tla index 0a01e66ed702cc7125a06826e5c50d5f5eb86dfe..886fe8e0aba2014d6ae394130e5baa181e20eaba 100644 --- a/tlatools/test-model/suite/test212.tla +++ b/tlatools/test-model/suite/test212.tla @@ -1,33 +1,33 @@ ---------------------------- MODULE test212 -------------------------- -\* Test of Leibniz checking -\* Uses the fact that you can't substitute a non-Leibniz operator -\* for a constant operator. -VARIABLE x - -Leibniz(a2) == {a2 , x'} -NonLeibniz2(a, b) == <<a, b'>> -L == INSTANCE test212b WITH y <- x - -NonLeibniz(a1) == a1' -Leibniz2(a, b) == <<a, b, x'>> - -I(a) == INSTANCE test212b WITH y <- a -LL == INSTANCE test212b WITH y <- ENABLED (x'=x) -NonL(a) ==INSTANCE test212b WITH y <- ENABLED a - -\* Legal -L1 == INSTANCE test212a WITH Op <- Leibniz, Op2 <- Leibniz2 -L2 == INSTANCE test212a WITH Op <- LAMBDA a : I(a)!Leibniz(1), - Op2 <- Leibniz2 -L3 == INSTANCE test212a WITH Op <- Leibniz, Op2 <- I!Leibniz -L4 == INSTANCE test212a WITH Op <- Leibniz, Op2 <- LL!Leibniz2 -L5 == INSTANCE test212a WITH Op <- LL!Leibniz, Op2 <- Leibniz2 - -\* Illegal -I1 == INSTANCE test212a WITH Op <- Leibniz, Op2 <- NonLeibniz2 -I2 == INSTANCE test212a WITH Op <- NonLeibniz, Op2 <- Leibniz2 -I3 == INSTANCE test212a WITH Op <- NonL!NoArg, Op2 <- Leibniz2 -I4 == INSTANCE test212a WITH Op <- Leibniz, Op2 <- L!NonLeibniz2 -I5 == INSTANCE test212a WITH Op <- Leibniz, Op2 <- NonL!Leibniz -I6 == INSTANCE test212a WITH Op <- Leibniz, Op2 <- I!NonLeibniz +--------------------------- MODULE test212 -------------------------- +\* Test of Leibniz checking +\* Uses the fact that you can't substitute a non-Leibniz operator +\* for a constant operator. +VARIABLE x + +Leibniz(a2) == {a2 , x'} +NonLeibniz2(a, b) == <<a, b'>> +L == INSTANCE test212b WITH y <- x + +NonLeibniz(a1) == a1' +Leibniz2(a, b) == <<a, b, x'>> + +I(a) == INSTANCE test212b WITH y <- a +LL == INSTANCE test212b WITH y <- ENABLED (x'=x) +NonL(a) ==INSTANCE test212b WITH y <- ENABLED a + +\* Legal +L1 == INSTANCE test212a WITH Op <- Leibniz, Op2 <- Leibniz2 +L2 == INSTANCE test212a WITH Op <- LAMBDA a : I(a)!Leibniz(1), + Op2 <- Leibniz2 +L3 == INSTANCE test212a WITH Op <- Leibniz, Op2 <- I!Leibniz +L4 == INSTANCE test212a WITH Op <- Leibniz, Op2 <- LL!Leibniz2 +L5 == INSTANCE test212a WITH Op <- LL!Leibniz, Op2 <- Leibniz2 + +\* Illegal +I1 == INSTANCE test212a WITH Op <- Leibniz, Op2 <- NonLeibniz2 +I2 == INSTANCE test212a WITH Op <- NonLeibniz, Op2 <- Leibniz2 +I3 == INSTANCE test212a WITH Op <- NonL!NoArg, Op2 <- Leibniz2 +I4 == INSTANCE test212a WITH Op <- Leibniz, Op2 <- L!NonLeibniz2 +I5 == INSTANCE test212a WITH Op <- Leibniz, Op2 <- NonL!Leibniz +I6 == INSTANCE test212a WITH Op <- Leibniz, Op2 <- I!NonLeibniz ================================================================== \ No newline at end of file diff --git a/tlatools/test-model/suite/test212a.tla b/tlatools/test-model/suite/test212a.tla index 2962bbf49049ab640821169326a73456a7deb7eb..175fea251f1af826e385c7502a6b02b0ed34d7fd 100644 --- a/tlatools/test-model/suite/test212a.tla +++ b/tlatools/test-model/suite/test212a.tla @@ -1,5 +1,5 @@ --------------------------- MODULE test212a ------------------------- - -CONSTANT Op(_) , Op2(_,_) - +-------------------------- MODULE test212a ------------------------- + +CONSTANT Op(_) , Op2(_,_) + ============================================================================= \ No newline at end of file diff --git a/tlatools/test-model/suite/test212b.tla b/tlatools/test-model/suite/test212b.tla index bc02b8bdcc15d1579d492a1bbec1efc83e460aeb..c6027040a338c85e81f4fecaad02b100943cebcc 100644 --- a/tlatools/test-model/suite/test212b.tla +++ b/tlatools/test-model/suite/test212b.tla @@ -1,9 +1,9 @@ --------------------------- MODULE test212b ------------------------- -VARIABLE y -NoArg == y' -Leibniz(a4) == <<a4, y>> -Leibniz2(a44, a45) == <<a44, a45, y>> -NonLeibniz(a5) == ENABLED a5 -NonLeibniz2(a6, a7) == {a6', a7} - -============================================================================= +-------------------------- MODULE test212b ------------------------- +VARIABLE y +NoArg == y' +Leibniz(a4) == <<a4, y>> +Leibniz2(a44, a45) == <<a44, a45, y>> +NonLeibniz(a5) == ENABLED a5 +NonLeibniz2(a6, a7) == {a6', a7} + +============================================================================= diff --git a/tlatools/test-model/suite/test213.tla b/tlatools/test-model/suite/test213.tla index 9f26d15e40c135e9418e30057a543630fa28a58b..b16ab4c8616d80bc47be3c071be5090b0c132668 100644 --- a/tlatools/test-model/suite/test213.tla +++ b/tlatools/test-model/suite/test213.tla @@ -1,47 +1,47 @@ -------------------------------- MODULE test213 ------------------------------ -\* Test that -\* - A non-temporal theorem or proof step cannot have a -\* temporal formula in its proof. -\* - A declared constant that appears in an ASSUME or an ASSUME/PROVE -\* cannot be instantiated with a temporal formula -\* -\* Parsing only; produces errors. - -VARIABLE x - -I1 == INSTANCE test213b WITH C <- x', D <- x' -I2 == INSTANCE test213b WITH C <- [](x=0), D <- TRUE \* ERROR -I3 == INSTANCE test213b WITH C <- TRUE, D <- [](x=0) \* ERROR - -THEOREM [](x=0) -<1>1. CASE FALSE - <2>1. [](x=0) - <2>2. QED - <3>1. [](x # 0) - BY [](x # 0) - <3>2. QED -<1>2. x=0 \* ERROR - <2>1. (x=0) - <2>2. QED - <3>1. [](x=0) - <3>2. QED -<1>3. CASE TRUE - <2>1. CASE x=0 \* ERROR - <2>1a. CASE FALSE - <2>2. HAVE x=0 \* ERROR - <2>2a HAVE TRUE - <2>3. WITNESS 3 \in x \* ERROR - <2>4. WITNESS 2 \in {} - <2>5. QED -<1>4. QED - <2>1. [](x=0) - <2>2. QED - - - -THEOREM x=0 \* ERROR - <1>1. x'=0 \* ERROR - BY [](x=0) \* This BY causes an error, though it needn't - <1>2. [](x=0) \* this causes error in THEOREM - <1>3. QED +------------------------------- MODULE test213 ------------------------------ +\* Test that +\* - A non-temporal theorem or proof step cannot have a +\* temporal formula in its proof. +\* - A declared constant that appears in an ASSUME or an ASSUME/PROVE +\* cannot be instantiated with a temporal formula +\* +\* Parsing only; produces errors. + +VARIABLE x + +I1 == INSTANCE test213b WITH C <- x', D <- x' +I2 == INSTANCE test213b WITH C <- [](x=0), D <- TRUE \* ERROR +I3 == INSTANCE test213b WITH C <- TRUE, D <- [](x=0) \* ERROR + +THEOREM [](x=0) +<1>1. CASE FALSE + <2>1. [](x=0) + <2>2. QED + <3>1. [](x # 0) + BY [](x # 0) + <3>2. QED +<1>2. x=0 \* ERROR + <2>1. (x=0) + <2>2. QED + <3>1. [](x=0) + <3>2. QED +<1>3. CASE TRUE + <2>1. CASE x=0 \* ERROR + <2>1a. CASE FALSE + <2>2. HAVE x=0 \* ERROR + <2>2a HAVE TRUE + <2>3. WITNESS 3 \in x \* ERROR + <2>4. WITNESS 2 \in {} + <2>5. QED +<1>4. QED + <2>1. [](x=0) + <2>2. QED + + + +THEOREM x=0 \* ERROR + <1>1. x'=0 \* ERROR + BY [](x=0) \* This BY causes an error, though it needn't + <1>2. [](x=0) \* this causes error in THEOREM + <1>3. QED ============================================================================= \ No newline at end of file diff --git a/tlatools/test-model/suite/test213b.tla b/tlatools/test-model/suite/test213b.tla index 61dc880f1c2e02f4fd32c140001f18a9cc20c0d8..099e566da5f15f4cfa6f67e8b0246a70ccc94933 100644 --- a/tlatools/test-model/suite/test213b.tla +++ b/tlatools/test-model/suite/test213b.tla @@ -1,7 +1,7 @@ ------------------------------- MODULE test213b ------------------------------ -CONSTANT C, D -ASSUME C = {} - -THEOREM ASSUME D - PROVE TRUE -============================================================================= +------------------------------ MODULE test213b ------------------------------ +CONSTANT C, D +ASSUME C = {} + +THEOREM ASSUME D + PROVE TRUE +============================================================================= diff --git a/tlatools/test-model/suite/test214.tla b/tlatools/test-model/suite/test214.tla index cfd10fd75d92e25194aa256bec7f1b1b87a0b0fe..c2be50d9d42b446fec0f1fb51588a4b4237d1087 100644 --- a/tlatools/test-model/suite/test214.tla +++ b/tlatools/test-model/suite/test214.tla @@ -1,16 +1,16 @@ ------------------------------- MODULE test214 ------------------------------ -\* Test that USE and HIDE cannot contain arbitrary expressions as -\* facts. - -THEOREM bar == <<1, 2>> - -USE bar, bar!1 (*ERROR*) - - -HIDE bar, TRUE (*ERROR*) - -THEOREM xx == ASSUME TRUE PROVE FALSE - <1>2. USE TRUE (*ERROR*), bar , xx , xx!1 (*ERROR*) - <1>3. QED - -============================================================================= +------------------------------ MODULE test214 ------------------------------ +\* Test that USE and HIDE cannot contain arbitrary expressions as +\* facts. + +THEOREM bar == <<1, 2>> + +USE bar, bar!1 (*ERROR*) + + +HIDE bar, TRUE (*ERROR*) + +THEOREM xx == ASSUME TRUE PROVE FALSE + <1>2. USE TRUE (*ERROR*), bar , xx , xx!1 (*ERROR*) + <1>3. QED + +============================================================================= diff --git a/tlatools/test-model/suite/test215.tla b/tlatools/test-model/suite/test215.tla index 9d163643c0c68afb486ca8c166bfd620a6c422e6..b4d5f7845d1db4f8c0f29aea9931bb0e3ba91ca5 100644 --- a/tlatools/test-model/suite/test215.tla +++ b/tlatools/test-model/suite/test215.tla @@ -1,29 +1,29 @@ -------------------------- MODULE test215 ------------------------- -\* Test of constraints on levels of temporal operators that -\* outlaw any form of raw TLA. - -VARIABLE x - -a == x ~> []x -b == x' ~> []x \* ERROR -c == []x ~> x' \* ERROR - -d == x -+-> []x -e == x' -+-> []x \* ERROR -f == []x -+-> x' \* ERROR - -g == <><<x'>>_x -h == <>(x') \* ERROR - -foo == [][x']_x - -bar == [](x') \* ERROR - -m == \A i \in {}, j \in x : []x -n == \A i \in {}, j \in x' : []x \* ERROR - -mm == \E i \in {}, j \in x : []x -nn == \E i \in {}, j \in x' : []x \* ERROR - -m2 == \A i \in x' : x' +------------------------- MODULE test215 ------------------------- +\* Test of constraints on levels of temporal operators that +\* outlaw any form of raw TLA. + +VARIABLE x + +a == x ~> []x +b == x' ~> []x \* ERROR +c == []x ~> x' \* ERROR + +d == x -+-> []x +e == x' -+-> []x \* ERROR +f == []x -+-> x' \* ERROR + +g == <><<x'>>_x +h == <>(x') \* ERROR + +foo == [][x']_x + +bar == [](x') \* ERROR + +m == \A i \in {}, j \in x : []x +n == \A i \in {}, j \in x' : []x \* ERROR + +mm == \E i \in {}, j \in x : []x +nn == \E i \in {}, j \in x' : []x \* ERROR + +m2 == \A i \in x' : x' ======================================================================= \ No newline at end of file diff --git a/tlatools/test-model/suite/test216.cfg b/tlatools/test-model/suite/test216.cfg index e0c9dfebfe69a9f1a896f4323120f3e0aaff51b5..87210cf3d20b205f9d171b521f757ef61f2f98ff 100644 --- a/tlatools/test-model/suite/test216.cfg +++ b/tlatools/test-model/suite/test216.cfg @@ -1,4 +1,4 @@ -SPECIFICATION Spec1 \* Spec -CONSTANT C=6 -INVARIANT Inv Inv2 +SPECIFICATION Spec1 \* Spec +CONSTANT C=6 +INVARIANT Inv Inv2 PROPERTIES Prop1 Prop2 Prop3 Prop4 Prop5 \ No newline at end of file diff --git a/tlatools/test-model/suite/test216.tla b/tlatools/test-model/suite/test216.tla index 92836ec9a1f4b23552acdb30510381a63f79318a..e54d2f85b7e0d3b8e7422ab9b1ba590d2e490bd1 100644 --- a/tlatools/test-model/suite/test216.tla +++ b/tlatools/test-model/suite/test216.tla @@ -1,72 +1,72 @@ ----------------------------- MODULE test216 ------------------------ -EXTENDS TLC, Naturals - -INSTANCE test216a WITH D <- 42 -Foo == INSTANCE test216a WITH D <- 43 -FooG == INSTANCE test216a WITH D <- 42 -VARIABLE x -CONSTANT C - -THEOREM Thm1 == x \in 0..C - -THEOREM Thm1Prime == x' \in 0..C - -THEOREM Thm1a == 1+1=2 -Bar == x \in 0..C -Init == Bar \/ Thm1!: \/ (Thm1 /\ ENABLED Thm1Prime!:) -Next == x'=(x+1)%C /\ Thm1!: - /\ Thm1Prime!: /\ Thm1 /\ Thm1Prime -Spec == /\ Init - /\ [][Next]_x - /\ WF_x(Next) - - - - -Inv == Thm1 -Inv2 == Thm1!<< \in Thm1!>> - -THEOREM Thm1b == Spec => /\ []Inv - /\ []<>(x=0) - -Spec1 == Thm1b!1 -\* need to build two tests, since there are two specs - -THEOREM Thm1c == [][Next]_x -Spec2 == Init /\ Thm1c \* Doesn't work - -Thm1d == []<>(x=0) -Prop3 == Thm1d - -Prop1 == Thm1b!2!1 -Prop2 == Thm1b!2!2 - -ASSUME Thm2 -ASSUME ~ Foo!Thm2 -ASSUME ~Foo!Thm3 -ASSUME ~Foo!I!Thm3 -ASSUME FooG!Thm2 -ASSUME FooG!Thm3 -ASSUME FooG!I!Thm3 -ASSUME Thm2!: -ASSUME ~ Foo!Thm2!: -ASSUME Thm2!1 = 42 -ASSUME Foo!Thm2!1 = 43 - -THEOREM Thm3!: -THEOREM ~ Foo!Thm3!: -ASSUME Foo!Thm3!2!2 = 42 -ASSUME Foo!I!Thm3!2!2 = 42 -ASSUME I!Thm3!2!2 = 42 -ASSUME Thm3!2!2 = 42 - - -J == INSTANCE test216c -Prop4 == J!ThmC!1 /\ J!ThmC!2 /\ J!ThmC2!: - -Thm1aDef == Thm1a - -INSTANCE test216c -ThmC3Def == ThmC3 -Prop5 == ThmC!1 /\ ThmC!2 /\ ThmC3!: /\ Thm1aDef /\ ThmC3Def -==================================================================== +---------------------------- MODULE test216 ------------------------ +EXTENDS TLC, Naturals + +INSTANCE test216a WITH D <- 42 +Foo == INSTANCE test216a WITH D <- 43 +FooG == INSTANCE test216a WITH D <- 42 +VARIABLE x +CONSTANT C + +THEOREM Thm1 == x \in 0..C + +THEOREM Thm1Prime == x' \in 0..C + +THEOREM Thm1a == 1+1=2 +Bar == x \in 0..C +Init == Bar \/ Thm1!: \/ (Thm1 /\ ENABLED Thm1Prime!:) +Next == x'=(x+1)%C /\ Thm1!: + /\ Thm1Prime!: /\ Thm1 /\ Thm1Prime +Spec == /\ Init + /\ [][Next]_x + /\ WF_x(Next) + + + + +Inv == Thm1 +Inv2 == Thm1!<< \in Thm1!>> + +THEOREM Thm1b == Spec => /\ []Inv + /\ []<>(x=0) + +Spec1 == Thm1b!1 +\* need to build two tests, since there are two specs + +THEOREM Thm1c == [][Next]_x +Spec2 == Init /\ Thm1c \* Doesn't work + +Thm1d == []<>(x=0) +Prop3 == Thm1d + +Prop1 == Thm1b!2!1 +Prop2 == Thm1b!2!2 + +ASSUME Thm2 +ASSUME ~ Foo!Thm2 +ASSUME ~Foo!Thm3 +ASSUME ~Foo!I!Thm3 +ASSUME FooG!Thm2 +ASSUME FooG!Thm3 +ASSUME FooG!I!Thm3 +ASSUME Thm2!: +ASSUME ~ Foo!Thm2!: +ASSUME Thm2!1 = 42 +ASSUME Foo!Thm2!1 = 43 + +THEOREM Thm3!: +THEOREM ~ Foo!Thm3!: +ASSUME Foo!Thm3!2!2 = 42 +ASSUME Foo!I!Thm3!2!2 = 42 +ASSUME I!Thm3!2!2 = 42 +ASSUME Thm3!2!2 = 42 + + +J == INSTANCE test216c +Prop4 == J!ThmC!1 /\ J!ThmC!2 /\ J!ThmC2!: + +Thm1aDef == Thm1a + +INSTANCE test216c +ThmC3Def == ThmC3 +Prop5 == ThmC!1 /\ ThmC!2 /\ ThmC3!: /\ Thm1aDef /\ ThmC3Def +==================================================================== diff --git a/tlatools/test-model/suite/test216a.tla b/tlatools/test-model/suite/test216a.tla index 01d4408c842f7a0bf61289ab3bbe9649a17b5c1c..bd7e81a7f7135e6f0c521c0fe0e10ad6ab545f39 100644 --- a/tlatools/test-model/suite/test216a.tla +++ b/tlatools/test-model/suite/test216a.tla @@ -1,15 +1,15 @@ ----------------------------- MODULE test216a ------------------------ -EXTENDS Naturals -CONSTANT D - -ASSUME Ass2 == D + 0 = 42 -THEOREM Thm2 == D + 0 = 42 -Thm2Def == D + 0 = 42 - -INSTANCE test216b WITH E <- D, y <- 0 - \* 12 June 2014: Changed from Test216b, which is now illegal -I == INSTANCE test216b WITH E <- D, y <- 0 - \* 12 June 2014: Changed from Test216b, which is now illegal - - -==================================================================== +---------------------------- MODULE test216a ------------------------ +EXTENDS Naturals +CONSTANT D + +ASSUME Ass2 == D + 0 = 42 +THEOREM Thm2 == D + 0 = 42 +Thm2Def == D + 0 = 42 + +INSTANCE test216b WITH E <- D, y <- 0 + \* 12 June 2014: Changed from Test216b, which is now illegal +I == INSTANCE test216b WITH E <- D, y <- 0 + \* 12 June 2014: Changed from Test216b, which is now illegal + + +==================================================================== diff --git a/tlatools/test-model/suite/test216b.tla b/tlatools/test-model/suite/test216b.tla index 0efdfc41b5baa8bfe82eb860358ff92b681fe0dd..e576811063d60194ff88e1a84535b2c8df319426 100644 --- a/tlatools/test-model/suite/test216b.tla +++ b/tlatools/test-model/suite/test216b.tla @@ -1,7 +1,7 @@ ----------------------------- MODULE test216b ------------------------ -CONSTANT E, y - -THEOREM Thm3 == y \in {y} /\ E = 42 - - -==================================================================== +---------------------------- MODULE test216b ------------------------ +CONSTANT E, y + +THEOREM Thm3 == y \in {y} /\ E = 42 + + +==================================================================== diff --git a/tlatools/test-model/suite/test216c.tla b/tlatools/test-model/suite/test216c.tla index 9a970c318e1aac754b5c0f46b5e012a155ac3932..80175592a06892a00b77745635ca7c34780e210c 100644 --- a/tlatools/test-model/suite/test216c.tla +++ b/tlatools/test-model/suite/test216c.tla @@ -1,15 +1,15 @@ ------------------- MODULE test216c --------------------- -EXTENDS Naturals -VARIABLE x - -InitC == x = 0 -NextC == x'=(x+1) %6 - -SpecC == [][NextC]_x - -THEOREM ThmC == SpecC => [](x \in Nat) - -THEOREM ThmC2 == [](x \in Nat) - -THEOREM ThmC3 == 1+1 = 2 +------------------ MODULE test216c --------------------- +EXTENDS Naturals +VARIABLE x + +InitC == x = 0 +NextC == x'=(x+1) %6 + +SpecC == [][NextC]_x + +THEOREM ThmC == SpecC => [](x \in Nat) + +THEOREM ThmC2 == [](x \in Nat) + +THEOREM ThmC3 == 1+1 = 2 ====================================================== \ No newline at end of file diff --git a/tlatools/test-model/suite/test217.tla b/tlatools/test-model/suite/test217.tla index 13e13d185e992fbbd33b2887296cb58e058c05a9..f9028c3320e16e4d3b138a711e42b0929187bbe4 100644 --- a/tlatools/test-model/suite/test217.tla +++ b/tlatools/test-model/suite/test217.tla @@ -1,14 +1,14 @@ -Sany should produce two level errors when parsing this module. - ----- MODULE test217 ---- - \* 12 June 2014: Changed module name from Test217, which is now illegal -EXTENDS test217a - \* 12 June 2014: Changed from Test217a, which is now illegal -VARIABLE x - -I(z) == INSTANCE test217a WITH y <- z - \* 12 June 2014: Changed from Test217a, which is now illegal - -FooBar == I(x')!Foo -THEOREM I({x'})!Foo +Sany should produce two level errors when parsing this module. + +---- MODULE test217 ---- + \* 12 June 2014: Changed module name from Test217, which is now illegal +EXTENDS test217a + \* 12 June 2014: Changed from Test217a, which is now illegal +VARIABLE x + +I(z) == INSTANCE test217a WITH y <- z + \* 12 June 2014: Changed from Test217a, which is now illegal + +FooBar == I(x')!Foo +THEOREM I({x'})!Foo =============================== \ No newline at end of file diff --git a/tlatools/test-model/suite/test217a.tla b/tlatools/test-model/suite/test217a.tla index e72a4e15fd8711bd68a597f8046875f16e6051f8..8617c81c5013269b6071dd14549d5930a40c697c 100644 --- a/tlatools/test-model/suite/test217a.tla +++ b/tlatools/test-model/suite/test217a.tla @@ -1,5 +1,5 @@ ----- MODULE test217a ---- -VARIABLE y - -THEOREM Foo == y'=0 +---- MODULE test217a ---- +VARIABLE y + +THEOREM Foo == y'=0 ========================= \ No newline at end of file diff --git a/tlatools/test-model/suite/test218.tla b/tlatools/test-model/suite/test218.tla index 12492617d5b78cd24dc845afe630ce63f9f4398c..ab3fb749971531ec4e114cdce17c8b40c92383a3 100644 --- a/tlatools/test-model/suite/test218.tla +++ b/tlatools/test-model/suite/test218.tla @@ -1,11 +1,11 @@ -Check fix to handling of ThmOrAssumpDefNode in Tool.java -on 23 Oct 2012. - ----- MODULE test218 ---- -EXTENDS Test218a, TLC - -I(z) == INSTANCE Test218a WITH y <- z - -ASSUME PrintT(I(55)!Foo) - +Check fix to handling of ThmOrAssumpDefNode in Tool.java +on 23 Oct 2012. + +---- MODULE test218 ---- +EXTENDS Test218a, TLC + +I(z) == INSTANCE Test218a WITH y <- z + +ASSUME PrintT(I(55)!Foo) + =============================== \ No newline at end of file diff --git a/tlatools/test-model/suite/test219.tla b/tlatools/test-model/suite/test219.tla index da6d5328bdad929a233c2e29b55e261dbdf16005..2d17f4b8388b4b797c8865562b804eba5a2f82cb 100644 --- a/tlatools/test-model/suite/test219.tla +++ b/tlatools/test-model/suite/test219.tla @@ -1,227 +1,227 @@ -------------------------------- MODULE test219 ------------------------------ -\* Test of use of labels from instantiated theorems, and repeat -\* test of some instantiations - -EXTENDS TLC , Integers - -I(x) == INSTANCE test219a WITH C <- 4 -J == INSTANCE test219a WITH C <- 4 -INSTANCE test219a WITH C <- 4 - -LOCAL K(x) == INSTANCE test219a WITH C <- 4 -LOCAL L == INSTANCE test219a WITH C <- 4 - - -ASSUME J!Thm2!lab3 -ASSUME I(55)!Thm2!lab3 -ASSUME L!Thm2!lab3 -ASSUME K(55)!Thm2!lab3 -ASSUME Thm2!lab3 - - -ASSUME Op(Foo, 9) - -ASSUME Thm2!lab3 - -ASSUME Bar - -ASSUME Op(Foo, 9)!lab(1,2,3)!label2 = Op(Foo, 9)!lab(1,2,3)!:!++(9, 4) -ASSUME OOp1(SOp1, 2) = 2 -ASSUME OOp2(SOp1b!@, 2, 3) = 5 -ASSUME OOp2(SOp1c!@!c, 2, 3) = 2 * 3 -ASSUME OOp3(SOp1d!@!c, 2, 3, 4) = 2 * 3 + 4 -ASSUME Op1(2)!(3)!2!1 = 2 + 4*3 + 6 -ASSUME Op1(2)!(3)!2!Op1a(4) = 16 + 6 -ASSUME Op3(Op1!@!2!Op1a, 2, 3, 4) = 22 -ASSUME COp(1, 2)!(3)!++(4, 5) = {2,1, 3, 4, 5} -ASSUME COp(1, 2)!(3) = <<1, {99, 1, 2, 3} >> -ASSUME COp(1, 2)!(3)!1 = <<1, {99, 1, 2, 3} >> -ASSUME COp(1, 2)!(3)!1!>> = {99, 1, 2, 3} -ASSUME OOp5(COp!@!++, 1, 2, 3, 4, 5) = {2,1, 3, 4, 5} -ASSUME COp(1, 2)!lab(3)!:!++(4, 5) = {2,1, 3, 4, 5} -ASSUME Inst!Foo(1, 2, 3, 4, 5) = {2,1, 3, 4, 5} -ASSUME Inst!Bar(3)!>> = 3 -ASSUME Inst!Bar2(3)!>> = 3 -ASSUME Inst!Bar3!>> = 2 -ASSUME Inst!Bar4(1)!(2)!<< = 2 -ASSUME Inst!Bar4(1)!(2)!>> = 1 -ASSUME Inst!Bar4(1)!lab(2)!<< = 2 -ASSUME Inst!Bar4(1)!lab(2)!>> = 1 -ASSUME OOp2(Inst!Bar4!@!<<, 1, 2) = 2 -ASSUME OOp2(Inst!Bar4!@!>>, 1, 2) = 1 -ASSUME OOp2(Inst!Bar4!lab!<<, 1, 2) = 2 -ASSUME OOp2(Inst!Bar4!lab!>>, 1, 2) = 1 -ASSUME Inst!Bar5(1)!lab(2)!:!++(3, 4) = <<1, 3, 4, 2>> -ASSUME Inst!Bar5(1)!(2)!++(3, 4) = <<1, 3, 4, 2>> -ASSUME OOp4(Inst!Bar5!lab!:!++, 1, 2, 3, 4) = <<1, 3, 4, 2>> -ASSUME Inst2(COp!@!++)!Foo(1, 2, 3, 4, 5) = {2,1, 3, 4, 5} -ASSUME COp2(1,2)!lab(3)!:!++(9,10)!lab(11) = 30 -ASSUME COp2(1,2)!(3)!++(9,10)!lab(11) = 30 -ASSUME COp2(1,2)!lab(3)!:!++(9,10)!(11) = 30 -ASSUME OOp6(COp2!lab!:!++!lab, 1, 2, 3, 9, 10, 11) = 30 -ASSUME OOp6(COp2!@!++!lab, 1, 2, 3, 9, 10, 11) = 30 -ASSUME OOp6(COp2!lab!:!++!@, 1, 2, 3, 9, 10, 11) = 30 -ASSUME Def1!2 = 2 -ASSUME Def2!(14)!<< = 14 -ASSUME Def3!2!1 = 2 -ASSUME Def3!(1, 2)!<< = 1 -ASSUME Def4!<<!<<!2 = {2} -ASSUME Def5!>> = 3 -ASSUME Def5!<<[4] = 5 -ASSUME Def5!<<!1!>> = 10 -ASSUME Def6!1[3] = 4 -ASSUME Def7!1 = 3 -ASSUME Def7!2 = "a" -ASSUME Def8!2 = 2 -ASSUME Def9!2 = 2 -ASSUME Def10!2 = 2 -ASSUME Def11!3!1 = 3 - -ASSUME L!Op(Foo, 9)!lab(1,2,3)!label2 = Op(Foo, 9)!lab(1,2,3)!:!++(9, 4) -ASSUME L!OOp1(SOp1, 2) = 2 -ASSUME L!OOp2(SOp1b!@, 2, 3) = 5 -ASSUME L!OOp2(SOp1c!@!c, 2, 3) = 2 * 3 -ASSUME L!OOp3(SOp1d!@!c, 2, 3, 4) = 2 * 3 + 4 -ASSUME L!Op1(2)!(3)!2!1 = 2 + 4*3 + 6 -ASSUME L!Op1(2)!(3)!2!Op1a(4) = 16 + 6 -ASSUME L!Op3(Op1!@!2!Op1a, 2, 3, 4) = 22 -ASSUME L!COp(1, 2)!(3)!++(4, 5) = {2,1, 3, 4, 5} -ASSUME L!COp(1, 2)!(3) = <<1, {99, 1, 2, 3} >> -ASSUME L!COp(1, 2)!(3)!1 = <<1, {99, 1, 2, 3} >> -ASSUME L!COp(1, 2)!(3)!1!>> = {99, 1, 2, 3} -ASSUME L!OOp5(COp!@!++, 1, 2, 3, 4, 5) = {2,1, 3, 4, 5} -ASSUME L!COp(1, 2)!lab(3)!:!++(4, 5) = {2,1, 3, 4, 5} -ASSUME L!Inst!Foo(1, 2, 3, 4, 5) = {2,1, 3, 4, 5} -ASSUME L!Inst!Bar(3)!>> = 3 -ASSUME L!Inst!Bar2(3)!>> = 3 -ASSUME L!Inst!Bar3!>> = 2 -ASSUME L!Inst!Bar4(1)!(2)!<< = 2 -ASSUME L!Inst!Bar4(1)!(2)!>> = 1 -ASSUME L!Inst!Bar4(1)!lab(2)!<< = 2 -ASSUME L!Inst!Bar4(1)!lab(2)!>> = 1 -ASSUME L!OOp2(Inst!Bar4!@!<<, 1, 2) = 2 -ASSUME L!OOp2(Inst!Bar4!@!>>, 1, 2) = 1 -ASSUME L!OOp2(Inst!Bar4!lab!<<, 1, 2) = 2 -ASSUME L!OOp2(Inst!Bar4!lab!>>, 1, 2) = 1 -ASSUME L!Inst!Bar5(1)!lab(2)!:!++(3, 4) = <<1, 3, 4, 2>> -ASSUME L!Inst!Bar5(1)!(2)!++(3, 4) = <<1, 3, 4, 2>> -ASSUME L!OOp4(Inst!Bar5!lab!:!++, 1, 2, 3, 4) = <<1, 3, 4, 2>> -ASSUME L!Inst2(COp!@!++)!Foo(1, 2, 3, 4, 5) = {2,1, 3, 4, 5} -ASSUME L!COp2(1,2)!lab(3)!:!++(9,10)!lab(11) = 30 -ASSUME L!COp2(1,2)!(3)!++(9,10)!lab(11) = 30 -ASSUME L!COp2(1,2)!lab(3)!:!++(9,10)!(11) = 30 -ASSUME L!OOp6(COp2!lab!:!++!lab, 1, 2, 3, 9, 10, 11) = 30 -ASSUME L!OOp6(COp2!@!++!lab, 1, 2, 3, 9, 10, 11) = 30 -ASSUME L!OOp6(COp2!lab!:!++!@, 1, 2, 3, 9, 10, 11) = 30 -ASSUME L!Def1!2 = 2 -ASSUME L!Def2!(14)!<< = 14 -ASSUME L!Def3!2!1 = 2 -ASSUME L!Def3!(1, 2)!<< = 1 -ASSUME L!Def4!<<!<<!2 = {2} -ASSUME L!Def5!>> = 3 -ASSUME L!Def5!<<[4] = 5 -ASSUME L!Def5!<<!1!>> = 10 -ASSUME L!Def6!1[3] = 4 -ASSUME L!Def7!1 = 3 -ASSUME L!Def7!2 = "a" -ASSUME L!Def8!2 = 2 -ASSUME L!Def9!2 = 2 -ASSUME L!Def10!2 = 2 -ASSUME L!Def11!3!1 = 3 - -ASSUME I(55)!Op(Foo, 9)!lab(1,2,3)!label2 = Op(Foo, 9)!lab(1,2,3)!:!++(9, 4) -ASSUME I(55)!OOp1(SOp1, 2) = 2 -ASSUME I(55)!OOp2(SOp1b!@, 2, 3) = 5 -ASSUME I(55)!OOp2(SOp1c!@!c, 2, 3) = 2 * 3 -ASSUME I(55)!OOp3(SOp1d!@!c, 2, 3, 4) = 2 * 3 + 4 -ASSUME I(55)!Op1(2)!(3)!2!1 = 2 + 4*3 + 6 -ASSUME I(55)!Op1(2)!(3)!2!Op1a(4) = 16 + 6 -ASSUME I(55)!Op3(Op1!@!2!Op1a, 2, 3, 4) = 22 -ASSUME I(55)!COp(1, 2)!(3)!++(4, 5) = {2,1, 3, 4, 5} -ASSUME I(55)!COp(1, 2)!(3) = <<1, {99, 1, 2, 3} >> -ASSUME I(55)!COp(1, 2)!(3)!1 = <<1, {99, 1, 2, 3} >> -ASSUME I(55)!COp(1, 2)!(3)!1!>> = {99, 1, 2, 3} -ASSUME I(55)!OOp5(COp!@!++, 1, 2, 3, 4, 5) = {2,1, 3, 4, 5} -ASSUME I(55)!COp(1, 2)!lab(3)!:!++(4, 5) = {2,1, 3, 4, 5} -ASSUME I(55)!Inst!Foo(1, 2, 3, 4, 5) = {2,1, 3, 4, 5} -ASSUME I(55)!Inst!Bar(3)!>> = 3 -ASSUME I(55)!Inst!Bar2(3)!>> = 3 -ASSUME I(55)!Inst!Bar3!>> = 2 -ASSUME I(55)!Inst!Bar4(1)!(2)!<< = 2 -ASSUME I(55)!Inst!Bar4(1)!(2)!>> = 1 -ASSUME I(55)!Inst!Bar4(1)!lab(2)!<< = 2 -ASSUME I(55)!Inst!Bar4(1)!lab(2)!>> = 1 -ASSUME I(55)!OOp2(Inst!Bar4!@!<<, 1, 2) = 2 -ASSUME I(55)!OOp2(Inst!Bar4!@!>>, 1, 2) = 1 -ASSUME I(55)!OOp2(Inst!Bar4!lab!<<, 1, 2) = 2 -ASSUME I(55)!OOp2(Inst!Bar4!lab!>>, 1, 2) = 1 -ASSUME I(55)!Inst!Bar5(1)!lab(2)!:!++(3, 4) = <<1, 3, 4, 2>> -ASSUME I(55)!Inst!Bar5(1)!(2)!++(3, 4) = <<1, 3, 4, 2>> -ASSUME I(55)!OOp4(Inst!Bar5!lab!:!++, 1, 2, 3, 4) = <<1, 3, 4, 2>> -ASSUME I(55)!Inst2(COp!@!++)!Foo(1, 2, 3, 4, 5) = {2,1, 3, 4, 5} -ASSUME I(55)!COp2(1,2)!lab(3)!:!++(9,10)!lab(11) = 30 -ASSUME I(55)!COp2(1,2)!(3)!++(9,10)!lab(11) = 30 -ASSUME I(55)!COp2(1,2)!lab(3)!:!++(9,10)!(11) = 30 -ASSUME I(55)!OOp6(COp2!lab!:!++!lab, 1, 2, 3, 9, 10, 11) = 30 -ASSUME I(55)!OOp6(COp2!@!++!lab, 1, 2, 3, 9, 10, 11) = 30 -ASSUME I(55)!OOp6(COp2!lab!:!++!@, 1, 2, 3, 9, 10, 11) = 30 -ASSUME I(55)!Def1!2 = 2 -ASSUME I(55)!Def2!(14)!<< = 14 -ASSUME I(55)!Def3!2!1 = 2 -ASSUME I(55)!Def3!(1, 2)!<< = 1 -ASSUME I(55)!Def4!<<!<<!2 = {2} -ASSUME I(55)!Def5!>> = 3 -ASSUME I(55)!Def5!<<[4] = 5 -ASSUME I(55)!Def5!<<!1!>> = 10 -ASSUME I(55)!Def6!1[3] = 4 -ASSUME I(55)!Def7!1 = 3 -ASSUME I(55)!Def7!2 = "a" -ASSUME I(55)!Def8!2 = 2 -ASSUME I(55)!Def9!2 = 2 -ASSUME I(55)!Def10!2 = 2 -ASSUME I(55)!Def11!3!1 = 3 - -ASSUME /\ Def12!1!<< = 2 - /\ Def12!2 = 2 - /\ Def12!3 = 3 -ASSUME /\ Def13!(42)!1!<<!<< = 42 - /\ Def13!(42)!1!>> = 1 - /\ Def13!(42)!2!>> = 2 - /\ Def13!(42)!3!>> = 3 - -ASSUME /\ Def14!(2)!<< = 2 - /\ Def14!1!1 = 1 - -ASSUME /\ Def15!(2,3)!<<!<< = 2 - /\ Def15!(2,3)!>>!<< = 3 - /\ Def15!2!<< = 2 - -ASSUME /\ Def16!(2,3,4)!1!1 = 2 - /\ Def16!(2,3,4)!2!1 = 3 - /\ Def16!2!1!<< = 2 - -ASSUME /\ Def17!(2,3,4)!1!1 = 2 - /\ Def17!(2,3,4)!2!1 = 3 - -ASSUME Def18!(2)!<< = 2 - -ASSUME /\ Def19!(2)!<< = 2 - /\ Def19!1!1 = 42 - -ASSUME /\ Def20!1 = 12 - /\ Def20!>> = 23 - -ASSUME /\ Def21!1 = 12 - /\ Def21!>> = 23 - -ASSUME /\ Def22!1 = 12 - /\ Def22!>> = 23 - -ASSUME /\ Def23!(2,3,4)!1!1 = 2 - /\ Def23!(2,3,4)!2!1 = 3 - - -============================================================================= - -last modified on Thu 1 November 2012 at 10:11:43 PST by lamport +------------------------------- MODULE test219 ------------------------------ +\* Test of use of labels from instantiated theorems, and repeat +\* test of some instantiations + +EXTENDS TLC , Integers + +I(x) == INSTANCE test219a WITH C <- 4 +J == INSTANCE test219a WITH C <- 4 +INSTANCE test219a WITH C <- 4 + +LOCAL K(x) == INSTANCE test219a WITH C <- 4 +LOCAL L == INSTANCE test219a WITH C <- 4 + + +ASSUME J!Thm2!lab3 +ASSUME I(55)!Thm2!lab3 +ASSUME L!Thm2!lab3 +ASSUME K(55)!Thm2!lab3 +ASSUME Thm2!lab3 + + +ASSUME Op(Foo, 9) + +ASSUME Thm2!lab3 + +ASSUME Bar + +ASSUME Op(Foo, 9)!lab(1,2,3)!label2 = Op(Foo, 9)!lab(1,2,3)!:!++(9, 4) +ASSUME OOp1(SOp1, 2) = 2 +ASSUME OOp2(SOp1b!@, 2, 3) = 5 +ASSUME OOp2(SOp1c!@!c, 2, 3) = 2 * 3 +ASSUME OOp3(SOp1d!@!c, 2, 3, 4) = 2 * 3 + 4 +ASSUME Op1(2)!(3)!2!1 = 2 + 4*3 + 6 +ASSUME Op1(2)!(3)!2!Op1a(4) = 16 + 6 +ASSUME Op3(Op1!@!2!Op1a, 2, 3, 4) = 22 +ASSUME COp(1, 2)!(3)!++(4, 5) = {2,1, 3, 4, 5} +ASSUME COp(1, 2)!(3) = <<1, {99, 1, 2, 3} >> +ASSUME COp(1, 2)!(3)!1 = <<1, {99, 1, 2, 3} >> +ASSUME COp(1, 2)!(3)!1!>> = {99, 1, 2, 3} +ASSUME OOp5(COp!@!++, 1, 2, 3, 4, 5) = {2,1, 3, 4, 5} +ASSUME COp(1, 2)!lab(3)!:!++(4, 5) = {2,1, 3, 4, 5} +ASSUME Inst!Foo(1, 2, 3, 4, 5) = {2,1, 3, 4, 5} +ASSUME Inst!Bar(3)!>> = 3 +ASSUME Inst!Bar2(3)!>> = 3 +ASSUME Inst!Bar3!>> = 2 +ASSUME Inst!Bar4(1)!(2)!<< = 2 +ASSUME Inst!Bar4(1)!(2)!>> = 1 +ASSUME Inst!Bar4(1)!lab(2)!<< = 2 +ASSUME Inst!Bar4(1)!lab(2)!>> = 1 +ASSUME OOp2(Inst!Bar4!@!<<, 1, 2) = 2 +ASSUME OOp2(Inst!Bar4!@!>>, 1, 2) = 1 +ASSUME OOp2(Inst!Bar4!lab!<<, 1, 2) = 2 +ASSUME OOp2(Inst!Bar4!lab!>>, 1, 2) = 1 +ASSUME Inst!Bar5(1)!lab(2)!:!++(3, 4) = <<1, 3, 4, 2>> +ASSUME Inst!Bar5(1)!(2)!++(3, 4) = <<1, 3, 4, 2>> +ASSUME OOp4(Inst!Bar5!lab!:!++, 1, 2, 3, 4) = <<1, 3, 4, 2>> +ASSUME Inst2(COp!@!++)!Foo(1, 2, 3, 4, 5) = {2,1, 3, 4, 5} +ASSUME COp2(1,2)!lab(3)!:!++(9,10)!lab(11) = 30 +ASSUME COp2(1,2)!(3)!++(9,10)!lab(11) = 30 +ASSUME COp2(1,2)!lab(3)!:!++(9,10)!(11) = 30 +ASSUME OOp6(COp2!lab!:!++!lab, 1, 2, 3, 9, 10, 11) = 30 +ASSUME OOp6(COp2!@!++!lab, 1, 2, 3, 9, 10, 11) = 30 +ASSUME OOp6(COp2!lab!:!++!@, 1, 2, 3, 9, 10, 11) = 30 +ASSUME Def1!2 = 2 +ASSUME Def2!(14)!<< = 14 +ASSUME Def3!2!1 = 2 +ASSUME Def3!(1, 2)!<< = 1 +ASSUME Def4!<<!<<!2 = {2} +ASSUME Def5!>> = 3 +ASSUME Def5!<<[4] = 5 +ASSUME Def5!<<!1!>> = 10 +ASSUME Def6!1[3] = 4 +ASSUME Def7!1 = 3 +ASSUME Def7!2 = "a" +ASSUME Def8!2 = 2 +ASSUME Def9!2 = 2 +ASSUME Def10!2 = 2 +ASSUME Def11!3!1 = 3 + +ASSUME L!Op(Foo, 9)!lab(1,2,3)!label2 = Op(Foo, 9)!lab(1,2,3)!:!++(9, 4) +ASSUME L!OOp1(SOp1, 2) = 2 +ASSUME L!OOp2(SOp1b!@, 2, 3) = 5 +ASSUME L!OOp2(SOp1c!@!c, 2, 3) = 2 * 3 +ASSUME L!OOp3(SOp1d!@!c, 2, 3, 4) = 2 * 3 + 4 +ASSUME L!Op1(2)!(3)!2!1 = 2 + 4*3 + 6 +ASSUME L!Op1(2)!(3)!2!Op1a(4) = 16 + 6 +ASSUME L!Op3(Op1!@!2!Op1a, 2, 3, 4) = 22 +ASSUME L!COp(1, 2)!(3)!++(4, 5) = {2,1, 3, 4, 5} +ASSUME L!COp(1, 2)!(3) = <<1, {99, 1, 2, 3} >> +ASSUME L!COp(1, 2)!(3)!1 = <<1, {99, 1, 2, 3} >> +ASSUME L!COp(1, 2)!(3)!1!>> = {99, 1, 2, 3} +ASSUME L!OOp5(COp!@!++, 1, 2, 3, 4, 5) = {2,1, 3, 4, 5} +ASSUME L!COp(1, 2)!lab(3)!:!++(4, 5) = {2,1, 3, 4, 5} +ASSUME L!Inst!Foo(1, 2, 3, 4, 5) = {2,1, 3, 4, 5} +ASSUME L!Inst!Bar(3)!>> = 3 +ASSUME L!Inst!Bar2(3)!>> = 3 +ASSUME L!Inst!Bar3!>> = 2 +ASSUME L!Inst!Bar4(1)!(2)!<< = 2 +ASSUME L!Inst!Bar4(1)!(2)!>> = 1 +ASSUME L!Inst!Bar4(1)!lab(2)!<< = 2 +ASSUME L!Inst!Bar4(1)!lab(2)!>> = 1 +ASSUME L!OOp2(Inst!Bar4!@!<<, 1, 2) = 2 +ASSUME L!OOp2(Inst!Bar4!@!>>, 1, 2) = 1 +ASSUME L!OOp2(Inst!Bar4!lab!<<, 1, 2) = 2 +ASSUME L!OOp2(Inst!Bar4!lab!>>, 1, 2) = 1 +ASSUME L!Inst!Bar5(1)!lab(2)!:!++(3, 4) = <<1, 3, 4, 2>> +ASSUME L!Inst!Bar5(1)!(2)!++(3, 4) = <<1, 3, 4, 2>> +ASSUME L!OOp4(Inst!Bar5!lab!:!++, 1, 2, 3, 4) = <<1, 3, 4, 2>> +ASSUME L!Inst2(COp!@!++)!Foo(1, 2, 3, 4, 5) = {2,1, 3, 4, 5} +ASSUME L!COp2(1,2)!lab(3)!:!++(9,10)!lab(11) = 30 +ASSUME L!COp2(1,2)!(3)!++(9,10)!lab(11) = 30 +ASSUME L!COp2(1,2)!lab(3)!:!++(9,10)!(11) = 30 +ASSUME L!OOp6(COp2!lab!:!++!lab, 1, 2, 3, 9, 10, 11) = 30 +ASSUME L!OOp6(COp2!@!++!lab, 1, 2, 3, 9, 10, 11) = 30 +ASSUME L!OOp6(COp2!lab!:!++!@, 1, 2, 3, 9, 10, 11) = 30 +ASSUME L!Def1!2 = 2 +ASSUME L!Def2!(14)!<< = 14 +ASSUME L!Def3!2!1 = 2 +ASSUME L!Def3!(1, 2)!<< = 1 +ASSUME L!Def4!<<!<<!2 = {2} +ASSUME L!Def5!>> = 3 +ASSUME L!Def5!<<[4] = 5 +ASSUME L!Def5!<<!1!>> = 10 +ASSUME L!Def6!1[3] = 4 +ASSUME L!Def7!1 = 3 +ASSUME L!Def7!2 = "a" +ASSUME L!Def8!2 = 2 +ASSUME L!Def9!2 = 2 +ASSUME L!Def10!2 = 2 +ASSUME L!Def11!3!1 = 3 + +ASSUME I(55)!Op(Foo, 9)!lab(1,2,3)!label2 = Op(Foo, 9)!lab(1,2,3)!:!++(9, 4) +ASSUME I(55)!OOp1(SOp1, 2) = 2 +ASSUME I(55)!OOp2(SOp1b!@, 2, 3) = 5 +ASSUME I(55)!OOp2(SOp1c!@!c, 2, 3) = 2 * 3 +ASSUME I(55)!OOp3(SOp1d!@!c, 2, 3, 4) = 2 * 3 + 4 +ASSUME I(55)!Op1(2)!(3)!2!1 = 2 + 4*3 + 6 +ASSUME I(55)!Op1(2)!(3)!2!Op1a(4) = 16 + 6 +ASSUME I(55)!Op3(Op1!@!2!Op1a, 2, 3, 4) = 22 +ASSUME I(55)!COp(1, 2)!(3)!++(4, 5) = {2,1, 3, 4, 5} +ASSUME I(55)!COp(1, 2)!(3) = <<1, {99, 1, 2, 3} >> +ASSUME I(55)!COp(1, 2)!(3)!1 = <<1, {99, 1, 2, 3} >> +ASSUME I(55)!COp(1, 2)!(3)!1!>> = {99, 1, 2, 3} +ASSUME I(55)!OOp5(COp!@!++, 1, 2, 3, 4, 5) = {2,1, 3, 4, 5} +ASSUME I(55)!COp(1, 2)!lab(3)!:!++(4, 5) = {2,1, 3, 4, 5} +ASSUME I(55)!Inst!Foo(1, 2, 3, 4, 5) = {2,1, 3, 4, 5} +ASSUME I(55)!Inst!Bar(3)!>> = 3 +ASSUME I(55)!Inst!Bar2(3)!>> = 3 +ASSUME I(55)!Inst!Bar3!>> = 2 +ASSUME I(55)!Inst!Bar4(1)!(2)!<< = 2 +ASSUME I(55)!Inst!Bar4(1)!(2)!>> = 1 +ASSUME I(55)!Inst!Bar4(1)!lab(2)!<< = 2 +ASSUME I(55)!Inst!Bar4(1)!lab(2)!>> = 1 +ASSUME I(55)!OOp2(Inst!Bar4!@!<<, 1, 2) = 2 +ASSUME I(55)!OOp2(Inst!Bar4!@!>>, 1, 2) = 1 +ASSUME I(55)!OOp2(Inst!Bar4!lab!<<, 1, 2) = 2 +ASSUME I(55)!OOp2(Inst!Bar4!lab!>>, 1, 2) = 1 +ASSUME I(55)!Inst!Bar5(1)!lab(2)!:!++(3, 4) = <<1, 3, 4, 2>> +ASSUME I(55)!Inst!Bar5(1)!(2)!++(3, 4) = <<1, 3, 4, 2>> +ASSUME I(55)!OOp4(Inst!Bar5!lab!:!++, 1, 2, 3, 4) = <<1, 3, 4, 2>> +ASSUME I(55)!Inst2(COp!@!++)!Foo(1, 2, 3, 4, 5) = {2,1, 3, 4, 5} +ASSUME I(55)!COp2(1,2)!lab(3)!:!++(9,10)!lab(11) = 30 +ASSUME I(55)!COp2(1,2)!(3)!++(9,10)!lab(11) = 30 +ASSUME I(55)!COp2(1,2)!lab(3)!:!++(9,10)!(11) = 30 +ASSUME I(55)!OOp6(COp2!lab!:!++!lab, 1, 2, 3, 9, 10, 11) = 30 +ASSUME I(55)!OOp6(COp2!@!++!lab, 1, 2, 3, 9, 10, 11) = 30 +ASSUME I(55)!OOp6(COp2!lab!:!++!@, 1, 2, 3, 9, 10, 11) = 30 +ASSUME I(55)!Def1!2 = 2 +ASSUME I(55)!Def2!(14)!<< = 14 +ASSUME I(55)!Def3!2!1 = 2 +ASSUME I(55)!Def3!(1, 2)!<< = 1 +ASSUME I(55)!Def4!<<!<<!2 = {2} +ASSUME I(55)!Def5!>> = 3 +ASSUME I(55)!Def5!<<[4] = 5 +ASSUME I(55)!Def5!<<!1!>> = 10 +ASSUME I(55)!Def6!1[3] = 4 +ASSUME I(55)!Def7!1 = 3 +ASSUME I(55)!Def7!2 = "a" +ASSUME I(55)!Def8!2 = 2 +ASSUME I(55)!Def9!2 = 2 +ASSUME I(55)!Def10!2 = 2 +ASSUME I(55)!Def11!3!1 = 3 + +ASSUME /\ Def12!1!<< = 2 + /\ Def12!2 = 2 + /\ Def12!3 = 3 +ASSUME /\ Def13!(42)!1!<<!<< = 42 + /\ Def13!(42)!1!>> = 1 + /\ Def13!(42)!2!>> = 2 + /\ Def13!(42)!3!>> = 3 + +ASSUME /\ Def14!(2)!<< = 2 + /\ Def14!1!1 = 1 + +ASSUME /\ Def15!(2,3)!<<!<< = 2 + /\ Def15!(2,3)!>>!<< = 3 + /\ Def15!2!<< = 2 + +ASSUME /\ Def16!(2,3,4)!1!1 = 2 + /\ Def16!(2,3,4)!2!1 = 3 + /\ Def16!2!1!<< = 2 + +ASSUME /\ Def17!(2,3,4)!1!1 = 2 + /\ Def17!(2,3,4)!2!1 = 3 + +ASSUME Def18!(2)!<< = 2 + +ASSUME /\ Def19!(2)!<< = 2 + /\ Def19!1!1 = 42 + +ASSUME /\ Def20!1 = 12 + /\ Def20!>> = 23 + +ASSUME /\ Def21!1 = 12 + /\ Def21!>> = 23 + +ASSUME /\ Def22!1 = 12 + /\ Def22!>> = 23 + +ASSUME /\ Def23!(2,3,4)!1!1 = 2 + /\ Def23!(2,3,4)!2!1 = 3 + + +============================================================================= + +last modified on Thu 1 November 2012 at 10:11:43 PST by lamport ============================================================================== \ No newline at end of file diff --git a/tlatools/test-model/suite/test219a.tla b/tlatools/test-model/suite/test219a.tla index a0013107280618a02f89df7776cfb92aeffac8ba..efbdb448b87ea70fac806c8b0329ad875d804370 100644 --- a/tlatools/test-model/suite/test219a.tla +++ b/tlatools/test-model/suite/test219a.tla @@ -1,239 +1,239 @@ -------------------------------- MODULE test219a ------------------------------ -\* Test of labels and their use in subexpression selectors. - -EXTENDS TLC, Integers - -CONSTANT C -\* C == 4 - -Op(Arg(_), p) == - \A x \in {1,2}, <<y, z>> \in {<<3, 4>>} : - lab(x,y,z) :: LET a ++ b == - Arg(a) + b + x + 2*y + 3*z - IN (Arg(1) + Arg(p) + C + - 2*x + 4*y + 6*z) = - 1 ++ ( label2 :: p ++ C) -\* IN /\label2:: PrintT("FOO") -\* /\ PrintT(Arg(1)) -\* /\ PrintT("FOO2") -\* /\ PrintT(<<p, Arg(p)>>) -\* /\ PrintT("FOO3") -\* /\ PrintT(<<p, C>>) -\* /\ PrintT("FOO3a") -\* /\ PrintT(1++2) -\* /\ PrintT(p++C) -\* /\ PrintT("FOO4") -\* /\ PrintT(<<x, y, z>>) - -Foo(u) == 2*u - -\* ASSUME Foo(5) = Foo(5)!: - -THEOREM Thm == ASSUME FALSE - PROVE lab:: C > 0 - -THEOREM Thm2 == lab3 :: TRUE - - -\* ASSUME Foo(25) = 50 - -Bar == Op(Foo, 9)!lab(1,2,3) - -\* ASSUME Op(Foo, 9) -\* -\* ASSUME Thm2!lab3 -\* -\* ASSUME Bar -\* -\* ASSUME Op(Foo, 9)!lab(1,2,3)!label2 = Op(Foo, 9)!lab(1,2,3)!:!++(9, 4) - -Op3(A(_,_,_), a1, a2, a3) == A(a1, a2, a3) - -Op1(a) == \A x \in {} : lab(x) :: IF TRUE - THEN LET Op1a(c) == 4 * c + a*x - IN a + Op1a(x) - ELSE 1 -SOp1(a) == a -OOp1(A(_), a) == A(a) -\* ASSUME OOp1(SOp1, 2) = 2 - -SOp1a(a) == {x \in {1,2} : a = x} -OOp2(A(_,_), a, b) == A(a, b) -\* ASSUME OOp2(SOp1a!@, 2, 2) = TRUE - -SOp1b(a) == {x + a : x \in {1,2}} -\* ASSUME OOp2(SOp1b!@, 2, 3) = 5 - -SOp1c(a) == {(LET c == a * x IN x + a) : x \in {1,2}} -\* ASSUME OOp2(SOp1c!@!c, 2, 3) = 2 * 3 - -SOp1d(a) == {(LET c(y) == (a * x) + y IN x + a) : x \in {1,2}} -OOp3(A(_,_,_), a, b, c) == A(a, b, c) -\* ASSUME OOp3(SOp1d!@!c, 2, 3, 4) = 2 * 3 + 4 - -OOp4(A(_,_,_,_), a, b, c, d) == A(a, b, c, d) - - -\* Foo1 == Op1(2)!(3)!2!1 -\* ASSUME Op1(2)!(3)!2!1 = 2 + 4*3 + 6 -\* ASSUME Op1(2)!(3)!2!Op1a(4) = 16 + 6 -\* ASSUME Op3(Op1!@!2!Op1a, 2, 3, 4) = 22 - -COp(q, p) == - CHOOSE x : lab(x) :: LET a ++ b == {a, b, q, p, x} - IN <<q, 99 ++ p >> - - -\* ASSUME COp(1, 2)!(3)!++(4, 5) = {2,1, 3, 4, 5} - -\* ASSUME COp(1, 2)!(3) = <<1, {99, 1, 2, 3} >> -\* ASSUME COp(1, 2)!(3)!1 = <<1, {99, 1, 2, 3} >> -\* ASSUME COp(1, 2)!(3)!1!>> = {99, 1, 2, 3} - -OOp5(A(_, _, _, _, _), a1, a2, a3, a4, a5) == A(a1, a2, a3, a4, a5) - -\* ASSUME OOp5(COp!@!++, 1, 2, 3, 4, 5) = {2,1, 3, 4, 5} -\* ASSUME COp(1, 2)!lab(3)!:!++(4, 5) = {2,1, 3, 4, 5} - -Inst == INSTANCE test206a WITH A5 <- COp!@!++ -\* ASSUME Inst!Foo(1, 2, 3, 4, 5) = {2,1, 3, 4, 5} -\* ASSUME Inst!Bar(3)!>> = 3 -\* ASSUME Inst!Bar2(3)!>> = 3 -\* ASSUME Inst!Bar3!>> = 2 -\* ASSUME Inst!Bar4(1)!(2)!<< = 2 -\* ASSUME Inst!Bar4(1)!(2)!>> = 1 -\* ASSUME Inst!Bar4(1)!lab(2)!<< = 2 -\* ASSUME Inst!Bar4(1)!lab(2)!>> = 1 -\* ASSUME OOp2(Inst!Bar4!@!<<, 1, 2) = 2 -\* ASSUME OOp2(Inst!Bar4!@!>>, 1, 2) = 1 -\* ASSUME OOp2(Inst!Bar4!lab!<<, 1, 2) = 2 -\* ASSUME OOp2(Inst!Bar4!lab!>>, 1, 2) = 1 -\* ASSUME Inst!Bar5(1)!lab(2)!:!++(3, 4) = <<1, 3, 4, 2>> -\* ASSUME Inst!Bar5(1)!(2)!++(3, 4) = <<1, 3, 4, 2>> -\* ASSUME OOp4(Inst!Bar5!lab!:!++, 1, 2, 3, 4) = <<1, 3, 4, 2>> - -Inst2(A5(_, _, _, _, _)) == INSTANCE test206a -\* ASSUME Inst2(COp!@!++)!Foo(1, 2, 3, 4, 5) = {2,1, 3, 4, 5} - - -COp2(q, p) == - CHOOSE x : lab(x) :: LET a ++ b == {lab(y):: y + a + b : y \in {1}} - IN <<q, 99 ++ p >> - -\* ASSUME COp2(1,2)!lab(3)!:!++(9,10)!lab(11) = 30 -\* ASSUME COp2(1,2)!(3)!++(9,10)!lab(11) = 30 -\* ASSUME COp2(1,2)!lab(3)!:!++(9,10)!(11) = 30 -OOp6(A(_, _, _, _, _, _), a1, a2, a3, a4, a5, a6) == A(a1, a2, a3, a4, a5, a6) -\* ASSUME OOp6(COp2!lab!:!++!lab, 1, 2, 3, 9, 10, 11) = 30 -\* ASSUME OOp6(COp2!@!++!lab, 1, 2, 3, 9, 10, 11) = 30 -\* ASSUME OOp6(COp2!lab!:!++!@, 1, 2, 3, 9, 10, 11) = 30 - -\* Let's test all the different kinds of operators - -Def1 == {1, 2, 3, 4} -\* ASSUME Def1!2 = 2 - -Def2 == {x \in {1, 2, 3} : x > 17} -\* ASSUME Def2!1 = {1, 2, 3} -\* ASSUME Def2!(14)!<< = 14 - -Def3 == {<<x, y>> : x \in {1}, y \in {2}} -\* ASSUME Def3!2!1 = 2 -\* ASSUME Def3!(1, 2)!<< = 1 - -Def4 == SUBSET UNION {{1}, {2}} -\* ASSUME Def4!<<!<<!2 = {2} - -Def5 == [i \in 1..10 |-> i+1][3] -\* ASSUME Def5!>> = 3 -\* ASSUME Def5!<<[4] = 5 -\* ASSUME Def5!<<!1!>> = 10 - -Def6 == [[i \in 1..10 |-> i+1] EXCEPT ![2] = 1, ![3] = 2] -\* ASSUME Def6!1[3] = 4 -\* The following two subexpression expressions are now -\* considered to be illegal because they could contain -\* a "@". -\* ASSUME Def6!2=1 -\* ASSUME Def6!3=2 - -Def7 == 3.a -\* ASSUME Def7!1 = 3 -\* ASSUME Def7!2 = "a" - -Def8 == [a |-> 1, b |-> 2] -\* ASSUME Def8!2 = 2 - -Def9 == [a : 1, b : 2] -\* ASSUME Def9!2 = 2 - -Def10 == <<1, 2, 3>> -\* ASSUME Def10!2 = 2 - -Def11 == {1} \X {2} \X {3} -\* ASSUME Def11!3!1 = 3 - -Def12 == IF 2=3 THEN 2 ELSE 3 -\* ASSUME /\ Def12!1!<< = 2 -\* /\ Def12!2 = 2 -\* /\ Def12!3 = 3 - -Def13 == \A x : CASE x=1 -> 1 - [] x=2 -> 2 - [] OTHER -> 3 -\* ASSUME /\ Def13!(42)!1!<<!<< = 42 -\* /\ Def13!(42)!1!>> = 1 -\* /\ Def13!(42)!2!>> = 2 -\* /\ Def13!(42)!3!>> = 3 - -Def14 == \A x \in {1} : x = 1 -\* ASSUME /\ Def14!(2)!<< = 2 -\* /\ Def14!1!1 = 1 - -Def15 == \A x \in {1}, y \in {2} : (x = 1) /\ (y = 2) -\* ASSUME /\ Def15!(2,3)!<<!<< = 2 -\* /\ Def15!(2,3)!>>!<< = 3 -\* /\ Def15!2!<< = 2 - -Def16 == \E x \in {1}, <<y, z>> \in {<<2,3>>} : /\ ((x = 1)) - /\ y = 2 - /\ (z=3) -\* ASSUME /\ Def16!(2,3,4)!1!1 = 2 -\* /\ Def16!(2,3,4)!2!1 = 3 -\* /\ Def16!2!1!<< = 2 - -Def17 == \E x , y, z : /\ ((x = 1)) - /\ y = 2 - /\ (z=3) -\* ASSUME /\ Def17!(2,3,4)!1!1 = 2 -\* /\ Def17!(2,3,4)!2!1 = 3 - -Def18 == CHOOSE x : (x=1) -\* ASSUME Def18!(2)!<< = 2 - -Def19 == CHOOSE x \in {42}: (x=1) -\* ASSUME /\ Def19!(2)!<< = 2 -\* /\ Def19!1!1 = 42 - -Def20 == [12]_(23) -\* ASSUME /\ Def20!1 = 12 -\* /\ Def20!>> = 23 - -Def21 == <<12>>_(23) -\* ASSUME /\ Def21!1 = 12 -\* /\ Def21!>> = 23 - -Def22 == WF_(12)(23) -\* ASSUME /\ Def22!1 = 12 -\* /\ Def22!>> = 23 - -Def23 == \EE x , y, z : /\ ((x = 1)) - /\ y = 2 - /\ (z=3) -\* ASSUME /\ Def23!(2,3,4)!1!1 = 2 -\* /\ Def23!(2,3,4)!2!1 = 3 - - -============================================================================= - +------------------------------- MODULE test219a ------------------------------ +\* Test of labels and their use in subexpression selectors. + +EXTENDS TLC, Integers + +CONSTANT C +\* C == 4 + +Op(Arg(_), p) == + \A x \in {1,2}, <<y, z>> \in {<<3, 4>>} : + lab(x,y,z) :: LET a ++ b == + Arg(a) + b + x + 2*y + 3*z + IN (Arg(1) + Arg(p) + C + + 2*x + 4*y + 6*z) = + 1 ++ ( label2 :: p ++ C) +\* IN /\label2:: PrintT("FOO") +\* /\ PrintT(Arg(1)) +\* /\ PrintT("FOO2") +\* /\ PrintT(<<p, Arg(p)>>) +\* /\ PrintT("FOO3") +\* /\ PrintT(<<p, C>>) +\* /\ PrintT("FOO3a") +\* /\ PrintT(1++2) +\* /\ PrintT(p++C) +\* /\ PrintT("FOO4") +\* /\ PrintT(<<x, y, z>>) + +Foo(u) == 2*u + +\* ASSUME Foo(5) = Foo(5)!: + +THEOREM Thm == ASSUME FALSE + PROVE lab:: C > 0 + +THEOREM Thm2 == lab3 :: TRUE + + +\* ASSUME Foo(25) = 50 + +Bar == Op(Foo, 9)!lab(1,2,3) + +\* ASSUME Op(Foo, 9) +\* +\* ASSUME Thm2!lab3 +\* +\* ASSUME Bar +\* +\* ASSUME Op(Foo, 9)!lab(1,2,3)!label2 = Op(Foo, 9)!lab(1,2,3)!:!++(9, 4) + +Op3(A(_,_,_), a1, a2, a3) == A(a1, a2, a3) + +Op1(a) == \A x \in {} : lab(x) :: IF TRUE + THEN LET Op1a(c) == 4 * c + a*x + IN a + Op1a(x) + ELSE 1 +SOp1(a) == a +OOp1(A(_), a) == A(a) +\* ASSUME OOp1(SOp1, 2) = 2 + +SOp1a(a) == {x \in {1,2} : a = x} +OOp2(A(_,_), a, b) == A(a, b) +\* ASSUME OOp2(SOp1a!@, 2, 2) = TRUE + +SOp1b(a) == {x + a : x \in {1,2}} +\* ASSUME OOp2(SOp1b!@, 2, 3) = 5 + +SOp1c(a) == {(LET c == a * x IN x + a) : x \in {1,2}} +\* ASSUME OOp2(SOp1c!@!c, 2, 3) = 2 * 3 + +SOp1d(a) == {(LET c(y) == (a * x) + y IN x + a) : x \in {1,2}} +OOp3(A(_,_,_), a, b, c) == A(a, b, c) +\* ASSUME OOp3(SOp1d!@!c, 2, 3, 4) = 2 * 3 + 4 + +OOp4(A(_,_,_,_), a, b, c, d) == A(a, b, c, d) + + +\* Foo1 == Op1(2)!(3)!2!1 +\* ASSUME Op1(2)!(3)!2!1 = 2 + 4*3 + 6 +\* ASSUME Op1(2)!(3)!2!Op1a(4) = 16 + 6 +\* ASSUME Op3(Op1!@!2!Op1a, 2, 3, 4) = 22 + +COp(q, p) == + CHOOSE x : lab(x) :: LET a ++ b == {a, b, q, p, x} + IN <<q, 99 ++ p >> + + +\* ASSUME COp(1, 2)!(3)!++(4, 5) = {2,1, 3, 4, 5} + +\* ASSUME COp(1, 2)!(3) = <<1, {99, 1, 2, 3} >> +\* ASSUME COp(1, 2)!(3)!1 = <<1, {99, 1, 2, 3} >> +\* ASSUME COp(1, 2)!(3)!1!>> = {99, 1, 2, 3} + +OOp5(A(_, _, _, _, _), a1, a2, a3, a4, a5) == A(a1, a2, a3, a4, a5) + +\* ASSUME OOp5(COp!@!++, 1, 2, 3, 4, 5) = {2,1, 3, 4, 5} +\* ASSUME COp(1, 2)!lab(3)!:!++(4, 5) = {2,1, 3, 4, 5} + +Inst == INSTANCE test206a WITH A5 <- COp!@!++ +\* ASSUME Inst!Foo(1, 2, 3, 4, 5) = {2,1, 3, 4, 5} +\* ASSUME Inst!Bar(3)!>> = 3 +\* ASSUME Inst!Bar2(3)!>> = 3 +\* ASSUME Inst!Bar3!>> = 2 +\* ASSUME Inst!Bar4(1)!(2)!<< = 2 +\* ASSUME Inst!Bar4(1)!(2)!>> = 1 +\* ASSUME Inst!Bar4(1)!lab(2)!<< = 2 +\* ASSUME Inst!Bar4(1)!lab(2)!>> = 1 +\* ASSUME OOp2(Inst!Bar4!@!<<, 1, 2) = 2 +\* ASSUME OOp2(Inst!Bar4!@!>>, 1, 2) = 1 +\* ASSUME OOp2(Inst!Bar4!lab!<<, 1, 2) = 2 +\* ASSUME OOp2(Inst!Bar4!lab!>>, 1, 2) = 1 +\* ASSUME Inst!Bar5(1)!lab(2)!:!++(3, 4) = <<1, 3, 4, 2>> +\* ASSUME Inst!Bar5(1)!(2)!++(3, 4) = <<1, 3, 4, 2>> +\* ASSUME OOp4(Inst!Bar5!lab!:!++, 1, 2, 3, 4) = <<1, 3, 4, 2>> + +Inst2(A5(_, _, _, _, _)) == INSTANCE test206a +\* ASSUME Inst2(COp!@!++)!Foo(1, 2, 3, 4, 5) = {2,1, 3, 4, 5} + + +COp2(q, p) == + CHOOSE x : lab(x) :: LET a ++ b == {lab(y):: y + a + b : y \in {1}} + IN <<q, 99 ++ p >> + +\* ASSUME COp2(1,2)!lab(3)!:!++(9,10)!lab(11) = 30 +\* ASSUME COp2(1,2)!(3)!++(9,10)!lab(11) = 30 +\* ASSUME COp2(1,2)!lab(3)!:!++(9,10)!(11) = 30 +OOp6(A(_, _, _, _, _, _), a1, a2, a3, a4, a5, a6) == A(a1, a2, a3, a4, a5, a6) +\* ASSUME OOp6(COp2!lab!:!++!lab, 1, 2, 3, 9, 10, 11) = 30 +\* ASSUME OOp6(COp2!@!++!lab, 1, 2, 3, 9, 10, 11) = 30 +\* ASSUME OOp6(COp2!lab!:!++!@, 1, 2, 3, 9, 10, 11) = 30 + +\* Let's test all the different kinds of operators + +Def1 == {1, 2, 3, 4} +\* ASSUME Def1!2 = 2 + +Def2 == {x \in {1, 2, 3} : x > 17} +\* ASSUME Def2!1 = {1, 2, 3} +\* ASSUME Def2!(14)!<< = 14 + +Def3 == {<<x, y>> : x \in {1}, y \in {2}} +\* ASSUME Def3!2!1 = 2 +\* ASSUME Def3!(1, 2)!<< = 1 + +Def4 == SUBSET UNION {{1}, {2}} +\* ASSUME Def4!<<!<<!2 = {2} + +Def5 == [i \in 1..10 |-> i+1][3] +\* ASSUME Def5!>> = 3 +\* ASSUME Def5!<<[4] = 5 +\* ASSUME Def5!<<!1!>> = 10 + +Def6 == [[i \in 1..10 |-> i+1] EXCEPT ![2] = 1, ![3] = 2] +\* ASSUME Def6!1[3] = 4 +\* The following two subexpression expressions are now +\* considered to be illegal because they could contain +\* a "@". +\* ASSUME Def6!2=1 +\* ASSUME Def6!3=2 + +Def7 == 3.a +\* ASSUME Def7!1 = 3 +\* ASSUME Def7!2 = "a" + +Def8 == [a |-> 1, b |-> 2] +\* ASSUME Def8!2 = 2 + +Def9 == [a : 1, b : 2] +\* ASSUME Def9!2 = 2 + +Def10 == <<1, 2, 3>> +\* ASSUME Def10!2 = 2 + +Def11 == {1} \X {2} \X {3} +\* ASSUME Def11!3!1 = 3 + +Def12 == IF 2=3 THEN 2 ELSE 3 +\* ASSUME /\ Def12!1!<< = 2 +\* /\ Def12!2 = 2 +\* /\ Def12!3 = 3 + +Def13 == \A x : CASE x=1 -> 1 + [] x=2 -> 2 + [] OTHER -> 3 +\* ASSUME /\ Def13!(42)!1!<<!<< = 42 +\* /\ Def13!(42)!1!>> = 1 +\* /\ Def13!(42)!2!>> = 2 +\* /\ Def13!(42)!3!>> = 3 + +Def14 == \A x \in {1} : x = 1 +\* ASSUME /\ Def14!(2)!<< = 2 +\* /\ Def14!1!1 = 1 + +Def15 == \A x \in {1}, y \in {2} : (x = 1) /\ (y = 2) +\* ASSUME /\ Def15!(2,3)!<<!<< = 2 +\* /\ Def15!(2,3)!>>!<< = 3 +\* /\ Def15!2!<< = 2 + +Def16 == \E x \in {1}, <<y, z>> \in {<<2,3>>} : /\ ((x = 1)) + /\ y = 2 + /\ (z=3) +\* ASSUME /\ Def16!(2,3,4)!1!1 = 2 +\* /\ Def16!(2,3,4)!2!1 = 3 +\* /\ Def16!2!1!<< = 2 + +Def17 == \E x , y, z : /\ ((x = 1)) + /\ y = 2 + /\ (z=3) +\* ASSUME /\ Def17!(2,3,4)!1!1 = 2 +\* /\ Def17!(2,3,4)!2!1 = 3 + +Def18 == CHOOSE x : (x=1) +\* ASSUME Def18!(2)!<< = 2 + +Def19 == CHOOSE x \in {42}: (x=1) +\* ASSUME /\ Def19!(2)!<< = 2 +\* /\ Def19!1!1 = 42 + +Def20 == [12]_(23) +\* ASSUME /\ Def20!1 = 12 +\* /\ Def20!>> = 23 + +Def21 == <<12>>_(23) +\* ASSUME /\ Def21!1 = 12 +\* /\ Def21!>> = 23 + +Def22 == WF_(12)(23) +\* ASSUME /\ Def22!1 = 12 +\* /\ Def22!>> = 23 + +Def23 == \EE x , y, z : /\ ((x = 1)) + /\ y = 2 + /\ (z=3) +\* ASSUME /\ Def23!(2,3,4)!1!1 = 2 +\* /\ Def23!(2,3,4)!2!1 = 3 + + +============================================================================= + last modified on Wed 31 October 2012 at 14:45:24 PST by lamport \ No newline at end of file diff --git a/tlatools/test-model/suite/test49.cfg b/tlatools/test-model/suite/test49.cfg index a90b2d83eaffc0a49e4b947d3b1b1b9345cc8605..21d01a242b550020aa2f6bbd1102bc40ef14e051 100644 --- a/tlatools/test-model/suite/test49.cfg +++ b/tlatools/test-model/suite/test49.cfg @@ -1,3 +1,3 @@ -INIT Init -NEXT Next - +INIT Init +NEXT Next + diff --git a/tlatools/test-model/suite/test51.cfg b/tlatools/test-model/suite/test51.cfg index 56f3b36e2773a56fe267643b6b1678e06c9584eb..8d1c8b69c3fce7bea45c73efd06983e3c419a92f 100644 --- a/tlatools/test-model/suite/test51.cfg +++ b/tlatools/test-model/suite/test51.cfg @@ -1 +1 @@ - + diff --git a/tlatools/test-model/suite/test51.tla b/tlatools/test-model/suite/test51.tla index fe1bbe6406f326c7167277f97dbd59e4314168a3..1c8976bc7e53c74505bc38652e13bbed4a9a708c 100644 --- a/tlatools/test-model/suite/test51.tla +++ b/tlatools/test-model/suite/test51.tla @@ -1,495 +1,495 @@ ----------------------- MODULE test51 ----------------------- -\* Test of handling of infix operator symbols - -EXTENDS TLC - -\* Test parser on action/temporal infix operators - -FooA == INSTANCE test51a -FooB == INSTANCE test51b - -TempTest(_+_) == TRUE + FALSE -Foo1 == TempTest(-+->) -Foo2 == TempTest(~>) -Foo3 == TempTest(\cdot) - -\* Definining all undefined infix operators - -a + b == {a, b} -a - b == {a, b} -a * b == {a, b} -a / b == {a, b} -a ..b == {a, b} -a < b == {a, b} -a > b == {a, b} -a \leq b == {a, b} -a \geq b == {a, b} -a % b == {a, b} -a ^b == {a, b} -a \o b == {a, b} -a ++ b == {a, b} -a \div b == {a, b} -a ...b == {a, b} -a -- b == {a, b} -a (+)b == {a, b} -a (-)b == {a, b} -a (\X)b == {a, b} -a (/)b == {a, b} -a (.)b == {a, b} -a ** b == {a, b} -a \sqcap b == {a, b} -a // b == {a, b} -a \prec b == {a, b} -a \succ b == {a, b} -a \preceq b == {a, b} -a \succeq b == {a, b} -a \sqcup b == {a, b} -a ^^b == {a, b} -a \ll b == {a, b} -a \gg b == {a, b} -a <: b == {a, b} -a & b == {a, b} -a && b == {a, b} -a \sqsubset b == {a, b} -a \sqsupset b == {a, b} -a \sqsubseteq b == {a, b} -a \sqsupseteq b == {a, b} -a | b == {a, b} -a || b == {a, b} -a \subset b == {a, b} -a \supset b == {a, b} -a \supseteq b == {a, b} -a \star b == {a, b} -a %% b == {a, b} -a |- b == {a, b} -a -|b == {a, b} -a |= b == {a, b} -a =|b == {a, b} -a \bullet b == {a, b} -a ##b == {a, b} -a \sim b == {a, b} -a \simeq b == {a, b} -a \approx b == {a, b} -a \cong b == {a, b} -a $b == {a, b} -a $$b == {a, b} -a := b == {a, b} -a ::= b == {a, b} -a \asymp b == {a, b} -a \doteq b == {a, b} -a ?? b == {a, b} -a !! b == {a, b} -a \propto b == {a, b} -a \wr b == {a, b} -a \uplus b == {a, b} -a \bigcirc b == {a, b} - -TestOpArg(Foo(_,_)) == Foo("a", "b") - -TestTLCOps(colongt(_,_), atat(_,_)) == - atat( colongt(1, "ab"), colongt(2, "cd")) - \* 1 :> "ab" @@ 2 :> "cd" - -TestDefinedSetOp(Foo(_,_)) == Foo({"a", "b"}, {"b", "c"}) -TestDefinedBooleanOp(Foo(_,_)) == Foo(TRUE,FALSE) -TestIn(Foo(_,_)) == Foo("a", {"b", "c"}) - -ASSUME - /\ IF TestOpArg(+ ) = {"a", "b"} - THEN Print("Test 1 OK", TRUE) - ELSE Assert(FALSE, "Test 1 Failed") - /\ IF TestOpArg( - ) = {"a", "b"} - THEN Print("Test 2 OK", TRUE) - ELSE Assert(FALSE, "Test 2 Failed") - /\ IF TestOpArg( * ) = {"a", "b"} - THEN Print("Test 3 OK", TRUE) - ELSE Assert(FALSE, "Test 3 Failed") - /\ IF TestOpArg(/ ) = {"a", "b"} - THEN Print("Test 4 OK", TRUE) - ELSE Assert(FALSE, "Test 4 Failed") - /\ IF TestOpArg(..) = {"a", "b"} - THEN Print("Test 5 OK", TRUE) - ELSE Assert(FALSE, "Test 5 Failed") - /\ IF TestOpArg(< ) = {"a", "b"} - THEN Print("Test 6 OK", TRUE) - ELSE Assert(FALSE, "Test 6 Failed") - /\ IF TestOpArg(> ) = {"a", "b"} - THEN Print("Test 7 OK", TRUE) - ELSE Assert(FALSE, "Test 7 Failed") - /\ IF TestOpArg(\leq ) = {"a", "b"} - THEN Print("Test 8 OK", TRUE) - ELSE Assert(FALSE, "Test 8 Failed") - /\ IF TestOpArg(=<) = {"a", "b"} - THEN Print("Test 9 OK", TRUE) - ELSE Assert(FALSE, "Test 9 Failed") - /\ IF TestOpArg(<=) = {"a", "b"} - THEN Print("Test 10 OK", TRUE) - ELSE Assert(FALSE, "Test 10 Failed") - /\ IF TestOpArg(\geq ) = {"a", "b"} - THEN Print("Test 11 OK", TRUE) - ELSE Assert(FALSE, "Test 11 Failed") - /\ IF TestOpArg(>=) = {"a", "b"} - THEN Print("Test 12 OK", TRUE) - ELSE Assert(FALSE, "Test 12 Failed") - /\ IF TestOpArg(% ) = {"a", "b"} - THEN Print("Test 13 OK", TRUE) - ELSE Assert(FALSE, "Test 13 Failed") - /\ IF TestOpArg(^) = {"a", "b"} - THEN Print("Test 14 OK", TRUE) - ELSE Assert(FALSE, "Test 14 Failed") - /\ IF TestOpArg(\circ ) = {"a", "b"} - THEN Print("Test 15 OK", TRUE) - ELSE Assert(FALSE, "Test 15 Failed") - /\ IF TestOpArg(\o) = {"a", "b"} - THEN Print("Test 16 OK", TRUE) - ELSE Assert(FALSE, "Test 16 Failed") - /\ IF TestOpArg(++ ) = {"a", "b"} - THEN Print("Test 17 OK", TRUE) - ELSE Assert(FALSE, "Test 17 Failed") - /\ IF TestOpArg(\div ) = {"a", "b"} - THEN Print("Test 18 OK", TRUE) - ELSE Assert(FALSE, "Test 18 Failed") - /\ IF TestOpArg(...) = {"a", "b"} - THEN Print("Test 19 OK", TRUE) - ELSE Assert(FALSE, "Test 19 Failed") - /\ IF TestOpArg(-- ) = {"a", "b"} - THEN Print("Test 20 OK", TRUE) - ELSE Assert(FALSE, "Test 20 Failed") - /\ IF TestOpArg(\oplus ) = {"a", "b"} - THEN Print("Test 21 OK", TRUE) - ELSE Assert(FALSE, "Test 21 Failed") - /\ IF TestOpArg((+)) = {"a", "b"} - THEN Print("Test 22 OK", TRUE) - ELSE Assert(FALSE, "Test 22 Failed") - /\ IF TestOpArg(\ominus ) = {"a", "b"} - THEN Print("Test 23 OK", TRUE) - ELSE Assert(FALSE, "Test 23 Failed") - /\ IF TestOpArg((-)) = {"a", "b"} - THEN Print("Test 24 OK", TRUE) - ELSE Assert(FALSE, "Test 24 Failed") - /\ IF TestOpArg(\otimes ) = {"a", "b"} - THEN Print("Test 25 OK", TRUE) - ELSE Assert(FALSE, "Test 25 Failed") - /\ IF TestOpArg((\X)) = {"a", "b"} - THEN Print("Test 26 OK", TRUE) - ELSE Assert(FALSE, "Test 26 Failed") - /\ IF TestOpArg(\oslash ) = {"a", "b"} - THEN Print("Test 27 OK", TRUE) - ELSE Assert(FALSE, "Test 27 Failed") - /\ IF TestOpArg((/)) = {"a", "b"} - THEN Print("Test 28 OK", TRUE) - ELSE Assert(FALSE, "Test 28 Failed") - /\ IF TestOpArg(\odot ) = {"a", "b"} - THEN Print("Test 29 OK", TRUE) - ELSE Assert(FALSE, "Test 29 Failed") - /\ IF TestOpArg((.)) = {"a", "b"} - THEN Print("Test 30 OK", TRUE) - ELSE Assert(FALSE, "Test 30 Failed") - /\ IF TestOpArg( ** ) = {"a", "b"} - THEN Print("Test 31 OK", TRUE) - ELSE Assert(FALSE, "Test 31 Failed") - /\ IF TestOpArg(\sqcap ) = {"a", "b"} - THEN Print("Test 32 OK", TRUE) - ELSE Assert(FALSE, "Test 32 Failed") - /\ IF TestOpArg(// ) = {"a", "b"} - THEN Print("Test 33 OK", TRUE) - ELSE Assert(FALSE, "Test 33 Failed") - /\ IF TestOpArg(\prec ) = {"a", "b"} - THEN Print("Test 34 OK", TRUE) - ELSE Assert(FALSE, "Test 34 Failed") - /\ IF TestOpArg(\succ ) = {"a", "b"} - THEN Print("Test 35 OK", TRUE) - ELSE Assert(FALSE, "Test 35 Failed") - /\ IF TestOpArg(\preceq ) = {"a", "b"} - THEN Print("Test 36 OK", TRUE) - ELSE Assert(FALSE, "Test 36 Failed") - /\ IF TestOpArg(\succeq ) = {"a", "b"} - THEN Print("Test 37 OK", TRUE) - ELSE Assert(FALSE, "Test 37 Failed") - /\ IF TestOpArg(\sqcup ) = {"a", "b"} - THEN Print("Test 38 OK", TRUE) - ELSE Assert(FALSE, "Test 38 Failed") - /\ IF TestOpArg(^^) = {"a", "b"} - THEN Print("Test 39 OK", TRUE) - ELSE Assert(FALSE, "Test 39 Failed") - /\ IF TestOpArg(\ll ) = {"a", "b"} - THEN Print("Test 40 OK", TRUE) - ELSE Assert(FALSE, "Test 40 Failed") - /\ IF TestOpArg(\gg ) = {"a", "b"} - THEN Print("Test 41 OK", TRUE) - ELSE Assert(FALSE, "Test 41 Failed") - /\ IF TestOpArg(<: ) = {"a", "b"} - THEN Print("Test 42 OK", TRUE) - ELSE Assert(FALSE, "Test 42 Failed") - /\ IF TestOpArg(& ) = {"a", "b"} - THEN Print("Test 43 OK", TRUE) - ELSE Assert(FALSE, "Test 43 Failed") - /\ IF TestOpArg(&& ) = {"a", "b"} - THEN Print("Test 44 OK", TRUE) - ELSE Assert(FALSE, "Test 44 Failed") - /\ IF TestOpArg(\sqsubset ) = {"a", "b"} - THEN Print("Test 45 OK", TRUE) - ELSE Assert(FALSE, "Test 45 Failed") - /\ IF TestOpArg(\sqsupset ) = {"a", "b"} - THEN Print("Test 46 OK", TRUE) - ELSE Assert(FALSE, "Test 46 Failed") - /\ IF TestOpArg(\sqsubseteq ) = {"a", "b"} - THEN Print("Test 47 OK", TRUE) - ELSE Assert(FALSE, "Test 47 Failed") - /\ IF TestOpArg(\sqsupseteq ) = {"a", "b"} - THEN Print("Test 48 OK", TRUE) - ELSE Assert(FALSE, "Test 48 Failed") - /\ IF TestOpArg(| ) = {"a", "b"} - THEN Print("Test 49 OK", TRUE) - ELSE Assert(FALSE, "Test 49 Failed") - /\ IF TestOpArg(|| ) = {"a", "b"} - THEN Print("Test 50 OK", TRUE) - ELSE Assert(FALSE, "Test 50 Failed") - /\ IF TestOpArg(\subset ) = {"a", "b"} - THEN Print("Test 51 OK", TRUE) - ELSE Assert(FALSE, "Test 51 Failed") - /\ IF TestOpArg(\supset ) = {"a", "b"} - THEN Print("Test 52 OK", TRUE) - ELSE Assert(FALSE, "Test 52 Failed") - /\ IF TestOpArg(\supseteq ) = {"a", "b"} - THEN Print("Test 53 OK", TRUE) - ELSE Assert(FALSE, "Test 53 Failed") - /\ IF TestOpArg(\star ) = {"a", "b"} - THEN Print("Test 54 OK", TRUE) - ELSE Assert(FALSE, "Test 54 Failed") - /\ IF TestOpArg(%% ) = {"a", "b"} - THEN Print("Test 55 OK", TRUE) - ELSE Assert(FALSE, "Test 55 Failed") - /\ IF TestOpArg(|- ) = {"a", "b"} - THEN Print("Test 56 OK", TRUE) - ELSE Assert(FALSE, "Test 56 Failed") - /\ IF TestOpArg(-|) = {"a", "b"} - THEN Print("Test 57 OK", TRUE) - ELSE Assert(FALSE, "Test 57 Failed") - /\ IF TestOpArg(|= ) = {"a", "b"} - THEN Print("Test 58 OK", TRUE) - ELSE Assert(FALSE, "Test 58 Failed") - /\ IF TestOpArg(=|) = {"a", "b"} - THEN Print("Test 59 OK", TRUE) - ELSE Assert(FALSE, "Test 59 Failed") - /\ IF TestOpArg(\bullet ) = {"a", "b"} - THEN Print("Test 60 OK", TRUE) - ELSE Assert(FALSE, "Test 60 Failed") - /\ IF TestOpArg(##) = {"a", "b"} - THEN Print("Test 61 OK", TRUE) - ELSE Assert(FALSE, "Test 61 Failed") - /\ IF TestOpArg(\sim ) = {"a", "b"} - THEN Print("Test 62 OK", TRUE) - ELSE Assert(FALSE, "Test 62 Failed") - /\ IF TestOpArg(\simeq ) = {"a", "b"} - THEN Print("Test 63 OK", TRUE) - ELSE Assert(FALSE, "Test 63 Failed") - /\ IF TestOpArg(\approx ) = {"a", "b"} - THEN Print("Test 64 OK", TRUE) - ELSE Assert(FALSE, "Test 64 Failed") - /\ IF TestOpArg(\cong ) = {"a", "b"} - THEN Print("Test 65 OK", TRUE) - ELSE Assert(FALSE, "Test 65 Failed") - /\ IF TestOpArg($) = {"a", "b"} - THEN Print("Test 66 OK", TRUE) - ELSE Assert(FALSE, "Test 66 Failed") - /\ IF TestOpArg($$) = {"a", "b"} - THEN Print("Test 67 OK", TRUE) - ELSE Assert(FALSE, "Test 67 Failed") - /\ IF TestOpArg(:= ) = {"a", "b"} - THEN Print("Test 68 OK", TRUE) - ELSE Assert(FALSE, "Test 68 Failed") - /\ IF TestOpArg(::= ) = {"a", "b"} - THEN Print("Test 69 OK", TRUE) - ELSE Assert(FALSE, "Test 69 Failed") - /\ IF TestOpArg(\asymp ) = {"a", "b"} - THEN Print("Test 70 OK", TRUE) - ELSE Assert(FALSE, "Test 70 Failed") - /\ IF TestOpArg(\doteq ) = {"a", "b"} - THEN Print("Test 71 OK", TRUE) - ELSE Assert(FALSE, "Test 71 Failed") - /\ IF TestOpArg(?? ) = {"a", "b"} - THEN Print("Test 72 OK", TRUE) - ELSE Assert(FALSE, "Test 72 Failed") - /\ IF TestOpArg(!! ) = {"a", "b"} - THEN Print("Test 73 OK", TRUE) - ELSE Assert(FALSE, "Test 73 Failed") - /\ IF TestOpArg(\propto ) = {"a", "b"} - THEN Print("Test 74 OK", TRUE) - ELSE Assert(FALSE, "Test 74 Failed") - /\ IF TestOpArg(\wr ) = {"a", "b"} - THEN Print("Test 75 OK", TRUE) - ELSE Assert(FALSE, "Test 75 Failed") - /\ IF TestOpArg(\uplus ) = {"a", "b"} - THEN Print("Test 76 OK", TRUE) - ELSE Assert(FALSE, "Test 76 Failed") - /\ IF TestOpArg(\bigcirc ) = {"a", "b"} - THEN Print("Test 77 OK", TRUE) - ELSE Assert(FALSE, "Test 77 Failed") - /\ IF TestTLCOps(:>, @@) = 1 :> "ab" @@ 2 :> "cd" - THEN Print("Test 78 OK", TRUE) - ELSE Assert(FALSE, "Test 78 Failed") - /\ IF TestDefinedBooleanOp(=>) = (TRUE => FALSE) - THEN Print("Test 79 OK", TRUE) - ELSE Assert(FALSE, "Test 79 Failed") - /\ IF TestDefinedBooleanOp(\equiv) = (TRUE \equiv FALSE) - THEN Print("Test 80 OK", TRUE) - ELSE Assert(FALSE, "Test 80 Failed") - /\ IF TestDefinedBooleanOp(<=>) = (TRUE <=> FALSE) - THEN Print("Test 81 OK", TRUE) - ELSE Assert(FALSE, "Test 81 Failed") -\* /\ Print("Test 82 fails because of parser bug", TRUE) - /\ IF TestDefinedBooleanOp(/\) = (TRUE /\ FALSE) - THEN Print("Test 82 OK", TRUE) - ELSE Assert(FALSE, "Test 82 Failed") - /\ IF TestDefinedBooleanOp(\land) = (TRUE \land FALSE) - THEN Print("Test 83 OK", TRUE) - ELSE Assert(FALSE, "Test 83 Failed") -\* /\ Print("Test 84 fails because of parser bug", TRUE) - /\ IF TestDefinedBooleanOp(\/) = (TRUE \/ FALSE) - THEN Print("Test 84 OK", TRUE) - ELSE Assert(FALSE, "Test 84 Failed") - /\ IF TestDefinedBooleanOp(\lor) = (TRUE \lor FALSE) - THEN Print("Test 85 OK", TRUE) - ELSE Assert(FALSE, "Test 85 Failed") - /\ IF TestDefinedSetOp(#) = ({"a", "b"} # {"b", "c"}) - THEN Print("Test 86 OK", TRUE) - ELSE Assert(FALSE, "Test 86 Failed") - /\ IF TestDefinedSetOp(/=) = ({"a", "b"} /= {"b", "c"}) - THEN Print("Test 87 OK", TRUE) - ELSE Assert(FALSE, "Test 87 Failed") - /\ IF TestIn(\in) = ("a"\in {"b", "c"}) - THEN Print("Test 88 OK", TRUE) - ELSE Assert(FALSE, "Test 88 Failed") - /\ IF TestIn(\notin) = ("a" \notin {"b", "c"}) - THEN Print("Test 89 OK", TRUE) - ELSE Assert(FALSE, "Test 89 Failed") - /\ IF TestDefinedSetOp(\subseteq) = ({"a", "b"} \subseteq {"b", "c"}) - THEN Print("Test 90 OK", TRUE) - ELSE Assert(FALSE, "Test 90 Failed") - /\ IF TestDefinedSetOp(\) = ({"a", "b"} \ {"b", "c"}) - THEN Print("Test 91 OK", TRUE) - ELSE Assert(FALSE, "Test 91 Failed") - /\ IF TestDefinedSetOp(\cap) = ({"a", "b"} \cap {"b", "c"}) - THEN Print("Test 92 OK", TRUE) - ELSE Assert(FALSE, "Test 92 Failed") - /\ IF TestDefinedSetOp(\intersect) = ({"a", "b"} \intersect {"b", "c"}) - THEN Print("Test 93 OK", TRUE) - ELSE Assert(FALSE, "Test 93 Failed") - /\ IF TestDefinedSetOp(\cup) = ({"a", "b"} \cup {"b", "c"}) - THEN Print("Test 94 OK", TRUE) - ELSE Assert(FALSE, "Test 94 Failed") - /\ IF TestDefinedSetOp(\union) = ({"a", "b"} \union {"b", "c"}) - THEN Print("Test 95 OK", TRUE) - ELSE Assert(FALSE, "Test 95 Failed") - - -============================================================== -78 -ALL UNDEFINED INFIX OPERATORS - -+ -- -* -/ -.. -< -> -\leq -=< -<= -\geq ->= -% -^ -\circ -\o -++ -\div -... --- -\oplus -(+) -\ominus -(-) -\otimes -(\X) -\oslash -(/) -\odot -(.) -** -\sqcap -// -\prec -\succ -\preceq -\succeq -\sqcup -^^ -\ll -\gg -<: -& -&& -\sqsubset -\sqsupset -\sqsubseteq -\sqsupseteq -| -|| -\subset -\supset -\supseteq -\star -%% -|- --| -|= -=| -\bullet -## -\sim -\simeq -\approx -\cong -$ -$$ -:= -::= -\asymp -\doteq -?? -!! -\propto -\wr -\uplus -\bigcirc - - -BUILT-IN BOOLEANS -=> -\equiv -<=> -/\ -\land -\/ -\lor - -BUILT-IN SET OPERATORS -# -/= -\in -\notin -\subseteq -\ -\cap -\intersect -\cup -\union - -OTHER - --+-> -~> -\cdot +---------------------- MODULE test51 ----------------------- +\* Test of handling of infix operator symbols + +EXTENDS TLC + +\* Test parser on action/temporal infix operators + +FooA == INSTANCE test51a +FooB == INSTANCE test51b + +TempTest(_+_) == TRUE + FALSE +Foo1 == TempTest(-+->) +Foo2 == TempTest(~>) +Foo3 == TempTest(\cdot) + +\* Definining all undefined infix operators + +a + b == {a, b} +a - b == {a, b} +a * b == {a, b} +a / b == {a, b} +a ..b == {a, b} +a < b == {a, b} +a > b == {a, b} +a \leq b == {a, b} +a \geq b == {a, b} +a % b == {a, b} +a ^b == {a, b} +a \o b == {a, b} +a ++ b == {a, b} +a \div b == {a, b} +a ...b == {a, b} +a -- b == {a, b} +a (+)b == {a, b} +a (-)b == {a, b} +a (\X)b == {a, b} +a (/)b == {a, b} +a (.)b == {a, b} +a ** b == {a, b} +a \sqcap b == {a, b} +a // b == {a, b} +a \prec b == {a, b} +a \succ b == {a, b} +a \preceq b == {a, b} +a \succeq b == {a, b} +a \sqcup b == {a, b} +a ^^b == {a, b} +a \ll b == {a, b} +a \gg b == {a, b} +a <: b == {a, b} +a & b == {a, b} +a && b == {a, b} +a \sqsubset b == {a, b} +a \sqsupset b == {a, b} +a \sqsubseteq b == {a, b} +a \sqsupseteq b == {a, b} +a | b == {a, b} +a || b == {a, b} +a \subset b == {a, b} +a \supset b == {a, b} +a \supseteq b == {a, b} +a \star b == {a, b} +a %% b == {a, b} +a |- b == {a, b} +a -|b == {a, b} +a |= b == {a, b} +a =|b == {a, b} +a \bullet b == {a, b} +a ##b == {a, b} +a \sim b == {a, b} +a \simeq b == {a, b} +a \approx b == {a, b} +a \cong b == {a, b} +a $b == {a, b} +a $$b == {a, b} +a := b == {a, b} +a ::= b == {a, b} +a \asymp b == {a, b} +a \doteq b == {a, b} +a ?? b == {a, b} +a !! b == {a, b} +a \propto b == {a, b} +a \wr b == {a, b} +a \uplus b == {a, b} +a \bigcirc b == {a, b} + +TestOpArg(Foo(_,_)) == Foo("a", "b") + +TestTLCOps(colongt(_,_), atat(_,_)) == + atat( colongt(1, "ab"), colongt(2, "cd")) + \* 1 :> "ab" @@ 2 :> "cd" + +TestDefinedSetOp(Foo(_,_)) == Foo({"a", "b"}, {"b", "c"}) +TestDefinedBooleanOp(Foo(_,_)) == Foo(TRUE,FALSE) +TestIn(Foo(_,_)) == Foo("a", {"b", "c"}) + +ASSUME + /\ IF TestOpArg(+ ) = {"a", "b"} + THEN Print("Test 1 OK", TRUE) + ELSE Assert(FALSE, "Test 1 Failed") + /\ IF TestOpArg( - ) = {"a", "b"} + THEN Print("Test 2 OK", TRUE) + ELSE Assert(FALSE, "Test 2 Failed") + /\ IF TestOpArg( * ) = {"a", "b"} + THEN Print("Test 3 OK", TRUE) + ELSE Assert(FALSE, "Test 3 Failed") + /\ IF TestOpArg(/ ) = {"a", "b"} + THEN Print("Test 4 OK", TRUE) + ELSE Assert(FALSE, "Test 4 Failed") + /\ IF TestOpArg(..) = {"a", "b"} + THEN Print("Test 5 OK", TRUE) + ELSE Assert(FALSE, "Test 5 Failed") + /\ IF TestOpArg(< ) = {"a", "b"} + THEN Print("Test 6 OK", TRUE) + ELSE Assert(FALSE, "Test 6 Failed") + /\ IF TestOpArg(> ) = {"a", "b"} + THEN Print("Test 7 OK", TRUE) + ELSE Assert(FALSE, "Test 7 Failed") + /\ IF TestOpArg(\leq ) = {"a", "b"} + THEN Print("Test 8 OK", TRUE) + ELSE Assert(FALSE, "Test 8 Failed") + /\ IF TestOpArg(=<) = {"a", "b"} + THEN Print("Test 9 OK", TRUE) + ELSE Assert(FALSE, "Test 9 Failed") + /\ IF TestOpArg(<=) = {"a", "b"} + THEN Print("Test 10 OK", TRUE) + ELSE Assert(FALSE, "Test 10 Failed") + /\ IF TestOpArg(\geq ) = {"a", "b"} + THEN Print("Test 11 OK", TRUE) + ELSE Assert(FALSE, "Test 11 Failed") + /\ IF TestOpArg(>=) = {"a", "b"} + THEN Print("Test 12 OK", TRUE) + ELSE Assert(FALSE, "Test 12 Failed") + /\ IF TestOpArg(% ) = {"a", "b"} + THEN Print("Test 13 OK", TRUE) + ELSE Assert(FALSE, "Test 13 Failed") + /\ IF TestOpArg(^) = {"a", "b"} + THEN Print("Test 14 OK", TRUE) + ELSE Assert(FALSE, "Test 14 Failed") + /\ IF TestOpArg(\circ ) = {"a", "b"} + THEN Print("Test 15 OK", TRUE) + ELSE Assert(FALSE, "Test 15 Failed") + /\ IF TestOpArg(\o) = {"a", "b"} + THEN Print("Test 16 OK", TRUE) + ELSE Assert(FALSE, "Test 16 Failed") + /\ IF TestOpArg(++ ) = {"a", "b"} + THEN Print("Test 17 OK", TRUE) + ELSE Assert(FALSE, "Test 17 Failed") + /\ IF TestOpArg(\div ) = {"a", "b"} + THEN Print("Test 18 OK", TRUE) + ELSE Assert(FALSE, "Test 18 Failed") + /\ IF TestOpArg(...) = {"a", "b"} + THEN Print("Test 19 OK", TRUE) + ELSE Assert(FALSE, "Test 19 Failed") + /\ IF TestOpArg(-- ) = {"a", "b"} + THEN Print("Test 20 OK", TRUE) + ELSE Assert(FALSE, "Test 20 Failed") + /\ IF TestOpArg(\oplus ) = {"a", "b"} + THEN Print("Test 21 OK", TRUE) + ELSE Assert(FALSE, "Test 21 Failed") + /\ IF TestOpArg((+)) = {"a", "b"} + THEN Print("Test 22 OK", TRUE) + ELSE Assert(FALSE, "Test 22 Failed") + /\ IF TestOpArg(\ominus ) = {"a", "b"} + THEN Print("Test 23 OK", TRUE) + ELSE Assert(FALSE, "Test 23 Failed") + /\ IF TestOpArg((-)) = {"a", "b"} + THEN Print("Test 24 OK", TRUE) + ELSE Assert(FALSE, "Test 24 Failed") + /\ IF TestOpArg(\otimes ) = {"a", "b"} + THEN Print("Test 25 OK", TRUE) + ELSE Assert(FALSE, "Test 25 Failed") + /\ IF TestOpArg((\X)) = {"a", "b"} + THEN Print("Test 26 OK", TRUE) + ELSE Assert(FALSE, "Test 26 Failed") + /\ IF TestOpArg(\oslash ) = {"a", "b"} + THEN Print("Test 27 OK", TRUE) + ELSE Assert(FALSE, "Test 27 Failed") + /\ IF TestOpArg((/)) = {"a", "b"} + THEN Print("Test 28 OK", TRUE) + ELSE Assert(FALSE, "Test 28 Failed") + /\ IF TestOpArg(\odot ) = {"a", "b"} + THEN Print("Test 29 OK", TRUE) + ELSE Assert(FALSE, "Test 29 Failed") + /\ IF TestOpArg((.)) = {"a", "b"} + THEN Print("Test 30 OK", TRUE) + ELSE Assert(FALSE, "Test 30 Failed") + /\ IF TestOpArg( ** ) = {"a", "b"} + THEN Print("Test 31 OK", TRUE) + ELSE Assert(FALSE, "Test 31 Failed") + /\ IF TestOpArg(\sqcap ) = {"a", "b"} + THEN Print("Test 32 OK", TRUE) + ELSE Assert(FALSE, "Test 32 Failed") + /\ IF TestOpArg(// ) = {"a", "b"} + THEN Print("Test 33 OK", TRUE) + ELSE Assert(FALSE, "Test 33 Failed") + /\ IF TestOpArg(\prec ) = {"a", "b"} + THEN Print("Test 34 OK", TRUE) + ELSE Assert(FALSE, "Test 34 Failed") + /\ IF TestOpArg(\succ ) = {"a", "b"} + THEN Print("Test 35 OK", TRUE) + ELSE Assert(FALSE, "Test 35 Failed") + /\ IF TestOpArg(\preceq ) = {"a", "b"} + THEN Print("Test 36 OK", TRUE) + ELSE Assert(FALSE, "Test 36 Failed") + /\ IF TestOpArg(\succeq ) = {"a", "b"} + THEN Print("Test 37 OK", TRUE) + ELSE Assert(FALSE, "Test 37 Failed") + /\ IF TestOpArg(\sqcup ) = {"a", "b"} + THEN Print("Test 38 OK", TRUE) + ELSE Assert(FALSE, "Test 38 Failed") + /\ IF TestOpArg(^^) = {"a", "b"} + THEN Print("Test 39 OK", TRUE) + ELSE Assert(FALSE, "Test 39 Failed") + /\ IF TestOpArg(\ll ) = {"a", "b"} + THEN Print("Test 40 OK", TRUE) + ELSE Assert(FALSE, "Test 40 Failed") + /\ IF TestOpArg(\gg ) = {"a", "b"} + THEN Print("Test 41 OK", TRUE) + ELSE Assert(FALSE, "Test 41 Failed") + /\ IF TestOpArg(<: ) = {"a", "b"} + THEN Print("Test 42 OK", TRUE) + ELSE Assert(FALSE, "Test 42 Failed") + /\ IF TestOpArg(& ) = {"a", "b"} + THEN Print("Test 43 OK", TRUE) + ELSE Assert(FALSE, "Test 43 Failed") + /\ IF TestOpArg(&& ) = {"a", "b"} + THEN Print("Test 44 OK", TRUE) + ELSE Assert(FALSE, "Test 44 Failed") + /\ IF TestOpArg(\sqsubset ) = {"a", "b"} + THEN Print("Test 45 OK", TRUE) + ELSE Assert(FALSE, "Test 45 Failed") + /\ IF TestOpArg(\sqsupset ) = {"a", "b"} + THEN Print("Test 46 OK", TRUE) + ELSE Assert(FALSE, "Test 46 Failed") + /\ IF TestOpArg(\sqsubseteq ) = {"a", "b"} + THEN Print("Test 47 OK", TRUE) + ELSE Assert(FALSE, "Test 47 Failed") + /\ IF TestOpArg(\sqsupseteq ) = {"a", "b"} + THEN Print("Test 48 OK", TRUE) + ELSE Assert(FALSE, "Test 48 Failed") + /\ IF TestOpArg(| ) = {"a", "b"} + THEN Print("Test 49 OK", TRUE) + ELSE Assert(FALSE, "Test 49 Failed") + /\ IF TestOpArg(|| ) = {"a", "b"} + THEN Print("Test 50 OK", TRUE) + ELSE Assert(FALSE, "Test 50 Failed") + /\ IF TestOpArg(\subset ) = {"a", "b"} + THEN Print("Test 51 OK", TRUE) + ELSE Assert(FALSE, "Test 51 Failed") + /\ IF TestOpArg(\supset ) = {"a", "b"} + THEN Print("Test 52 OK", TRUE) + ELSE Assert(FALSE, "Test 52 Failed") + /\ IF TestOpArg(\supseteq ) = {"a", "b"} + THEN Print("Test 53 OK", TRUE) + ELSE Assert(FALSE, "Test 53 Failed") + /\ IF TestOpArg(\star ) = {"a", "b"} + THEN Print("Test 54 OK", TRUE) + ELSE Assert(FALSE, "Test 54 Failed") + /\ IF TestOpArg(%% ) = {"a", "b"} + THEN Print("Test 55 OK", TRUE) + ELSE Assert(FALSE, "Test 55 Failed") + /\ IF TestOpArg(|- ) = {"a", "b"} + THEN Print("Test 56 OK", TRUE) + ELSE Assert(FALSE, "Test 56 Failed") + /\ IF TestOpArg(-|) = {"a", "b"} + THEN Print("Test 57 OK", TRUE) + ELSE Assert(FALSE, "Test 57 Failed") + /\ IF TestOpArg(|= ) = {"a", "b"} + THEN Print("Test 58 OK", TRUE) + ELSE Assert(FALSE, "Test 58 Failed") + /\ IF TestOpArg(=|) = {"a", "b"} + THEN Print("Test 59 OK", TRUE) + ELSE Assert(FALSE, "Test 59 Failed") + /\ IF TestOpArg(\bullet ) = {"a", "b"} + THEN Print("Test 60 OK", TRUE) + ELSE Assert(FALSE, "Test 60 Failed") + /\ IF TestOpArg(##) = {"a", "b"} + THEN Print("Test 61 OK", TRUE) + ELSE Assert(FALSE, "Test 61 Failed") + /\ IF TestOpArg(\sim ) = {"a", "b"} + THEN Print("Test 62 OK", TRUE) + ELSE Assert(FALSE, "Test 62 Failed") + /\ IF TestOpArg(\simeq ) = {"a", "b"} + THEN Print("Test 63 OK", TRUE) + ELSE Assert(FALSE, "Test 63 Failed") + /\ IF TestOpArg(\approx ) = {"a", "b"} + THEN Print("Test 64 OK", TRUE) + ELSE Assert(FALSE, "Test 64 Failed") + /\ IF TestOpArg(\cong ) = {"a", "b"} + THEN Print("Test 65 OK", TRUE) + ELSE Assert(FALSE, "Test 65 Failed") + /\ IF TestOpArg($) = {"a", "b"} + THEN Print("Test 66 OK", TRUE) + ELSE Assert(FALSE, "Test 66 Failed") + /\ IF TestOpArg($$) = {"a", "b"} + THEN Print("Test 67 OK", TRUE) + ELSE Assert(FALSE, "Test 67 Failed") + /\ IF TestOpArg(:= ) = {"a", "b"} + THEN Print("Test 68 OK", TRUE) + ELSE Assert(FALSE, "Test 68 Failed") + /\ IF TestOpArg(::= ) = {"a", "b"} + THEN Print("Test 69 OK", TRUE) + ELSE Assert(FALSE, "Test 69 Failed") + /\ IF TestOpArg(\asymp ) = {"a", "b"} + THEN Print("Test 70 OK", TRUE) + ELSE Assert(FALSE, "Test 70 Failed") + /\ IF TestOpArg(\doteq ) = {"a", "b"} + THEN Print("Test 71 OK", TRUE) + ELSE Assert(FALSE, "Test 71 Failed") + /\ IF TestOpArg(?? ) = {"a", "b"} + THEN Print("Test 72 OK", TRUE) + ELSE Assert(FALSE, "Test 72 Failed") + /\ IF TestOpArg(!! ) = {"a", "b"} + THEN Print("Test 73 OK", TRUE) + ELSE Assert(FALSE, "Test 73 Failed") + /\ IF TestOpArg(\propto ) = {"a", "b"} + THEN Print("Test 74 OK", TRUE) + ELSE Assert(FALSE, "Test 74 Failed") + /\ IF TestOpArg(\wr ) = {"a", "b"} + THEN Print("Test 75 OK", TRUE) + ELSE Assert(FALSE, "Test 75 Failed") + /\ IF TestOpArg(\uplus ) = {"a", "b"} + THEN Print("Test 76 OK", TRUE) + ELSE Assert(FALSE, "Test 76 Failed") + /\ IF TestOpArg(\bigcirc ) = {"a", "b"} + THEN Print("Test 77 OK", TRUE) + ELSE Assert(FALSE, "Test 77 Failed") + /\ IF TestTLCOps(:>, @@) = 1 :> "ab" @@ 2 :> "cd" + THEN Print("Test 78 OK", TRUE) + ELSE Assert(FALSE, "Test 78 Failed") + /\ IF TestDefinedBooleanOp(=>) = (TRUE => FALSE) + THEN Print("Test 79 OK", TRUE) + ELSE Assert(FALSE, "Test 79 Failed") + /\ IF TestDefinedBooleanOp(\equiv) = (TRUE \equiv FALSE) + THEN Print("Test 80 OK", TRUE) + ELSE Assert(FALSE, "Test 80 Failed") + /\ IF TestDefinedBooleanOp(<=>) = (TRUE <=> FALSE) + THEN Print("Test 81 OK", TRUE) + ELSE Assert(FALSE, "Test 81 Failed") +\* /\ Print("Test 82 fails because of parser bug", TRUE) + /\ IF TestDefinedBooleanOp(/\) = (TRUE /\ FALSE) + THEN Print("Test 82 OK", TRUE) + ELSE Assert(FALSE, "Test 82 Failed") + /\ IF TestDefinedBooleanOp(\land) = (TRUE \land FALSE) + THEN Print("Test 83 OK", TRUE) + ELSE Assert(FALSE, "Test 83 Failed") +\* /\ Print("Test 84 fails because of parser bug", TRUE) + /\ IF TestDefinedBooleanOp(\/) = (TRUE \/ FALSE) + THEN Print("Test 84 OK", TRUE) + ELSE Assert(FALSE, "Test 84 Failed") + /\ IF TestDefinedBooleanOp(\lor) = (TRUE \lor FALSE) + THEN Print("Test 85 OK", TRUE) + ELSE Assert(FALSE, "Test 85 Failed") + /\ IF TestDefinedSetOp(#) = ({"a", "b"} # {"b", "c"}) + THEN Print("Test 86 OK", TRUE) + ELSE Assert(FALSE, "Test 86 Failed") + /\ IF TestDefinedSetOp(/=) = ({"a", "b"} /= {"b", "c"}) + THEN Print("Test 87 OK", TRUE) + ELSE Assert(FALSE, "Test 87 Failed") + /\ IF TestIn(\in) = ("a"\in {"b", "c"}) + THEN Print("Test 88 OK", TRUE) + ELSE Assert(FALSE, "Test 88 Failed") + /\ IF TestIn(\notin) = ("a" \notin {"b", "c"}) + THEN Print("Test 89 OK", TRUE) + ELSE Assert(FALSE, "Test 89 Failed") + /\ IF TestDefinedSetOp(\subseteq) = ({"a", "b"} \subseteq {"b", "c"}) + THEN Print("Test 90 OK", TRUE) + ELSE Assert(FALSE, "Test 90 Failed") + /\ IF TestDefinedSetOp(\) = ({"a", "b"} \ {"b", "c"}) + THEN Print("Test 91 OK", TRUE) + ELSE Assert(FALSE, "Test 91 Failed") + /\ IF TestDefinedSetOp(\cap) = ({"a", "b"} \cap {"b", "c"}) + THEN Print("Test 92 OK", TRUE) + ELSE Assert(FALSE, "Test 92 Failed") + /\ IF TestDefinedSetOp(\intersect) = ({"a", "b"} \intersect {"b", "c"}) + THEN Print("Test 93 OK", TRUE) + ELSE Assert(FALSE, "Test 93 Failed") + /\ IF TestDefinedSetOp(\cup) = ({"a", "b"} \cup {"b", "c"}) + THEN Print("Test 94 OK", TRUE) + ELSE Assert(FALSE, "Test 94 Failed") + /\ IF TestDefinedSetOp(\union) = ({"a", "b"} \union {"b", "c"}) + THEN Print("Test 95 OK", TRUE) + ELSE Assert(FALSE, "Test 95 Failed") + + +============================================================== +78 +ALL UNDEFINED INFIX OPERATORS + ++ +- +* +/ +.. +< +> +\leq +=< +<= +\geq +>= +% +^ +\circ +\o +++ +\div +... +-- +\oplus +(+) +\ominus +(-) +\otimes +(\X) +\oslash +(/) +\odot +(.) +** +\sqcap +// +\prec +\succ +\preceq +\succeq +\sqcup +^^ +\ll +\gg +<: +& +&& +\sqsubset +\sqsupset +\sqsubseteq +\sqsupseteq +| +|| +\subset +\supset +\supseteq +\star +%% +|- +-| +|= +=| +\bullet +## +\sim +\simeq +\approx +\cong +$ +$$ +:= +::= +\asymp +\doteq +?? +!! +\propto +\wr +\uplus +\bigcirc + + +BUILT-IN BOOLEANS +=> +\equiv +<=> +/\ +\land +\/ +\lor + +BUILT-IN SET OPERATORS +# +/= +\in +\notin +\subseteq +\ +\cap +\intersect +\cup +\union + +OTHER + +-+-> +~> +\cdot diff --git a/tlatools/test-model/suite/test51a.tla b/tlatools/test-model/suite/test51a.tla index 8b749bda774d56f358042e9847888f60afce327e..60ad0e2ab62f2eacf5e53750e7756146a60ea403 100644 --- a/tlatools/test-model/suite/test51a.tla +++ b/tlatools/test-model/suite/test51a.tla @@ -1,13 +1,13 @@ -------------------- MODULE test51a ------------------------- - -\* Test definability of some aliases - -a =< b == {a, b} -a >=b == {a, b} -a \circ b == {a, b} -a \oplus b == {a, b} -a \ominus b == {a, b} -a \otimes b == {a, b} -a \oslash b == {a, b} -a \odot b == {a, b} -============================================================================= +------------------- MODULE test51a ------------------------- + +\* Test definability of some aliases + +a =< b == {a, b} +a >=b == {a, b} +a \circ b == {a, b} +a \oplus b == {a, b} +a \ominus b == {a, b} +a \otimes b == {a, b} +a \oslash b == {a, b} +a \odot b == {a, b} +============================================================================= diff --git a/tlatools/test-model/suite/test51b.tla b/tlatools/test-model/suite/test51b.tla index d673cef351f233e955741afb399942291266d9da..2c21874d170bd255904e7f7e66218df301c8c19b 100644 --- a/tlatools/test-model/suite/test51b.tla +++ b/tlatools/test-model/suite/test51b.tla @@ -1,4 +1,4 @@ ----------------- MODULE test51b ----------------- -a <= b == {a, b} - -================================================================== +---------------- MODULE test51b ----------------- +a <= b == {a, b} + +================================================================== diff --git a/tlatools/test-model/suite/test52.cfg b/tlatools/test-model/suite/test52.cfg index 8990f16d455df1338b40f248faa8eb41101160d1..942df65a55fdabbd31d3495a5c5124ef762101af 100644 --- a/tlatools/test-model/suite/test52.cfg +++ b/tlatools/test-model/suite/test52.cfg @@ -1,6 +1,6 @@ -SPECIFICATION Spec -PROPERTY Property -\* The Invariant is commented because of a known bug in TLC. -\* If this bug is ever addressed, Invariant can be re-enabled -\* and the test test52enabled be deleted. -\*INVARIANT Invariant +SPECIFICATION Spec +PROPERTY Property +\* The Invariant is commented because of a known bug in TLC. +\* If this bug is ever addressed, Invariant can be re-enabled +\* and the test test52enabled be deleted. +\*INVARIANT Invariant diff --git a/tlatools/test-model/suite/test52.tla b/tlatools/test-model/suite/test52.tla index dbdd9e94de638cd5ce31d7fbfc6f3d6f22a1d9b2..0cf62f56535b99a564eee848238b31b57ea68d98 100644 --- a/tlatools/test-model/suite/test52.tla +++ b/tlatools/test-model/suite/test52.tla @@ -1,71 +1,71 @@ ----------------------- MODULE test52 ----------------------- - -\* Test of prefix and postfix operators as arguments - -EXTENDS TLC - -VARIABLES x, y - -BoxTest(-._) == -(x=0) -Foo1 == BoxTest([]) -Foo2 == BoxTest(<>) - --. a == {{"a"}, {"b"}} \ a -a ^+ == {{"a"}, {"b"}} \ a -a ^* == {{"a"}, {"b"}} \ a -a ^# == {{"a"}, {"b"}} \ a - -SetOpTest(Foo(_)) == Foo({{"b"}, {"c"}}) -DomainTest(Foo(_)) == Foo([i\in {"a", "b"} |-> i]) - -ASSUME - /\ Print("Test1 Begun", TRUE) - /\ SetOpTest(-.) = - {{"b"}, {"c"}} - /\ SetOpTest(^+) = {{"b"}, {"c"}} ^+ - /\ SetOpTest(^*) = {{"b"}, {"c"}} ^* - /\ SetOpTest(^#) = {{"b"}, {"c"}} ^# - /\ SetOpTest(SUBSET) = SUBSET {{"b"}, {"c"}} - /\ SetOpTest(UNION) = UNION {{"b"}, {"c"}} - /\ DomainTest(DOMAIN) = DOMAIN [i\in {"a", "b"} |-> i] - /\ Print("Test1 Finished", TRUE) - - -Init == /\ x = {"a"} - /\ y = {"a"} -Next == /\ x'= x \cup {"a"} - /\ y'= y \cup {"b"} +---------------------- MODULE test52 ----------------------- + +\* Test of prefix and postfix operators as arguments + +EXTENDS TLC + +VARIABLES x, y + +BoxTest(-._) == -(x=0) +Foo1 == BoxTest([]) +Foo2 == BoxTest(<>) + +-. a == {{"a"}, {"b"}} \ a +a ^+ == {{"a"}, {"b"}} \ a +a ^* == {{"a"}, {"b"}} \ a +a ^# == {{"a"}, {"b"}} \ a + +SetOpTest(Foo(_)) == Foo({{"b"}, {"c"}}) +DomainTest(Foo(_)) == Foo([i\in {"a", "b"} |-> i]) + +ASSUME + /\ Print("Test1 Begun", TRUE) + /\ SetOpTest(-.) = - {{"b"}, {"c"}} + /\ SetOpTest(^+) = {{"b"}, {"c"}} ^+ + /\ SetOpTest(^*) = {{"b"}, {"c"}} ^* + /\ SetOpTest(^#) = {{"b"}, {"c"}} ^# + /\ SetOpTest(SUBSET) = SUBSET {{"b"}, {"c"}} + /\ SetOpTest(UNION) = UNION {{"b"}, {"c"}} + /\ DomainTest(DOMAIN) = DOMAIN [i\in {"a", "b"} |-> i] + /\ Print("Test1 Finished", TRUE) + + +Init == /\ x = {"a"} + /\ y = {"a"} +Next == /\ x'= x \cup {"a"} + /\ y'= y \cup {"b"} Spec == Init /\ [][Next]_<<x, y>> - + EnabledTest(Foo(_)) == Foo(x'=x) -UnchangedTest(Foo(_)) == Foo(x) -PrimeTest(Foo(_)) == Foo(x) = x - -Invariant == - /\ EnabledTest(ENABLED) - -ImpliedAction == - /\ UnchangedTest(UNCHANGED) - /\ PrimeTest(') - -Property == [][ImpliedAction]_<<x, y>> - -================================================================== -\* Prefix Operators -~ -ENABLED -UNCHANGED -[] -<> -SUBSET -UNION -DOMAIN -- - -\* Postfix Operators -\* Predefined -' - -\* Undefined -^+ -^* -^# +UnchangedTest(Foo(_)) == Foo(x) +PrimeTest(Foo(_)) == Foo(x) = x + +Invariant == + /\ EnabledTest(ENABLED) + +ImpliedAction == + /\ UnchangedTest(UNCHANGED) + /\ PrimeTest(') + +Property == [][ImpliedAction]_<<x, y>> + +================================================================== +\* Prefix Operators +~ +ENABLED +UNCHANGED +[] +<> +SUBSET +UNION +DOMAIN +- + +\* Postfix Operators +\* Predefined +' + +\* Undefined +^+ +^* +^# diff --git a/tlatools/test-model/suite/test55.cfg b/tlatools/test-model/suite/test55.cfg index fe7d864f88046c4367c05c018a558362c39fe97c..305c3a68fbd27fb38d68161f05488ca00c1b8202 100644 --- a/tlatools/test-model/suite/test55.cfg +++ b/tlatools/test-model/suite/test55.cfg @@ -1,3 +1,3 @@ -SPECIFICATION Spec -INVARIANT Invariant -PROPERTY InitProperty +SPECIFICATION Spec +INVARIANT Invariant +PROPERTY InitProperty diff --git a/tlatools/test-model/suite/test55.tla b/tlatools/test-model/suite/test55.tla index fd95511e3caad8f32b2dd3be3e3fe8cfa02a4f21..3b94b2d51d54bd4283f59c7737a8e369b478416e 100644 --- a/tlatools/test-model/suite/test55.tla +++ b/tlatools/test-model/suite/test55.tla @@ -1,22 +1,22 @@ -------------------------------- MODULE test55 ------------------------------- -\* Test of ENABLED with INSTANCE semantics -EXTENDS Naturals - -VARIABLE z - -I == INSTANCE test55a WITH x <- z, y <- z - -Init == z = 0 -Next == z' = 1 - z - -Spec == Init /\ [][Next]_z /\ WF_z(Next) -Invariant == /\ I!F - /\ ~I!G - -InitProperty == I!Init -SafeProperty == I!SafeSpec -LiveProperty == I!LiveSpec - -============================================================================= - - +------------------------------- MODULE test55 ------------------------------- +\* Test of ENABLED with INSTANCE semantics +EXTENDS Naturals + +VARIABLE z + +I == INSTANCE test55a WITH x <- z, y <- z + +Init == z = 0 +Next == z' = 1 - z + +Spec == Init /\ [][Next]_z /\ WF_z(Next) +Invariant == /\ I!F + /\ ~I!G + +InitProperty == I!Init +SafeProperty == I!SafeSpec +LiveProperty == I!LiveSpec + +============================================================================= + + diff --git a/tlatools/test-model/suite/test55a.tla b/tlatools/test-model/suite/test55a.tla index bd17db17c8ca799dc92596fd99f1300a7bc8b231..ad6aee45a926630145f1336ac71eb2fccdeb2ff2 100644 --- a/tlatools/test-model/suite/test55a.tla +++ b/tlatools/test-model/suite/test55a.tla @@ -1,14 +1,14 @@ -------------------------------- MODULE test55a ------------------------------ -EXTENDS Naturals -VARIABLES x, y - -F == ENABLED (x'=0 /\ y'=1) -G == ENABLED ((x # y) /\ (x'=0) /\ (y'=1)) - -Init == (x = 0) /\ (y = 0) -Next == /\ x' = 1 - x - /\ y' = y - -SafeSpec == Init /\ [][Next]_<<x,y>> -LiveSpec == SafeSpec /\ WF_<<x,y>>(Next) -============================================================================= +------------------------------- MODULE test55a ------------------------------ +EXTENDS Naturals +VARIABLES x, y + +F == ENABLED (x'=0 /\ y'=1) +G == ENABLED ((x # y) /\ (x'=0) /\ (y'=1)) + +Init == (x = 0) /\ (y = 0) +Next == /\ x' = 1 - x + /\ y' = y + +SafeSpec == Init /\ [][Next]_<<x,y>> +LiveSpec == SafeSpec /\ WF_<<x,y>>(Next) +============================================================================= diff --git a/tlatools/test-model/suite/test56.cfg b/tlatools/test-model/suite/test56.cfg index 59df66b1045c7bbcce67167852fd154f3d81c41e..8a93632b965223198ef42bd956c09e80e1a9dfb5 100644 --- a/tlatools/test-model/suite/test56.cfg +++ b/tlatools/test-model/suite/test56.cfg @@ -1,2 +1,2 @@ -SPECIFICATION Spec +SPECIFICATION Spec PROPERTY Property \ No newline at end of file diff --git a/tlatools/test-model/suite/test56.tla b/tlatools/test-model/suite/test56.tla index 4f204445c4a3d8157babd576089f7b0e5cbf62f1..e44515da94c7d77852bfd7b3994f8e0ceac11bbb 100644 --- a/tlatools/test-model/suite/test56.tla +++ b/tlatools/test-model/suite/test56.tla @@ -1,18 +1,18 @@ -------------------------------- MODULE test56 ------------------------------- -\* Test of subtle INSTANCE semantics -EXTENDS Naturals -VARIABLE x - -I == INSTANCE test56a WITH u <- x - -NotIBangH == (x'=x) /\ I!G(x, x'=x+1) - -Init == \E i \in 1..3 : x = i -Next == x' = 9-x -Spec == Init /\ [][Next]_x - -Property == [][I!H = NotIBangH]_x - -============================================================================= -I!H = (x'=x) /\ ENABLED (u'=x+1 \/ (u'=x /\ u'=x) \/ (u'=x /\ u'=x)) -NotIBangH = (x'=x) /\ ENABLED (x'=x+1 \/ (u'=x /\ x'=x) \/ (u'=x /\ x'=u)) +------------------------------- MODULE test56 ------------------------------- +\* Test of subtle INSTANCE semantics +EXTENDS Naturals +VARIABLE x + +I == INSTANCE test56a WITH u <- x + +NotIBangH == (x'=x) /\ I!G(x, x'=x+1) + +Init == \E i \in 1..3 : x = i +Next == x' = 9-x +Spec == Init /\ [][Next]_x + +Property == [][I!H = NotIBangH]_x + +============================================================================= +I!H = (x'=x) /\ ENABLED (u'=x+1 \/ (u'=x /\ u'=x) \/ (u'=x /\ u'=x)) +NotIBangH = (x'=x) /\ ENABLED (x'=x+1 \/ (u'=x /\ x'=x) \/ (u'=x /\ x'=u)) diff --git a/tlatools/test-model/suite/test56a.tla b/tlatools/test-model/suite/test56a.tla index 521cf1046b8d7dc9b71f0117916beb05f98b665e..449dd447ff88465b7a710a7eb77853c563fce942 100644 --- a/tlatools/test-model/suite/test56a.tla +++ b/tlatools/test-model/suite/test56a.tla @@ -1,7 +1,7 @@ -------------------------------- MODULE test56a ------------------------------ -\* Test of subtle INSTANCE semantics -EXTENDS Naturals -VARIABLE u -G(v, A) == ENABLED (A \/ (u'=u /\ v'=v) \/ (v'=u /\ u'=v)) -H == (u'=u) /\ G(u, u' = u + 1) +------------------------------- MODULE test56a ------------------------------ +\* Test of subtle INSTANCE semantics +EXTENDS Naturals +VARIABLE u +G(v, A) == ENABLED (A \/ (u'=u /\ v'=v) \/ (v'=u /\ u'=v)) +H == (u'=u) /\ G(u, u' = u + 1) ============================================================================= \ No newline at end of file diff --git a/tlatools/test-model/suite/test57.cfg b/tlatools/test-model/suite/test57.cfg index eafb6be0934c428f10a4f7987554ed5e2426af96..e9294d0442019c6b2d506c2a5118da6ffb19b55a 100644 --- a/tlatools/test-model/suite/test57.cfg +++ b/tlatools/test-model/suite/test57.cfg @@ -1,3 +1,3 @@ -SPECIFICATION Spec -INVARIANT Invariant0 Invariant2 Invariant3 Invariant1 +SPECIFICATION Spec +INVARIANT Invariant0 Invariant2 Invariant3 Invariant1 PROPERTY Property \ No newline at end of file diff --git a/tlatools/test-model/suite/test57.tla b/tlatools/test-model/suite/test57.tla index fc9a77c38ed1ab471b60f289c92fe0bc7e8a06a3..08adb6d0e2ac94935105328a0935bc037cbec538 100644 --- a/tlatools/test-model/suite/test57.tla +++ b/tlatools/test-model/suite/test57.tla @@ -1,20 +1,20 @@ -------------------------------- MODULE test57 ------------------------------- -\* Test of subtle INSTANCE semantics -EXTENDS Naturals -VARIABLE x - -I == INSTANCE test57a WITH u <- x, v <- x - -Init == \E i \in 1..3 : x = i -Next == x' = 9-x -Spec == Init /\ [][Next]_x - -Invariant0 == I!B(Next) -Invariant1 == I!C -Invariant2 == ~ I!B(I!A) -Invariant3 == I!D -Property == [][~I!A]_x -============================================================================= -I!C = ENABLED((u'=x) /\ (v' = x+1)) -I!B(I!A) = ENABLED ((x'=x) /\ (x'=x+1)) - +------------------------------- MODULE test57 ------------------------------- +\* Test of subtle INSTANCE semantics +EXTENDS Naturals +VARIABLE x + +I == INSTANCE test57a WITH u <- x, v <- x + +Init == \E i \in 1..3 : x = i +Next == x' = 9-x +Spec == Init /\ [][Next]_x + +Invariant0 == I!B(Next) +Invariant1 == I!C +Invariant2 == ~ I!B(I!A) +Invariant3 == I!D +Property == [][~I!A]_x +============================================================================= +I!C = ENABLED((u'=x) /\ (v' = x+1)) +I!B(I!A) = ENABLED ((x'=x) /\ (x'=x+1)) + diff --git a/tlatools/test-model/suite/test57a.tla b/tlatools/test-model/suite/test57a.tla index e319f592379eeec07234cb18fc43a91305114801..4fde946c021c6d5e2ed2267ef65fa1fdb6376616 100644 --- a/tlatools/test-model/suite/test57a.tla +++ b/tlatools/test-model/suite/test57a.tla @@ -1,9 +1,9 @@ -------------------------------- MODULE test57a ------------------------------ -\* Test of subtle INSTANCE semantics -EXTENDS Naturals -VARIABLES u, v -A == (u'=u) /\ (v'=v+1) -B(d) == ENABLED d -C == B(A) -D == ENABLED A +------------------------------- MODULE test57a ------------------------------ +\* Test of subtle INSTANCE semantics +EXTENDS Naturals +VARIABLES u, v +A == (u'=u) /\ (v'=v+1) +B(d) == ENABLED d +C == B(A) +D == ENABLED A ============================================================================= \ No newline at end of file diff --git a/tlatools/test-model/suite/test58.cfg b/tlatools/test-model/suite/test58.cfg index 56f3b36e2773a56fe267643b6b1678e06c9584eb..8d1c8b69c3fce7bea45c73efd06983e3c419a92f 100644 --- a/tlatools/test-model/suite/test58.cfg +++ b/tlatools/test-model/suite/test58.cfg @@ -1 +1 @@ - + diff --git a/tlatools/test-model/suite/test58.tla b/tlatools/test-model/suite/test58.tla index 514f9353cf3c9a836bb7152f3572b54fc66da5a1..8fff7e580b1e748907f8d3de6e2a3554031c506f 100644 --- a/tlatools/test-model/suite/test58.tla +++ b/tlatools/test-model/suite/test58.tla @@ -1,16 +1,16 @@ -------------------- MODULE test58 -------------------- -\* Test of binary, octal, and hexadecimal numbers - -EXTENDS Naturals - -ASSUME - /\ 63 = \b111111 - /\ 63 = \o77 - /\ 63 = \h3F - /\ 63 = \B111111 - /\ 63 = \O77 - /\ 63 = \H3f - /\ 63 = \H3F - /\ 63 = \h3f - -======================================================= +------------------- MODULE test58 -------------------- +\* Test of binary, octal, and hexadecimal numbers + +EXTENDS Naturals + +ASSUME + /\ 63 = \b111111 + /\ 63 = \o77 + /\ 63 = \h3F + /\ 63 = \B111111 + /\ 63 = \O77 + /\ 63 = \H3f + /\ 63 = \H3F + /\ 63 = \h3f + +======================================================= diff --git a/tlatools/test-model/suite/test59.cfg b/tlatools/test-model/suite/test59.cfg index 9816c74f9b53e2266134e30e7da07fa5392c5384..8e570acdc96c3b5f8e28b4ecccd0273858365db2 100644 --- a/tlatools/test-model/suite/test59.cfg +++ b/tlatools/test-model/suite/test59.cfg @@ -1,2 +1,2 @@ -SPECIFICATION Spec -PROPERTY Liveness +SPECIFICATION Spec +PROPERTY Liveness diff --git a/tlatools/test-model/suite/test59.tla b/tlatools/test-model/suite/test59.tla index 8a1b24ddf2904342cb22317bb7122f775a6de463..f1e1d2dff5279079471423bfa94b06a8450547d1 100644 --- a/tlatools/test-model/suite/test59.tla +++ b/tlatools/test-model/suite/test59.tla @@ -1,18 +1,18 @@ -------------------------------- MODULE test59 ------------------------------- -EXTENDS Naturals -\* Test of INSTANCE inside LET - -VARIABLE y - -Next == LET x == y+1 - M == INSTANCE test59a - IN y' = (M!xplus1 - 1) % 5 - -Init == y = 0 - -Spec == Init /\ [][Next]_y /\ WF_y(Next) - -Invariant == y \in 0..4 -Liveness == []<>(y = 4) - +------------------------------- MODULE test59 ------------------------------- +EXTENDS Naturals +\* Test of INSTANCE inside LET + +VARIABLE y + +Next == LET x == y+1 + M == INSTANCE test59a + IN y' = (M!xplus1 - 1) % 5 + +Init == y = 0 + +Spec == Init /\ [][Next]_y /\ WF_y(Next) + +Invariant == y \in 0..4 +Liveness == []<>(y = 4) + ============================================================================= \ No newline at end of file diff --git a/tlatools/test-model/suite/test59a.tla b/tlatools/test-model/suite/test59a.tla index 2963511f41478b31003db2ae4ff96c17207f1f9d..a5c42c5d2c8769bffa23a0d871a100c4d0799fda 100644 --- a/tlatools/test-model/suite/test59a.tla +++ b/tlatools/test-model/suite/test59a.tla @@ -1,9 +1,9 @@ -------------------------------- MODULE test59a ------------------------------- -EXTENDS Naturals -\* Test of INSTANCE inside LET - -VARIABLE x - -xplus1 == x+1 - +------------------------------- MODULE test59a ------------------------------- +EXTENDS Naturals +\* Test of INSTANCE inside LET + +VARIABLE x + +xplus1 == x+1 + ============================================================================= \ No newline at end of file diff --git a/tlatools/test-model/suite/test60.cfg b/tlatools/test-model/suite/test60.cfg index 56f3b36e2773a56fe267643b6b1678e06c9584eb..8d1c8b69c3fce7bea45c73efd06983e3c419a92f 100644 --- a/tlatools/test-model/suite/test60.cfg +++ b/tlatools/test-model/suite/test60.cfg @@ -1 +1 @@ - + diff --git a/tlatools/test-model/suite/test60.tla b/tlatools/test-model/suite/test60.tla index 49fa97c0d1fed5c3bd5cd8e6259c6b2f98b9ab5a..0fef36a2cd81fa358d639907cb7dee87e547659f 100644 --- a/tlatools/test-model/suite/test60.tla +++ b/tlatools/test-model/suite/test60.tla @@ -1,14 +1,14 @@ --------------------- MODULE test60 -------------------- -(***************************************************************************) -(* Test of handling strings as sequences. *) -(***************************************************************************) - -EXTENDS Sequences, TLC - -ASSUME "abc" \o "def" = "abcdef" -ASSUME Len("abcdef") = 6 -ASSUME "a\\b\"c\nd" = "a\\b\"" \o "c\nd" -ASSUME Len("a\\b\"c\nd") = 7 - -======================================== - +-------------------- MODULE test60 -------------------- +(***************************************************************************) +(* Test of handling strings as sequences. *) +(***************************************************************************) + +EXTENDS Sequences, TLC + +ASSUME "abc" \o "def" = "abcdef" +ASSUME Len("abcdef") = 6 +ASSUME "a\\b\"c\nd" = "a\\b\"" \o "c\nd" +ASSUME Len("a\\b\"c\nd") = 7 + +======================================== + diff --git a/tlatools/test-model/suite/test61.cfg b/tlatools/test-model/suite/test61.cfg index d943a80dfc6f753930e5d1a345b64936e9bdd9d1..d2c069de399c1fe1495c4a2ca92e0320fd53347d 100644 --- a/tlatools/test-model/suite/test61.cfg +++ b/tlatools/test-model/suite/test61.cfg @@ -1,2 +1,2 @@ -SPECIFICATION ISpec -INVARIANT Invariant +SPECIFICATION ISpec +INVARIANT Invariant diff --git a/tlatools/test-model/suite/test61.tla b/tlatools/test-model/suite/test61.tla index 8e43b969e0af483522fc091a310b85327abaa791..bb8de9ead6edc804da3c2325d4a7f3db36a63b9d 100644 --- a/tlatools/test-model/suite/test61.tla +++ b/tlatools/test-model/suite/test61.tla @@ -1,21 +1,21 @@ --------------------- MODULE test61 -------------------- -(***************************************************************************) -(* Test of parametrized INSTANCE *) -(***************************************************************************) -\* Because of bug, it Handles JSpec but not ISpec - -EXTENDS Naturals - -VARIABLE y - -IM(x) == INSTANCE test61a - -ISpec == IM(y)!Spec - -Invariant == y \in 0..4 - -JM == INSTANCE test61a WITH x <- y -JSpec == JM!Spec - -======================================== - +-------------------- MODULE test61 -------------------- +(***************************************************************************) +(* Test of parametrized INSTANCE *) +(***************************************************************************) +\* Because of bug, it Handles JSpec but not ISpec + +EXTENDS Naturals + +VARIABLE y + +IM(x) == INSTANCE test61a + +ISpec == IM(y)!Spec + +Invariant == y \in 0..4 + +JM == INSTANCE test61a WITH x <- y +JSpec == JM!Spec + +======================================== + diff --git a/tlatools/test-model/suite/test61a.tla b/tlatools/test-model/suite/test61a.tla index 91dcc0541cabe2770f338cd068d5325bcf392076..c7f83a41bb788675f361125b200224a40b167f73 100644 --- a/tlatools/test-model/suite/test61a.tla +++ b/tlatools/test-model/suite/test61a.tla @@ -1,11 +1,11 @@ --------------------- MODULE test61a -------------------- -(***************************************************************************) -(* Test of parametrized INSTANCE *) -(***************************************************************************) - -EXTENDS Naturals - -VARIABLE x - -Spec == (x = 0) /\ [][x'=(x+1)%5]_x -======================================== +-------------------- MODULE test61a -------------------- +(***************************************************************************) +(* Test of parametrized INSTANCE *) +(***************************************************************************) + +EXTENDS Naturals + +VARIABLE x + +Spec == (x = 0) /\ [][x'=(x+1)%5]_x +======================================== diff --git a/tlatools/test-model/suite/test62.cfg b/tlatools/test-model/suite/test62.cfg index d3f5a12faa99758192ecc4ed3fc22c9249232e86..8b137891791fe96927ad78e64b0aad7bded08bdc 100644 --- a/tlatools/test-model/suite/test62.cfg +++ b/tlatools/test-model/suite/test62.cfg @@ -1 +1 @@ - + diff --git a/tlatools/test-model/suite/test62.tla b/tlatools/test-model/suite/test62.tla index eb18a3e5df15d72c29a4e6320f67148c84ae223e..ccff29bbedd611998e86e8be370b1917fd446e04 100644 --- a/tlatools/test-model/suite/test62.tla +++ b/tlatools/test-model/suite/test62.tla @@ -1,5 +1,5 @@ ------------------------ MODULE test62 -------------------------- -EXTENDS TLC -ASSUME Print("Should print this", TRUE) -ASSUME PrintT("And this") -================================================================= +----------------------- MODULE test62 -------------------------- +EXTENDS TLC +ASSUME Print("Should print this", TRUE) +ASSUME PrintT("And this") +================================================================= diff --git a/tlatools/test-model/suite/test64.cfg b/tlatools/test-model/suite/test64.cfg index 290675219f918e816d76cd9539ec1f1bc60323f2..4d07be4bdd383dc53e46a5cbb701afa9dba3c30d 100644 --- a/tlatools/test-model/suite/test64.cfg +++ b/tlatools/test-model/suite/test64.cfg @@ -1 +1 @@ -SPECIFICATION Spec +SPECIFICATION Spec diff --git a/tlatools/test-model/suite/test64.tla b/tlatools/test-model/suite/test64.tla index 741839b0f33e14517bd90ea106573b7085c5ea1e..5e66d028eafb7af9c2594c394f3cc4a10f874203 100644 --- a/tlatools/test-model/suite/test64.tla +++ b/tlatools/test-model/suite/test64.tla @@ -1,8 +1,8 @@ --------------------------------- MODULE test64 -------------------------------- -VARIABLE y - -I == INSTANCE test64a WITH x <- y - \* Changed from Test64a on 12 June 2014 because that's now illegal - -Spec == I!Spec -======================================================================= +-------------------------------- MODULE test64 -------------------------------- +VARIABLE y + +I == INSTANCE test64a WITH x <- y + \* Changed from Test64a on 12 June 2014 because that's now illegal + +Spec == I!Spec +======================================================================= diff --git a/tlatools/test-model/suite/test64a.cfg b/tlatools/test-model/suite/test64a.cfg index 290675219f918e816d76cd9539ec1f1bc60323f2..4d07be4bdd383dc53e46a5cbb701afa9dba3c30d 100644 --- a/tlatools/test-model/suite/test64a.cfg +++ b/tlatools/test-model/suite/test64a.cfg @@ -1 +1 @@ -SPECIFICATION Spec +SPECIFICATION Spec diff --git a/tlatools/test-model/suite/test64a.tla b/tlatools/test-model/suite/test64a.tla index af9d702a422591fe87245d9e3ddd9bdbb04d4b24..c8a0994d90665a3bb9c5e1fb80d527b77fa61f6f 100644 --- a/tlatools/test-model/suite/test64a.tla +++ b/tlatools/test-model/suite/test64a.tla @@ -1,8 +1,8 @@ ------------------------ MODULE test64a ----------------------- -VARIABLE x - -ASet == {r \in [{0} -> {0}] : x} - -Spec == x = TRUE /\ [][x' = (ASet = {})]_x -============================================================= +----------------------- MODULE test64a ----------------------- +VARIABLE x + +ASet == {r \in [{0} -> {0}] : x} + +Spec == x = TRUE /\ [][x' = (ASet = {})]_x +============================================================= \ No newline at end of file diff --git a/tlatools/test-model/suite/test65.cfg b/tlatools/test-model/suite/test65.cfg index d996c9a48b652401c2185136d4bab906b05f1d5e..1446df75569d1fca6a285c43b13fb3d99699e1f8 100644 --- a/tlatools/test-model/suite/test65.cfg +++ b/tlatools/test-model/suite/test65.cfg @@ -1 +1 @@ -CONSTANT c = "a" +CONSTANT c = "a" diff --git a/tlatools/test-model/suite/test65.tla b/tlatools/test-model/suite/test65.tla index 6fd8b5802763bf090aaeec90be7a66964e6ae668..ea1615d4a5ebee5d42b25f3db547d961ebcfad95 100644 --- a/tlatools/test-model/suite/test65.tla +++ b/tlatools/test-model/suite/test65.tla @@ -1,8 +1,8 @@ --------------------------------- MODULE test65 -------------------------------- -EXTENDS test65a - -I == INSTANCE test65a WITH c <- 42 -J == INSTANCE test65a WITH c <- 44 -ASSUME /\ <<I!foo, J!foo>> = <<42, 44>> - /\ foo = c -======================================================================= +-------------------------------- MODULE test65 -------------------------------- +EXTENDS test65a + +I == INSTANCE test65a WITH c <- 42 +J == INSTANCE test65a WITH c <- 44 +ASSUME /\ <<I!foo, J!foo>> = <<42, 44>> + /\ foo = c +======================================================================= diff --git a/tlatools/test-model/suite/test65a.cfg b/tlatools/test-model/suite/test65a.cfg index d996c9a48b652401c2185136d4bab906b05f1d5e..1446df75569d1fca6a285c43b13fb3d99699e1f8 100644 --- a/tlatools/test-model/suite/test65a.cfg +++ b/tlatools/test-model/suite/test65a.cfg @@ -1 +1 @@ -CONSTANT c = "a" +CONSTANT c = "a" diff --git a/tlatools/test-model/suite/test65a.tla b/tlatools/test-model/suite/test65a.tla index 86da3688faef5d3fa02c0a85448010e04f782b95..c82bd7513ae6ec612280ac37a5063262cbec4369 100644 --- a/tlatools/test-model/suite/test65a.tla +++ b/tlatools/test-model/suite/test65a.tla @@ -1,7 +1,7 @@ ------------------------ MODULE test65a ----------------------- -CONSTANT c - -bar == c -foo == bar -============================================================= +----------------------- MODULE test65a ----------------------- +CONSTANT c + +bar == c +foo == bar +============================================================= \ No newline at end of file diff --git a/tlatools/test-model/symmetry/ErrorTraceConstructionPhases.png b/tlatools/test-model/symmetry/ErrorTraceConstructionPhases.png index 63209449e9b3237e960f8d14e05dc557de4d4d5f..9a87f95c1080372fea4548fa09851cdb997b9303 100644 Binary files a/tlatools/test-model/symmetry/ErrorTraceConstructionPhases.png and b/tlatools/test-model/symmetry/ErrorTraceConstructionPhases.png differ diff --git a/tlatools/test-model/symmetry/MC_Graph.png b/tlatools/test-model/symmetry/MC_Graph.png index d0d2ef0ac98d6f8c53f924427ff82ee246d4082d..ca330f79ea241615b55cca76c3b6ab3c3acd8ead 100644 Binary files a/tlatools/test-model/symmetry/MC_Graph.png and b/tlatools/test-model/symmetry/MC_Graph.png differ diff --git a/tlatools/test-model/symmetry/MCa_Graph.png b/tlatools/test-model/symmetry/MCa_Graph.png index 072c9c3f70e2c33ebb3c53b353e22c176fe55fa3..c4944d2074755519584364eef815feca0f8d6c7a 100644 Binary files a/tlatools/test-model/symmetry/MCa_Graph.png and b/tlatools/test-model/symmetry/MCa_Graph.png differ diff --git a/tlatools/test-model/symmetry/NQ/MC.tla b/tlatools/test-model/symmetry/NQ/MC.tla index ef950829c17ba7720e55ee1e4a1da4d1d02ec906..78bbe6b0fee0b7560146e68c33eaae4b0f0a675f 100644 --- a/tlatools/test-model/symmetry/NQ/MC.tla +++ b/tlatools/test-model/symmetry/NQ/MC.tla @@ -64,5 +64,5 @@ prop_14467714433621121000 == (\E e \in elts : e.data = v2) ~> (\E d \in DeQers : deq[d] = v2) ---- ============================================================================= -\* Modification History -\* Created Thu Nov 05 16:57:23 PST 2015 by lamport +\* Modification History +\* Created Thu Nov 05 16:57:23 PST 2015 by lamport diff --git a/tlatools/test-model/symmetry/NQ/MCa.tla b/tlatools/test-model/symmetry/NQ/MCa.tla index ba6600dc97f8d85e69b2a4c0ff9c1fccb005939c..76e9f8de9d9e3def7841e3fcee240631ea6972fd 100644 --- a/tlatools/test-model/symmetry/NQ/MCa.tla +++ b/tlatools/test-model/symmetry/NQ/MCa.tla @@ -64,5 +64,5 @@ prop_14467710210701039000 == (\E e \in EnQers : enq[e] = v2) ~> (\E d \in DeQers : deq[d] = v2) ---- ============================================================================= -\* Modification History -\* Created Thu Nov 05 16:50:21 PST 2015 by lamport +\* Modification History +\* Created Thu Nov 05 16:50:21 PST 2015 by lamport diff --git a/tlatools/test-model/symmetry/NQ/NQSpec.tla b/tlatools/test-model/symmetry/NQ/NQSpec.tla index 985e0634adbd5d0f7938685fbd0ba2d9ce3b829f..09774ed31418f2d0b6d970ac2b57a317332c2557 100644 --- a/tlatools/test-model/symmetry/NQ/NQSpec.tla +++ b/tlatools/test-model/symmetry/NQ/NQSpec.tla @@ -1,84 +1,84 @@ -------------------------------- MODULE NQSpec ------------------------------- -EXTENDS Integers, Sequences - -CONSTANTS EnQers, DeQers, Data, InitData, Ids - -ASSUME InitData \in Data - -Done == CHOOSE D : D \notin Data -Busy == CHOOSE D : D \notin Data -NotAnId == CHOOSE i : i \notin Ids -NotData == CHOOSE D : D \notin Data -Elements == [data : Data, id : Ids] -NotAnElement == CHOOSE E : E \notin Elements - -VARIABLES enq, deq, elts, after, adding -vars == <<enq, deq, elts, after, adding>> - - - -TypeOK == /\ enq \in [EnQers -> Data \cup {Done}] - /\ deq \in [DeQers -> Data \cup {Busy}] - /\ elts \in SUBSET Elements - /\ after \in [elts -> SUBSET elts] - /\ adding \in [EnQers -> Elements \cup {NotAnElement}] - -Init == /\ enq = [e \in EnQers |-> Done] - /\ deq = [d \in DeQers |-> InitData] - /\ elts = {} - /\ after = << >> - /\ adding = [e \in EnQers |-> NotAnElement] ------------------------------------------------------------------------------ - -Assign(var, idx, val) == var' = [var EXCEPT ![idx] = val] - -UnusedIds == Ids \ {el.id : el \in elts} - -AddElt(el) == - /\ elts' = elts \cup {el} - /\ after' = [x \in elts' |-> - IF x = el THEN elts \ {adding[e] : e \in EnQers} - ELSE after[x] ] - -RemoveElt(el) == - /\ elts' = elts \ {el} - /\ after' = [x \in elts' |-> after[x] \ {el}] - -minimalElts == {el \in elts : after[el] = {}} - -BeginEnq(e) == /\ enq[e] = Done - /\ \E D \in Data, id \in UnusedIds : - LET el == [data |-> D, id |-> id] - IN /\ Assign(enq, e, D) - /\ AddElt(el) - /\ Assign(adding, e, el) - /\ UNCHANGED deq - -EndEnq(e) == /\ enq[e] # Done - /\ Assign(enq, e, Done) - /\ Assign(adding, e, NotAnElement) - /\ UNCHANGED <<deq, elts, after>> - -\* enq, deq, elts, after, adding -BeginDeq(d) == /\ deq[d] # Busy - /\ Assign(deq, d, Busy) - /\ UNCHANGED <<enq, elts, after, adding>> - -EndDeq(d) == /\ deq[d] = Busy - /\ \E el \in minimalElts : - /\ RemoveElt(el) - /\ Assign(deq, d, el.data) - /\ UNCHANGED <<enq, adding>> - -Next == \/ \E e \in EnQers : BeginEnq(e) \/ EndEnq(e) - \/ \E d \in DeQers : BeginDeq(d) \/ EndDeq(d) - -Liveness == /\ \A e \in EnQers : WF_vars(BeginEnq(e) \/ EndEnq(e)) - /\ \A d \in DeQers : WF_vars(BeginDeq(d) \/ EndDeq(d)) - -Spec == Init /\ [][Next]_vars /\ Liveness - +------------------------------- MODULE NQSpec ------------------------------- +EXTENDS Integers, Sequences + +CONSTANTS EnQers, DeQers, Data, InitData, Ids + +ASSUME InitData \in Data + +Done == CHOOSE D : D \notin Data +Busy == CHOOSE D : D \notin Data +NotAnId == CHOOSE i : i \notin Ids +NotData == CHOOSE D : D \notin Data +Elements == [data : Data, id : Ids] +NotAnElement == CHOOSE E : E \notin Elements + +VARIABLES enq, deq, elts, after, adding +vars == <<enq, deq, elts, after, adding>> + + + +TypeOK == /\ enq \in [EnQers -> Data \cup {Done}] + /\ deq \in [DeQers -> Data \cup {Busy}] + /\ elts \in SUBSET Elements + /\ after \in [elts -> SUBSET elts] + /\ adding \in [EnQers -> Elements \cup {NotAnElement}] + +Init == /\ enq = [e \in EnQers |-> Done] + /\ deq = [d \in DeQers |-> InitData] + /\ elts = {} + /\ after = << >> + /\ adding = [e \in EnQers |-> NotAnElement] +----------------------------------------------------------------------------- + +Assign(var, idx, val) == var' = [var EXCEPT ![idx] = val] + +UnusedIds == Ids \ {el.id : el \in elts} + +AddElt(el) == + /\ elts' = elts \cup {el} + /\ after' = [x \in elts' |-> + IF x = el THEN elts \ {adding[e] : e \in EnQers} + ELSE after[x] ] + +RemoveElt(el) == + /\ elts' = elts \ {el} + /\ after' = [x \in elts' |-> after[x] \ {el}] + +minimalElts == {el \in elts : after[el] = {}} + +BeginEnq(e) == /\ enq[e] = Done + /\ \E D \in Data, id \in UnusedIds : + LET el == [data |-> D, id |-> id] + IN /\ Assign(enq, e, D) + /\ AddElt(el) + /\ Assign(adding, e, el) + /\ UNCHANGED deq + +EndEnq(e) == /\ enq[e] # Done + /\ Assign(enq, e, Done) + /\ Assign(adding, e, NotAnElement) + /\ UNCHANGED <<deq, elts, after>> + +\* enq, deq, elts, after, adding +BeginDeq(d) == /\ deq[d] # Busy + /\ Assign(deq, d, Busy) + /\ UNCHANGED <<enq, elts, after, adding>> + +EndDeq(d) == /\ deq[d] = Busy + /\ \E el \in minimalElts : + /\ RemoveElt(el) + /\ Assign(deq, d, el.data) + /\ UNCHANGED <<enq, adding>> + +Next == \/ \E e \in EnQers : BeginEnq(e) \/ EndEnq(e) + \/ \E d \in DeQers : BeginDeq(d) \/ EndDeq(d) + +Liveness == /\ \A e \in EnQers : WF_vars(BeginEnq(e) \/ EndEnq(e)) + /\ \A d \in DeQers : WF_vars(BeginDeq(d) \/ EndDeq(d)) + +Spec == Init /\ [][Next]_vars /\ Liveness + ============================================================================= -\* Modification History -\* Last modified Thu Nov 05 16:16:15 PST 2015 by lamport -\* Created Thu Nov 05 15:07:25 PST 2015 by lamport +\* Modification History +\* Last modified Thu Nov 05 16:16:15 PST 2015 by lamport +\* Created Thu Nov 05 15:07:25 PST 2015 by lamport diff --git a/tlatools/test-model/symmetry/TableauSymmetry.png b/tlatools/test-model/symmetry/TableauSymmetry.png deleted file mode 100644 index f8728c24966313e1c35a748d4087d2ddc5903fdc..0000000000000000000000000000000000000000 Binary files a/tlatools/test-model/symmetry/TableauSymmetry.png and /dev/null differ diff --git a/tlatools/test-model/symmetry/TableauSymmetryDisabled.png b/tlatools/test-model/symmetry/TableauSymmetryDisabled.png index 3e0726a6ea541ac93c7f8d7711858c8404d26951..ea8343cbd6d4ad9494a0f0b456f6bb5faf58360e 100644 Binary files a/tlatools/test-model/symmetry/TableauSymmetryDisabled.png and b/tlatools/test-model/symmetry/TableauSymmetryDisabled.png differ diff --git a/tlatools/test-model/symmetry/UnsymmetricAWithSymmetry.png b/tlatools/test-model/symmetry/UnsymmetricAWithSymmetry.png index d6577f415881f559328f751ce0f4da4ebe491fb3..dceb2092db2b2ec7a633f63a20f3e3ac4d7ff2ea 100644 Binary files a/tlatools/test-model/symmetry/UnsymmetricAWithSymmetry.png and b/tlatools/test-model/symmetry/UnsymmetricAWithSymmetry.png differ diff --git a/tlatools/test-model/symmetry/UnsymmetricAWithoutSymmetry.png b/tlatools/test-model/symmetry/UnsymmetricAWithoutSymmetry.png index f63daa7fbda24acd2fcfaf3594606669a08aea5d..47bb11b146cb7a64522bb3df45c769e73d71107a 100644 Binary files a/tlatools/test-model/symmetry/UnsymmetricAWithoutSymmetry.png and b/tlatools/test-model/symmetry/UnsymmetricAWithoutSymmetry.png differ diff --git a/tlatools/test-model/symmetry/UnsymmetricBWithSymmetry.png b/tlatools/test-model/symmetry/UnsymmetricBWithSymmetry.png index 8cba463e0c3a6065f1677c29f8e43450f5b39eaa..5c8b7da1242badefaf7eaab33930c4e537727d83 100644 Binary files a/tlatools/test-model/symmetry/UnsymmetricBWithSymmetry.png and b/tlatools/test-model/symmetry/UnsymmetricBWithSymmetry.png differ diff --git a/tlatools/test-model/symmetry/UnsymmetricBWithoutSymmetry.png b/tlatools/test-model/symmetry/UnsymmetricBWithoutSymmetry.png index 360660991fb15ce163ca79d39b0fbddb192ffaaf..47242297c74fd5ad0abba3e90e3ff1b9996e13f1 100644 Binary files a/tlatools/test-model/symmetry/UnsymmetricBWithoutSymmetry.png and b/tlatools/test-model/symmetry/UnsymmetricBWithoutSymmetry.png differ diff --git a/tlatools/test-model/test52.cfg b/tlatools/test-model/test52.cfg index 8990f16d455df1338b40f248faa8eb41101160d1..942df65a55fdabbd31d3495a5c5124ef762101af 100644 --- a/tlatools/test-model/test52.cfg +++ b/tlatools/test-model/test52.cfg @@ -1,6 +1,6 @@ -SPECIFICATION Spec -PROPERTY Property -\* The Invariant is commented because of a known bug in TLC. -\* If this bug is ever addressed, Invariant can be re-enabled -\* and the test test52enabled be deleted. -\*INVARIANT Invariant +SPECIFICATION Spec +PROPERTY Property +\* The Invariant is commented because of a known bug in TLC. +\* If this bug is ever addressed, Invariant can be re-enabled +\* and the test test52enabled be deleted. +\*INVARIANT Invariant diff --git a/tlatools/test-model/test52.tla b/tlatools/test-model/test52.tla index fca1986e07ac0a46c857d22cf49eb36482e08e21..0cf62f56535b99a564eee848238b31b57ea68d98 100644 --- a/tlatools/test-model/test52.tla +++ b/tlatools/test-model/test52.tla @@ -1,71 +1,71 @@ ----------------------- MODULE test52 ----------------------- - -\* Test of prefix and postfix operators as arguments - -EXTENDS TLC - -VARIABLES x, y - -BoxTest(-._) == -(x=0) -Foo1 == BoxTest([]) -Foo2 == BoxTest(<>) - --. a == {{"a"}, {"b"}} \ a -a ^+ == {{"a"}, {"b"}} \ a -a ^* == {{"a"}, {"b"}} \ a -a ^# == {{"a"}, {"b"}} \ a - -SetOpTest(Foo(_)) == Foo({{"b"}, {"c"}}) -DomainTest(Foo(_)) == Foo([i\in {"a", "b"} |-> i]) - -ASSUME - /\ Print("Test1 Begun", TRUE) - /\ SetOpTest(-.) = - {{"b"}, {"c"}} - /\ SetOpTest(^+) = {{"b"}, {"c"}} ^+ - /\ SetOpTest(^*) = {{"b"}, {"c"}} ^* - /\ SetOpTest(^#) = {{"b"}, {"c"}} ^# - /\ SetOpTest(SUBSET) = SUBSET {{"b"}, {"c"}} - /\ SetOpTest(UNION) = UNION {{"b"}, {"c"}} - /\ DomainTest(DOMAIN) = DOMAIN [i\in {"a", "b"} |-> i] - /\ Print("Test1 Finished", TRUE) - - -Init == /\ x = {"a"} - /\ y = {"a"} -Next == /\ x'= x \cup {"a"} - /\ y'= y \cup {"b"} -Spec == Init /\ [][Next]_<<x, y>> - -EnabledTest(Foo(_)) == Foo(x'=x) -UnchangedTest(Foo(_)) == Foo(x) -PrimeTest(Foo(_)) == Foo(x) = x - -Invariant == - /\ EnabledTest(ENABLED) - -ImpliedAction == - /\ UnchangedTest(UNCHANGED) - /\ PrimeTest(') - -Property == [][ImpliedAction]_<<x, y>> - -================================================================== -\* Prefix Operators -~ -ENABLED -UNCHANGED -[] -<> -SUBSET -UNION -DOMAIN -- - -\* Postfix Operators -\* Predefined -' - -\* Undefined -^+ -^* -^# +---------------------- MODULE test52 ----------------------- + +\* Test of prefix and postfix operators as arguments + +EXTENDS TLC + +VARIABLES x, y + +BoxTest(-._) == -(x=0) +Foo1 == BoxTest([]) +Foo2 == BoxTest(<>) + +-. a == {{"a"}, {"b"}} \ a +a ^+ == {{"a"}, {"b"}} \ a +a ^* == {{"a"}, {"b"}} \ a +a ^# == {{"a"}, {"b"}} \ a + +SetOpTest(Foo(_)) == Foo({{"b"}, {"c"}}) +DomainTest(Foo(_)) == Foo([i\in {"a", "b"} |-> i]) + +ASSUME + /\ Print("Test1 Begun", TRUE) + /\ SetOpTest(-.) = - {{"b"}, {"c"}} + /\ SetOpTest(^+) = {{"b"}, {"c"}} ^+ + /\ SetOpTest(^*) = {{"b"}, {"c"}} ^* + /\ SetOpTest(^#) = {{"b"}, {"c"}} ^# + /\ SetOpTest(SUBSET) = SUBSET {{"b"}, {"c"}} + /\ SetOpTest(UNION) = UNION {{"b"}, {"c"}} + /\ DomainTest(DOMAIN) = DOMAIN [i\in {"a", "b"} |-> i] + /\ Print("Test1 Finished", TRUE) + + +Init == /\ x = {"a"} + /\ y = {"a"} +Next == /\ x'= x \cup {"a"} + /\ y'= y \cup {"b"} +Spec == Init /\ [][Next]_<<x, y>> + +EnabledTest(Foo(_)) == Foo(x'=x) +UnchangedTest(Foo(_)) == Foo(x) +PrimeTest(Foo(_)) == Foo(x) = x + +Invariant == + /\ EnabledTest(ENABLED) + +ImpliedAction == + /\ UnchangedTest(UNCHANGED) + /\ PrimeTest(') + +Property == [][ImpliedAction]_<<x, y>> + +================================================================== +\* Prefix Operators +~ +ENABLED +UNCHANGED +[] +<> +SUBSET +UNION +DOMAIN +- + +\* Postfix Operators +\* Predefined +' + +\* Undefined +^+ +^* +^# diff --git a/tlatools/test-model/test55.cfg b/tlatools/test-model/test55.cfg index fe7d864f88046c4367c05c018a558362c39fe97c..305c3a68fbd27fb38d68161f05488ca00c1b8202 100644 --- a/tlatools/test-model/test55.cfg +++ b/tlatools/test-model/test55.cfg @@ -1,3 +1,3 @@ -SPECIFICATION Spec -INVARIANT Invariant -PROPERTY InitProperty +SPECIFICATION Spec +INVARIANT Invariant +PROPERTY InitProperty diff --git a/tlatools/test-model/test55.tla b/tlatools/test-model/test55.tla index fd95511e3caad8f32b2dd3be3e3fe8cfa02a4f21..3b94b2d51d54bd4283f59c7737a8e369b478416e 100644 --- a/tlatools/test-model/test55.tla +++ b/tlatools/test-model/test55.tla @@ -1,22 +1,22 @@ -------------------------------- MODULE test55 ------------------------------- -\* Test of ENABLED with INSTANCE semantics -EXTENDS Naturals - -VARIABLE z - -I == INSTANCE test55a WITH x <- z, y <- z - -Init == z = 0 -Next == z' = 1 - z - -Spec == Init /\ [][Next]_z /\ WF_z(Next) -Invariant == /\ I!F - /\ ~I!G - -InitProperty == I!Init -SafeProperty == I!SafeSpec -LiveProperty == I!LiveSpec - -============================================================================= - - +------------------------------- MODULE test55 ------------------------------- +\* Test of ENABLED with INSTANCE semantics +EXTENDS Naturals + +VARIABLE z + +I == INSTANCE test55a WITH x <- z, y <- z + +Init == z = 0 +Next == z' = 1 - z + +Spec == Init /\ [][Next]_z /\ WF_z(Next) +Invariant == /\ I!F + /\ ~I!G + +InitProperty == I!Init +SafeProperty == I!SafeSpec +LiveProperty == I!LiveSpec + +============================================================================= + + diff --git a/tlatools/test-model/test55a.tla b/tlatools/test-model/test55a.tla index bd17db17c8ca799dc92596fd99f1300a7bc8b231..ad6aee45a926630145f1336ac71eb2fccdeb2ff2 100644 --- a/tlatools/test-model/test55a.tla +++ b/tlatools/test-model/test55a.tla @@ -1,14 +1,14 @@ -------------------------------- MODULE test55a ------------------------------ -EXTENDS Naturals -VARIABLES x, y - -F == ENABLED (x'=0 /\ y'=1) -G == ENABLED ((x # y) /\ (x'=0) /\ (y'=1)) - -Init == (x = 0) /\ (y = 0) -Next == /\ x' = 1 - x - /\ y' = y - -SafeSpec == Init /\ [][Next]_<<x,y>> -LiveSpec == SafeSpec /\ WF_<<x,y>>(Next) -============================================================================= +------------------------------- MODULE test55a ------------------------------ +EXTENDS Naturals +VARIABLES x, y + +F == ENABLED (x'=0 /\ y'=1) +G == ENABLED ((x # y) /\ (x'=0) /\ (y'=1)) + +Init == (x = 0) /\ (y = 0) +Next == /\ x' = 1 - x + /\ y' = y + +SafeSpec == Init /\ [][Next]_<<x,y>> +LiveSpec == SafeSpec /\ WF_<<x,y>>(Next) +============================================================================= diff --git a/tlatools/test-model/test56.cfg b/tlatools/test-model/test56.cfg index 59df66b1045c7bbcce67167852fd154f3d81c41e..8a93632b965223198ef42bd956c09e80e1a9dfb5 100644 --- a/tlatools/test-model/test56.cfg +++ b/tlatools/test-model/test56.cfg @@ -1,2 +1,2 @@ -SPECIFICATION Spec +SPECIFICATION Spec PROPERTY Property \ No newline at end of file diff --git a/tlatools/test-model/test56.tla b/tlatools/test-model/test56.tla index 4f204445c4a3d8157babd576089f7b0e5cbf62f1..e44515da94c7d77852bfd7b3994f8e0ceac11bbb 100644 --- a/tlatools/test-model/test56.tla +++ b/tlatools/test-model/test56.tla @@ -1,18 +1,18 @@ -------------------------------- MODULE test56 ------------------------------- -\* Test of subtle INSTANCE semantics -EXTENDS Naturals -VARIABLE x - -I == INSTANCE test56a WITH u <- x - -NotIBangH == (x'=x) /\ I!G(x, x'=x+1) - -Init == \E i \in 1..3 : x = i -Next == x' = 9-x -Spec == Init /\ [][Next]_x - -Property == [][I!H = NotIBangH]_x - -============================================================================= -I!H = (x'=x) /\ ENABLED (u'=x+1 \/ (u'=x /\ u'=x) \/ (u'=x /\ u'=x)) -NotIBangH = (x'=x) /\ ENABLED (x'=x+1 \/ (u'=x /\ x'=x) \/ (u'=x /\ x'=u)) +------------------------------- MODULE test56 ------------------------------- +\* Test of subtle INSTANCE semantics +EXTENDS Naturals +VARIABLE x + +I == INSTANCE test56a WITH u <- x + +NotIBangH == (x'=x) /\ I!G(x, x'=x+1) + +Init == \E i \in 1..3 : x = i +Next == x' = 9-x +Spec == Init /\ [][Next]_x + +Property == [][I!H = NotIBangH]_x + +============================================================================= +I!H = (x'=x) /\ ENABLED (u'=x+1 \/ (u'=x /\ u'=x) \/ (u'=x /\ u'=x)) +NotIBangH = (x'=x) /\ ENABLED (x'=x+1 \/ (u'=x /\ x'=x) \/ (u'=x /\ x'=u)) diff --git a/tlatools/test-model/test56a.tla b/tlatools/test-model/test56a.tla index 521cf1046b8d7dc9b71f0117916beb05f98b665e..449dd447ff88465b7a710a7eb77853c563fce942 100644 --- a/tlatools/test-model/test56a.tla +++ b/tlatools/test-model/test56a.tla @@ -1,7 +1,7 @@ -------------------------------- MODULE test56a ------------------------------ -\* Test of subtle INSTANCE semantics -EXTENDS Naturals -VARIABLE u -G(v, A) == ENABLED (A \/ (u'=u /\ v'=v) \/ (v'=u /\ u'=v)) -H == (u'=u) /\ G(u, u' = u + 1) +------------------------------- MODULE test56a ------------------------------ +\* Test of subtle INSTANCE semantics +EXTENDS Naturals +VARIABLE u +G(v, A) == ENABLED (A \/ (u'=u /\ v'=v) \/ (v'=u /\ u'=v)) +H == (u'=u) /\ G(u, u' = u + 1) ============================================================================= \ No newline at end of file diff --git a/tlatools/test-model/test57.cfg b/tlatools/test-model/test57.cfg index 1c93dc177bbf3221d89d0e33bbdccfd430a54c82..1b03e11d2bb2c543031f557793dc2996896d77aa 100644 --- a/tlatools/test-model/test57.cfg +++ b/tlatools/test-model/test57.cfg @@ -1,3 +1,3 @@ -SPECIFICATION Spec -INVARIANT Invariant0 Invariant2 Invariant3 Invariant1 +SPECIFICATION Spec +INVARIANT Invariant0 Invariant2 Invariant3 Invariant1 PROPERTY Property \ No newline at end of file diff --git a/tlatools/test-model/test57.tla b/tlatools/test-model/test57.tla index fc9a77c38ed1ab471b60f289c92fe0bc7e8a06a3..08adb6d0e2ac94935105328a0935bc037cbec538 100644 --- a/tlatools/test-model/test57.tla +++ b/tlatools/test-model/test57.tla @@ -1,20 +1,20 @@ -------------------------------- MODULE test57 ------------------------------- -\* Test of subtle INSTANCE semantics -EXTENDS Naturals -VARIABLE x - -I == INSTANCE test57a WITH u <- x, v <- x - -Init == \E i \in 1..3 : x = i -Next == x' = 9-x -Spec == Init /\ [][Next]_x - -Invariant0 == I!B(Next) -Invariant1 == I!C -Invariant2 == ~ I!B(I!A) -Invariant3 == I!D -Property == [][~I!A]_x -============================================================================= -I!C = ENABLED((u'=x) /\ (v' = x+1)) -I!B(I!A) = ENABLED ((x'=x) /\ (x'=x+1)) - +------------------------------- MODULE test57 ------------------------------- +\* Test of subtle INSTANCE semantics +EXTENDS Naturals +VARIABLE x + +I == INSTANCE test57a WITH u <- x, v <- x + +Init == \E i \in 1..3 : x = i +Next == x' = 9-x +Spec == Init /\ [][Next]_x + +Invariant0 == I!B(Next) +Invariant1 == I!C +Invariant2 == ~ I!B(I!A) +Invariant3 == I!D +Property == [][~I!A]_x +============================================================================= +I!C = ENABLED((u'=x) /\ (v' = x+1)) +I!B(I!A) = ENABLED ((x'=x) /\ (x'=x+1)) + diff --git a/tlatools/test-model/test57a.tla b/tlatools/test-model/test57a.tla index e319f592379eeec07234cb18fc43a91305114801..4fde946c021c6d5e2ed2267ef65fa1fdb6376616 100644 --- a/tlatools/test-model/test57a.tla +++ b/tlatools/test-model/test57a.tla @@ -1,9 +1,9 @@ -------------------------------- MODULE test57a ------------------------------ -\* Test of subtle INSTANCE semantics -EXTENDS Naturals -VARIABLES u, v -A == (u'=u) /\ (v'=v+1) -B(d) == ENABLED d -C == B(A) -D == ENABLED A +------------------------------- MODULE test57a ------------------------------ +\* Test of subtle INSTANCE semantics +EXTENDS Naturals +VARIABLES u, v +A == (u'=u) /\ (v'=v+1) +B(d) == ENABLED d +C == B(A) +D == ENABLED A ============================================================================= \ No newline at end of file diff --git a/tlatools/test-model/test59.cfg b/tlatools/test-model/test59.cfg index 9816c74f9b53e2266134e30e7da07fa5392c5384..8e570acdc96c3b5f8e28b4ecccd0273858365db2 100644 --- a/tlatools/test-model/test59.cfg +++ b/tlatools/test-model/test59.cfg @@ -1,2 +1,2 @@ -SPECIFICATION Spec -PROPERTY Liveness +SPECIFICATION Spec +PROPERTY Liveness diff --git a/tlatools/test-model/test59.tla b/tlatools/test-model/test59.tla index 8a1b24ddf2904342cb22317bb7122f775a6de463..f1e1d2dff5279079471423bfa94b06a8450547d1 100644 --- a/tlatools/test-model/test59.tla +++ b/tlatools/test-model/test59.tla @@ -1,18 +1,18 @@ -------------------------------- MODULE test59 ------------------------------- -EXTENDS Naturals -\* Test of INSTANCE inside LET - -VARIABLE y - -Next == LET x == y+1 - M == INSTANCE test59a - IN y' = (M!xplus1 - 1) % 5 - -Init == y = 0 - -Spec == Init /\ [][Next]_y /\ WF_y(Next) - -Invariant == y \in 0..4 -Liveness == []<>(y = 4) - +------------------------------- MODULE test59 ------------------------------- +EXTENDS Naturals +\* Test of INSTANCE inside LET + +VARIABLE y + +Next == LET x == y+1 + M == INSTANCE test59a + IN y' = (M!xplus1 - 1) % 5 + +Init == y = 0 + +Spec == Init /\ [][Next]_y /\ WF_y(Next) + +Invariant == y \in 0..4 +Liveness == []<>(y = 4) + ============================================================================= \ No newline at end of file diff --git a/tlatools/test-model/test59a.tla b/tlatools/test-model/test59a.tla index 2963511f41478b31003db2ae4ff96c17207f1f9d..a5c42c5d2c8769bffa23a0d871a100c4d0799fda 100644 --- a/tlatools/test-model/test59a.tla +++ b/tlatools/test-model/test59a.tla @@ -1,9 +1,9 @@ -------------------------------- MODULE test59a ------------------------------- -EXTENDS Naturals -\* Test of INSTANCE inside LET - -VARIABLE x - -xplus1 == x+1 - +------------------------------- MODULE test59a ------------------------------- +EXTENDS Naturals +\* Test of INSTANCE inside LET + +VARIABLE x + +xplus1 == x+1 + ============================================================================= \ No newline at end of file diff --git a/tlatools/test-model/testinvalidinvariant.cfg b/tlatools/test-model/testinvalidinvariant.cfg index f0e860231ad0256721aa61b69aec5db318681a6c..da219465bfd7a82d092808d0c6661eed71f7d66a 100644 --- a/tlatools/test-model/testinvalidinvariant.cfg +++ b/tlatools/test-model/testinvalidinvariant.cfg @@ -1,3 +1,3 @@ -SPECIFICATION Spec -PROPERTY Property -INVARIANT Invariant +SPECIFICATION Spec +PROPERTY Property +INVARIANT Invariant diff --git a/tlatools/test/pcal/AssignmentToUndeclaredVariableTest.java b/tlatools/test/pcal/AssignmentToUndeclaredVariableTest.java new file mode 100644 index 0000000000000000000000000000000000000000..0cee19e1b625bee6fe40a55bb921e95fd242e96e --- /dev/null +++ b/tlatools/test/pcal/AssignmentToUndeclaredVariableTest.java @@ -0,0 +1,192 @@ +package pcal; + +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Arrays; + +import org.junit.Test; + +import util.ToolIO; + +public class AssignmentToUndeclaredVariableTest extends PCalTest { + @Test + public void procedure() throws IOException { + assertNull(trans.runMe(new String[] {"-nocfg", + writeTempFile("AssignmentToUndeclaredVariableTest", + "---- MODULE algo ----\n" + + "CONSTANT c\n" + + "(*\n" + + "--algorithm algo {\n" + + " variables v, w;\n" + + " procedure Proc1() \n" + + " {p1 : v := 23;\n" + + " c := 42 }\n" + + " {\n" + + " i: call Proc1();\n" + // Assignment to constant + " }\n" + + "}*)\n" + + "====" + )})); + + assertTrue(Arrays.toString(ToolIO.getAllMessages()), + Arrays.asList(ToolIO.getAllMessages()).contains("\nUnrecoverable error:\n" + + " -- Assignment to undeclared variable c\n" + + " at line 8, column 13.\n")); + } + + @Test + public void process() throws IOException { + assertNull(trans.runMe(new String[] {"-nocfg", + writeTempFile("AssignmentToUndeclaredVariableTest", + "---- MODULE algo ----\n" + + "CONSTANT c\n" + + "(*\n" + + "--algorithm algo {\n" + + " variables v, w;\n" + + " process (proc \\in {1,2})\n" + + " variable loc\n" + + " {\n" + + " lbl1: loc := 42;\n" + + " lbl2: v := 23;\n" + + " lbl3: w := 174;\n" + + " lbl4: c := \"fail\";\n" + // Assignment to constant + " }\n" + + "}*)\n" + + "====" + )})); + + assertTrue(Arrays.toString(ToolIO.getAllMessages()), + Arrays.asList(ToolIO.getAllMessages()).contains("\nUnrecoverable error:\n" + + " -- Assignment to undeclared variable c\n" + + " at line 12, column 10.\n")); + } + + @Test + public void multiAssignment() throws IOException { + assertNull(trans.runMe(new String[] {"-nocfg", + writeTempFile("AssignmentToUndeclaredVariableTest", + "---- MODULE algo ----\n" + + "CONSTANT c\n" + + "(*\n" + + "--algorithm algo {\n" + + " variables v, w;\n" + + " {\n" + + " v := 42 || w := 23;\n" + + " v := 42 || c := 23;\n" + // Assignment to constant + " }\n" + + "}*)\n" + + "====" + )})); + + assertTrue(Arrays.toString(ToolIO.getAllMessages()), + Arrays.asList(ToolIO.getAllMessages()).contains("\nUnrecoverable error:\n" + + " -- Assignment to undeclared variable c\n" + + " at line 8, column 11.\n")); + } + + @Test + public void macro() throws IOException { + assertNull(trans.runMe(new String[] {"-nocfg", + writeTempFile("AssignmentToUndeclaredVariableTest", + "---- MODULE algo ----\n" + + "CONSTANT c\n" + + "(*\n" + + "--algorithm algo {\n" + + " variables v;\n" + + " macro Mac() { v := \"pmac\";\n c := 42; }\n" + + " {\n" + + " Mac();\n" + // Assignment to constant + " }\n" + + "}*)\n" + + "====" + )})); + + assertTrue(Arrays.toString(ToolIO.getAllMessages()), + Arrays.asList(ToolIO.getAllMessages()).contains("\nUnrecoverable error:\n" + + " -- Assignment to undeclared variable c\n" + + " at line 7, column 2 of macro called at line 9, column 3.\n")); + } + + @Test + public void macroParam() throws IOException { + assertNull(trans.runMe(new String[] {"-nocfg", + writeTempFile("AssignmentToUndeclaredVariableTest", + "---- MODULE algo ----\n" + + "CONSTANT c\n" + + "(*\n" + + "--algorithm algo {\n" + + " variables v;\n" + + " macro Mac2(p) { p := \"pmac\"}\n" + + " {\n" + + " lbl1: Mac2(v);\n" + + " lbl2: Mac2(c);\n" + // Assignment to constant + " }\n" + + "}*)\n" + + "====" + )})); + + assertTrue(Arrays.asList(ToolIO.getAllMessages()).contains("\nUnrecoverable error:\n" + + " -- Assignment to undeclared variable c\n" + + " at line 6, column 19 of macro called at line 9, column 9.\n")); + } + + @Test + public void boundIdentifier() throws IOException { + assertNull(trans.runMe(new String[] {"-nocfg", + writeTempFile("AssignmentToUndeclaredVariableTest", + "---- MODULE algo ----\n" + + "CONSTANT c\n" + + "(*\n" + + "--algorithm algo\n" + + " variables v;\n" + + "begin\n" + + " with n \\in {1,2,3} do\n" + + " v := n;\n" + + " n := 42;\n" + // Assignment to bound identifier! + " end with;" + + "end algorithm\n" + + " *)\n" + + "====" + )})); + + assertTrue(Arrays.asList(ToolIO.getAllMessages()).contains("\nUnrecoverable error:\n" + + " -- Assignment to undeclared variable n\n" + + " at line 9, column 7.\n")); + } + + @Test + public void constant() throws IOException { + assertNull(trans.runMe(new String[] {"-nocfg", + writeTempFile("AssignmentToUndeclaredVariableTest", + "---- MODULE algo ----\n" + + "CONSTANT c\n" + + "(*\n" + + "--algorithm algo\n" + + " variables v;\n" + + "begin\n" + + " v := 23;\n" + + " c := 42;\n" + // Assignment to constant! + "end algorithm\n" + + " *)\n" + + "====" + )})); + + assertTrue(Arrays.asList(ToolIO.getAllMessages()).contains("\nUnrecoverable error:\n" + + " -- Assignment to undeclared variable c\n" + + " at line 8, column 4.\n")); + } + + private static String writeTempFile(String filename, String content) throws IOException { + final Path path = Files.createTempFile(filename, ".tla"); + Files.write(path, content.getBytes()); + + final File file = path.toFile(); + file.deleteOnExit(); + return file.getAbsolutePath(); + } +} diff --git a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/job/DeleteOutOfSyncJob.java b/tlatools/test/pcal/BakeryTest.java similarity index 50% rename from org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/job/DeleteOutOfSyncJob.java rename to tlatools/test/pcal/BakeryTest.java index bc875b889b769d9f8fe7024478138a0fb08ce64d..b423978d671b138b41df0ce14dc1659e803e4aac 100644 --- a/org.lamport.tla.toolbox/src/org/lamport/tla/toolbox/job/DeleteOutOfSyncJob.java +++ b/tlatools/test/pcal/BakeryTest.java @@ -1,61 +1,49 @@ -/******************************************************************************* - * Copyright (c) 2015 Microsoft Research. All rights reserved. - * - * The MIT License (MIT) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is furnished to do - * so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - * Contributors: - * Simon Zambrovski - initial API and implementation - ******************************************************************************/ -package org.lamport.tla.toolbox.job; - -import org.eclipse.core.resources.IResource; -import org.eclipse.core.resources.IWorkspace; -import org.eclipse.core.resources.ResourcesPlugin; -import org.eclipse.core.resources.WorkspaceJob; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Status; -import org.lamport.tla.toolbox.util.ResourceHelper; - -/** - * Delete files out of sync - */ -public class DeleteOutOfSyncJob extends WorkspaceJob { - private final IResource[] files; - - /** - * @param name - */ - public DeleteOutOfSyncJob(final IResource[] files) { - super("deleteOutOfSyncFiles"); - this.files = files; - this.setRule(ResourceHelper.getDeleteRule(files)); - } - - /** - * @see org.eclipse.core.resources.WorkspaceJob#runInWorkspace(org.eclipse.core.runtime.IProgressMonitor) - */ - public IStatus runInWorkspace(final IProgressMonitor monitor) throws CoreException { - final IWorkspace ws = ResourcesPlugin.getWorkspace(); - ws.delete(files, isBlocking(), monitor); - return Status.OK_STATUS; - } -} +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class BakeryTest extends PCalModelCheckerTestCase { + + public BakeryTest() { + super("Bakery", "pcal"); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "1")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "1183", "668", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "41")); + } +} diff --git a/tlatools/test/pcal/Bug051003Test.java b/tlatools/test/pcal/Bug051003Test.java new file mode 100644 index 0000000000000000000000000000000000000000..4a2fc3565a4fc587479d36e18a06ac9f6d6995e8 --- /dev/null +++ b/tlatools/test/pcal/Bug051003Test.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class Bug051003Test extends PCalModelCheckerTestCase { + + public Bug051003Test() { + super("bug_05_10_03", "pcal"); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "1")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "6", "4", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "3")); + } +} diff --git a/tlatools/test/pcal/Bug051210aTest.java b/tlatools/test/pcal/Bug051210aTest.java new file mode 100644 index 0000000000000000000000000000000000000000..1d69aa1d0fca710314e2f2f0546b5dfd9a7f63ca --- /dev/null +++ b/tlatools/test/pcal/Bug051210aTest.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class Bug051210aTest extends PCalModelCheckerTestCase { + + public Bug051210aTest() { + super("bug_05_12_10a", "pcal"); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "1")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "15", "14", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "14")); + } +} diff --git a/tlatools/test/pcal/Bug051216bTest.java b/tlatools/test/pcal/Bug051216bTest.java new file mode 100644 index 0000000000000000000000000000000000000000..79b17e012eb887b86bb3ee5d214282f54b63a3f6 --- /dev/null +++ b/tlatools/test/pcal/Bug051216bTest.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class Bug051216bTest extends PCalModelCheckerTestCase { + + public Bug051216bTest() { + super("bug_05_12_16b", "pcal"); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "1")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "146", "64", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "10")); + } +} diff --git a/tlatools/test/pcal/Bug051231Test.java b/tlatools/test/pcal/Bug051231Test.java new file mode 100644 index 0000000000000000000000000000000000000000..240c13e4d52db009752aaa5b098b792291ee8ac6 --- /dev/null +++ b/tlatools/test/pcal/Bug051231Test.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class Bug051231Test extends PCalModelCheckerTestCase { + + public Bug051231Test() { + super("bug_05_12_31", "pcal"); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "1")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "4", "3", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "3")); + } +} diff --git a/tlatools/test/pcal/Bug060125Test.java b/tlatools/test/pcal/Bug060125Test.java new file mode 100644 index 0000000000000000000000000000000000000000..4e5522ed0091925d5619368e46694ed2a1618cae --- /dev/null +++ b/tlatools/test/pcal/Bug060125Test.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class Bug060125Test extends PCalModelCheckerTestCase { + + public Bug060125Test() { + super("bug_06_01_25", "pcal"); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "1")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "130", "64", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "15")); + } +} diff --git a/tlatools/test/pcal/CBakeryTest.java b/tlatools/test/pcal/CBakeryTest.java new file mode 100644 index 0000000000000000000000000000000000000000..dbced2596fc535cc97a9e33df2e9d61fd10e8b36 --- /dev/null +++ b/tlatools/test/pcal/CBakeryTest.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class CBakeryTest extends PCalModelCheckerTestCase { + + public CBakeryTest() { + super("CBakery", "pcal"); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "1")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "867", "486", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "31")); + } +} diff --git a/tlatools/test/pcal/CCallReturn1Test.java b/tlatools/test/pcal/CCallReturn1Test.java new file mode 100644 index 0000000000000000000000000000000000000000..e61be7defd3a2da47bafeebcbe880727e56ecb1c --- /dev/null +++ b/tlatools/test/pcal/CCallReturn1Test.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class CCallReturn1Test extends PCalModelCheckerTestCase { + + public CCallReturn1Test() { + super("CCallReturn1", "pcal", new String[] {"-wf", "-termination"}); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "1")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_CHECKING_TEMPORAL_PROPS, "complete", "8")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "9", "8", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "8")); + } +} diff --git a/tlatools/test/pcal/CDiningPhilosophersTest.java b/tlatools/test/pcal/CDiningPhilosophersTest.java new file mode 100644 index 0000000000000000000000000000000000000000..8b4ffd5af7ff8bb5f8412d386a1d044898667099 --- /dev/null +++ b/tlatools/test/pcal/CDiningPhilosophersTest.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class CDiningPhilosophersTest extends PCalModelCheckerTestCase { + + public CDiningPhilosophersTest() { + super("CDiningPhilosophers", "pcal", new String[] {"-sf"}); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "1")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "301", "118", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "14")); + } +} diff --git a/tlatools/test/pcal/CEither1Test.java b/tlatools/test/pcal/CEither1Test.java new file mode 100644 index 0000000000000000000000000000000000000000..c6358c81931b2dd0666f059431f4f7e0158b3c05 --- /dev/null +++ b/tlatools/test/pcal/CEither1Test.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class CEither1Test extends PCalModelCheckerTestCase { + + public CEither1Test() { + super("CEither1", "pcal", new String[] {"-wf", "-termination"}); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "1")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_CHECKING_TEMPORAL_PROPS, "complete", "7")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "9", "7", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "4")); + } +} diff --git a/tlatools/test/pcal/CMultiprocDefineTest.java b/tlatools/test/pcal/CMultiprocDefineTest.java new file mode 100644 index 0000000000000000000000000000000000000000..95318f7fb848055b2d4e9ef62b883130d393121f --- /dev/null +++ b/tlatools/test/pcal/CMultiprocDefineTest.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class CMultiprocDefineTest extends PCalModelCheckerTestCase { + + public CMultiprocDefineTest() { + super("CMultiprocDefine", "pcal", new String[] {"-wf", "-termination"}); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "1")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_CHECKING_TEMPORAL_PROPS, "complete", "8")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "14", "8", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "4")); + } +} diff --git a/tlatools/test/pcal/CallGotoUnlabeledTest.java b/tlatools/test/pcal/CallGotoUnlabeledTest.java new file mode 100644 index 0000000000000000000000000000000000000000..b977fb13501a7b5d49b981000f03f8dd31126f06 --- /dev/null +++ b/tlatools/test/pcal/CallGotoUnlabeledTest.java @@ -0,0 +1,37 @@ +package pcal; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.util.Arrays; + +import org.junit.Test; + +import tlc2.tool.CommonTestCase; +import util.ToolIO; + +public class CallGotoUnlabeledTest extends PCalTest { + + // https://groups.google.com/forum/#!topic/tlaplus/6M1oFOtN-5k/discussion + + @Test + public void test() { + + final String fileName = "CallGotoUnlabeledTest.tla"; + + final TLAtoPCalMapping mapping = trans.runMe(new String[] {"-nocfg", "-unixEOL", "-reportLabels", CommonTestCase.BASE_PATH + fileName}); + assertNotNull(mapping); + + final String[] messages = ToolIO.getAllMessages(); + assertTrue(Arrays.toString(messages), messages.length == 6); + + assertEquals("The following labels were added:", messages[0]); + assertEquals(" Lbl_1 at line 10, column 3", messages[1]); + assertEquals(" Lbl_2 at line 19, column 3", messages[2]); + assertEquals("Parsing completed.", messages[3]); + assertEquals("Translation completed.", messages[4]); + // Ignore last line "New file ...." because it depends on from where the test is executed. +// assertEquals("New file test-model/" + fileName + " written.", messages[5]); + } +} diff --git a/tlatools/test/pcal/CallReturn1Test.java b/tlatools/test/pcal/CallReturn1Test.java new file mode 100644 index 0000000000000000000000000000000000000000..2046e764ad3dae9c8337fb540662f1c5f2c9c4da --- /dev/null +++ b/tlatools/test/pcal/CallReturn1Test.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class CallReturn1Test extends PCalModelCheckerTestCase { + + public CallReturn1Test() { + super("CallReturn1", "pcal", new String[] {"-wf", "-termination"}); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "1")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_CHECKING_TEMPORAL_PROPS, "complete", "8")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "9", "8", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "8")); + } +} diff --git a/tlatools/test/pcal/CallReturn2Test.java b/tlatools/test/pcal/CallReturn2Test.java new file mode 100644 index 0000000000000000000000000000000000000000..a2a9a75d8bab87a4ebafda6ccee6e2b35cf77b7e --- /dev/null +++ b/tlatools/test/pcal/CallReturn2Test.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class CallReturn2Test extends PCalModelCheckerTestCase { + + public CallReturn2Test() { + super("CallReturn2", "pcal", new String[] {"-wf", "-termination"}); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "1")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_CHECKING_TEMPORAL_PROPS, "complete", "11")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "12", "11", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "11")); + } +} diff --git a/tlatools/test/pcal/DetlefSpecTest.java b/tlatools/test/pcal/DetlefSpecTest.java new file mode 100644 index 0000000000000000000000000000000000000000..7a94a0c3e1782e2c843eb9ee37a471e6b0ab74a0 --- /dev/null +++ b/tlatools/test/pcal/DetlefSpecTest.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class DetlefSpecTest extends PCalModelCheckerTestCase { + + public DetlefSpecTest() { + super("DetlefSpec", "pcal", new String[] {"-wf"}); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "1")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "31", "15", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "8")); + } +} diff --git a/tlatools/test/pcal/DetlefsTest.java b/tlatools/test/pcal/DetlefsTest.java new file mode 100644 index 0000000000000000000000000000000000000000..bdd914593e80054c8debda5c4b3790279e21d736 --- /dev/null +++ b/tlatools/test/pcal/DetlefsTest.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class DetlefsTest extends PCalModelCheckerTestCase { + + public DetlefsTest() { + super("Detlefs", "pcal"); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "1")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "2127012", "952912", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "82")); + } +} diff --git a/tlatools/test/pcal/Dijkstra1Test.java b/tlatools/test/pcal/Dijkstra1Test.java new file mode 100644 index 0000000000000000000000000000000000000000..8d9659b901ae12f7a7b5aa2b56baa1aecf6496a7 --- /dev/null +++ b/tlatools/test/pcal/Dijkstra1Test.java @@ -0,0 +1,76 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class Dijkstra1Test extends PCalModelCheckerTestCase { + + public Dijkstra1Test() { + super("Dijkstra1", "pcal", new String[] {"-wf"}); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "625")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_CHECKING_TEMPORAL_PROPS, "complete", "5510")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "16775", "5510", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "10")); + } +} +/* +C:\lamport\tla\pluscal>java -mx1000m -cp "c:/lamport/tla/newtools/tla2-inria-workspace/tla2-inria/tlatools/class" tlc2.TLC -cleanup Dijkstra1.tla +TLC2 Version 2.05 of 18 May 2012 +Running in Model-Checking mode. +Parsing file Dijkstra1.tla +Parsing file C:\lamport\tla\newtools\tla2-inria-workspace\tla2-inria\tlatools\class\tla2sany\StandardModules\FiniteSets.tla +Parsing file C:\lamport\tla\newtools\tla2-inria-workspace\tla2-inria\tlatools\class\tla2sany\StandardModules\Naturals.tla +Parsing file C:\lamport\tla\newtools\tla2-inria-workspace\tla2-inria\tlatools\class\tla2sany\StandardModules\Sequences.tla +Semantic processing of module Naturals +Semantic processing of module Sequences +Semantic processing of module FiniteSets +Semantic processing of module Dijkstra1 +Starting... (2012-08-10 17:39:54) +Implied-temporal checking--satisfiability problem has 1 branches. +Computing initial states... +Finished computing initial states: 625 distinct states generated. +Checking temporal properties for the complete state space... +Model checking completed. No error has been found. + Estimates of the probability that TLC did not check all reachable states + because two distinct states had the same fingerprint: + calculated (optimistic): val = 3.4E-12 + based on the actual fingerprints: val = 5.3E-14 +16775 states generated, 5510 distinct states found, 0 states left on queue. +The depth of the complete state graph search is 10. +Finished. (2012-08-10 17:39:55) +*/ \ No newline at end of file diff --git a/tlatools/test/pcal/DiningPhilosophersTest.java b/tlatools/test/pcal/DiningPhilosophersTest.java new file mode 100644 index 0000000000000000000000000000000000000000..815fc383ce3cd299a1061912e94d14dad8aa5237 --- /dev/null +++ b/tlatools/test/pcal/DiningPhilosophersTest.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class DiningPhilosophersTest extends PCalModelCheckerTestCase { + + public DiningPhilosophersTest() { + super("DiningPhilosophers", "pcal", new String[] {"-sf"}); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "1")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_CHECKING_TEMPORAL_PROPS, "complete", "118")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "301", "118", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "14")); + } +} diff --git a/tlatools/test/pcal/Either1Test.java b/tlatools/test/pcal/Either1Test.java new file mode 100644 index 0000000000000000000000000000000000000000..d9a51d1422707723b7391a1f85e255c61b82ee6b --- /dev/null +++ b/tlatools/test/pcal/Either1Test.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class Either1Test extends PCalModelCheckerTestCase { + + public Either1Test() { + super("Either1", "pcal", new String[] {"-wf", "-termination"}); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "1")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_CHECKING_TEMPORAL_PROPS, "complete", "7")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "9", "7", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "4")); + } +} diff --git a/tlatools/test/pcal/Either2Test.java b/tlatools/test/pcal/Either2Test.java new file mode 100644 index 0000000000000000000000000000000000000000..94c61c104bd4770afb1b33aafc986275af97293d --- /dev/null +++ b/tlatools/test/pcal/Either2Test.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class Either2Test extends PCalModelCheckerTestCase { + + public Either2Test() { + super("Either2", "pcal", new String[] {"-wf", "-termination"}); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "1")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_CHECKING_TEMPORAL_PROPS, "complete", "7")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "9", "7", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "4")); + } +} diff --git a/tlatools/test/pcal/Either3Test.java b/tlatools/test/pcal/Either3Test.java new file mode 100644 index 0000000000000000000000000000000000000000..c4998c51b537e682a9e33a1ab8bb56d1528a2465 --- /dev/null +++ b/tlatools/test/pcal/Either3Test.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class Either3Test extends PCalModelCheckerTestCase { + + public Either3Test() { + super("Either3", "pcal", new String[] {"-wf", "-termination"}); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "1")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_CHECKING_TEMPORAL_PROPS, "complete", "9")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "12", "9", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "4")); + } +} diff --git a/tlatools/test/pcal/Either4Test.java b/tlatools/test/pcal/Either4Test.java new file mode 100644 index 0000000000000000000000000000000000000000..b34891ce311673bc1eedecea4ed1a407c1880938 --- /dev/null +++ b/tlatools/test/pcal/Either4Test.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class Either4Test extends PCalModelCheckerTestCase { + + public Either4Test() { + super("Either4", "pcal", new String[] {"-wf", "-termination"}); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "1")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_CHECKING_TEMPORAL_PROPS, "complete", "81")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "154", "81", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "7")); + } +} diff --git a/tlatools/test/pcal/Either5Test.java b/tlatools/test/pcal/Either5Test.java new file mode 100644 index 0000000000000000000000000000000000000000..5ef4e87cbb8f34d7622deff693788be76c014e20 --- /dev/null +++ b/tlatools/test/pcal/Either5Test.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class Either5Test extends PCalModelCheckerTestCase { + + public Either5Test() { + super("Either5", "pcal", new String[] {"-wf", "-termination"}); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "1")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_CHECKING_TEMPORAL_PROPS, "complete", "7")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "10", "7", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "3")); + } +} diff --git a/tlatools/test/pcal/Euclid2Test.java b/tlatools/test/pcal/Euclid2Test.java new file mode 100644 index 0000000000000000000000000000000000000000..2083719054204f79de93ca070fea202b9e3e570f --- /dev/null +++ b/tlatools/test/pcal/Euclid2Test.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class Euclid2Test extends PCalModelCheckerTestCase { + + public Euclid2Test() { + super("Euclid2", "pcal", new String[] {"-wf", "-termination"}); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "500")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_CHECKING_TEMPORAL_PROPS, "complete", "18852")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "19352", "18852", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "90")); + } +} diff --git a/tlatools/test/pcal/Euclid3Test.java b/tlatools/test/pcal/Euclid3Test.java new file mode 100644 index 0000000000000000000000000000000000000000..fb10c50cd759e7c56fdc6d6096102a4e4a395b0f --- /dev/null +++ b/tlatools/test/pcal/Euclid3Test.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class Euclid3Test extends PCalModelCheckerTestCase { + + public Euclid3Test() { + super("Euclid3", "pcal", new String[] {"-wf", "-termination"}); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "3")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_CHECKING_TEMPORAL_PROPS, "complete", "94")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "97", "94", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "50")); + } +} diff --git a/tlatools/test/pcal/EuclidTest.java b/tlatools/test/pcal/EuclidTest.java new file mode 100644 index 0000000000000000000000000000000000000000..61167ed1d899695067b142bcc09d652ece1c3b1d --- /dev/null +++ b/tlatools/test/pcal/EuclidTest.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class EuclidTest extends PCalModelCheckerTestCase { + + public EuclidTest() { + super("Euclid", "pcal", new String[] {"-wf", "-termination"}); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "400")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_CHECKING_TEMPORAL_PROPS, "complete", "6352")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "6752", "6352", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "42")); + } +} diff --git a/tlatools/test/pcal/EvenOddBadTest.java b/tlatools/test/pcal/EvenOddBadTest.java new file mode 100644 index 0000000000000000000000000000000000000000..01cfc3fbe193028eaf5dd6904a3575457abff816 --- /dev/null +++ b/tlatools/test/pcal/EvenOddBadTest.java @@ -0,0 +1,51 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class EvenOddBadTest extends PCalModelCheckerTestCase { + + public EvenOddBadTest() { + super("EvenOddBad", "pcal", new String[] {"-wf", "-termination"}); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "2")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_CHECKING_TEMPORAL_PROPS, "complete", "13")); + assertTrue(recorder.recorded(EC.TLC_CHECKING_TEMPORAL_PROPS_END)); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "15", "13", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "9")); + } +} diff --git a/tlatools/test/pcal/EvenOddTest.java b/tlatools/test/pcal/EvenOddTest.java new file mode 100644 index 0000000000000000000000000000000000000000..4bbee35bcdf3d43e5b80c6bc14ddf8c258b4d642 --- /dev/null +++ b/tlatools/test/pcal/EvenOddTest.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class EvenOddTest extends PCalModelCheckerTestCase { + + public EvenOddTest() { + super("EvenOdd", "pcal", new String[] {"-wf", "-termination"}); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "1")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_CHECKING_TEMPORAL_PROPS, "complete", "13")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "14", "13", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "13")); + } +} diff --git a/tlatools/test/pcal/Factorial2Test.java b/tlatools/test/pcal/Factorial2Test.java new file mode 100644 index 0000000000000000000000000000000000000000..010aab9e3d7852b3b29c22123d91ce3265643abb --- /dev/null +++ b/tlatools/test/pcal/Factorial2Test.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class Factorial2Test extends PCalModelCheckerTestCase { + + public Factorial2Test() { + super("Factorial2", "pcal", new String[] {"-wf", "-termination"}); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "1")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_CHECKING_TEMPORAL_PROPS, "complete", "12")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "13", "12", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "12")); + } +} diff --git a/tlatools/test/pcal/FactorialTest.java b/tlatools/test/pcal/FactorialTest.java new file mode 100644 index 0000000000000000000000000000000000000000..cfa47463ce89f1056c5f09ec5b0337ac27f54fe0 --- /dev/null +++ b/tlatools/test/pcal/FactorialTest.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class FactorialTest extends PCalModelCheckerTestCase { + + public FactorialTest() { + super("Factorial", "pcal", new String[] {"-wf", "-termination"}); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "1")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_CHECKING_TEMPORAL_PROPS, "complete", "9")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "10", "9", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "9")); + } +} diff --git a/tlatools/test/pcal/FairSeq2Test.java b/tlatools/test/pcal/FairSeq2Test.java new file mode 100644 index 0000000000000000000000000000000000000000..21d2e83f0b450d595b3b5a2017182be022d0ba17 --- /dev/null +++ b/tlatools/test/pcal/FairSeq2Test.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class FairSeq2Test extends PCalModelCheckerTestCase { + + public FairSeq2Test() { + super("FairSeq2", "pcal", new String[] {"-wf", "-termination"}); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "1")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_CHECKING_TEMPORAL_PROPS, "complete", "12")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "13", "12", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "12")); + } +} diff --git a/tlatools/test/pcal/FairSeqTest.java b/tlatools/test/pcal/FairSeqTest.java new file mode 100644 index 0000000000000000000000000000000000000000..a06b739637e48ae5cabdc3c0d8df6451b5dce530 --- /dev/null +++ b/tlatools/test/pcal/FairSeqTest.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class FairSeqTest extends PCalModelCheckerTestCase { + + public FairSeqTest() { + super("FairSeq", "pcal", new String[] {"-wf", "-termination"}); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "1")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_CHECKING_TEMPORAL_PROPS, "complete", "24")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "13", "12", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "12")); + } +} diff --git a/tlatools/test/pcal/FastMutex2Test.java b/tlatools/test/pcal/FastMutex2Test.java new file mode 100644 index 0000000000000000000000000000000000000000..5a76df2b7616a8bf670aded933cff78d98d1eb07 --- /dev/null +++ b/tlatools/test/pcal/FastMutex2Test.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class FastMutex2Test extends PCalModelCheckerTestCase { + + public FastMutex2Test() { + super("FastMutex2", "pcal", new String[] {"-wf"}); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "1")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_CHECKING_TEMPORAL_PROPS, "complete", "1415")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "2679", "1415", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "60")); + } +} diff --git a/tlatools/test/pcal/FastMutex3Test.java b/tlatools/test/pcal/FastMutex3Test.java new file mode 100644 index 0000000000000000000000000000000000000000..2d278a720e7ec04680ba7cd6a38d85fb4f243ac4 --- /dev/null +++ b/tlatools/test/pcal/FastMutex3Test.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class FastMutex3Test extends PCalModelCheckerTestCase { + + public FastMutex3Test() { + super("FastMutex3", "pcal", new String[] {"-wf"}); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "1")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_CHECKING_TEMPORAL_PROPS, "complete", "1415")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "2679", "1415", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "60")); + } +} diff --git a/tlatools/test/pcal/FastMutexTest.java b/tlatools/test/pcal/FastMutexTest.java new file mode 100644 index 0000000000000000000000000000000000000000..d0867c55d86fa81662b975312657f0285a311d42 --- /dev/null +++ b/tlatools/test/pcal/FastMutexTest.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class FastMutexTest extends PCalModelCheckerTestCase { + + public FastMutexTest() { + super("FastMutex", "pcal", new String[] {"-wf"}); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "1")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_CHECKING_TEMPORAL_PROPS, "complete", "1415")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "2679", "1415", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "60")); + } +} diff --git a/tlatools/test/pcal/FastMutexWithGoto2Test.java b/tlatools/test/pcal/FastMutexWithGoto2Test.java new file mode 100644 index 0000000000000000000000000000000000000000..616788e3801babeccf21ad96a2b0e4eb52a374d5 --- /dev/null +++ b/tlatools/test/pcal/FastMutexWithGoto2Test.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class FastMutexWithGoto2Test extends PCalModelCheckerTestCase { + + public FastMutexWithGoto2Test() { + super("FastMutexWithGoto2", "pcal", new String[] {"-wfNext"}); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "1")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_CHECKING_TEMPORAL_PROPS, "complete", "15900")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "42277", "15900", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "47")); + } +} diff --git a/tlatools/test/pcal/FastMutexWithGotoTest.java b/tlatools/test/pcal/FastMutexWithGotoTest.java new file mode 100644 index 0000000000000000000000000000000000000000..69b4e77b0f635d50c2bb842b3b61ee4b13f327af --- /dev/null +++ b/tlatools/test/pcal/FastMutexWithGotoTest.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class FastMutexWithGotoTest extends PCalModelCheckerTestCase { + + public FastMutexWithGotoTest() { + super("FastMutexWithGoto", "pcal"); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "1")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_CHECKING_TEMPORAL_PROPS, "complete", "1415")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "2679", "1415", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "58")); + } +} diff --git a/tlatools/test/pcal/FischerTest.java b/tlatools/test/pcal/FischerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..1fa293f93fdeb896848d840e8b955614ba37eebf --- /dev/null +++ b/tlatools/test/pcal/FischerTest.java @@ -0,0 +1,82 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class FischerTest extends PCalModelCheckerTestCase { + + public FischerTest() { + super("Fischer", "pcal", new String[] {"-wf"}); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "1")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_CHECKING_TEMPORAL_PROPS, "complete", "1002")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "2487", "1002", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "24")); + } +} +/* +C:\lamport\tla\pluscal>java -mx1000m -cp "c:/lamport/tla/newtools/tla2-inria-workspace/tla2-inria/tlatools/class" tlc2.TLC -cleanup Fischer.tla +TLC2 Version 2.05 of 18 May 2012 +Running in Model-Checking mode. +Parsing file Fischer.tla +Parsing file C:\lamport\tla\newtools\tla2-inria-workspace\tla2-inria\tlatools\class\tla2sany\StandardModules\Naturals.tla +Parsing file C:\lamport\tla\newtools\tla2-inria-workspace\tla2-inria\tlatools\class\tla2sany\StandardModules\TLC.tla +Parsing file C:\lamport\tla\newtools\tla2-inria-workspace\tla2-inria\tlatools\class\tla2sany\StandardModules\Sequences.tla +Semantic processing of module Naturals +Semantic processing of module Sequences +Semantic processing of module TLC +Semantic processing of module Fischer +Starting... (2012-08-10 17:38:12) +Implied-temporal checking--satisfiability problem has 1 branches. +"Testing Fischer's Mutual Exclusion Algorithm" TRUE +<<" Number of processes = ", 3>> TRUE +<<" Delta = ", 2>> TRUE +<<" Epsilon = ", 3>> TRUE +"Should find a bug if N > 1 and Delta >= Epsilon" TRUE +Computing initial states... +Finished computing initial states: 1 distinct state generated. +Checking temporal properties for the complete state space... +Model checking completed. No error has been found. + Estimates of the probability that TLC did not check all reachable states + because two distinct states had the same fingerprint: + calculated (optimistic): val = 8.1E-14 + based on the actual fingerprints: val = 8.0E-15 +2487 states generated, 1002 distinct states found, 0 states left on queue. +The depth of the complete state graph search is 24. +Finished. (2012-08-10 17:38:13) +InnerLabeledIf.tla +*/ \ No newline at end of file diff --git a/tlatools/test/pcal/InnerLabeledIfTest.java b/tlatools/test/pcal/InnerLabeledIfTest.java new file mode 100644 index 0000000000000000000000000000000000000000..a95419d8e50f63391c00ea2c9837d1d43fd3bc01 --- /dev/null +++ b/tlatools/test/pcal/InnerLabeledIfTest.java @@ -0,0 +1,84 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class InnerLabeledIfTest extends PCalModelCheckerTestCase { + + public InnerLabeledIfTest() { + super("InnerLabeledIf", "pcal", new String[] {"-wf", "-termination"}); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "4")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_CHECKING_TEMPORAL_PROPS, "complete", "16")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "20", "16", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "4")); + } +} +/* +C:\lamport\tla\pluscal>java -mx1000m -cp "c:/lamport/tla/newtools/tla2-inria-workspace/tla2-inria/tlatools/class" tlc2.TLC -cleanup InnerLabeledIf.tla +TLC2 Version 2.05 of 18 May 2012 +Running in Model-Checking mode. +Parsing file InnerLabeledIf.tla +Parsing file C:\lamport\tla\newtools\tla2-inria-workspace\tla2-inria\tlatools\class\tla2sany\StandardModules\Sequences.tla +Parsing file C:\lamport\tla\newtools\tla2-inria-workspace\tla2-inria\tlatools\class\tla2sany\StandardModules\Naturals.tla +Parsing file C:\lamport\tla\newtools\tla2-inria-workspace\tla2-inria\tlatools\class\tla2sany\StandardModules\TLC.tla +Semantic processing of module Naturals +Semantic processing of module Sequences +Semantic processing of module TLC +Semantic processing of module InnerLabeledIf +Starting... (2012-08-10 17:38:14) +Implied-temporal checking--satisfiability problem has 1 branches. +Computing initial states... +Finished computing initial states: 4 distinct states generated. +"made it to end" +"made it to end" +"made it to end" +"made it to end" +"made it to end" +"made it to end" +"made it to end" +"made it to end" +Checking temporal properties for the complete state space... +Model checking completed. No error has been found. + Estimates of the probability that TLC did not check all reachable states + because two distinct states had the same fingerprint: + calculated (optimistic): val = 3.5E-18 + based on the actual fingerprints: val = 1.7E-17 +20 states generated, 16 distinct states found, 0 states left on queue. +The depth of the complete state graph search is 4. +Finished. (2012-08-10 17:38:14) +*/ \ No newline at end of file diff --git a/tlatools/test/pcal/MPFactorial2Test.java b/tlatools/test/pcal/MPFactorial2Test.java new file mode 100644 index 0000000000000000000000000000000000000000..33d0353cafac25eaa095fa18fa30a9b267707197 --- /dev/null +++ b/tlatools/test/pcal/MPFactorial2Test.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class MPFactorial2Test extends PCalModelCheckerTestCase { + + public MPFactorial2Test() { + super("MPFactorial2", "pcal", new String[] {"-wf", "-termination"}); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "1")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_CHECKING_TEMPORAL_PROPS, "complete", "1728")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "4754", "1728", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "34")); + } +} diff --git a/tlatools/test/pcal/MPFactorialTest.java b/tlatools/test/pcal/MPFactorialTest.java new file mode 100644 index 0000000000000000000000000000000000000000..ffebcfcba6d6c1a371502134e39aeee890a7833b --- /dev/null +++ b/tlatools/test/pcal/MPFactorialTest.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class MPFactorialTest extends PCalModelCheckerTestCase { + + public MPFactorialTest() { + super("MPFactorial", "pcal", new String[] {"-wf", "-termination"}); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "1")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_CHECKING_TEMPORAL_PROPS, "complete", "729")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "1946", "729", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "25")); + } +} diff --git a/tlatools/test/pcal/MPNoParamsTest.java b/tlatools/test/pcal/MPNoParamsTest.java new file mode 100644 index 0000000000000000000000000000000000000000..5156082529a96fca194bf0418ae0825665177624 --- /dev/null +++ b/tlatools/test/pcal/MPNoParamsTest.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class MPNoParamsTest extends PCalModelCheckerTestCase { + + public MPNoParamsTest() { + super("MPNoParams", "pcal", new String[] {"-wf", "-termination"}); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "1")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_CHECKING_TEMPORAL_PROPS, "complete", "96")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "250", "96", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "13")); + } +} diff --git a/tlatools/test/pcal/MacroQuicksortTest.java b/tlatools/test/pcal/MacroQuicksortTest.java new file mode 100644 index 0000000000000000000000000000000000000000..f132b260dc32947a199089e453e1cec267c0b388 --- /dev/null +++ b/tlatools/test/pcal/MacroQuicksortTest.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class MacroQuicksortTest extends PCalModelCheckerTestCase { + + public MacroQuicksortTest() { + super("MacroQuicksort", "pcal", new String[] {"-wf", "-termination"}); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "256")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_CHECKING_TEMPORAL_PROPS, "complete", "31092")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "38084", "31092", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "23")); + } +} diff --git a/tlatools/test/pcal/MacroRealQuicksortTest.java b/tlatools/test/pcal/MacroRealQuicksortTest.java new file mode 100644 index 0000000000000000000000000000000000000000..34b9f96c75c266b23dd092b5782464c25c5502aa --- /dev/null +++ b/tlatools/test/pcal/MacroRealQuicksortTest.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class MacroRealQuicksortTest extends PCalModelCheckerTestCase { + + public MacroRealQuicksortTest() { + super("MacroRealQuicksort", "pcal", new String[] {"-wf", "-termination"}); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "256")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_CHECKING_TEMPORAL_PROPS, "complete", "27336")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "64072", "27336", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "9")); + } +} diff --git a/tlatools/test/pcal/MergeSortTest.java b/tlatools/test/pcal/MergeSortTest.java new file mode 100644 index 0000000000000000000000000000000000000000..92106edd3c41077e665f82c7639c214688978262 --- /dev/null +++ b/tlatools/test/pcal/MergeSortTest.java @@ -0,0 +1,77 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class MergeSortTest extends PCalModelCheckerTestCase { + + public MergeSortTest() { + super("MergeSort", "pcal", new String[] {"-wf", "-termination"}); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "6")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_CHECKING_TEMPORAL_PROPS, "complete", "80", "")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "86", "80", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "18")); + } +} +/* +C:\lamport\tla\pluscal>java -mx1000m -cp "c:/lamport/tla/newtools/tla2-inria-workspace/tla2-inria/tlatools/class" tlc2.TLC -cleanup MergeSort.tla +TLC2 Version 2.05 of 18 May 2012 +Running in Model-Checking mode. +Parsing file MergeSort.tla +Parsing file C:\lamport\tla\newtools\tla2-inria-workspace\tla2-inria\tlatools\class\tla2sany\StandardModules\Naturals.tla +Parsing file C:\lamport\tla\newtools\tla2-inria-workspace\tla2-inria\tlatools\class\tla2sany\StandardModules\Sequences.tla +Parsing file C:\lamport\tla\newtools\tla2-inria-workspace\tla2-inria\tlatools\class\tla2sany\StandardModules\TLC.tla +Semantic processing of module Naturals +Semantic processing of module Sequences +Semantic processing of module TLC +Semantic processing of module MergeSort +Starting... (2012-08-10 17:38:17) +Implied-temporal checking--satisfiability problem has 1 branches. +<<"Testing Mergesort on all arrays of length <= ", 2>> TRUE +Computing initial states... +Finished computing initial states: 6 distinct states generated. +Checking temporal properties for the complete state space... +Model checking completed. No error has been found. + Estimates of the probability that TLC did not check all reachable states + because two distinct states had the same fingerprint: + calculated (optimistic): val = 2.6E-17 + based on the actual fingerprints: val = 1.6E-16 +86 states generated, 80 distinct states found, 0 states left on queue. +The depth of the complete state graph search is 18. +Finished. (2012-08-10 17:38:17) +*/ \ No newline at end of file diff --git a/tlatools/test/pcal/MissingBodyInWithTest.java b/tlatools/test/pcal/MissingBodyInWithTest.java index 5df279e7a4a54820ce2ca6d828943ed426d74eb6..c184963b26483a1e7a7fa78a6dfdcf378a3ea2bb 100644 --- a/tlatools/test/pcal/MissingBodyInWithTest.java +++ b/tlatools/test/pcal/MissingBodyInWithTest.java @@ -9,14 +9,10 @@ import org.junit.Test; import tlc2.tool.CommonTestCase; import util.ToolIO; -public class MissingBodyInWithTest { +public class MissingBodyInWithTest extends PCalTest { @Test public void test() { - // Make tool capture the output written to ToolIO.out. Otherwise, - // ToolIO#getAllMessages returns an empty array. - ToolIO.setMode(ToolIO.TOOL); - assertNull(trans.runMe(new String[] {"-nocfg", CommonTestCase.BASE_PATH + "MissingBodyInWith.tla"})); final String[] messages = ToolIO.getAllMessages(); diff --git a/tlatools/test/pcal/MultiAssignmentTest.java b/tlatools/test/pcal/MultiAssignmentTest.java new file mode 100644 index 0000000000000000000000000000000000000000..46c9819d51a0b8f7dc8402ecf3ed15d8cc2e90e3 --- /dev/null +++ b/tlatools/test/pcal/MultiAssignmentTest.java @@ -0,0 +1,76 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class MultiAssignmentTest extends PCalModelCheckerTestCase { + + public MultiAssignmentTest() { + super("MultiAssignment", "pcal", new String[] {"-wf", "-termination"}); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "1")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_CHECKING_TEMPORAL_PROPS, "complete", "27")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "56", "27", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "7")); + } +} +/* +C:\lamport\tla\pluscal>java -mx1000m -cp "c:/lamport/tla/newtools/tla2-inria-workspace/tla2-inria/tlatools/class" tlc2.TLC -cleanup MultiAssignment.tla +TLC2 Version 2.05 of 18 May 2012 +Running in Model-Checking mode. +Parsing file MultiAssignment.tla +Parsing file C:\lamport\tla\newtools\tla2-inria-workspace\tla2-inria\tlatools\class\tla2sany\StandardModules\Naturals.tla +Parsing file C:\lamport\tla\newtools\tla2-inria-workspace\tla2-inria\tlatools\class\tla2sany\StandardModules\TLC.tla +Parsing file C:\lamport\tla\newtools\tla2-inria-workspace\tla2-inria\tlatools\class\tla2sany\StandardModules\Sequences.tla +Semantic processing of module Naturals +Semantic processing of module Sequences +Semantic processing of module TLC +Semantic processing of module MultiAssignment +Starting... (2012-08-10 17:38:18) +Implied-temporal checking--satisfiability problem has 1 branches. +Computing initial states... +Finished computing initial states: 1 distinct state generated. +Checking temporal properties for the complete state space... +Model checking completed. No error has been found. + Estimates of the probability that TLC did not check all reachable states + because two distinct states had the same fingerprint: + calculated (optimistic): val = 4.2E-17 + based on the actual fingerprints: val = 1.4E-17 +56 states generated, 27 distinct states found, 0 states left on queue. +The depth of the complete state graph search is 7. +Finished. (2012-08-10 17:38:18) +*/ \ No newline at end of file diff --git a/tlatools/test/pcal/MultiProc2Test.java b/tlatools/test/pcal/MultiProc2Test.java new file mode 100644 index 0000000000000000000000000000000000000000..283fea019b7b68fc1e6f2486c7c229dd0494fc57 --- /dev/null +++ b/tlatools/test/pcal/MultiProc2Test.java @@ -0,0 +1,84 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class MultiProc2Test extends PCalModelCheckerTestCase { + + public MultiProc2Test() { + super("MultiProc2", "pcal", new String[] {"-wf", "-termination"}); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "4")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_CHECKING_TEMPORAL_PROPS, "complete", "504")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "1212", "504", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "14")); + } +} +/* +C:\lamport\tla\pluscal>java -mx1000m -cp "c:/lamport/tla/newtools/tla2-inria-workspace/tla2-inria/tlatools/class" tlc2.TLC -cleanup MultiProc2.tla +TLC2 Version 2.05 of 18 May 2012 +Running in Model-Checking mode. +Parsing file MultiProc2.tla +Parsing file C:\lamport\tla\newtools\tla2-inria-workspace\tla2-inria\tlatools\class\tla2sany\StandardModules\Sequences.tla +Parsing file C:\lamport\tla\newtools\tla2-inria-workspace\tla2-inria\tlatools\class\tla2sany\StandardModules\Naturals.tla +Parsing file C:\lamport\tla\newtools\tla2-inria-workspace\tla2-inria\tlatools\class\tla2sany\StandardModules\TLC.tla +Semantic processing of module Naturals +Semantic processing of module Sequences +Semantic processing of module TLC +Semantic processing of module MultiProc2 +Starting... (2012-08-10 17:38:19) +Implied-temporal checking--satisfiability problem has 1 branches. +Computing initial states... +Finished computing initial states: 4 distinct states generated. +13 TRUE +13 TRUE +14 TRUE +14 TRUE +14 TRUE +14 TRUE +15 TRUE +15 TRUE +Checking temporal properties for the complete state space... +Model checking completed. No error has been found. + Estimates of the probability that TLC did not check all reachable states + because two distinct states had the same fingerprint: + calculated (optimistic): val = 1.9E-14 + based on the actual fingerprints: val = 3.7E-13 +1212 states generated, 504 distinct states found, 0 states left on queue. +The depth of the complete state graph search is 14. +Finished. (2012-08-10 17:38:20) +*/ \ No newline at end of file diff --git a/tlatools/test/pcal/MultiprocDefineTest.java b/tlatools/test/pcal/MultiprocDefineTest.java new file mode 100644 index 0000000000000000000000000000000000000000..35a658ea7386687b855df34cf600bfdc21ec7045 --- /dev/null +++ b/tlatools/test/pcal/MultiprocDefineTest.java @@ -0,0 +1,73 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class MultiprocDefineTest extends PCalModelCheckerTestCase { + + public MultiprocDefineTest() { + super("MultiprocDefine", "pcal"); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "1")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "14", "8", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "4")); + } +} +/* +C:\lamport\tla\pluscal>java -mx1000m -cp "c:/lamport/tla/newtools/tla2-inria-workspace/tla2-inria/tlatools/class" tlc2.TLC -cleanup MultiprocDefine.tla +TLC2 Version 2.05 of 18 May 2012 +Running in Model-Checking mode. +Parsing file MultiprocDefine.tla +Parsing file C:\lamport\tla\newtools\tla2-inria-workspace\tla2-inria\tlatools\class\tla2sany\StandardModules\Naturals.tla +Parsing file C:\lamport\tla\newtools\tla2-inria-workspace\tla2-inria\tlatools\class\tla2sany\StandardModules\Sequences.tla +Parsing file C:\lamport\tla\newtools\tla2-inria-workspace\tla2-inria\tlatools\class\tla2sany\StandardModules\TLC.tla +Semantic processing of module Naturals +Semantic processing of module Sequences +Semantic processing of module TLC +Semantic processing of module MultiprocDefine +Starting... (2012-08-10 17:40:00) +Computing initial states... +Finished computing initial states: 1 distinct state generated. +Model checking completed. No error has been found. + Estimates of the probability that TLC did not check all reachable states + because two distinct states had the same fingerprint: + calculated (optimistic): val = 2.6E-18 + based on the actual fingerprints: val = 4.8E-19 +14 states generated, 8 distinct states found, 0 states left on queue. +The depth of the complete state graph search is 4. +Finished. (2012-08-10 17:40:00) +*/ \ No newline at end of file diff --git a/tlatools/test/pcal/NestedMacrosTest.java b/tlatools/test/pcal/NestedMacrosTest.java new file mode 100644 index 0000000000000000000000000000000000000000..255a605311624a01bc92a334b97367655281cc00 --- /dev/null +++ b/tlatools/test/pcal/NestedMacrosTest.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class NestedMacrosTest extends PCalModelCheckerTestCase { + + public NestedMacrosTest() { + super("NestedMacros", "pcal", new String[] {"-wf", "-termination"}); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "1")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_CHECKING_TEMPORAL_PROPS, "complete", "9")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "14", "9", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "5")); + } +} diff --git a/tlatools/test/pcal/NoLoop2Test.java b/tlatools/test/pcal/NoLoop2Test.java new file mode 100644 index 0000000000000000000000000000000000000000..99917b0402eaca0374c22de25ba17474b5c4d0d4 --- /dev/null +++ b/tlatools/test/pcal/NoLoop2Test.java @@ -0,0 +1,80 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class NoLoop2Test extends PCalModelCheckerTestCase { + + public NoLoop2Test() { + super("NoLoop2", "pcal", new String[] {"-wf", "-termination"}); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "1")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_CHECKING_TEMPORAL_PROPS, "complete", "9")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "11", "9", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "6")); + } +} +/* +C:\lamport\tla\pluscal>java -mx1000m -cp "c:/lamport/tla/newtools/tla2-inria-workspace/tla2-inria/tlatools/class" tlc2.TLC -cleanup NoLoop2.tla +TLC2 Version 2.05 of 18 May 2012 +Running in Model-Checking mode. +Parsing file NoLoop2.tla +Parsing file C:\lamport\tla\newtools\tla2-inria-workspace\tla2-inria\tlatools\class\tla2sany\StandardModules\Naturals.tla +Parsing file C:\lamport\tla\newtools\tla2-inria-workspace\tla2-inria\tlatools\class\tla2sany\StandardModules\TLC.tla +Parsing file C:\lamport\tla\newtools\tla2-inria-workspace\tla2-inria\tlatools\class\tla2sany\StandardModules\Sequences.tla +Semantic processing of module Naturals +Semantic processing of module Sequences +Semantic processing of module TLC +Semantic processing of module NoLoop2 +Starting... (2012-08-10 17:38:22) +Implied-temporal checking--satisfiability problem has 1 branches. +Computing initial states... +Finished computing initial states: 1 distinct state generated. +7 TRUE +7 TRUE +10 TRUE +10 TRUE +Checking temporal properties for the complete state space... +Model checking completed. No error has been found. + Estimates of the probability that TLC did not check all reachable states + because two distinct states had the same fingerprint: + calculated (optimistic): val = 9.8E-19 + based on the actual fingerprints: val = 1.6E-17 +11 states generated, 9 distinct states found, 0 states left on queue. +The depth of the complete state graph search is 6. +Finished. (2012-08-10 17:38:22) +*/ \ No newline at end of file diff --git a/tlatools/test/pcal/NoLoopTest.java b/tlatools/test/pcal/NoLoopTest.java new file mode 100644 index 0000000000000000000000000000000000000000..9a846828ebf6e7f94c23c7d768506a49d5ce5d9c --- /dev/null +++ b/tlatools/test/pcal/NoLoopTest.java @@ -0,0 +1,80 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class NoLoopTest extends PCalModelCheckerTestCase { + + public NoLoopTest() { + super("NoLoop", "pcal", new String[] {"-wf", "-termination"}); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "1")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_CHECKING_TEMPORAL_PROPS, "complete", "6")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "8", "6", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "4")); + } +} +/* +C:\lamport\tla\pluscal>java -mx1000m -cp "c:/lamport/tla/newtools/tla2-inria-workspace/tla2-inria/tlatools/class" tlc2.TLC -cleanup NoLoop.tla +TLC2 Version 2.05 of 18 May 2012 +Running in Model-Checking mode. +Parsing file NoLoop.tla +Parsing file C:\lamport\tla\newtools\tla2-inria-workspace\tla2-inria\tlatools\class\tla2sany\StandardModules\Sequences.tla +Parsing file C:\lamport\tla\newtools\tla2-inria-workspace\tla2-inria\tlatools\class\tla2sany\StandardModules\Naturals.tla +Parsing file C:\lamport\tla\newtools\tla2-inria-workspace\tla2-inria\tlatools\class\tla2sany\StandardModules\TLC.tla +Semantic processing of module Naturals +Semantic processing of module Sequences +Semantic processing of module TLC +Semantic processing of module NoLoop +Starting... (2012-08-10 17:38:21) +Implied-temporal checking--satisfiability problem has 1 branches. +Computing initial states... +Finished computing initial states: 1 distinct state generated. +5 TRUE +5 TRUE +7 TRUE +7 TRUE +Checking temporal properties for the complete state space... +Model checking completed. No error has been found. + Estimates of the probability that TLC did not check all reachable states + because two distinct states had the same fingerprint: + calculated (optimistic): val = 6.5E-19 + based on the actual fingerprints: val = 1.5E-18 +8 states generated, 6 distinct states found, 0 states left on queue. +The depth of the complete state graph search is 4. +Finished. (2012-08-10 17:38:21) +*/ \ No newline at end of file diff --git a/tlatools/test/pcal/NoParamsTest.java b/tlatools/test/pcal/NoParamsTest.java new file mode 100644 index 0000000000000000000000000000000000000000..2c4d35107f32a7d941c6a2a0fc979b34544043e7 --- /dev/null +++ b/tlatools/test/pcal/NoParamsTest.java @@ -0,0 +1,78 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class NoParamsTest extends PCalModelCheckerTestCase { + + public NoParamsTest() { + super("NoParams", "pcal", new String[] {"-wf", "-termination"}); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "1")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_CHECKING_TEMPORAL_PROPS, "complete", "6")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "7", "6", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "6")); + } +} +/* +C:\lamport\tla\pluscal>java -mx1000m -cp "c:/lamport/tla/newtools/tla2-inria-workspace/tla2-inria/tlatools/class" tlc2.TLC -cleanup NoParams.tla +TLC2 Version 2.05 of 18 May 2012 +Running in Model-Checking mode. +Parsing file NoParams.tla +Parsing file C:\lamport\tla\newtools\tla2-inria-workspace\tla2-inria\tlatools\class\tla2sany\StandardModules\Sequences.tla +Parsing file C:\lamport\tla\newtools\tla2-inria-workspace\tla2-inria\tlatools\class\tla2sany\StandardModules\Naturals.tla +Parsing file C:\lamport\tla\newtools\tla2-inria-workspace\tla2-inria\tlatools\class\tla2sany\StandardModules\TLC.tla +Semantic processing of module Naturals +Semantic processing of module Sequences +Semantic processing of module TLC +Semantic processing of module NoParams +Starting... (2012-08-10 17:38:23) +Implied-temporal checking--satisfiability problem has 1 branches. +Computing initial states... +Finished computing initial states: 1 distinct state generated. +2 TRUE +2 TRUE +Checking temporal properties for the complete state space... +Model checking completed. No error has been found. + Estimates of the probability that TLC did not check all reachable states + because two distinct states had the same fingerprint: + calculated (optimistic): val = 3.3E-19 + based on the actual fingerprints: val = 1.7E-18 +7 states generated, 6 distinct states found, 0 states left on queue. +The depth of the complete state graph search is 6. +Finished. (2012-08-10 17:38:23) +*/ \ No newline at end of file diff --git a/tlatools/test/pcal/NotSoSimpleLoopTest.java b/tlatools/test/pcal/NotSoSimpleLoopTest.java new file mode 100644 index 0000000000000000000000000000000000000000..9f498eb48fc03a23dc581a348514a7e205698dde --- /dev/null +++ b/tlatools/test/pcal/NotSoSimpleLoopTest.java @@ -0,0 +1,76 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class NotSoSimpleLoopTest extends PCalModelCheckerTestCase { + + public NotSoSimpleLoopTest() { + super("NotSoSimpleLoop", "pcal", new String[] {"-wf", "-termination"}); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "1")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_CHECKING_TEMPORAL_PROPS, "complete", "13")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "14", "13", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "13")); + } +} +/* +C:\lamport\tla\pluscal>java -mx1000m -cp "c:/lamport/tla/newtools/tla2-inria-workspace/tla2-inria/tlatools/class" tlc2.TLC -cleanup NotSoSimpleLoop.tla +TLC2 Version 2.05 of 18 May 2012 +Running in Model-Checking mode. +Parsing file NotSoSimpleLoop.tla +Parsing file C:\lamport\tla\newtools\tla2-inria-workspace\tla2-inria\tlatools\class\tla2sany\StandardModules\Naturals.tla +Parsing file C:\lamport\tla\newtools\tla2-inria-workspace\tla2-inria\tlatools\class\tla2sany\StandardModules\TLC.tla +Parsing file C:\lamport\tla\newtools\tla2-inria-workspace\tla2-inria\tlatools\class\tla2sany\StandardModules\Sequences.tla +Semantic processing of module Naturals +Semantic processing of module Sequences +Semantic processing of module TLC +Semantic processing of module NotSoSimpleLoop +Starting... (2012-08-10 17:38:24) +Implied-temporal checking--satisfiability problem has 1 branches. +Computing initial states... +Finished computing initial states: 1 distinct state generated. +Checking temporal properties for the complete state space... +Model checking completed. No error has been found. + Estimates of the probability that TLC did not check all reachable states + because two distinct states had the same fingerprint: + calculated (optimistic): val = 7.0E-19 + based on the actual fingerprints: val = 3.3E-18 +14 states generated, 13 distinct states found, 0 states left on queue. +The depth of the complete state graph search is 13. +Finished. (2012-08-10 17:38:25) +*/ \ No newline at end of file diff --git a/tlatools/test/pcal/PCalModelCheckerTestCase.java b/tlatools/test/pcal/PCalModelCheckerTestCase.java new file mode 100644 index 0000000000000000000000000000000000000000..b291923729ed7bbcc6f18881f6db68ff15d8463d --- /dev/null +++ b/tlatools/test/pcal/PCalModelCheckerTestCase.java @@ -0,0 +1,71 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.junit.Before; + +import tlc2.tool.CommonTestCase; +import tlc2.tool.liveness.ModelCheckerTestCase; +import util.ToolIO; + +public abstract class PCalModelCheckerTestCase extends ModelCheckerTestCase { + + private final List<String> pcalArgs = new ArrayList<String>(); + + public PCalModelCheckerTestCase(final String spec, final String path) { + super(spec, path); + this.pcalArgs.add("-unixEOL"); + } + + public PCalModelCheckerTestCase(final String spec, final String path, final String[] extraPcalArgs) { + this(spec, path); + this.pcalArgs.addAll(Arrays.asList(extraPcalArgs)); + } + + @Before + @Override + public void setUp() { + this.pcalArgs.add(CommonTestCase.BASE_PATH + File.separator + path + File.separator + spec + ".tla"); + + // Run PCal translator + final TLAtoPCalMapping pcal2tla = trans.runMe(pcalArgs.toArray(new String[pcalArgs.size()])); + assertNotNull(pcal2tla); // successfully translated PCal to TLA+ + + final String[] messages = ToolIO.getAllMessages(); + assertTrue(Arrays.toString(messages), messages.length == 0); + + // Run TLC + super.setUp(); + } +} diff --git a/tlatools/test/pcal/PCalTest.java b/tlatools/test/pcal/PCalTest.java new file mode 100644 index 0000000000000000000000000000000000000000..100ed726e11abd87ee52564c4a11091dda622ae0 --- /dev/null +++ b/tlatools/test/pcal/PCalTest.java @@ -0,0 +1,19 @@ +package pcal; + +import org.junit.Before; + +import util.ToolIO; + +public abstract class PCalTest { + + @Before + public void setup() { + // Make tool capture the output written to ToolIO.out. Otherwise, + // ToolIO#getAllMessages returns an empty array. + ToolIO.setMode(ToolIO.TOOL); + + // Reset ToolIO for each test case. Otherwise, a test case sees the output of + // the previous tests. + ToolIO.reset(); + } +} diff --git a/tlatools/test/pcal/PcalPaxosTest.java b/tlatools/test/pcal/PcalPaxosTest.java new file mode 100644 index 0000000000000000000000000000000000000000..a8526a2e004d6d5c89afb22ce5f707c65093055e --- /dev/null +++ b/tlatools/test/pcal/PcalPaxosTest.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class PcalPaxosTest extends PCalModelCheckerTestCase { + + public PcalPaxosTest() { + super("PcalPaxos", "pcal"); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "1")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "", "", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "")); + } +} diff --git a/tlatools/test/pcal/PetersonTest.java b/tlatools/test/pcal/PetersonTest.java new file mode 100644 index 0000000000000000000000000000000000000000..6238f85d2bf82bcb025048e14a785932c1f27559 --- /dev/null +++ b/tlatools/test/pcal/PetersonTest.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class PetersonTest extends PCalModelCheckerTestCase { + + public PetersonTest() { + super("Peterson", "pcal"); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "1")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "85", "42", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "11")); + } +} diff --git a/tlatools/test/pcal/Quicksort2ProcsTest.java b/tlatools/test/pcal/Quicksort2ProcsTest.java new file mode 100644 index 0000000000000000000000000000000000000000..4750a70ffba8c9be04b6c1acc415eb2a4436f75a --- /dev/null +++ b/tlatools/test/pcal/Quicksort2ProcsTest.java @@ -0,0 +1,74 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class Quicksort2ProcsTest extends PCalModelCheckerTestCase { + + public Quicksort2ProcsTest() { + super("Quicksort2Procs", "pcal", new String[] {"-wf", "-termination"}); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "27")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_CHECKING_TEMPORAL_PROPS, "complete", "361")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "445", "361", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "15")); + } +} +/* +C:\lamport\tla\pluscal>java -mx1000m -cp "c:/lamport/tla/newtools/tla2-inria-workspace/tla2-inria/tlatools/class" tlc2.TLC -cleanup Quicksort2Procs.tla +TLC2 Version 2.05 of 18 May 2012 +Running in Model-Checking mode. +Parsing file Quicksort2Procs.tla +Parsing file C:\lamport\tla\newtools\tla2-inria-workspace\tla2-inria\tlatools\class\tla2sany\StandardModules\Naturals.tla +Parsing file C:\lamport\tla\newtools\tla2-inria-workspace\tla2-inria\tlatools\class\tla2sany\StandardModules\Sequences.tla +Semantic processing of module Naturals +Semantic processing of module Sequences +Semantic processing of module Quicksort2Procs +Starting... (2012-08-10 17:38:29) +Implied-temporal checking--satisfiability problem has 1 branches. +Computing initial states... +Finished computing initial states: 27 distinct states generated. +Checking temporal properties for the complete state space... +Model checking completed. No error has been found. + Estimates of the probability that TLC did not check all reachable states + because two distinct states had the same fingerprint: + calculated (optimistic): val = 1.6E-15 + based on the actual fingerprints: val = 1.1E-14 +445 states generated, 361 distinct states found, 0 states left on queue. +The depth of the complete state graph search is 15. +Finished. (2012-08-10 17:38:29) +*/ \ No newline at end of file diff --git a/tlatools/test/pcal/QuicksortMacroTest.java b/tlatools/test/pcal/QuicksortMacroTest.java new file mode 100644 index 0000000000000000000000000000000000000000..b59d9bd21a488551ee49d6a5cb79d08c785ba909 --- /dev/null +++ b/tlatools/test/pcal/QuicksortMacroTest.java @@ -0,0 +1,74 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class QuicksortMacroTest extends PCalModelCheckerTestCase { + + public QuicksortMacroTest() { + super("QuicksortMacro", "pcal", new String[] {"-wf", "-termination"}); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "27")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_CHECKING_TEMPORAL_PROPS, "complete", "306")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "390", "306", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "13")); + } +} +/* +C:\lamport\tla\pluscal>java -mx1000m -cp "c:/lamport/tla/newtools/tla2-inria-workspace/tla2-inria/tlatools/class" tlc2.TLC -cleanup QuicksortMacro.tla +TLC2 Version 2.05 of 18 May 2012 +Running in Model-Checking mode. +Parsing file QuicksortMacro.tla +Parsing file C:\lamport\tla\newtools\tla2-inria-workspace\tla2-inria\tlatools\class\tla2sany\StandardModules\Naturals.tla +Parsing file C:\lamport\tla\newtools\tla2-inria-workspace\tla2-inria\tlatools\class\tla2sany\StandardModules\Sequences.tla +Semantic processing of module Naturals +Semantic processing of module Sequences +Semantic processing of module QuicksortMacro +Starting... (2012-08-10 17:38:27) +Implied-temporal checking--satisfiability problem has 1 branches. +Computing initial states... +Finished computing initial states: 27 distinct states generated. +Checking temporal properties for the complete state space... +Model checking completed. No error has been found. + Estimates of the probability that TLC did not check all reachable states + because two distinct states had the same fingerprint: + calculated (optimistic): val = 1.4E-15 + based on the actual fingerprints: val = 4.6E-15 +390 states generated, 306 distinct states found, 0 states left on queue. +The depth of the complete state graph search is 13. +Finished. (2012-08-10 17:38:28) +*/ \ No newline at end of file diff --git a/tlatools/test/pcal/QuicksortTest.java b/tlatools/test/pcal/QuicksortTest.java new file mode 100644 index 0000000000000000000000000000000000000000..3a26d807e8e340fa119672b008d997a463e283c7 --- /dev/null +++ b/tlatools/test/pcal/QuicksortTest.java @@ -0,0 +1,76 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class QuicksortTest extends PCalModelCheckerTestCase { + + public QuicksortTest() { + super("Quicksort", "pcal", new String[] {"-wf", "-termination"}); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "27")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_CHECKING_TEMPORAL_PROPS, "complete", "933")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "1017", "933", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "16")); + } +} +/* +C:\lamport\tla\pluscal>java -mx1000m -cp "c:/lamport/tla/newtools/tla2-inria-workspace/tla2-inria/tlatools/class" tlc2.TLC -cleanup Quicksort.tla +TLC2 Version 2.05 of 18 May 2012 +Running in Model-Checking mode. +Parsing file Quicksort.tla +Parsing file C:\lamport\tla\newtools\tla2-inria-workspace\tla2-inria\tlatools\class\tla2sany\StandardModules\Naturals.tla +Parsing file C:\lamport\tla\newtools\tla2-inria-workspace\tla2-inria\tlatools\class\tla2sany\StandardModules\Sequences.tla +Parsing file C:\lamport\tla\newtools\tla2-inria-workspace\tla2-inria\tlatools\class\tla2sany\StandardModules\TLC.tla +Semantic processing of module Naturals +Semantic processing of module Sequences +Semantic processing of module TLC +Semantic processing of module Quicksort +Starting... (2012-08-10 17:38:26) +Implied-temporal checking--satisfiability problem has 1 branches. +Computing initial states... +Finished computing initial states: 27 distinct states generated. +Checking temporal properties for the complete state space... +Model checking completed. No error has been found. + Estimates of the probability that TLC did not check all reachable states + because two distinct states had the same fingerprint: + calculated (optimistic): val = 4.2E-15 + based on the actual fingerprints: val = 2.3E-14 +1017 states generated, 933 distinct states found, 0 states left on queue. +The depth of the complete state graph search is 16. +Finished. (2012-08-10 17:38:26) +*/ \ No newline at end of file diff --git a/tlatools/test/pcal/RABTest.java b/tlatools/test/pcal/RABTest.java new file mode 100644 index 0000000000000000000000000000000000000000..fe470122f450c612d02ad63e5262e8ae6bc6954b --- /dev/null +++ b/tlatools/test/pcal/RABTest.java @@ -0,0 +1,245 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Test; + +import tlc2.output.EC; + +public class RABTest extends PCalModelCheckerTestCase { + + public RABTest() { + super("RAB", "pcal"); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "4")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "551", "350", "130")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "7")); + + assertTrue(recorder.recorded(EC.TLC_STATE_PRINT2)); + final List<String> expectedTrace = new ArrayList<String>(); + expectedTrace.add("/\\ myattr = (p0 :> \"A\" @@ p1 :> \"A\")\n" + + "/\\ temp = ( p0 :>\n" + + " [ A |-> [valid |-> FALSE, value |-> FALSE],\n" + + " B |-> [valid |-> FALSE, value |-> FALSE] ] @@\n" + + " p1 :>\n" + + " [ A |-> [valid |-> FALSE, value |-> FALSE],\n" + + " B |-> [valid |-> FALSE, value |-> FALSE] ] )\n" + + "/\\ calc = [A |-> FALSE, B |-> TRUE]\n" + + "/\\ pc = (p0 :> \"Loop\" @@ p1 :> \"Loop\")\n" + + "/\\ flags = [ A |-> [valid |-> FALSE, value |-> FALSE],\n" + + " B |-> [valid |-> FALSE, value |-> FALSE] ]"); + expectedTrace.add("/\\ myattr = (p0 :> \"A\" @@ p1 :> \"A\")\n" + + "/\\ temp = ( p0 :>\n" + + " [ A |-> [valid |-> TRUE, value |-> FALSE],\n" + + " B |-> [valid |-> FALSE, value |-> FALSE] ] @@\n" + + " p1 :>\n" + + " [ A |-> [valid |-> FALSE, value |-> FALSE],\n" + + " B |-> [valid |-> FALSE, value |-> FALSE] ] )\n" + + "/\\ calc = [A |-> FALSE, B |-> TRUE]\n" + + "/\\ pc = (p0 :> \"FetchFlags\" @@ p1 :> \"Loop\")\n" + + "/\\ flags = [ A |-> [valid |-> FALSE, value |-> FALSE],\n" + + " B |-> [valid |-> FALSE, value |-> FALSE] ]"); + expectedTrace.add("/\\ myattr = (p0 :> \"A\" @@ p1 :> \"A\")\n" + + "/\\ temp = ( p0 :>\n" + + " [ A |-> [valid |-> TRUE, value |-> FALSE],\n" + + " B |-> [valid |-> FALSE, value |-> FALSE] ] @@\n" + + " p1 :>\n" + + " [ A |-> [valid |-> FALSE, value |-> FALSE],\n" + + " B |-> [valid |-> FALSE, value |-> FALSE] ] )\n" + + "/\\ calc = [A |-> FALSE, B |-> TRUE]\n" + + "/\\ pc = (p0 :> \"StoreFlags\" @@ p1 :> \"Loop\")\n" + + "/\\ flags = [ A |-> [valid |-> FALSE, value |-> FALSE],\n" + + " B |-> [valid |-> FALSE, value |-> FALSE] ]"); + expectedTrace.add("/\\ myattr = (p0 :> \"A\" @@ p1 :> \"B\")\n" + + "/\\ temp = ( p0 :>\n" + + " [ A |-> [valid |-> TRUE, value |-> FALSE],\n" + + " B |-> [valid |-> FALSE, value |-> FALSE] ] @@\n" + + " p1 :>\n" + + " [ A |-> [valid |-> FALSE, value |-> FALSE],\n" + + " B |-> [valid |-> TRUE, value |-> TRUE] ] )\n" + + "/\\ calc = [A |-> FALSE, B |-> TRUE]\n" + + "/\\ pc = (p0 :> \"StoreFlags\" @@ p1 :> \"FetchFlags\")\n" + + "/\\ flags = [ A |-> [valid |-> FALSE, value |-> FALSE],\n" + + " B |-> [valid |-> FALSE, value |-> FALSE] ]"); + expectedTrace.add("/\\ myattr = (p0 :> \"A\" @@ p1 :> \"B\")\n" + + "/\\ temp = ( p0 :>\n" + + " [ A |-> [valid |-> TRUE, value |-> FALSE],\n" + + " B |-> [valid |-> FALSE, value |-> FALSE] ] @@\n" + + " p1 :>\n" + + " [ A |-> [valid |-> FALSE, value |-> FALSE],\n" + + " B |-> [valid |-> TRUE, value |-> TRUE] ] )\n" + + "/\\ calc = [A |-> FALSE, B |-> TRUE]\n" + + "/\\ pc = (p0 :> \"StoreFlags\" @@ p1 :> \"StoreFlags\")\n" + + "/\\ flags = [ A |-> [valid |-> FALSE, value |-> FALSE],\n" + + " B |-> [valid |-> FALSE, value |-> FALSE] ]"); + expectedTrace.add("/\\ myattr = (p0 :> \"A\" @@ p1 :> \"B\")\n" + + "/\\ temp = ( p0 :>\n" + + " [ A |-> [valid |-> TRUE, value |-> FALSE],\n" + + " B |-> [valid |-> FALSE, value |-> FALSE] ] @@\n" + + " p1 :>\n" + + " [ A |-> [valid |-> FALSE, value |-> FALSE],\n" + + " B |-> [valid |-> TRUE, value |-> TRUE] ] )\n" + + "/\\ calc = [A |-> FALSE, B |-> TRUE]\n" + + "/\\ pc = (p0 :> \"StoreFlags\" @@ p1 :> \"ReadFlags\")\n" + + "/\\ flags = [ A |-> [valid |-> FALSE, value |-> FALSE],\n" + + " B |-> [valid |-> TRUE, value |-> TRUE] ]"); + expectedTrace.add("/\\ myattr = (p0 :> \"A\" @@ p1 :> \"B\")\n" + + "/\\ temp = ( p0 :>\n" + + " [ A |-> [valid |-> TRUE, value |-> FALSE],\n" + + " B |-> [valid |-> FALSE, value |-> FALSE] ] @@\n" + + " p1 :>\n" + + " [ A |-> [valid |-> FALSE, value |-> FALSE],\n" + + " B |-> [valid |-> TRUE, value |-> TRUE] ] )\n" + + "/\\ calc = [A |-> FALSE, B |-> TRUE]\n" + + "/\\ pc = (p0 :> \"ReadFlags\" @@ p1 :> \"ReadFlags\")\n" + + "/\\ flags = [ A |-> [valid |-> TRUE, value |-> FALSE],\n" + + " B |-> [valid |-> FALSE, value |-> FALSE] ]"); + assertTraceWith(recorder.getRecords(EC.TLC_STATE_PRINT2), expectedTrace); + } +} +/* +C:\lamport\tla\pluscal>java -mx1000m -cp "c:/lamport/tla/newtools/tla2-inria-workspace/tla2-inria/tlatools/class" tlc2.TLC -cleanup RAB.tla +TLC2 Version 2.05 of 18 May 2012 +Running in Model-Checking mode. +Parsing file RAB.tla +Parsing file C:\lamport\tla\newtools\tla2-inria-workspace\tla2-inria\tlatools\class\tla2sany\StandardModules\Naturals.tla +Parsing file C:\lamport\tla\newtools\tla2-inria-workspace\tla2-inria\tlatools\class\tla2sany\StandardModules\Sequences.tla +Parsing file C:\lamport\tla\newtools\tla2-inria-workspace\tla2-inria\tlatools\class\tla2sany\StandardModules\TLC.tla +Semantic processing of module Naturals +Semantic processing of module Sequences +Semantic processing of module TLC +Semantic processing of module RAB +Starting... (2012-08-10 17:38:30) +Computing initial states... +Finished computing initial states: 4 distinct states generated. +Error: Invariant Consistency is violated. +Error: The behavior up to this point is: +State 1: <Initial predicate> +/\ myattr = (p0 :> "A" @@ p1 :> "A") +/\ temp = ( p0 :> + [ A |-> [valid |-> FALSE, value |-> FALSE], + B |-> [valid |-> FALSE, value |-> FALSE] ] @@ + p1 :> + [ A |-> [valid |-> FALSE, value |-> FALSE], + B |-> [valid |-> FALSE, value |-> FALSE] ] ) +/\ calc = [A |-> FALSE, B |-> TRUE] +/\ pc = (p0 :> "Loop" @@ p1 :> "Loop") +/\ flags = [ A |-> [valid |-> FALSE, value |-> FALSE], + B |-> [valid |-> FALSE, value |-> FALSE] ] + +State 2: <Action line 163, col 15 to line 175, col 44 of module RAB> +/\ myattr = (p0 :> "A" @@ p1 :> "A") +/\ temp = ( p0 :> + [ A |-> [valid |-> TRUE, value |-> FALSE], + B |-> [valid |-> FALSE, value |-> FALSE] ] @@ + p1 :> + [ A |-> [valid |-> FALSE, value |-> FALSE], + B |-> [valid |-> FALSE, value |-> FALSE] ] ) +/\ calc = [A |-> FALSE, B |-> TRUE] +/\ pc = (p0 :> "FetchFlags" @@ p1 :> "Loop") +/\ flags = [ A |-> [valid |-> FALSE, value |-> FALSE], + B |-> [valid |-> FALSE, value |-> FALSE] ] + +State 3: <Action line 182, col 21 to line 185, col 58 of module RAB> +/\ myattr = (p0 :> "A" @@ p1 :> "A") +/\ temp = ( p0 :> + [ A |-> [valid |-> TRUE, value |-> FALSE], + B |-> [valid |-> FALSE, value |-> FALSE] ] @@ + p1 :> + [ A |-> [valid |-> FALSE, value |-> FALSE], + B |-> [valid |-> FALSE, value |-> FALSE] ] ) +/\ calc = [A |-> FALSE, B |-> TRUE] +/\ pc = (p0 :> "StoreFlags" @@ p1 :> "Loop") +/\ flags = [ A |-> [valid |-> FALSE, value |-> FALSE], + B |-> [valid |-> FALSE, value |-> FALSE] ] + +State 4: <Action line 163, col 15 to line 175, col 44 of module RAB> +/\ myattr = (p0 :> "A" @@ p1 :> "B") +/\ temp = ( p0 :> + [ A |-> [valid |-> TRUE, value |-> FALSE], + B |-> [valid |-> FALSE, value |-> FALSE] ] @@ + p1 :> + [ A |-> [valid |-> FALSE, value |-> FALSE], + B |-> [valid |-> TRUE, value |-> TRUE] ] ) +/\ calc = [A |-> FALSE, B |-> TRUE] +/\ pc = (p0 :> "StoreFlags" @@ p1 :> "FetchFlags") +/\ flags = [ A |-> [valid |-> FALSE, value |-> FALSE], + B |-> [valid |-> FALSE, value |-> FALSE] ] + +State 5: <Action line 182, col 21 to line 185, col 58 of module RAB> +/\ myattr = (p0 :> "A" @@ p1 :> "B") +/\ temp = ( p0 :> + [ A |-> [valid |-> TRUE, value |-> FALSE], + B |-> [valid |-> FALSE, value |-> FALSE] ] @@ + p1 :> + [ A |-> [valid |-> FALSE, value |-> FALSE], + B |-> [valid |-> TRUE, value |-> TRUE] ] ) +/\ calc = [A |-> FALSE, B |-> TRUE] +/\ pc = (p0 :> "StoreFlags" @@ p1 :> "StoreFlags") +/\ flags = [ A |-> [valid |-> FALSE, value |-> FALSE], + B |-> [valid |-> FALSE, value |-> FALSE] ] + +State 6: <Action line 187, col 21 to line 190, col 57 of module RAB> +/\ myattr = (p0 :> "A" @@ p1 :> "B") +/\ temp = ( p0 :> + [ A |-> [valid |-> TRUE, value |-> FALSE], + B |-> [valid |-> FALSE, value |-> FALSE] ] @@ + p1 :> + [ A |-> [valid |-> FALSE, value |-> FALSE], + B |-> [valid |-> TRUE, value |-> TRUE] ] ) +/\ calc = [A |-> FALSE, B |-> TRUE] +/\ pc = (p0 :> "StoreFlags" @@ p1 :> "ReadFlags") +/\ flags = [ A |-> [valid |-> FALSE, value |-> FALSE], + B |-> [valid |-> TRUE, value |-> TRUE] ] + +State 7: <Action line 187, col 21 to line 190, col 57 of module RAB> +/\ myattr = (p0 :> "A" @@ p1 :> "B") +/\ temp = ( p0 :> + [ A |-> [valid |-> TRUE, value |-> FALSE], + B |-> [valid |-> FALSE, value |-> FALSE] ] @@ + p1 :> + [ A |-> [valid |-> FALSE, value |-> FALSE], + B |-> [valid |-> TRUE, value |-> TRUE] ] ) +/\ calc = [A |-> FALSE, B |-> TRUE] +/\ pc = (p0 :> "ReadFlags" @@ p1 :> "ReadFlags") +/\ flags = [ A |-> [valid |-> TRUE, value |-> FALSE], + B |-> [valid |-> FALSE, value |-> FALSE] ] + +551 states generated, 350 distinct states found, 131 states left on queue. +The depth of the complete state graph search is 7. +Finished. (2012-08-10 17:38:30) +*/ \ No newline at end of file diff --git a/tlatools/test/pcal/RealQuicksort2Test.java b/tlatools/test/pcal/RealQuicksort2Test.java new file mode 100644 index 0000000000000000000000000000000000000000..ea4a5563fb2028c748f3f75ce63b4a30210fe391 --- /dev/null +++ b/tlatools/test/pcal/RealQuicksort2Test.java @@ -0,0 +1,76 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class RealQuicksort2Test extends PCalModelCheckerTestCase { + + public RealQuicksort2Test() { + super("RealQuicksort2", "pcal", new String[] {"-wf", "-termination"}); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "33")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_CHECKING_TEMPORAL_PROPS, "complete", "612")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "853", "612", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "11")); + } +} +/* +C:\lamport\tla\pluscal>java -mx1000m -cp "c:/lamport/tla/newtools/tla2-inria-workspace/tla2-inria/tlatools/class" tlc2.TLC -cleanup RealQuicksort2.tla +TLC2 Version 2.05 of 18 May 2012 +Running in Model-Checking mode. +Parsing file RealQuicksort2.tla +Parsing file C:\lamport\tla\newtools\tla2-inria-workspace\tla2-inria\tlatools\class\tla2sany\StandardModules\Naturals.tla +Parsing file C:\lamport\tla\newtools\tla2-inria-workspace\tla2-inria\tlatools\class\tla2sany\StandardModules\Sequences.tla +Parsing file C:\lamport\tla\newtools\tla2-inria-workspace\tla2-inria\tlatools\class\tla2sany\StandardModules\FiniteSets.tla +Semantic processing of module Naturals +Semantic processing of module Sequences +Semantic processing of module FiniteSets +Semantic processing of module RealQuicksort2 +Starting... (2012-08-10 17:38:33) +Implied-temporal checking--satisfiability problem has 1 branches. +Computing initial states... +Finished computing initial states: 33 distinct states generated. +Checking temporal properties for the complete state space... +Model checking completed. No error has been found. + Estimates of the probability that TLC did not check all reachable states + because two distinct states had the same fingerprint: + calculated (optimistic): val = 8.0E-15 + based on the actual fingerprints: val = 2.2E-14 +853 states generated, 612 distinct states found, 0 states left on queue. +The depth of the complete state graph search is 11. +Finished. (2012-08-10 17:38:33) +*/ \ No newline at end of file diff --git a/tlatools/test/pcal/RealQuicksortTest.java b/tlatools/test/pcal/RealQuicksortTest.java new file mode 100644 index 0000000000000000000000000000000000000000..d7ba5e6841521f84e7812165cea7ea1f4557523d --- /dev/null +++ b/tlatools/test/pcal/RealQuicksortTest.java @@ -0,0 +1,76 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class RealQuicksortTest extends PCalModelCheckerTestCase { + + public RealQuicksortTest() { + super("RealQuicksort", "pcal", new String[] {"-wf", "-termination"}); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "33")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_CHECKING_TEMPORAL_PROPS, "complete", "495")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "706", "495", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "14")); + } +} +/* +C:\lamport\tla\pluscal>java -mx1000m -cp "c:/lamport/tla/newtools/tla2-inria-workspace/tla2-inria/tlatools/class" tlc2.TLC -cleanup RealQuicksort.tla +TLC2 Version 2.05 of 18 May 2012 +Running in Model-Checking mode. +Parsing file RealQuicksort.tla +Parsing file C:\lamport\tla\newtools\tla2-inria-workspace\tla2-inria\tlatools\class\tla2sany\StandardModules\Naturals.tla +Parsing file C:\lamport\tla\newtools\tla2-inria-workspace\tla2-inria\tlatools\class\tla2sany\StandardModules\Sequences.tla +Parsing file C:\lamport\tla\newtools\tla2-inria-workspace\tla2-inria\tlatools\class\tla2sany\StandardModules\FiniteSets.tla +Semantic processing of module Naturals +Semantic processing of module Sequences +Semantic processing of module FiniteSets +Semantic processing of module RealQuicksort +Starting... (2012-08-10 17:38:31) +Implied-temporal checking--satisfiability problem has 1 branches. +Computing initial states... +Finished computing initial states: 33 distinct states generated. +Checking temporal properties for the complete state space... +Model checking completed. No error has been found. + Estimates of the probability that TLC did not check all reachable states + because two distinct states had the same fingerprint: + calculated (optimistic): val = 5.7E-15 + based on the actual fingerprints: val = 2.7E-15 +706 states generated, 495 distinct states found, 0 states left on queue. +The depth of the complete state graph search is 14. +Finished. (2012-08-10 17:38:32) +*/ \ No newline at end of file diff --git a/tlatools/test/pcal/ReallySimpleMultiProcTest.java b/tlatools/test/pcal/ReallySimpleMultiProcTest.java new file mode 100644 index 0000000000000000000000000000000000000000..7e11812a17c7f0db2d4bca86e0529a7a57a1615a --- /dev/null +++ b/tlatools/test/pcal/ReallySimpleMultiProcTest.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class ReallySimpleMultiProcTest extends PCalModelCheckerTestCase { + + public ReallySimpleMultiProcTest() { + super("ReallySimpleMultiProc", "pcal", new String[] {"-wf", "-termination"}); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "4")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_CHECKING_TEMPORAL_PROPS, "complete", "76")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "144", "76", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "7")); + } +} diff --git a/tlatools/test/pcal/SBBTest.java b/tlatools/test/pcal/SBBTest.java new file mode 100644 index 0000000000000000000000000000000000000000..420682afb32bfec7321d8c6ea38c514a0c240d48 --- /dev/null +++ b/tlatools/test/pcal/SBBTest.java @@ -0,0 +1,146 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Test; + +import tlc2.output.EC; + +public class SBBTest extends PCalModelCheckerTestCase { + + public SBBTest() { + super("SBB", "pcal"); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "1")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "3126", "1617", "328")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "15")); + + assertTrue(recorder.recorded(EC.TLC_STATE_PRINT2)); + final List<String> expectedTrace = new ArrayList<String>(); + expectedTrace.add("/\\ availablebuffers = {b1, b2, b3}\n" + + "/\\ publishedbuffers = {}\n" + + "/\\ sb = [buf |-> b0, owner |-> NoPid]\n" + + "/\\ buf = (p0 :> NoBuf @@ p1 :> NoBuf)\n" + + "/\\ op = (p0 :> {} @@ p1 :> {})\n" + + "/\\ pc = (p0 :> \"Loop\" @@ p1 :> \"Loop\")"); + expectedTrace.add("/\\ availablebuffers = {b1, b2, b3}\n" + + "/\\ publishedbuffers = {}\n" + + "/\\ sb = [buf |-> b0, owner |-> NoPid]\n" + + "/\\ buf = (p0 :> b0 @@ p1 :> NoBuf)\n" + + "/\\ op = (p0 :> \"Publish\" @@ p1 :> {})\n" + + "/\\ pc = (p0 :> \"Publish1\" @@ p1 :> \"Loop\")"); + expectedTrace.add("/\\ availablebuffers = {b1, b2, b3}\n" + + "/\\ publishedbuffers = {}\n" + + "/\\ sb = [buf |-> b0, owner |-> NoPid]\n" + + "/\\ buf = (p0 :> b0 @@ p1 :> NoBuf)\n" + + "/\\ op = (p0 :> \"Publish\" @@ p1 :> {})\n" + + "/\\ pc = (p0 :> \"Publish2\" @@ p1 :> \"Loop\")"); + expectedTrace.add("/\\ availablebuffers = {b1, b2, b3}\n" + + "/\\ publishedbuffers = {}\n" + + "/\\ sb = [buf |-> b0, owner |-> NoPid]\n" + + "/\\ buf = (p0 :> b0 @@ p1 :> b0)\n" + + "/\\ op = (p0 :> \"Publish\" @@ p1 :> \"Modify\")\n" + + "/\\ pc = (p0 :> \"Publish2\" @@ p1 :> \"Modify1\")"); + expectedTrace.add("/\\ availablebuffers = {b2, b3}\n" + + "/\\ publishedbuffers = {}\n" + + "/\\ sb = [buf |-> b0, owner |-> NoPid]\n" + + "/\\ buf = (p0 :> b0 @@ p1 :> b1)\n" + + "/\\ op = (p0 :> \"Publish\" @@ p1 :> \"Modify\")\n" + + "/\\ pc = (p0 :> \"Publish2\" @@ p1 :> \"Modify2\")"); + expectedTrace.add("/\\ availablebuffers = {b2, b3}\n" + + "/\\ publishedbuffers = {}\n" + + "/\\ sb = [buf |-> b0, owner |-> p1]\n" + + "/\\ buf = (p0 :> b0 @@ p1 :> b1)\n" + + "/\\ op = (p0 :> \"Publish\" @@ p1 :> \"Modify\")\n" + + "/\\ pc = (p0 :> \"Publish2\" @@ p1 :> \"Modify3\")"); + expectedTrace.add("/\\ availablebuffers = {b2, b3}\n" + + "/\\ publishedbuffers = {}\n" + + "/\\ sb = [buf |-> b1, owner |-> p1]\n" + + "/\\ buf = (p0 :> b0 @@ p1 :> b1)\n" + + "/\\ op = (p0 :> \"Publish\" @@ p1 :> \"Modify\")\n" + + "/\\ pc = (p0 :> \"Publish2\" @@ p1 :> \"Loop\")"); + expectedTrace.add("/\\ availablebuffers = {b2, b3}\n" + + "/\\ publishedbuffers = {}\n" + + "/\\ sb = [buf |-> b1, owner |-> p1]\n" + + "/\\ buf = (p0 :> b0 @@ p1 :> b1)\n" + + "/\\ op = (p0 :> \"Publish\" @@ p1 :> \"Modify\")\n" + + "/\\ pc = (p0 :> \"Publish2\" @@ p1 :> \"Modify1\")"); + expectedTrace.add("/\\ availablebuffers = {b2, b3}\n" + + "/\\ publishedbuffers = {}\n" + + "/\\ sb = [buf |-> b1, owner |-> p1]\n" + + "/\\ buf = (p0 :> b0 @@ p1 :> b1)\n" + + "/\\ op = (p0 :> \"Publish\" @@ p1 :> \"Modify\")\n" + + "/\\ pc = (p0 :> \"Publish2\" @@ p1 :> \"Modify2\")"); + expectedTrace.add("/\\ availablebuffers = {b2, b3}\n" + + "/\\ publishedbuffers = {}\n" + + "/\\ sb = [buf |-> b1, owner |-> NoPid]\n" + + "/\\ buf = (p0 :> b0 @@ p1 :> b1)\n" + + "/\\ op = (p0 :> \"Publish\" @@ p1 :> \"Modify\")\n" + + "/\\ pc = (p0 :> \"Publish3\" @@ p1 :> \"Modify2\")"); + expectedTrace.add("/\\ availablebuffers = {b2, b3}\n" + + "/\\ publishedbuffers = {b0}\n" + + "/\\ sb = [buf |-> b1, owner |-> NoPid]\n" + + "/\\ buf = (p0 :> b0 @@ p1 :> b1)\n" + + "/\\ op = (p0 :> \"Publish\" @@ p1 :> \"Modify\")\n" + + "/\\ pc = (p0 :> \"Loop\" @@ p1 :> \"Modify2\")"); + expectedTrace.add("/\\ availablebuffers = {b2, b3}\n" + + "/\\ publishedbuffers = {b0}\n" + + "/\\ sb = [buf |-> b1, owner |-> NoPid]\n" + + "/\\ buf = (p0 :> b1 @@ p1 :> b1)\n" + + "/\\ op = (p0 :> \"Publish\" @@ p1 :> \"Modify\")\n" + + "/\\ pc = (p0 :> \"Publish1\" @@ p1 :> \"Modify2\")"); + expectedTrace.add("/\\ availablebuffers = {b2, b3}\n" + + "/\\ publishedbuffers = {b0}\n" + + "/\\ sb = [buf |-> b1, owner |-> NoPid]\n" + + "/\\ buf = (p0 :> b1 @@ p1 :> b1)\n" + + "/\\ op = (p0 :> \"Publish\" @@ p1 :> \"Modify\")\n" + + "/\\ pc = (p0 :> \"Publish2\" @@ p1 :> \"Modify2\")"); + expectedTrace.add("/\\ availablebuffers = {b2, b3}\n" + + "/\\ publishedbuffers = {b0}\n" + + "/\\ sb = [buf |-> b1, owner |-> NoPid]\n" + + "/\\ buf = (p0 :> b1 @@ p1 :> b1)\n" + + "/\\ op = (p0 :> \"Publish\" @@ p1 :> \"Modify\")\n" + + "/\\ pc = (p0 :> \"Publish3\" @@ p1 :> \"Modify2\")"); + expectedTrace.add("/\\ availablebuffers = {b2, b3}\n" + + "/\\ publishedbuffers = {b0, b1}\n" + + "/\\ sb = [buf |-> b1, owner |-> NoPid]\n" + + "/\\ buf = (p0 :> b1 @@ p1 :> b1)\n" + + "/\\ op = (p0 :> \"Publish\" @@ p1 :> \"Modify\")\n" + + "/\\ pc = (p0 :> \"Loop\" @@ p1 :> \"Modify2\")"); + assertTraceWith(recorder.getRecords(EC.TLC_STATE_PRINT2), expectedTrace); + } +} diff --git a/tlatools/test/pcal/SemaphoreMutexTest.java b/tlatools/test/pcal/SemaphoreMutexTest.java new file mode 100644 index 0000000000000000000000000000000000000000..a91ce5e588e603e393f399d8081ac31341e9f601 --- /dev/null +++ b/tlatools/test/pcal/SemaphoreMutexTest.java @@ -0,0 +1,72 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class SemaphoreMutexTest extends PCalModelCheckerTestCase { + + public SemaphoreMutexTest() { + super("SemaphoreMutex", "pcal", new String[] {"-sf"}); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "1")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_CHECKING_TEMPORAL_PROPS, "complete", "32")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "73", "32", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "6")); + } +} +/* +C:\lamport\tla\pluscal>java -mx1000m -cp "c:/lamport/tla/newtools/tla2-inria-workspace/tla2-inria/tlatools/class" tlc2.TLC -cleanup SemaphoreMutex.tla +TLC2 Version 2.05 of 18 May 2012 +Running in Model-Checking mode. +Parsing file SemaphoreMutex.tla +Parsing file C:\lamport\tla\newtools\tla2-inria-workspace\tla2-inria\tlatools\class\tla2sany\StandardModules\Naturals.tla +Semantic processing of module Naturals +Semantic processing of module SemaphoreMutex +Starting... (2012-08-10 17:38:36) +Implied-temporal checking--satisfiability problem has 1 branches. +Computing initial states... +Finished computing initial states: 1 distinct state generated. +Checking temporal properties for the complete state space... +Model checking completed. No error has been found. + Estimates of the probability that TLC did not check all reachable states + because two distinct states had the same fingerprint: + calculated (optimistic): val = 7.1E-17 + based on the actual fingerprints: val = 2.9E-15 +73 states generated, 32 distinct states found, 0 states left on queue. +The depth of the complete state graph search is 6. +Finished. (2012-08-10 17:38:36) +*/ \ No newline at end of file diff --git a/tlatools/test/pcal/SimpleLoopTest.java b/tlatools/test/pcal/SimpleLoopTest.java new file mode 100644 index 0000000000000000000000000000000000000000..d2a45d36af00cfe6ac888469af6407433b5bf21a --- /dev/null +++ b/tlatools/test/pcal/SimpleLoopTest.java @@ -0,0 +1,76 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class SimpleLoopTest extends PCalModelCheckerTestCase { + + public SimpleLoopTest() { + super("SimpleLoop", "pcal", new String[] {"-wf", "-termination"}); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "1")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_CHECKING_TEMPORAL_PROPS, "complete", "12")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "13", "12", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "12")); + } +} +/* +C:\lamport\tla\pluscal>java -mx1000m -cp "c:/lamport/tla/newtools/tla2-inria-workspace/tla2-inria/tlatools/class" tlc2.TLC -cleanup SimpleLoop.tla +TLC2 Version 2.05 of 18 May 2012 +Running in Model-Checking mode. +Parsing file SimpleLoop.tla +Parsing file C:\lamport\tla\newtools\tla2-inria-workspace\tla2-inria\tlatools\class\tla2sany\StandardModules\Naturals.tla +Parsing file C:\lamport\tla\newtools\tla2-inria-workspace\tla2-inria\tlatools\class\tla2sany\StandardModules\TLC.tla +Parsing file C:\lamport\tla\newtools\tla2-inria-workspace\tla2-inria\tlatools\class\tla2sany\StandardModules\Sequences.tla +Semantic processing of module Naturals +Semantic processing of module Sequences +Semantic processing of module TLC +Semantic processing of module SimpleLoop +Starting... (2012-08-10 17:38:37) +Implied-temporal checking--satisfiability problem has 1 branches. +Computing initial states... +Finished computing initial states: 1 distinct state generated. +Checking temporal properties for the complete state space... +Model checking completed. No error has been found. + Estimates of the probability that TLC did not check all reachable states + because two distinct states had the same fingerprint: + calculated (optimistic): val = 6.5E-19 + based on the actual fingerprints: val = 2.1E-18 +13 states generated, 12 distinct states found, 0 states left on queue. +The depth of the complete state graph search is 12. +Finished. (2012-08-10 17:38:37) +*/ \ No newline at end of file diff --git a/tlatools/test/pcal/SimpleLoopWithProcedureTest.java b/tlatools/test/pcal/SimpleLoopWithProcedureTest.java new file mode 100644 index 0000000000000000000000000000000000000000..8e94b05443fcbc8392785208f56e1b3141b71555 --- /dev/null +++ b/tlatools/test/pcal/SimpleLoopWithProcedureTest.java @@ -0,0 +1,156 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class SimpleLoopWithProcedureTest extends PCalModelCheckerTestCase { + + public SimpleLoopWithProcedureTest() { + super("SimpleLoopWithProcedure", "pcal", new String[] {"-wf", "-termination"}); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "2")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_CHECKING_TEMPORAL_PROPS, "complete", "64")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "66", "64", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "32")); + } +} +/* +C:\lamport\tla\pluscal>java -mx1000m -cp "c:/lamport/tla/newtools/tla2-inria-workspace/tla2-inria/tlatools/class" tlc2.TLC -cleanup SimpleLoopWithProcedure.tla +TLC2 Version 2.05 of 18 May 2012 +Running in Model-Checking mode. +Parsing file SimpleLoopWithProcedure.tla +Parsing file C:\lamport\tla\newtools\tla2-inria-workspace\tla2-inria\tlatools\class\tla2sany\StandardModules\Naturals.tla +Parsing file C:\lamport\tla\newtools\tla2-inria-workspace\tla2-inria\tlatools\class\tla2sany\StandardModules\Sequences.tla +Parsing file C:\lamport\tla\newtools\tla2-inria-workspace\tla2-inria\tlatools\class\tla2sany\StandardModules\TLC.tla +Semantic processing of module Naturals +Semantic processing of module Sequences +Semantic processing of module TLC +Semantic processing of module SimpleLoopWithProcedure +Starting... (2012-08-10 17:38:38) +Implied-temporal checking--satisfiability problem has 1 branches. +Computing initial states... +Finished computing initial states: 2 distinct states generated. +0 TRUE +0 TRUE +0 TRUE +0 TRUE +0 TRUE +0 TRUE +0 TRUE +0 TRUE +3 TRUE +3 TRUE +3 TRUE +3 TRUE +4 TRUE +4 TRUE +4 TRUE +4 TRUE +6 TRUE +6 TRUE +6 TRUE +6 TRUE +8 TRUE +8 TRUE +8 TRUE +8 TRUE +9 TRUE +9 TRUE +9 TRUE +9 TRUE +12 TRUE +12 TRUE +12 TRUE +12 TRUE +12 TRUE +12 TRUE +12 TRUE +12 TRUE +16 TRUE +16 TRUE +16 TRUE +16 TRUE +15 TRUE +15 TRUE +15 TRUE +15 TRUE +20 TRUE +20 TRUE +20 TRUE +20 TRUE +18 TRUE +18 TRUE +18 TRUE +18 TRUE +24 TRUE +24 TRUE +24 TRUE +24 TRUE +21 TRUE +21 TRUE +21 TRUE +21 TRUE +28 TRUE +28 TRUE +28 TRUE +28 TRUE +24 TRUE +24 TRUE +24 TRUE +24 TRUE +32 TRUE +32 TRUE +32 TRUE +32 TRUE +27 TRUE +27 TRUE +27 TRUE +27 TRUE +36 TRUE +36 TRUE +36 TRUE +36 TRUE +Checking temporal properties for the complete state space... +Model checking completed. No error has been found. + Estimates of the probability that TLC did not check all reachable states + because two distinct states had the same fingerprint: + calculated (optimistic): val = 6.9E-18 + based on the actual fingerprints: val = 8.3E-16 +66 states generated, 64 distinct states found, 0 states left on queue. +The depth of the complete state graph search is 32. +Finished. (2012-08-10 17:38:39) +*/ \ No newline at end of file diff --git a/tlatools/test/pcal/SimpleMultiProcTest.java b/tlatools/test/pcal/SimpleMultiProcTest.java new file mode 100644 index 0000000000000000000000000000000000000000..597ed04223c45cc6dfb1b3952c57b23850505524 --- /dev/null +++ b/tlatools/test/pcal/SimpleMultiProcTest.java @@ -0,0 +1,77 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class SimpleMultiProcTest extends PCalModelCheckerTestCase { + + public SimpleMultiProcTest() { + super("SimpleMultiProc", "pcal", new String[] {"-wf", "-termination"}); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "16")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_CHECKING_TEMPORAL_PROPS, "complete", "103944")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "369680", "103944", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "17")); + } +} +/* +C:\lamport\tla\pluscal>java -mx1000m -cp "c:/lamport/tla/newtools/tla2-inria-workspace/tla2-inria/tlatools/class" tlc2.TLC -cleanup SimpleMultiProc.tla +TLC2 Version 2.05 of 18 May 2012 +Running in Model-Checking mode. +Parsing file SimpleMultiProc.tla +Parsing file C:\lamport\tla\newtools\tla2-inria-workspace\tla2-inria\tlatools\class\tla2sany\StandardModules\Naturals.tla +Parsing file C:\lamport\tla\newtools\tla2-inria-workspace\tla2-inria\tlatools\class\tla2sany\StandardModules\Sequences.tla +Parsing file C:\lamport\tla\newtools\tla2-inria-workspace\tla2-inria\tlatools\class\tla2sany\StandardModules\TLC.tla +Semantic processing of module Naturals +Semantic processing of module Sequences +Semantic processing of module TLC +Semantic processing of module SimpleMultiProc +Starting... (2012-08-10 17:38:40) +Implied-temporal checking--satisfiability problem has 1 branches. +Computing initial states... +Finished computing initial states: 16 distinct states generated. +Progress(7) at 2012-08-10 17:38:43: 27922 states generated (27922 s/min), 12586 distinct states found (12586 ds/min), 6768 states left on queue. +Checking temporal properties for the complete state space... +Model checking completed. No error has been found. + Estimates of the probability that TLC did not check all reachable states + because two distinct states had the same fingerprint: + calculated (optimistic): val = 1.5E-9 + based on the actual fingerprints: val = 4.7E-10 +369680 states generated, 103944 distinct states found, 0 states left on queue. +The depth of the complete state graph search is 17. +Finished. (2012-08-10 17:39:23) +*/ \ No newline at end of file diff --git a/tlatools/test/pcal/StackTestTest.java b/tlatools/test/pcal/StackTestTest.java new file mode 100644 index 0000000000000000000000000000000000000000..752db590030723b19edf95465c80dd5af1161e41 --- /dev/null +++ b/tlatools/test/pcal/StackTestTest.java @@ -0,0 +1,98 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class StackTestTest extends PCalModelCheckerTestCase { + + public StackTestTest() { + super("StackTest", "pcal"); + } + + @Test + public void testSpec() { + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + } +} +/* +TLC2 Version 2.12 of 29 January 2018 +Running breadth-first search Model-Checking with 1 worker on 4 cores with 5303MB heap and 64MB offheap memory (Linux 4.15.0-22-generic amd64, Oracle Corporation 1.8.0_171 x86_64). +Parsing file /home/markus/Desktop/LesliePCalTest/alltests/StackTest.tla +Parsing file /home/markus/src/TLA/tla/tlatools/class/tla2sany/StandardModules/Sequences.tla +Parsing file /home/markus/src/TLA/tla/tlatools/class/tla2sany/StandardModules/Naturals.tla +Parsing file /home/markus/src/TLA/tla/tlatools/class/tla2sany/StandardModules/TLC.tla +Semantic processing of module Naturals +Semantic processing of module Sequences +Semantic processing of module TLC +Semantic processing of module StackTest +Starting... (2018-05-23 12:30:31) +Computing initial states... +Finished computing initial states: 1 distinct state generated. +Warning: The EXCEPT was applied to non-existing fields of the value at +line 36, col 26 to line 36, col 30 of module StackTest +(Use the -nowarning option to disable this warning.) +Error: TLC threw an unexpected exception. +This was probably caused by an error in the spec or model. +See the User Output or TLC Console for clues to what happened. +The exception was a tlc2.tool.EvalException +: Attempted to apply the operator overridden by the Java method +public static tlc2.value.Value tlc2.module.TLC.Assert(tlc2.value.Value,tlc2.value.Value), +but it produced the following error: +The first argument of Assert evaluated to FALSE; the second argument was: +"Failure of assertion at line 13, column 17." +Error: The behavior up to this point is: +State 1: <Initial predicate> +/\ stack = (0 :> <<>> @@ 1 :> <<>> @@ 2 :> <<>>) +/\ a = (0 :> 42 @@ 1 :> 42 @@ 2 :> 42) +/\ pc = (0 :> "Q1" @@ 1 :> "Q1" @@ 2 :> "Q1") + +State 2: <Q1 line 51, col 13 to line 59, col 47 of module StackTest> +/\ stack = ( 0 :> <<[pc |-> "Done", a |-> 42, procedure |-> "P"]>> @@ + 1 :> <<>> @@ + 2 :> <<>> ) +/\ a = (0 :> 22 @@ 1 :> 42 @@ 2 :> 42) +/\ pc = (0 :> "P1" @@ 1 :> "Q1" @@ 2 :> "Q1") + +Error: The error occurred when TLC was evaluating the nested +expressions at the following positions: +0. Line 35, column 13 to line 42, column 21 in StackTest +1. Line 35, column 16 to line 35, column 30 in StackTest +2. Line 36, column 16 to line 36, column 80 in StackTest +3. Line 37, column 16 to line 38, column 68 in StackTest + + +4 states generated, 4 distinct states found, 2 states left on queue. +The depth of the complete state graph search is 2. +The average outdegree of the complete state graph is 3 (minimum is 3, the maximum 3 and the 95th percentile is 3). +Finished in 00s at (2018-05-23 12:30:31) +*/ \ No newline at end of file diff --git a/tlatools/test/pcal/StarkMutexTest.java b/tlatools/test/pcal/StarkMutexTest.java new file mode 100644 index 0000000000000000000000000000000000000000..5e7f49fd994922090e50ece44a34444bb561a2e2 --- /dev/null +++ b/tlatools/test/pcal/StarkMutexTest.java @@ -0,0 +1,75 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class StarkMutexTest extends PCalModelCheckerTestCase { + + public StarkMutexTest() { + super("StarkMutex", "pcal"); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "1")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_CHECKING_TEMPORAL_PROPS, "complete", "69504", "3 branches of ")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "54809", "23168", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "92")); + } +} +/* +C:\lamport\tla\pluscal>java -mx1000m -cp "c:/lamport/tla/newtools/tla2-inria-workspace/tla2-inria/tlatools/class" tlc2.TLC -cleanup StarkMutex.tla +TLC2 Version 2.05 of 18 May 2012 +Running in Model-Checking mode. +Parsing file StarkMutex.tla +Parsing file C:\lamport\tla\newtools\tla2-inria-workspace\tla2-inria\tlatools\class\tla2sany\StandardModules\Naturals.tla +Parsing file C:\lamport\tla\newtools\tla2-inria-workspace\tla2-inria\tlatools\class\tla2sany\StandardModules\Sequences.tla +Semantic processing of module Naturals +Semantic processing of module Sequences +Semantic processing of module StarkMutex +Starting... (2012-08-10 17:39:24) +Implied-temporal checking--satisfiability problem has 3 branches. +Computing initial states... +Finished computing initial states: 1 distinct state generated. +Progress(34) at 2012-08-10 17:39:27: 6899 states generated (6899 s/min), 3423 distinct states found (3423 ds/min), 265 states left on queue. +Checking temporal properties for the complete state space... +Model checking completed. No error has been found. + Estimates of the probability that TLC did not check all reachable states + because two distinct states had the same fingerprint: + calculated (optimistic): val = 4.0E-11 + based on the actual fingerprints: val = 1.6E-10 +54809 states generated, 23168 distinct states found, 0 states left on queue. +The depth of the complete state graph search is 92. +Finished. (2012-08-10 17:39:49) +*/ \ No newline at end of file diff --git a/tlatools/test/pcal/SubSubTest.java b/tlatools/test/pcal/SubSubTest.java new file mode 100644 index 0000000000000000000000000000000000000000..f141f444a79a3c33fd61da51d0fec12d2a99ac61 --- /dev/null +++ b/tlatools/test/pcal/SubSubTest.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class SubSubTest extends PCalModelCheckerTestCase { + + public SubSubTest() { + super("SubSub", "pcal"); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "1")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "14", "8", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "4")); + } +} diff --git a/tlatools/test/pcal/SyncConsTest.java b/tlatools/test/pcal/SyncConsTest.java new file mode 100644 index 0000000000000000000000000000000000000000..792a988f6694e7a65dd064a21779e48ecf924892 --- /dev/null +++ b/tlatools/test/pcal/SyncConsTest.java @@ -0,0 +1,75 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class SyncConsTest extends PCalModelCheckerTestCase { + + public SyncConsTest() { + super("SyncCons", "pcal"); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "2")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "22580", "8754", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "48")); + } +} +/* +C:\lamport\tla\pluscal>java -mx1000m -cp "c:/lamport/tla/newtools/tla2-inria-workspace/tla2-inria/tlatools/class" tlc2.TLC -cleanup SyncCons.tla +TLC2 Version 2.05 of 18 May 2012 +Running in Model-Checking mode. +Parsing file SyncCons.tla +Parsing file C:\lamport\tla\newtools\tla2-inria-workspace\tla2-inria\tlatools\class\tla2sany\StandardModules\Naturals.tla +Parsing file C:\lamport\tla\newtools\tla2-inria-workspace\tla2-inria\tlatools\class\tla2sany\StandardModules\FiniteSets.tla +Parsing file C:\lamport\tla\newtools\tla2-inria-workspace\tla2-inria\tlatools\class\tla2sany\StandardModules\TLC.tla +Parsing file C:\lamport\tla\newtools\tla2-inria-workspace\tla2-inria\tlatools\class\tla2sany\StandardModules\Sequences.tla +Semantic processing of module Naturals +Semantic processing of module Sequences +Semantic processing of module FiniteSets +Semantic processing of module TLC +Semantic processing of module SyncCons +Starting... (2012-08-10 17:39:56) +Computing initial states... +Finished computing initial states: 2 distinct states generated. +Model checking completed. No error has been found. + Estimates of the probability that TLC did not check all reachable states + because two distinct states had the same fingerprint: + calculated (optimistic): val = 6.6E-12 + based on the actual fingerprints: val = 4.4E-12 +22580 states generated, 8754 distinct states found, 0 states left on queue. +The depth of the complete state graph search is 48. +Finished. (2012-08-10 17:39:57) +*/ \ No newline at end of file diff --git a/tlatools/test/pcal/TestPCandStackTest.java b/tlatools/test/pcal/TestPCandStackTest.java new file mode 100644 index 0000000000000000000000000000000000000000..239597e7744cdfe42aa229decbc76e13fb526eff --- /dev/null +++ b/tlatools/test/pcal/TestPCandStackTest.java @@ -0,0 +1,95 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class TestPCandStackTest extends PCalModelCheckerTestCase { + + public TestPCandStackTest() { + super("TestPCandStack", "pcal"); + } + + @Test + public void testSpec() { + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + } +} +/* +TLC2 Version 2.12 of 29 January 2018 +Running breadth-first search Model-Checking with 1 worker on 4 cores with 5303MB heap and 64MB offheap memory (Linux 4.15.0-22-generic amd64, Oracle Corporation 1.8.0_171 x86_64). +Parsing file /home/markus/Desktop/LesliePCalTest/alltests/TestPCandStack.tla +Parsing file /home/markus/src/TLA/tla/tlatools/class/tla2sany/StandardModules/Naturals.tla +Parsing file /home/markus/src/TLA/tla/tlatools/class/tla2sany/StandardModules/Sequences.tla +Parsing file /home/markus/src/TLA/tla/tlatools/class/tla2sany/StandardModules/TLC.tla +Semantic processing of module Naturals +Semantic processing of module Sequences +Semantic processing of module TLC +Semantic processing of module TestPCandStack +Starting... (2018-05-23 12:30:30) +Computing initial states... +Finished computing initial states: 1 distinct state generated. +Warning: The EXCEPT was applied to non-existing fields of the value at +line 46, col 26 to line 46, col 30 of module TestPCandStack +(Use the -nowarning option to disable this warning.) +Error: TLC threw an unexpected exception. +This was probably caused by an error in the spec or model. +See the User Output or TLC Console for clues to what happened. +The exception was a tlc2.tool.EvalException +: Attempted to apply the operator overridden by the Java method +public static tlc2.value.Value tlc2.module.TLC.Assert(tlc2.value.Value,tlc2.value.Value), +but it produced the following error: +The first argument of Assert evaluated to FALSE; the second argument was: +"Failure of assertion at line 16, column 26." +Error: The behavior up to this point is: +State 1: <Initial predicate> +/\ stack = <<<<>>, <<>>, <<>>>> +/\ pc = <<"M1", "M1", "M1">> + +State 2: <M1 line 43, col 13 to line 47, col 47 of module TestPCandStack> +/\ stack = <<<<>>, <<>>, <<>>>> +/\ pc = <<"M2", "M1", "M1">> + +Error: The error occurred when TLC was evaluating the nested +expressions at the following positions: +0. Line 49, column 13 to line 56, column 29 in TestPCandStack +1. Line 49, column 16 to line 49, column 30 in TestPCandStack +2. Line 50, column 16 to line 54, column 79 in TestPCandStack +3. Line 51, column 24 to line 52, column 79 in TestPCandStack +4. Line 51, column 27 to line 52, column 79 in TestPCandStack + + +4 states generated, 4 distinct states found, 2 states left on queue. +The depth of the complete state graph search is 2. +The average outdegree of the complete state graph is 3 (minimum is 3, the maximum 3 and the 95th percentile is 3). +Finished in 00s at (2018-05-23 12:30:30) +*/ \ No newline at end of file diff --git a/tlatools/test/pcal/TestReplaceTest.java b/tlatools/test/pcal/TestReplaceTest.java new file mode 100644 index 0000000000000000000000000000000000000000..f592c99d182dea0809a0eb038b7f65142ac51f2e --- /dev/null +++ b/tlatools/test/pcal/TestReplaceTest.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class TestReplaceTest extends PCalModelCheckerTestCase { + + public TestReplaceTest() { + super("TestReplace", "pcal"); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "1")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "18", "17", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "17")); + } +} diff --git a/tlatools/test/pcal/TestTabsTest.java b/tlatools/test/pcal/TestTabsTest.java new file mode 100644 index 0000000000000000000000000000000000000000..e5b966d56ba831aaaa1d9cd3bfad09d4dda966af --- /dev/null +++ b/tlatools/test/pcal/TestTabsTest.java @@ -0,0 +1,73 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class TestTabsTest extends PCalModelCheckerTestCase { + + public TestTabsTest() { + super("TestTabs", "pcal"); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "1")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "3", "2", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "2")); + } +} +/* +C:\lamport\tla\pluscal>java -mx1000m -cp "c:/lamport/tla/newtools/tla2-inria-workspace/tla2-inria/tlatools/class" tlc2.TLC -cleanup TestTabs.tla +TLC2 Version 2.05 of 18 May 2012 +Running in Model-Checking mode. +Parsing file TestTabs.tla +Parsing file C:\lamport\tla\newtools\tla2-inria-workspace\tla2-inria\tlatools\class\tla2sany\StandardModules\Naturals.tla +Parsing file C:\lamport\tla\newtools\tla2-inria-workspace\tla2-inria\tlatools\class\tla2sany\StandardModules\TLC.tla +Parsing file C:\lamport\tla\newtools\tla2-inria-workspace\tla2-inria\tlatools\class\tla2sany\StandardModules\Sequences.tla +Semantic processing of module Naturals +Semantic processing of module Sequences +Semantic processing of module TLC +Semantic processing of module TestTabs +Starting... (2012-08-10 17:40:01) +Computing initial states... +Finished computing initial states: 1 distinct state generated. +Model checking completed. No error has been found. + Estimates of the probability that TLC did not check all reachable states + because two distinct states had the same fingerprint: + calculated (optimistic): val = 1.1E-19 + based on the actual fingerprints: val = 1.1E-19 +3 states generated, 2 distinct states found, 0 states left on queue. +The depth of the complete state graph search is 2. +Finished. (2012-08-10 17:40:01) +*/ \ No newline at end of file diff --git a/tlatools/test/pcal/TestTest.java b/tlatools/test/pcal/TestTest.java new file mode 100644 index 0000000000000000000000000000000000000000..5bbcd74821e3610f5c6ee9aaa0eee14c35bce052 --- /dev/null +++ b/tlatools/test/pcal/TestTest.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class TestTest extends PCalModelCheckerTestCase { + + public TestTest() { + super("Test", "pcal", new String[] {"-wf", "-termination"}); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "1")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_CHECKING_TEMPORAL_PROPS, "complete", "4")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "5", "4", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "4")); + } +} diff --git a/tlatools/test/pcal/TreeBarrierTest.java b/tlatools/test/pcal/TreeBarrierTest.java new file mode 100644 index 0000000000000000000000000000000000000000..7a49f45f027f08ff0a0709f5b694adb88c379631 --- /dev/null +++ b/tlatools/test/pcal/TreeBarrierTest.java @@ -0,0 +1,74 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class TreeBarrierTest extends PCalModelCheckerTestCase { + + public TreeBarrierTest() { + super("TreeBarrier", "pcal", new String[] {"-wfNext"}); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "1")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_CHECKING_TEMPORAL_PROPS, "complete", "12570", "6 branches of ")); // 6 * 2095 = 12570 + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "5414", "2095", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "106")); + } +} +/* +C:\lamport\tla\pluscal>java -mx1000m -cp "c:/lamport/tla/newtools/tla2-inria-workspace/tla2-inria/tlatools/class" tlc2.TLC -cleanup TreeBarrier.tla +TLC2 Version 2.05 of 18 May 2012 +Running in Model-Checking mode. +Parsing file TreeBarrier.tla +Parsing file C:\lamport\tla\newtools\tla2-inria-workspace\tla2-inria\tlatools\class\tla2sany\StandardModules\Naturals.tla +Parsing file C:\lamport\tla\newtools\tla2-inria-workspace\tla2-inria\tlatools\class\tla2sany\StandardModules\Sequences.tla +Semantic processing of module Naturals +Semantic processing of module Sequences +Semantic processing of module TreeBarrier +Starting... (2012-08-10 17:39:50) +Implied-temporal checking--satisfiability problem has 6 branches. +Computing initial states... +Finished computing initial states: 1 distinct state generated. +Checking temporal properties for the complete state space... +Model checking completed. No error has been found. + Estimates of the probability that TLC did not check all reachable states + because two distinct states had the same fingerprint: + calculated (optimistic): val = 3.8E-13 + based on the actual fingerprints: val = 6.4E-14 +5414 states generated, 2095 distinct states found, 0 states left on queue. +The depth of the complete state graph search is 106. +Finished. (2012-08-10 17:39:53) +*/ \ No newline at end of file diff --git a/tlatools/test/pcal/ULCallReturn1Test.java b/tlatools/test/pcal/ULCallReturn1Test.java new file mode 100644 index 0000000000000000000000000000000000000000..5361b36bb5f25d8ac6fffec723809b9d7bb2a922 --- /dev/null +++ b/tlatools/test/pcal/ULCallReturn1Test.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class ULCallReturn1Test extends PCalModelCheckerTestCase { + + public ULCallReturn1Test() { + super("ULCallReturn1", "pcal", new String[] {"-wf", "-termination"}); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "1")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_CHECKING_TEMPORAL_PROPS, "complete", "8")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "9", "8", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "8")); + } +} diff --git a/tlatools/test/pcal/ULEuclidTest.java b/tlatools/test/pcal/ULEuclidTest.java new file mode 100644 index 0000000000000000000000000000000000000000..083d044e728fc04bd97fcd6122c41f95847e9aa6 --- /dev/null +++ b/tlatools/test/pcal/ULEuclidTest.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class ULEuclidTest extends PCalModelCheckerTestCase { + + public ULEuclidTest() { + super("ULEuclid", "pcal", new String[] {"-wf", "-termination"}); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "400")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_CHECKING_TEMPORAL_PROPS, "complete", "6352")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "6752", "6352", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "42")); + } +} diff --git a/tlatools/test/pcal/ULEvenOddTest.java b/tlatools/test/pcal/ULEvenOddTest.java new file mode 100644 index 0000000000000000000000000000000000000000..ce398ab24330a40d31cdd4e29a12588cd1a335fe --- /dev/null +++ b/tlatools/test/pcal/ULEvenOddTest.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class ULEvenOddTest extends PCalModelCheckerTestCase { + + public ULEvenOddTest() { + super("ULEvenOdd", "pcal", new String[] {"-wf", "-termination"}); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "1")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_CHECKING_TEMPORAL_PROPS, "complete", "13")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "14", "13", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "13")); + } +} diff --git a/tlatools/test/pcal/ULFactorial2Test.java b/tlatools/test/pcal/ULFactorial2Test.java new file mode 100644 index 0000000000000000000000000000000000000000..7503893b4f8306a9619a087b3ec2cead3e0fe9f6 --- /dev/null +++ b/tlatools/test/pcal/ULFactorial2Test.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class ULFactorial2Test extends PCalModelCheckerTestCase { + + public ULFactorial2Test() { + super("ULFactorial2", "pcal", new String[] {"-wf", "-termination"}); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "1")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_CHECKING_TEMPORAL_PROPS, "complete", "9")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "10", "9", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "9")); + } +} diff --git a/tlatools/test/pcal/ULQuicksortMacroTest.java b/tlatools/test/pcal/ULQuicksortMacroTest.java new file mode 100644 index 0000000000000000000000000000000000000000..d943dfefc7e2352be2ccc7daf263622dd655a57c --- /dev/null +++ b/tlatools/test/pcal/ULQuicksortMacroTest.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class ULQuicksortMacroTest extends PCalModelCheckerTestCase { + + public ULQuicksortMacroTest() { + super("ULQuicksortMacro", "pcal", new String[] {"-wf", "-termination"}); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "27")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_CHECKING_TEMPORAL_PROPS, "complete", "258")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "342", "258", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "11")); + } +} diff --git a/tlatools/test/pcal/UniprocDefineTest.java b/tlatools/test/pcal/UniprocDefineTest.java new file mode 100644 index 0000000000000000000000000000000000000000..2ed81ff4704b7b1e9e8d442b32fa0c418cc5e118 --- /dev/null +++ b/tlatools/test/pcal/UniprocDefineTest.java @@ -0,0 +1,73 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package pcal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; + +public class UniprocDefineTest extends PCalModelCheckerTestCase { + + public UniprocDefineTest() { + super("UniprocDefine", "pcal"); + } + + @Test + public void testSpec() { + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "1")); + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "5", "4", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "4")); + } +} +/* +C:\lamport\tla\pluscal>java -mx1000m -cp "c:/lamport/tla/newtools/tla2-inria-workspace/tla2-inria/tlatools/class" tlc2.TLC -cleanup UniprocDefine.tla +TLC2 Version 2.05 of 18 May 2012 +Running in Model-Checking mode. +Parsing file UniprocDefine.tla +Parsing file C:\lamport\tla\newtools\tla2-inria-workspace\tla2-inria\tlatools\class\tla2sany\StandardModules\Naturals.tla +Parsing file C:\lamport\tla\newtools\tla2-inria-workspace\tla2-inria\tlatools\class\tla2sany\StandardModules\Sequences.tla +Parsing file C:\lamport\tla\newtools\tla2-inria-workspace\tla2-inria\tlatools\class\tla2sany\StandardModules\TLC.tla +Semantic processing of module Naturals +Semantic processing of module Sequences +Semantic processing of module TLC +Semantic processing of module UniprocDefine +Starting... (2012-08-10 17:39:58) +Computing initial states... +Finished computing initial states: 1 distinct state generated. +Model checking completed. No error has been found. + Estimates of the probability that TLC did not check all reachable states + because two distinct states had the same fingerprint: + calculated (optimistic): val = 2.2E-19 + based on the actual fingerprints: val = 6.0E-19 +5 states generated, 4 distinct states found, 0 states left on queue. +The depth of the complete state graph search is 4. +Finished. (2012-08-10 17:39:59) +*/ \ No newline at end of file diff --git a/tlatools/test/tlc2/TestMPRecorder.java b/tlatools/test/tlc2/TestMPRecorder.java index b5cdb150c33edb10a05d722b69691fcb5ce6726c..cb5c02d9a6bf17b519f56fa535e4a9107004c4d7 100644 --- a/tlatools/test/tlc2/TestMPRecorder.java +++ b/tlatools/test/tlc2/TestMPRecorder.java @@ -108,9 +108,8 @@ public class TestMPRecorder extends tlc2.output.MPRecorder { if (!recordedWithStringValueAt(code, string, i++)) { return false; } - return true; } - return false; + return true; } /* (non-Javadoc) diff --git a/tlatools/test/tlc2/module/RandomizationTest.java b/tlatools/test/tlc2/module/RandomizationTest.java new file mode 100644 index 0000000000000000000000000000000000000000..2d5660a4ddbf31fa9263281b4a2a9dac984f8389 --- /dev/null +++ b/tlatools/test/tlc2/module/RandomizationTest.java @@ -0,0 +1,209 @@ +/******************************************************************************* + * Copyright (c) 20178 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.module; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import org.junit.BeforeClass; +import org.junit.Test; + +import tlc2.tool.EvalException; +import tlc2.util.FP64; +import tlc2.value.Enumerable; +import tlc2.value.EnumerableValue; +import tlc2.value.IntValue; +import tlc2.value.IntervalValue; +import tlc2.value.SetEnumValue; +import tlc2.value.StringValue; +import tlc2.value.Value; + +public class RandomizationTest { + + @BeforeClass + public static void setup() { + // Make test repeatable by setting random seed always to same value. + EnumerableValue.setRandom(15041980L); + + // Initialize FP64 to prevent NPE in hashCode (which relies on Value#fingerprint). + FP64.Init(); + } + + /* RandomSubsetSet */ + + @Test + public void testV1Valid() { + final Enumerable randomSubset = (Enumerable) Randomization.RandomSubsetSet(IntValue.gen(42), new StringValue("0.1"), + new IntervalValue(1, 42)); + + assertNotNull(randomSubset); + assertEquals(42, randomSubset.size()); + } + + @Test + public void testV2Larger1() { + try { + Randomization.RandomSubsetSet(IntValue.gen(23), new StringValue("1.1"), new IntervalValue(1, 42)); + } catch (final EvalException ee) { + assertTrue(ee.getMessage().contains("1.1")); + return; + } + fail(); + } + + /* RandomSetOfSubsets */ + + @Test + public void testV1Negative() { + final Value v1 = IntValue.gen(-42); + try { + Randomization.RandomSetOfSubsets(v1, IntValue.gen(42), new IntervalValue(1, 42)); + } catch (final EvalException ee) { + assertTrue(ee.getMessage().contains("The first argument of RandomSetOfSubsets should be a nonnegative integer, but instead it is:\n-42")); + return; + } + fail(); + } + + @Test + public void testV1NoIntValue() { + final Value v1 = new StringValue("52"); + try { + Randomization.RandomSetOfSubsets(v1, IntValue.gen(42), new IntervalValue(1, 42)); + } catch (final EvalException ee) { + assertTrue(ee.getMessage().contains("The first argument of RandomSetOfSubsets should be a nonnegative integer, but instead it is:\n\"52\"")); + return; + } + fail(); + } + + @Test + public void testV1Zero() { + final Value v1 = IntValue.gen(0); + final Enumerable randomSubset = (Enumerable) Randomization.RandomSetOfSubsets(v1, IntValue.gen(42), + new IntervalValue(1, 42)); + + assertNotNull(randomSubset); + assertEquals(0, randomSubset.size()); + } + + @Test + public void testV2Zero() { + final Enumerable randomSubset = (Enumerable) Randomization.RandomSetOfSubsets(IntValue.gen(23), IntValue.gen(0), + new IntervalValue(1, 42)); + assertEquals(1, randomSubset.size()); + // empty set is only member + assertTrue(randomSubset.member(new SetEnumValue())); + } + + @Test + public void testV2Negative() { + try { + Randomization.RandomSetOfSubsets(IntValue.gen(23), IntValue.gen(-1), new IntervalValue(1, 42)); + } catch (final EvalException ee) { + assertTrue(ee.getMessage().contains("The second argument of RandomSetOfSubsets should be a nonnegative integer, but instead it is:\n-1")); + return; + } + fail(); + } + + @Test + public void testV3Empty() { + try { + Randomization.RandomSetOfSubsets(IntValue.gen(42), IntValue.gen(42), new SetEnumValue()); + } catch (final EvalException ee) { + assertTrue(ee.getMessage().contains( + "The first argument of RandomSetOfSubsets should be a nonnegative integer that is smaller than the subset's size of 2^0, but instead it is:\n42")); + return; + } + fail(); + } + + @Test + public void testV3AstronomicallyLarge() { + final Enumerable randomSubset = (Enumerable) Randomization.RandomSetOfSubsets(IntValue.gen(42), IntValue.gen(42), + new IntervalValue(1, 256)); + + assertNotNull(randomSubset); + assertEquals(42, randomSubset.size()); + } + + @Test + public void testV3isInfinite() { + try { + Randomization.RandomSetOfSubsets(IntValue.gen(42), IntValue.gen(42), Naturals.Nat()); + } catch (final EvalException ee) { + assertTrue(ee.getMessage().contains( + "The third argument of RandomSetOfSubsets should be a finite set, but instead it is:\nNat")); + return; + } + fail(); + } + + @Test + public void testRSSV2Zero() { + final Enumerable randomSubset = (Enumerable) Randomization.RandomSetOfSubsets(IntValue.gen(23), IntValue.gen(0), + new IntervalValue(1, 42)); + assertEquals(1, randomSubset.size()); + // empty set is only member + assertTrue(randomSubset.member(new SetEnumValue())); + } + + @Test + public void testRSSV2Negative() { + try { + Randomization.RandomSetOfSubsets(IntValue.gen(23), IntValue.gen(-1), new IntervalValue(1, 42)); + } catch (final EvalException ee) { + assertTrue(ee.getMessage().contains("The second argument of RandomSetOfSubsets should be a nonnegative integer, but instead it is:\n-1")); + return; + } + fail(); + } + + @Test + public void testRSSV2Cardinality() { + final Enumerable randomSubset = (Enumerable) Randomization.RandomSetOfSubsets(IntValue.gen(32), IntValue.gen(5), + new IntervalValue(1, 5)); + assertEquals(1, randomSubset.size()); + // With probability 1 (n = 5), the operator - due to collisions - only generates + // a single subset which is the input set. + assertTrue(randomSubset.member(new IntervalValue(1, 5))); + } + + @Test + public void testRSSV2TwiceCardinality() { + try { + Randomization.RandomSetOfSubsets(IntValue.gen(23), IntValue.gen(10), new IntervalValue(1, 5)); + } catch (final EvalException ee) { + assertTrue(ee.getMessage().contains( + "The second argument of RandomSetOfSubsets should be a nonnegative integer in range 0..Cardinality(S), but instead it is:\n10")); + return; + } + fail(); + } +} diff --git a/tlatools/test/tlc2/module/TLCTest.java b/tlatools/test/tlc2/module/TLCTest.java index 2b7420f4aec25f6da2e8338387795cd8b3529c84..9a5dfc0e793d7b5145168dcb5136e40ecd4158cc 100644 --- a/tlatools/test/tlc2/module/TLCTest.java +++ b/tlatools/test/tlc2/module/TLCTest.java @@ -26,16 +26,30 @@ package tlc2.module; +import java.util.HashSet; +import java.util.Set; + import org.junit.Assert; +import org.junit.BeforeClass; import org.junit.Test; +import tlc2.util.FP64; +import tlc2.value.EnumerableValue; import tlc2.value.FcnRcdValue; import tlc2.value.IntValue; +import tlc2.value.IntervalValue; +import tlc2.value.SetEnumValue; import tlc2.value.TupleValue; import tlc2.value.Value; +import tlc2.value.ValueEnumeration; public class TLCTest { + @BeforeClass + public static void setup() { + FP64.Init(); + } + /** * func2 == <<1,2,3>> * ASSUME (3 :> 11 @@ func2) = <<1,2,11>> @@ -85,4 +99,25 @@ public class TLCTest { Assert.assertArrayEquals(new Value[] { IntValue.gen(1), IntValue.gen(2), IntValue.gen(3), IntValue.gen(11) }, rcdVal.values); } + + @Test + public void testPermutations() { + final SetEnumValue in = SetEnumValue.convert(new IntervalValue(1, 5)); + Assert.assertEquals(5, in.size()); + + final Value permutations = TLC.Permutations(in); + Assert.assertTrue(permutations instanceof EnumerableValue); + Assert.assertEquals(120, permutations.size()); + + final Set<Value> values = new HashSet<>(permutations.size()); + + final ValueEnumeration elements = ((EnumerableValue) permutations).elements(); + Value val = null; + while ((val = elements.nextElement()) != null) { + Assert.assertEquals(in.size(), val.size()); + values.add(val); + } + + Assert.assertEquals(120, values.size()); + } } diff --git a/tlatools/test/tlc2/tool/AssignmentNextTest.java b/tlatools/test/tlc2/tool/AssignmentNextTest.java index ba6798bdc40b2349a475505dcce7641d300ac76d..682cd3e5d499e023afb926ddbd8776ae5bd34f8e 100644 --- a/tlatools/test/tlc2/tool/AssignmentNextTest.java +++ b/tlatools/test/tlc2/tool/AssignmentNextTest.java @@ -43,6 +43,7 @@ public class AssignmentNextTest extends ModelCheckerTestCase { public void test() { assertTrue(recorder.recorded(EC.TLC_FINISHED)); assertFalse(recorder.recorded(EC.GENERAL)); - assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "3", "1", "0")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "3", "2", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "2")); } } diff --git a/tlatools/test/tlc2/tool/BagsTest.java b/tlatools/test/tlc2/tool/BagsTest.java new file mode 100644 index 0000000000000000000000000000000000000000..dedf5edf806bbf04ba263fb71816964ac19ddd34 --- /dev/null +++ b/tlatools/test/tlc2/tool/BagsTest.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ + +package tlc2.tool; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; +import tlc2.tool.liveness.ModelCheckerTestCase; + +public class BagsTest extends ModelCheckerTestCase { + + public BagsTest() { + super("BagsTest"); + } + + @Test + public void testSpec() { + // ModelChecker has finished and generated the expected amount of states + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "0", "0", "0")); + } +} diff --git a/tlatools/test/tlc2/tool/DumpAsDotTest.dot b/tlatools/test/tlc2/tool/DumpAsDotTest.dot index 18e710a0b296e028c48056bd9332ee9a8090fec8..88ab3c184ebc2776d4b3f40e09ce5301cb0f4368 100644 --- a/tlatools/test/tlc2/tool/DumpAsDotTest.dot +++ b/tlatools/test/tlc2/tool/DumpAsDotTest.dot @@ -1,4 +1,8 @@ strict digraph DiskGraph { +edge [colorscheme="paired12"] +nodesep=0.35; +subgraph cluster_graph { +color="white"; 609737673425276830 [style = filled] [label="/\\ b = FALSE /\\ x = 0"] 6816998822487979083 [style = filled] [label="/\\ b = TRUE @@ -15,47 +19,47 @@ strict digraph DiskGraph { /\\ x = 3"] 3881310712274735899 [style = filled] [label="/\\ b = TRUE /\\ x = 3"] -609737673425276830 -> 8671809759910816123; +609737673425276830 -> 8671809759910816123 [label="B" color="2" fontcolor="2"]; 609737673425276830 -> 609737673425276830 [style="dashed"]; 609737673425276830 [label="/\\ b = FALSE /\\ x = 0"]; -6816998822487979083 -> 609737673425276830; +6816998822487979083 -> 609737673425276830 [label="A" color="3" fontcolor="3"]; 6816998822487979083 -> 6816998822487979083 [style="dashed"]; 6816998822487979083 [label="/\\ b = TRUE /\\ x = 0"]; -3365478001808954030 -> 1377963776297717291; +3365478001808954030 -> 1377963776297717291 [label="B" color="2" fontcolor="2"]; 3365478001808954030 -> 3365478001808954030 [style="dashed"]; 3365478001808954030 [label="/\\ b = FALSE /\\ x = 1"]; -8671809759910816123 -> 3365478001808954030; +8671809759910816123 -> 3365478001808954030 [label="A" color="3" fontcolor="3"]; 8671809759910816123 -> 8671809759910816123 [style="dashed"]; 8671809759910816123 [label="/\\ b = TRUE /\\ x = 1"]; -5040481953810085374 -> 3881310712274735899; +5040481953810085374 -> 3881310712274735899 [label="B" color="2" fontcolor="2"]; 5040481953810085374 -> 5040481953810085374 [style="dashed"]; 5040481953810085374 [label="/\\ b = FALSE /\\ x = 2"]; -1377963776297717291 -> 5040481953810085374; +1377963776297717291 -> 5040481953810085374 [label="A" color="3" fontcolor="3"]; 1377963776297717291 -> 1377963776297717291 [style="dashed"]; 1377963776297717291 [label="/\\ b = TRUE /\\ x = 2"]; -7147721571019581646 -> -4210745456684007285; +7147721571019581646 -> -4210745456684007285 [label="B" color="2" fontcolor="2"]; -4210745456684007285 [label="/\\ b = TRUE /\\ x = 4"]; 7147721571019581646 -> 7147721571019581646 [style="dashed"]; 7147721571019581646 [label="/\\ b = FALSE /\\ x = 3"]; -3881310712274735899 -> 7147721571019581646; +3881310712274735899 -> 7147721571019581646 [label="A" color="3" fontcolor="3"]; 3881310712274735899 -> 3881310712274735899 [style="dashed"]; 3881310712274735899 [label="/\\ b = TRUE /\\ x = 3"]; --4210745456684007285 -> -7819220713745958050; +-4210745456684007285 -> -7819220713745958050 [label="A" color="3" fontcolor="3"]; -7819220713745958050 [label="/\\ b = FALSE /\\ x = 4"]; -4210745456684007285 -> -4210745456684007285 [style="dashed"]; -4210745456684007285 [label="/\\ b = TRUE /\\ x = 4"]; --7819220713745958050 -> -2066378075513578053; +-7819220713745958050 -> -2066378075513578053 [label="B" color="2" fontcolor="2"]; -2066378075513578053 [label="/\\ b = TRUE /\\ x = 5"]; -7819220713745958050 -> -7819220713745958050 [style="dashed"]; @@ -64,4 +68,13 @@ strict digraph DiskGraph { -2066378075513578053 -> -2066378075513578053 [style="dashed"]; -2066378075513578053 [label="/\\ b = TRUE /\\ x = 5"]; -} \ No newline at end of file +{rank = same; 1377963776297717291;5040481953810085374;8671809759910816123;3365478001808954030;6816998822487979083;609737673425276830;3881310712274735899;7147721571019581646;} +{rank = same; -4210745456684007285;} +{rank = same; -7819220713745958050;} +{rank = same; -2066378075513578053;} +} +subgraph cluster_legend {graph[style=bold];label = "Next State Actions" style="solid" +node [ labeljust="l" colorscheme="paired12" style=filled shape=record ] +A [label="A" fillcolor=3] +B [label="B" fillcolor=2] +}} \ No newline at end of file diff --git a/tlatools/test/tlc2/tool/DumpAsDotTest.java b/tlatools/test/tlc2/tool/DumpAsDotTest.java index ec0d2232b817e328aaa30093e19cda9fadd2353a..884d788a84a8d6b4ee9f38541753b39f07253a04 100644 --- a/tlatools/test/tlc2/tool/DumpAsDotTest.java +++ b/tlatools/test/tlc2/tool/DumpAsDotTest.java @@ -43,8 +43,8 @@ import tlc2.tool.liveness.ModelCheckerTestCase; public class DumpAsDotTest extends ModelCheckerTestCase { public DumpAsDotTest() { - super("MCa", "CodePlexBug08", - new String[] { "-dump", "dot", System.getProperty("java.io.tmpdir") + File.separator + "DumpAsDotTest" }); + super("MCa", "CodePlexBug08", new String[] { "-dump", "dot,colorize,actionlabels", + System.getProperty("java.io.tmpdir") + File.separator + "DumpAsDotTest" }); } @Test diff --git a/tlatools/test/tlc2/tool/IncompleteNextMultipleActionsTest.java b/tlatools/test/tlc2/tool/IncompleteNextMultipleActionsTest.java new file mode 100644 index 0000000000000000000000000000000000000000..b5ea799253314503885909be9547195ba973aa5b --- /dev/null +++ b/tlatools/test/tlc2/tool/IncompleteNextMultipleActionsTest.java @@ -0,0 +1,67 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ + +package tlc2.tool; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.ArrayList; +import java.util.List; +import org.junit.Test; +import tlc2.output.EC; +import tlc2.tool.liveness.ModelCheckerTestCase; + +public class IncompleteNextMultipleActionsTest extends ModelCheckerTestCase { + + public IncompleteNextMultipleActionsTest() { + super("IncompleteNextMultipleActions", ""); + } + + @Test + public void testSpec() { + // ModelChecker has finished and generated the expected amount of states + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "2", "1", "0")); + assertFalse(recorder.recorded(EC.GENERAL)); + + // Assert the error trace + assertTrue(recorder.recorded(EC.TLC_STATE_PRINT2)); + final List<String> expectedTrace = new ArrayList<String>(4); + expectedTrace.add("/\\ x = 0\n/\\ y = 0\n/\\ z = 0"); + expectedTrace.add("/\\ x = 1\n/\\ y = null\n/\\ z = null"); + assertTraceWith(recorder.getRecords(EC.TLC_STATE_PRINT2), expectedTrace); + + // Assert TLC indicates unassigned variable + assertTrue(recorder.recorded(EC.TLC_STATE_NOT_COMPLETELY_SPECIFIED_NEXT)); + final List<Object> records = recorder.getRecords(EC.TLC_STATE_NOT_COMPLETELY_SPECIFIED_NEXT); + assertEquals("A1", ((String[]) records.get(0))[0]); + assertEquals("s are", ((String[]) records.get(0))[1]); + assertEquals("y, z", ((String[]) records.get(0))[2]); + } +} diff --git a/tlatools/test/tlc2/tool/IncompleteNextTest.java b/tlatools/test/tlc2/tool/IncompleteNextTest.java index c3f52c03900846f733313622c6311147ece94f9c..0ecc3aea801b058683ccf67e7dd455fabdf024c4 100644 --- a/tlatools/test/tlc2/tool/IncompleteNextTest.java +++ b/tlatools/test/tlc2/tool/IncompleteNextTest.java @@ -26,6 +26,7 @@ package tlc2.tool; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -55,5 +56,11 @@ public class IncompleteNextTest extends ModelCheckerTestCase { expectedTrace.add("/\\ x = 0\n/\\ y = 0"); expectedTrace.add("/\\ x = 1\n/\\ y = null"); assertTraceWith(recorder.getRecords(EC.TLC_STATE_PRINT2), expectedTrace); + + // Assert TLC indicates unassigned variable + assertTrue(recorder.recorded(EC.TLC_STATE_NOT_COMPLETELY_SPECIFIED_NEXT)); + final List<Object> records = recorder.getRecords(EC.TLC_STATE_NOT_COMPLETELY_SPECIFIED_NEXT); + assertEquals(" is", ((String[]) records.get(0))[0]); + assertEquals("y", ((String[]) records.get(0))[1]); } } diff --git a/tlatools/test/tlc2/tool/MinimalSetOfInitStatesTest.java b/tlatools/test/tlc2/tool/MinimalSetOfInitStatesTest.java new file mode 100644 index 0000000000000000000000000000000000000000..9c80fa4cb56ae61072a4ca113966ac8c89bd92c3 --- /dev/null +++ b/tlatools/test/tlc2/tool/MinimalSetOfInitStatesTest.java @@ -0,0 +1,55 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.tool; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; +import tlc2.tool.liveness.ModelCheckerTestCase; + +public class MinimalSetOfInitStatesTest extends ModelCheckerTestCase { + + public MinimalSetOfInitStatesTest() { + super("MinimalSetOfInitStates"); + } + + @Test + public void testSpec() { + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + + // Without the fix to tlc2.tool.Tool.getInitStates(ActionItemList, TLCState, + // IStateFunctor), the number of generated initial states would be 6 with + // 4 being distinct. The fix in getInitStates causes TLC to more efficiently + // evaluate the init predicate and avoid generating the two duplicates. + assertTrue(recorder.recordedWithStringValues(EC.TLC_INIT_GENERATED2, "8", "s", "6")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "14", "6", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "0")); + } +} diff --git a/tlatools/test/tlc2/tool/MinimalSetOfNextStatesTest.java b/tlatools/test/tlc2/tool/MinimalSetOfNextStatesTest.java new file mode 100644 index 0000000000000000000000000000000000000000..b5ca39459207136cf3f975adf31de6d97a4277c3 --- /dev/null +++ b/tlatools/test/tlc2/tool/MinimalSetOfNextStatesTest.java @@ -0,0 +1,51 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.tool; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; +import tlc2.tool.liveness.ModelCheckerTestCase; + +public class MinimalSetOfNextStatesTest extends ModelCheckerTestCase { + + public MinimalSetOfNextStatesTest() { + super("MinimalSetOfNextStates"); + } + + @Test + public void testSpec() { + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "1")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "57", "7", "0")); // 57 instead of 71. + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "2")); + } +} diff --git a/tlatools/test/tlc2/tool/RandomElementT4Test.java b/tlatools/test/tlc2/tool/RandomElementT4Test.java new file mode 100644 index 0000000000000000000000000000000000000000..e331c7ddd7fa6dad23f4ae2371b890eade096d4c --- /dev/null +++ b/tlatools/test/tlc2/tool/RandomElementT4Test.java @@ -0,0 +1,81 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.tool; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.List; +import java.util.Map; + +import org.junit.Test; + +import tlc2.output.EC; +import tlc2.tool.liveness.ModelCheckerTestCase; +import tlc2.value.IntValue; +import tlc2.value.Value; +import util.UniqueString; + +public class RandomElementT4Test extends ModelCheckerTestCase { + + public RandomElementT4Test() { + super("RandomElement", new String[] {"-seed", Long.toString(15041980L)}); + } + + @Test + public void test() { + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.TLC_BUG)); + + assertTrue(recorder.recorded(EC.TLC_BEHAVIOR_UP_TO_THIS_POINT)); + + final List<Object> records = recorder.getRecords(EC.TLC_STATE_PRINT2); + assertEquals(11, records.size()); + + int cnt = 0; + for (Object r : records) { + final Object[] objs = (Object[]) r; + final TLCStateInfo info = (TLCStateInfo) objs[0]; + final Map<UniqueString, Value> vals = info.state.getVals(); + + final Value y = vals.get(UniqueString.uniqueStringOf("y")); + assertEquals(cnt++, ((IntValue) y).val); + + final Value x = info.state.getVals().get(UniqueString.uniqueStringOf("x")); + assertTrue(1 <= ((IntValue) x).val && ((IntValue) x).val < 1000); + + final int statenum = (int) objs[1]; + assertEquals(cnt, statenum); + } + } + + protected int getNumberOfThreads() { + // With 4 threads the counter-examples is not predictable anymore because it + // depends on thread scheduling. + return 4; + } +} diff --git a/tlatools/test/tlc2/tool/RandomElementTest.java b/tlatools/test/tlc2/tool/RandomElementTest.java new file mode 100644 index 0000000000000000000000000000000000000000..8f6302620d906f57aee0d1a96aac305ed709efad --- /dev/null +++ b/tlatools/test/tlc2/tool/RandomElementTest.java @@ -0,0 +1,66 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.tool; + +import static org.junit.Assert.*; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Test; + +import tlc2.output.EC; +import tlc2.tool.liveness.ModelCheckerTestCase; + +public class RandomElementTest extends ModelCheckerTestCase { + + public RandomElementTest() { + super("RandomElement", new String[] {"-seed", Long.toString(8006803340504660123L)}); + } + + @Test + public void test() { + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.TLC_BUG)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "933", "855", "388")); + + assertTrue(recorder.recorded(EC.TLC_BEHAVIOR_UP_TO_THIS_POINT)); + + final List<String> expectedTrace = new ArrayList<String>(11); + expectedTrace.add("/\\ x = 843\n/\\ y = 0"); + expectedTrace.add("/\\ x = 920\n/\\ y = 1"); + expectedTrace.add("/\\ x = 483\n/\\ y = 2"); + expectedTrace.add("/\\ x = 173\n/\\ y = 3"); + expectedTrace.add("/\\ x = 590\n/\\ y = 4"); + expectedTrace.add("/\\ x = 104\n/\\ y = 5"); + expectedTrace.add("/\\ x = 785\n/\\ y = 6"); + expectedTrace.add("/\\ x = 463\n/\\ y = 7"); + expectedTrace.add("/\\ x = 443\n/\\ y = 8"); + expectedTrace.add("/\\ x = 151\n/\\ y = 9"); + expectedTrace.add("/\\ x = 767\n/\\ y = 10"); + assertTraceWith(recorder.getRecords(EC.TLC_STATE_PRINT2), expectedTrace); + } +} diff --git a/tlatools/test/tlc2/tool/RandomElementXandYTest.java b/tlatools/test/tlc2/tool/RandomElementXandYTest.java new file mode 100644 index 0000000000000000000000000000000000000000..40423ffd01834869437e977ae67c6d66750e0738 --- /dev/null +++ b/tlatools/test/tlc2/tool/RandomElementXandYTest.java @@ -0,0 +1,61 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.tool; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Test; + +import tlc2.output.EC; +import tlc2.tool.liveness.ModelCheckerTestCase; + +public class RandomElementXandYTest extends ModelCheckerTestCase { + + public RandomElementXandYTest() { + super("RandomElementXandY", new String[] {"-seed", Long.toString(8006642976694192746L)}); + // 8006642976694192746L produces a trace of three states. + // 8006642976346685430L and 8006642974998076619L results in no violation of an invariant + // 8006642972812024640L a trace with two states + } + + @Test + public void test() { + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.TLC_BUG)); + + assertTrue(recorder.recorded(EC.TLC_BEHAVIOR_UP_TO_THIS_POINT)); + + final List<String> expectedTrace = new ArrayList<String>(11); + expectedTrace.add("/\\ x = 0\n/\\ y = 0"); + expectedTrace.add("/\\ x = 1\n/\\ y = 1"); + expectedTrace.add("/\\ x = 0\n/\\ y = 1"); + assertTraceWith(recorder.getRecords(EC.TLC_STATE_PRINT2), expectedTrace); + } +} diff --git a/tlatools/test/tlc2/tool/RandomSubset.java b/tlatools/test/tlc2/tool/RandomSubset.java new file mode 100644 index 0000000000000000000000000000000000000000..f2d2a06e003e4c23a607ac2d513d2ac0d2e6398f --- /dev/null +++ b/tlatools/test/tlc2/tool/RandomSubset.java @@ -0,0 +1,69 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.tool; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Test; + +import tlc2.output.EC; +import tlc2.tool.liveness.ModelCheckerTestCase; + +public abstract class RandomSubset extends ModelCheckerTestCase { + + private final int x; + private final int y; + + public RandomSubset(final long seed, final int x, final int y) { + // Initial seed with a randomly chosen but fixed value for x and y to be + // predictable. The two subclasses chose different values to test that different + // seeds result in different values. + super("RandomSubset", new String[] {"-seed", Long.toString(seed)}); + this.x = x; + this.y = y; + } + + @Test + public void testSpec() { + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "2002")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "2003", "2003", "2001")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "2")); + + assertTrue(recorder.recorded(EC.TLC_STATE_PRINT2)); + final List<String> expectedTrace = new ArrayList<String>(); + expectedTrace.add("/\\ x = " + x + "\n" + "/\\ y = " + y + "\n" + "/\\ z = TRUE"); + expectedTrace.add("/\\ x = " + x + "\n" + "/\\ y = " + y + "\n" + "/\\ z = FALSE"); + assertTraceWith(recorder.getRecords(EC.TLC_STATE_PRINT2), expectedTrace); + } + +} diff --git a/tlatools/test/tlc2/tool/RandomSubsetATest.java b/tlatools/test/tlc2/tool/RandomSubsetATest.java new file mode 100644 index 0000000000000000000000000000000000000000..44e4429427dad340128b7d396f2ea5cadbe72346 --- /dev/null +++ b/tlatools/test/tlc2/tool/RandomSubsetATest.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.tool; + +public class RandomSubsetATest extends RandomSubset { + + public RandomSubsetATest() { + super(15041980L, 47567, 100000003); + } +} diff --git a/tlatools/test/tlc2/tool/RandomSubsetBTest.java b/tlatools/test/tlc2/tool/RandomSubsetBTest.java new file mode 100644 index 0000000000000000000000000000000000000000..05edf09ddb478a1615b94b94c538077650934e79 --- /dev/null +++ b/tlatools/test/tlc2/tool/RandomSubsetBTest.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.tool; + +public class RandomSubsetBTest extends RandomSubset { + + public RandomSubsetBTest() { + super(918347981374L, 66058, 100000003); + } +} diff --git a/tlatools/test/tlc2/tool/RandomSubsetNextT4Test.java b/tlatools/test/tlc2/tool/RandomSubsetNextT4Test.java new file mode 100644 index 0000000000000000000000000000000000000000..81f34bebf39bdf0d339e6885753f2579423d6c0c --- /dev/null +++ b/tlatools/test/tlc2/tool/RandomSubsetNextT4Test.java @@ -0,0 +1,81 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.tool; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.List; +import java.util.Map; + +import org.junit.Test; + +import tlc2.output.EC; +import tlc2.tool.liveness.ModelCheckerTestCase; +import tlc2.value.IntValue; +import tlc2.value.Value; +import util.UniqueString; + +public class RandomSubsetNextT4Test extends ModelCheckerTestCase { + + public RandomSubsetNextT4Test() { + super("RandomSubsetNext"); + } + + @Test + public void testSpec() { + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.TLC_BUG)); + + assertTrue(recorder.recorded(EC.TLC_BEHAVIOR_UP_TO_THIS_POINT)); + + final List<Object> records = recorder.getRecords(EC.TLC_STATE_PRINT2); + assertEquals(11, records.size()); + + int cnt = 0; + for (Object r : records) { + final Object[] objs = (Object[]) r; + final TLCStateInfo info = (TLCStateInfo) objs[0]; + final Map<UniqueString, Value> vals = info.state.getVals(); + + final Value y = vals.get(UniqueString.uniqueStringOf("y")); + assertEquals(cnt++, ((IntValue) y).val); + + final Value x = info.state.getVals().get(UniqueString.uniqueStringOf("x")); + assertTrue(1 <= ((IntValue) x).val && ((IntValue) x).val < 1000); + + final int statenum = (int) objs[1]; + assertEquals(cnt, statenum); + } + } + + protected int getNumberOfThreads() { + // With 4 threads the counter-examples is not predictable anymore because it + // depends on thread scheduling. + return 4; + } +} diff --git a/tlatools/test/tlc2/tool/RandomSubsetNextTest.java b/tlatools/test/tlc2/tool/RandomSubsetNextTest.java new file mode 100644 index 0000000000000000000000000000000000000000..378c735ad0ace9522ff14988d731ed70a6bff71c --- /dev/null +++ b/tlatools/test/tlc2/tool/RandomSubsetNextTest.java @@ -0,0 +1,67 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.tool; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Test; + +import tlc2.output.EC; +import tlc2.tool.liveness.ModelCheckerTestCase; + +public class RandomSubsetNextTest extends ModelCheckerTestCase { + + public RandomSubsetNextTest() { + super("RandomSubsetNext", new String[] {"-seed", Long.toString(15041980L)}); + } + + @Test + public void testSpec() { + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.TLC_BUG)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "67330", "7732", "999")); + + assertTrue(recorder.recorded(EC.TLC_BEHAVIOR_UP_TO_THIS_POINT)); + + final List<String> expectedTrace = new ArrayList<String>(11); + expectedTrace.add("/\\ x = 43\n/\\ y = 0"); + expectedTrace.add("/\\ x = 2\n/\\ y = 1"); + expectedTrace.add("/\\ x = 95\n/\\ y = 2"); + expectedTrace.add("/\\ x = 40\n/\\ y = 3"); + expectedTrace.add("/\\ x = 6\n/\\ y = 4"); + expectedTrace.add("/\\ x = 168\n/\\ y = 5"); + expectedTrace.add("/\\ x = 225\n/\\ y = 6"); + expectedTrace.add("/\\ x = 93\n/\\ y = 7"); + expectedTrace.add("/\\ x = 42\n/\\ y = 8"); + expectedTrace.add("/\\ x = 8\n/\\ y = 9"); + expectedTrace.add("/\\ x = 30\n/\\ y = 10"); + assertTraceWith(recorder.getRecords(EC.TLC_STATE_PRINT2), expectedTrace); + } +} diff --git a/tlatools/test/tlc2/tool/RandomSubsetSetOfFcnsTest.java b/tlatools/test/tlc2/tool/RandomSubsetSetOfFcnsTest.java new file mode 100644 index 0000000000000000000000000000000000000000..8a74c0583ea4c54b97f0b8cad61baf9be92d2665 --- /dev/null +++ b/tlatools/test/tlc2/tool/RandomSubsetSetOfFcnsTest.java @@ -0,0 +1,88 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.tool; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.List; +import java.util.Map; + +import org.junit.Test; + +import tlc2.output.EC; +import tlc2.tool.liveness.ModelCheckerTestCase; +import tlc2.value.BoolValue; +import tlc2.value.IntValue; +import tlc2.value.Value; +import util.UniqueString; + +public class RandomSubsetSetOfFcnsTest extends ModelCheckerTestCase { + + public RandomSubsetSetOfFcnsTest() { + super("RandomSubsetSetOfFcns"); + } + + @Test + public void testSpec() { + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "1000")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "2000", "1000", "0")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "0")); +// +// assertTrue(recorder.recorded(EC.TLC_STATE_PRINT2)); +// +// final List<Object> actual = recorder.getRecords(EC.TLC_STATE_PRINT2); +// assertEquals(2, actual.size()); +// +// final TLCStateInfo first = (TLCStateInfo) ((Object[]) actual.get(0))[0]; +// assertTrue(((String) first.info).startsWith("<Initial predicate>")); +// final Map<UniqueString, Value> firstState = first.state.getVals(); +// assertEquals(3, firstState.size()); +// +// // Check x and y values are within defined ranges. +// final IntValue firstX = (IntValue) firstState.get(UniqueString.uniqueStringOf("x")); +// assertTrue(1 <= firstX.val && firstX.val <= 100000000); +// final IntValue firstY = (IntValue) firstState.get(UniqueString.uniqueStringOf("y")); +// assertTrue(100000000 <= firstY.val && firstX.val <= 100000010); +// +// // Check z is true +// assertEquals(BoolValue.ValTrue, (BoolValue) firstState.get(UniqueString.uniqueStringOf("z"))); +// +// final TLCStateInfo second = (TLCStateInfo) ((Object[]) actual.get(1))[0]; +// assertTrue(((String) second.info).startsWith("<Next line 10, col 9 to line 11, col 21 of module RandomSubset>")); +// final Map<UniqueString, Value> secondState = second.state.getVals(); +// assertEquals(3, secondState.size()); +// // UNCHANGED x,y +// assertEquals(firstX.val, ((IntValue) secondState.get(UniqueString.uniqueStringOf("x"))).val); +// assertEquals(firstY.val, ((IntValue) secondState.get(UniqueString.uniqueStringOf("y"))).val); +// // Check z is false +// assertEquals(BoolValue.ValFalse, (BoolValue) secondState.get(UniqueString.uniqueStringOf("z"))); + } +} diff --git a/tlatools/test/tlc2/tool/RandomSubsetTest.java b/tlatools/test/tlc2/tool/RandomSubsetTest.java new file mode 100644 index 0000000000000000000000000000000000000000..2a134577172894a9c523964a40f876b1de5f4893 --- /dev/null +++ b/tlatools/test/tlc2/tool/RandomSubsetTest.java @@ -0,0 +1,88 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.tool; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.List; +import java.util.Map; + +import org.junit.Test; + +import tlc2.output.EC; +import tlc2.tool.liveness.ModelCheckerTestCase; +import tlc2.value.BoolValue; +import tlc2.value.IntValue; +import tlc2.value.Value; +import util.UniqueString; + +public class RandomSubsetTest extends ModelCheckerTestCase { + + public RandomSubsetTest() { + super("RandomSubset"); + } + + @Test + public void testSpec() { + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + + assertTrue(recorder.recordedWithStringValue(EC.TLC_INIT_GENERATED1, "2002")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "2003", "2003", "2001")); + assertTrue(recorder.recordedWithStringValue(EC.TLC_SEARCH_DEPTH, "2")); + + assertTrue(recorder.recorded(EC.TLC_STATE_PRINT2)); + + final List<Object> actual = recorder.getRecords(EC.TLC_STATE_PRINT2); + assertEquals(2, actual.size()); + + final TLCStateInfo first = (TLCStateInfo) ((Object[]) actual.get(0))[0]; + assertTrue(((String) first.info).startsWith("<Initial predicate>")); + final Map<UniqueString, Value> firstState = first.state.getVals(); + assertEquals(3, firstState.size()); + + // Check x and y values are within defined ranges. + final IntValue firstX = (IntValue) firstState.get(UniqueString.uniqueStringOf("x")); + assertTrue(1 <= firstX.val && firstX.val <= 100000000); + final IntValue firstY = (IntValue) firstState.get(UniqueString.uniqueStringOf("y")); + assertTrue(100000000 <= firstY.val && firstX.val <= 100000010); + + // Check z is true + assertEquals(BoolValue.ValTrue, (BoolValue) firstState.get(UniqueString.uniqueStringOf("z"))); + + final TLCStateInfo second = (TLCStateInfo) ((Object[]) actual.get(1))[0]; + assertTrue(((String) second.info).startsWith("<Next line 10, col 9 to line 11, col 21 of module RandomSubset>")); + final Map<UniqueString, Value> secondState = second.state.getVals(); + assertEquals(3, secondState.size()); + // UNCHANGED x,y + assertEquals(firstX.val, ((IntValue) secondState.get(UniqueString.uniqueStringOf("x"))).val); + assertEquals(firstY.val, ((IntValue) secondState.get(UniqueString.uniqueStringOf("y"))).val); + // Check z is false + assertEquals(BoolValue.ValFalse, (BoolValue) secondState.get(UniqueString.uniqueStringOf("z"))); + } +} diff --git a/tlatools/test/tlc2/tool/StandardModulesTest.java b/tlatools/test/tlc2/tool/StandardModulesTest.java new file mode 100644 index 0000000000000000000000000000000000000000..cb44f02e65cbe17325fcd429594abbc191188fc5 --- /dev/null +++ b/tlatools/test/tlc2/tool/StandardModulesTest.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.tool; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; +import tlc2.output.EC; +import tlc2.tool.liveness.ModelCheckerTestCase; + +public class StandardModulesTest extends ModelCheckerTestCase { + + public StandardModulesTest() { + super("StandardModules"); + } + + @Test + public void testSpec() { + // Check that all standard modules parse (StandardModules.tla extends all of them). + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "0", "0", "0")); + } +} diff --git a/tlatools/test/tlc2/tool/SubsetEqTest.java b/tlatools/test/tlc2/tool/SubsetEqTest.java index 6b1774e8b6e58430e6d47c7f88655f28dc3f8847..4ffde29d2ff2cb2c8db31e1a256e988ab0a7593b 100644 --- a/tlatools/test/tlc2/tool/SubsetEqTest.java +++ b/tlatools/test/tlc2/tool/SubsetEqTest.java @@ -48,7 +48,7 @@ public class SubsetEqTest extends ModelCheckerTestCase { assertTrue(recorder.recorded(EC.TLC_FINISHED)); assertFalse(recorder.recorded(EC.GENERAL)); - assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "2", "2", "0")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "2", "1", "0")); // No error trace! assertFalse(recorder.recorded(EC.TLC_STATE_PRINT2)); } diff --git a/tlatools/test/tlc2/tool/ViewMapTest.java b/tlatools/test/tlc2/tool/ViewMapTest.java new file mode 100644 index 0000000000000000000000000000000000000000..70e3b98cf51c9953cc2b8e3f97af6500a9f2fd52 --- /dev/null +++ b/tlatools/test/tlc2/tool/ViewMapTest.java @@ -0,0 +1,65 @@ +/******************************************************************************* + * Copyright (c) 2017 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.tool; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Test; + +import tlc2.output.EC; +import tlc2.tool.liveness.ModelCheckerTestCase; + +public class ViewMapTest extends ModelCheckerTestCase { + + public ViewMapTest() { + super("ViewMap", new String[] { "-view" }); + } + + @Test + public void testSpec() { + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.GENERAL)); + assertFalse(recorder.recorded(EC.TLC_BUG)); + + assertTrue(recorder.recorded(EC.TLC_BEHAVIOR_UP_TO_THIS_POINT)); + + final List<String> expectedTrace = new ArrayList<String>(8); + expectedTrace.add("/\\ buffer = <<>>\n/\\ waitset = {}"); + expectedTrace.add("/\\ buffer = <<>>\n/\\ waitset = {c1}"); + expectedTrace.add("/\\ buffer = <<>>\n/\\ waitset = {c1, c2}"); + expectedTrace.add("/\\ buffer = <<\"d\">>\n/\\ waitset = {c2}"); + + expectedTrace.add("/\\ buffer = <<\"d\">>\n/\\ waitset = {c2, p1}"); + expectedTrace.add("/\\ buffer = << >>\n/\\ waitset = {p1}"); + expectedTrace.add("/\\ buffer = << >>\n/\\ waitset = {c1, p1}"); + expectedTrace.add("/\\ buffer = << >>\n/\\ waitset = {c1, c2, p1}"); + assertTraceWith(recorder.getRecords(EC.TLC_STATE_PRINT2), expectedTrace); + } +} diff --git a/tlatools/test/tlc2/tool/DoInitFunctorEvalExceptionTest.java b/tlatools/test/tlc2/tool/doinitfunctor/DoInitFunctorEvalExceptionTest.java similarity index 98% rename from tlatools/test/tlc2/tool/DoInitFunctorEvalExceptionTest.java rename to tlatools/test/tlc2/tool/doinitfunctor/DoInitFunctorEvalExceptionTest.java index 7c6f3fb7874a5113b889c7d8527a4069a72786c1..d351c5dde8382f31d3ce256096e021bb21251192 100644 --- a/tlatools/test/tlc2/tool/DoInitFunctorEvalExceptionTest.java +++ b/tlatools/test/tlc2/tool/doinitfunctor/DoInitFunctorEvalExceptionTest.java @@ -24,7 +24,7 @@ * Markus Alexander Kuppe - initial API and implementation ******************************************************************************/ -package tlc2.tool; +package tlc2.tool.doinitfunctor; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; diff --git a/tlatools/test/tlc2/tool/DoInitFunctorInvariantContinueTest.java b/tlatools/test/tlc2/tool/doinitfunctor/DoInitFunctorInvariantContinueTest.java similarity index 75% rename from tlatools/test/tlc2/tool/DoInitFunctorInvariantContinueTest.java rename to tlatools/test/tlc2/tool/doinitfunctor/DoInitFunctorInvariantContinueTest.java index 897a35ed19faeb2eb5042dbd13c95472e84c713e..2f9d01e63e29882f9b40389fc90b2ef987e14beb 100644 --- a/tlatools/test/tlc2/tool/DoInitFunctorInvariantContinueTest.java +++ b/tlatools/test/tlc2/tool/doinitfunctor/DoInitFunctorInvariantContinueTest.java @@ -24,11 +24,14 @@ * Markus Alexander Kuppe - initial API and implementation ******************************************************************************/ -package tlc2.tool; +package tlc2.tool.doinitfunctor; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import java.util.List; + import org.junit.Test; import tlc2.output.EC; import tlc2.tool.liveness.ModelCheckerTestCase; @@ -36,7 +39,7 @@ import tlc2.tool.liveness.ModelCheckerTestCase; public class DoInitFunctorInvariantContinueTest extends ModelCheckerTestCase { public DoInitFunctorInvariantContinueTest() { - super("DoInitFunctorInvariant", "DoInitFunctor", new String[] {"-continue"}); + super("DoInitFunctorInvariantContinue", "DoInitFunctor", new String[] {"-continue"}); } @Test @@ -45,6 +48,14 @@ public class DoInitFunctorInvariantContinueTest extends ModelCheckerTestCase { assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "21", "11")); assertFalse(recorder.recorded(EC.GENERAL)); - assertTrue(recorder.recordedWithStringValues(EC.TLC_INVARIANT_VIOLATED_INITIAL, "NotNine", "x = 9\n")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_INVARIANT_VIOLATED_INITIAL, "Inv", "x = 1\n")); + // Test that TLC - with continuation enabled - continues after finding the first inv violation. + final List<Object> records = recorder.getRecords(EC.TLC_INVARIANT_VIOLATED_INITIAL); + assertEquals(10, records.size()); + for (int j = 0; j < records.size(); j++) { + final String[] violation = (String[]) records.get(j); + assertEquals("Inv", violation[0]); + assertEquals("x = " + (j+1) + "\n", violation[1]); + } } } diff --git a/tlatools/test/tlc2/tool/doinitfunctor/DoInitFunctorInvariantMinimalErrorStackTest.java b/tlatools/test/tlc2/tool/doinitfunctor/DoInitFunctorInvariantMinimalErrorStackTest.java new file mode 100644 index 0000000000000000000000000000000000000000..80bf8a24000a1d6cfe18d95eff9eee20c09ecfa7 --- /dev/null +++ b/tlatools/test/tlc2/tool/doinitfunctor/DoInitFunctorInvariantMinimalErrorStackTest.java @@ -0,0 +1,59 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.tool.doinitfunctor; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; +import tlc2.tool.liveness.ModelCheckerTestCase; + +public class DoInitFunctorInvariantMinimalErrorStackTest extends ModelCheckerTestCase { + + public DoInitFunctorInvariantMinimalErrorStackTest() { + super("DoInitFunctorMinimalErrorStack", "DoInitFunctor"); + } + + @Test + public void testSpec() { + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "2", "2", "2")); + assertFalse(recorder.recorded(EC.GENERAL)); + + assertTrue(recorder.recordedWithStringValues(EC.TLC_MODULE_VALUE_JAVA_METHOD_OVERRIDE, + "public static tlc2.value.BoolValue tlc2.module.Naturals.GEQ(tlc2.value.Value,tlc2.value.Value)", + "The first argument of > should be an integer, but instead it is:\n" + + "<<1, 1>>")); + + String errorStack = "0. Line 8, column 3 to line 9, column 13 in DoInitFunctorMinimalErrorStack\n" + + "1. Line 8, column 6 to line 8, column 25 in DoInitFunctorMinimalErrorStack\n" + + "2. Line 9, column 6 to line 9, column 13 in DoInitFunctorMinimalErrorStack\n" + + "3. Line 14, column 8 to line 14, column 13 in DoInitFunctorMinimalErrorStack\n\n"; + assertTrue(recorder.recordedWithStringValue(EC.TLC_NESTED_EXPRESSION, errorStack)); + } +} diff --git a/tlatools/test/tlc2/tool/doinitfunctor/DoInitFunctorInvariantNoContinueTest.java b/tlatools/test/tlc2/tool/doinitfunctor/DoInitFunctorInvariantNoContinueTest.java new file mode 100644 index 0000000000000000000000000000000000000000..899ca79cba008ba08832de8f3a1d5a087ce78748 --- /dev/null +++ b/tlatools/test/tlc2/tool/doinitfunctor/DoInitFunctorInvariantNoContinueTest.java @@ -0,0 +1,53 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.tool.doinitfunctor; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.output.EC; +import tlc2.tool.liveness.ModelCheckerTestCase; + +public class DoInitFunctorInvariantNoContinueTest extends ModelCheckerTestCase { + + public DoInitFunctorInvariantNoContinueTest() { + super("DoInitFunctorInvariantContinue", "DoInitFunctor"); + } + + @Test + public void testSpec() { + assertTrue(recorder.recorded(EC.TLC_FINISHED)); + assertFalse(recorder.recorded(EC.TLC_STATS)); + assertFalse(recorder.recorded(EC.GENERAL)); + + assertTrue(recorder.recordedWithStringValues(EC.TLC_INVARIANT_VIOLATED_INITIAL, "Inv", "x = 1\n")); + // Test that TLC - with continuation disabled - stops after finding the first inv violation/finds exactly one violation. + assertEquals(1, recorder.getRecords(EC.TLC_INVARIANT_VIOLATED_INITIAL).size()); + } +} diff --git a/tlatools/test/tlc2/tool/DoInitFunctorInvariantTest.java b/tlatools/test/tlc2/tool/doinitfunctor/DoInitFunctorInvariantTest.java similarity index 87% rename from tlatools/test/tlc2/tool/DoInitFunctorInvariantTest.java rename to tlatools/test/tlc2/tool/doinitfunctor/DoInitFunctorInvariantTest.java index 7bfa4ecc5709e9164f35727ceae91f89636c7c98..2f92e1b1925738cf80d40faecef0c829ccd3c12e 100644 --- a/tlatools/test/tlc2/tool/DoInitFunctorInvariantTest.java +++ b/tlatools/test/tlc2/tool/doinitfunctor/DoInitFunctorInvariantTest.java @@ -24,8 +24,9 @@ * Markus Alexander Kuppe - initial API and implementation ******************************************************************************/ -package tlc2.tool; +package tlc2.tool.doinitfunctor; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -45,6 +46,8 @@ public class DoInitFunctorInvariantTest extends ModelCheckerTestCase { assertFalse(recorder.recorded(EC.TLC_STATS)); assertFalse(recorder.recorded(EC.GENERAL)); + // Test that TLC - with continuation disabled - stops after finding the first inv violation/finds exactly one violation. assertTrue(recorder.recordedWithStringValues(EC.TLC_INVARIANT_VIOLATED_INITIAL, "NotNine", "x = 9\n")); + assertEquals(1, recorder.getRecords(EC.TLC_INVARIANT_VIOLATED_INITIAL).size()); } } diff --git a/tlatools/test/tlc2/tool/DoInitFunctorPropertyTest.java b/tlatools/test/tlc2/tool/doinitfunctor/DoInitFunctorPropertyTest.java similarity index 98% rename from tlatools/test/tlc2/tool/DoInitFunctorPropertyTest.java rename to tlatools/test/tlc2/tool/doinitfunctor/DoInitFunctorPropertyTest.java index e83801909c54e922287942639e0d68f7149d304e..37a8637a2092a0698456e3220833d1d1ae5a95c1 100644 --- a/tlatools/test/tlc2/tool/DoInitFunctorPropertyTest.java +++ b/tlatools/test/tlc2/tool/doinitfunctor/DoInitFunctorPropertyTest.java @@ -24,7 +24,7 @@ * Markus Alexander Kuppe - initial API and implementation ******************************************************************************/ -package tlc2.tool; +package tlc2.tool.doinitfunctor; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; diff --git a/tlatools/test/tlc2/tool/fp/FPSetFactoryTest.java b/tlatools/test/tlc2/tool/fp/FPSetFactoryTest.java index 17a150a3ac935918ac82a01ebe27344db7535486..8820e49907e56cbe526a368c1cb9810bb56c5ae2 100644 --- a/tlatools/test/tlc2/tool/fp/FPSetFactoryTest.java +++ b/tlatools/test/tlc2/tool/fp/FPSetFactoryTest.java @@ -9,7 +9,6 @@ import java.rmi.NoSuchObjectException; import java.rmi.RemoteException; import org.junit.Assume; -import org.junit.Before; import org.junit.Test; import tlc2.tool.distributed.fp.FPSetRMI; @@ -199,7 +198,41 @@ public class FPSetFactoryTest { doTestNested(OffHeapDiskFPSet.class, fpSetConfiguration, mFPSet); } - + + @Test + public void testGetFPSetOffHeapMultiFPSet42() throws RemoteException { + System.setProperty(FPSetFactory.IMPL_PROPERTY, OffHeapDiskFPSet.class.getName()); + + final long nonHeapPhysicalMemory = TLCRuntime.getInstance().getNonHeapPhysicalMemory(); + + final FPSetConfiguration fpSetConfiguration = new FPSetConfiguration(); + assertEquals(nonHeapPhysicalMemory, fpSetConfiguration.getMemoryInBytes()); + assertEquals(nonHeapPhysicalMemory / FPSet.LongSize, fpSetConfiguration.getMemoryInFingerprintCnt()); + + final MultiFPSet mFPSet = (MultiFPSet) doTestGetFPSet(MultiFPSet.class, fpSetConfiguration); + + final FPSetConfiguration multiConfig = mFPSet.getConfiguration(); + assertEquals(OffHeapDiskFPSet.class.getName(), multiConfig.getImplementation()); + assertEquals(1, multiConfig.getFpBits()); + assertEquals(2, multiConfig.getMultiFPSetCnt()); + assertEquals(nonHeapPhysicalMemory, multiConfig.getMemoryInBytes()); + assertEquals(nonHeapPhysicalMemory / FPSet.LongSize, multiConfig.getMemoryInFingerprintCnt()); + + final FPSet[] fpSets = mFPSet.getFPSets(); + assertEquals(2, fpSets.length); + + for (FPSet fpSet : fpSets) { + final OffHeapDiskFPSet offFPset = (OffHeapDiskFPSet) fpSet; + final FPSetConfiguration offConfig = offFPset.getConfiguration(); + assertEquals(OffHeapDiskFPSet.class.getName(), offConfig.getImplementation()); + assertEquals(1, offConfig.getFpBits()); + assertEquals(2, offConfig.getMultiFPSetCnt()); + assertEquals(nonHeapPhysicalMemory / 2L, offConfig.getMemoryInBytes()); + assertEquals((nonHeapPhysicalMemory / FPSet.LongSize) / 2L, offConfig.getMemoryInFingerprintCnt()); + assertEquals((offConfig.getMemoryInBytes() / FPSet.LongSize), offConfig.getMemoryInFingerprintCnt()); + } + } + /* Helper methods */ private FPSet doTestGetFPSet(final Class<? extends FPSet> class1, final FPSetConfiguration fpSetConfig) throws RemoteException, NoSuchObjectException { diff --git a/tlatools/test/tlc2/tool/liveness/CodePlexBug08EWD840FL2FromCheckpointTest.java b/tlatools/test/tlc2/tool/liveness/CodePlexBug08EWD840FL2FromCheckpointTest.java index f40f7e0a9a0a36b74e9ac4af9e5282ffe0c9cd79..e09084076ba6838cf97160d4b3a495ebea23255d 100644 --- a/tlatools/test/tlc2/tool/liveness/CodePlexBug08EWD840FL2FromCheckpointTest.java +++ b/tlatools/test/tlc2/tool/liveness/CodePlexBug08EWD840FL2FromCheckpointTest.java @@ -93,9 +93,12 @@ public class CodePlexBug08EWD840FL2FromCheckpointTest extends ModelCheckerTestCa @Test public void testSpec() { + assertTrue(recorder.recorded(EC.TLC_CHECKPOINT_RECOVER_START)); + // Recovery completed. 1032 states examined. 996 states on queue. + assertTrue(recorder.recordedWithStringValues(EC.TLC_CHECKPOINT_RECOVER_END, "1028", "1013")); // ModelChecker has finished and generated the expected amount of states assertTrue(recorder.recorded(EC.TLC_FINISHED)); - assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "4938", "1566","0")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "15961", "1566","0")); assertFalse(recorder.recorded(EC.GENERAL)); // Assert it has found the temporal violation and also a counter example diff --git a/tlatools/test/tlc2/tool/liveness/Test057.java b/tlatools/test/tlc2/tool/liveness/Test057.java index 2c63d5022c5fde620e4823261281b5fc42b04416..9b0459f9c354a7d60f2b844161c68236303b5e95 100644 --- a/tlatools/test/tlc2/tool/liveness/Test057.java +++ b/tlatools/test/tlc2/tool/liveness/Test057.java @@ -45,6 +45,6 @@ public class Test057 extends ModelCheckerTestCase { assertTrue(recorder.recorded(EC.TLC_FINISHED)); assertFalse(recorder.recorded(EC.GENERAL)); assertTrue(recorder.recorded(EC.TLC_COMPUTING_INIT)); - assertTrue(recorder.recordedWithStringValues(EC.TLC_INVARIANT_VIOLATED_INITIAL, "Invariant1", "x = 1")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_INVARIANT_VIOLATED_INITIAL, "Invariant1", "x = 1\n")); } } diff --git a/tlatools/test/tlc2/tool/liveness/simulation/LiveCheckTest.java b/tlatools/test/tlc2/tool/liveness/simulation/LiveCheckTest.java index e4a73d0ad1d1eed2cca4f0a07eb0129ca78bda7b..85e3c0e031e596c86c645dd96b08b362166e0945 100644 --- a/tlatools/test/tlc2/tool/liveness/simulation/LiveCheckTest.java +++ b/tlatools/test/tlc2/tool/liveness/simulation/LiveCheckTest.java @@ -33,6 +33,7 @@ import java.io.IOException; import org.easymock.EasyMock; import org.junit.Test; + import tlc2.tool.Action; import tlc2.tool.TLCState; import tlc2.tool.Tool; @@ -106,7 +107,7 @@ public class LiveCheckTest { EasyMock.replay(oos); return new LiveCheck(EasyMock.createNiceMock(Tool.class), new Action[0], - new OrderOfSolution[] { oos }, System.getProperty("java.io.tmpdir"), new DummyBucketStatistics(), null); + new OrderOfSolution[] { oos }, System.getProperty("java.io.tmpdir"), new DummyBucketStatistics()); } private ILiveCheck getLiveCheckWithTableau() throws IOException { @@ -133,7 +134,7 @@ public class LiveCheckTest { EasyMock.replay(oos); return new LiveCheck(EasyMock.createNiceMock(Tool.class), new Action[0], - new OrderOfSolution[] { oos }, System.getProperty("java.io.tmpdir"), new DummyBucketStatistics(), null); + new OrderOfSolution[] { oos }, System.getProperty("java.io.tmpdir"), new DummyBucketStatistics()); } } diff --git a/tlatools/test/tlc2/tool/queue/DummyTLCState.java b/tlatools/test/tlc2/tool/queue/DummyTLCState.java index d5f7ef86677e8f6bebcec710016f440b467fc4df..cf40e6d0307be835e480014c1edfb0298451c065 100644 --- a/tlatools/test/tlc2/tool/queue/DummyTLCState.java +++ b/tlatools/test/tlc2/tool/queue/DummyTLCState.java @@ -1,5 +1,9 @@ package tlc2.tool.queue; +import java.util.HashSet; +import java.util.Set; + +import tla2sany.semantic.OpDeclNode; import tla2sany.semantic.SemanticNode; import tla2sany.semantic.SymbolNode; import tlc2.tool.StateVec; @@ -99,6 +103,13 @@ public class DummyTLCState extends TLCState { return false; } + /* (non-Javadoc) + * @see tlc2.tool.TLCState#getUnassigned() + */ + public final Set<OpDeclNode> getUnassigned() { + return new HashSet<OpDeclNode>(); + } + /* (non-Javadoc) * @see tlc2.tool.TLCState#createEmpty() */ diff --git a/tlatools/test/tlc2/tool/suite/ETest4.java b/tlatools/test/tlc2/tool/suite/ETest4.java index 09187b196bfb83a7c217ce7cecc696a769abd666..9125b626ce987b027a9a539e8b2ea842461f3396 100644 --- a/tlatools/test/tlc2/tool/suite/ETest4.java +++ b/tlatools/test/tlc2/tool/suite/ETest4.java @@ -39,9 +39,8 @@ public class ETest4 extends SuiteETestCase { assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "0", "0", "0")); String s = "0. Line 13, column 9 to line 16, column 51 in etest4\n" + "1. Line 13, column 12 to line 13, column 16 in etest4\n" - + "2. Line 14, column 12 to line 14, column 77 in etest4\n" - + "3. Line 15, column 12 to line 15, column 26 in etest4\n" - + "4. Line 15, column 12 to line 15, column 22 in etest4\n\n"; + + "2. Line 15, column 12 to line 15, column 26 in etest4\n" + + "3. Line 15, column 12 to line 15, column 22 in etest4\n\n"; assertTrue(recorder.recordedWithStringValues(EC.TLC_NESTED_EXPRESSION, s)); } } diff --git a/tlatools/test/tlc2/tool/suite/Test216.java b/tlatools/test/tlc2/tool/suite/Test216.java index 1341f88fb912388d6bc3e455d1d21f1b6c13fc97..e25554ac685f93d7a63ded5a1106068ca71c3479 100644 --- a/tlatools/test/tlc2/tool/suite/Test216.java +++ b/tlatools/test/tlc2/tool/suite/Test216.java @@ -37,7 +37,7 @@ public class Test216 extends SuiteETestCase { public void testSpec() { assertTrue(recorder.recorded(EC.TLC_FINISHED)); assertTrue(recorder.recordedWithStringValues(EC.TLC_STATS, "28", "7", "0")); - assertTrue(recorder.recordedWithStringValues(EC.TLC_INIT_GENERATED2, "21", "7")); + assertTrue(recorder.recordedWithStringValues(EC.TLC_INIT_GENERATED2, "21", "s", "7")); assertFalse(recorder.recorded(EC.GENERAL)); } } diff --git a/tlatools/test/tlc2/util/CombinatoricsTest.java b/tlatools/test/tlc2/util/CombinatoricsTest.java new file mode 100644 index 0000000000000000000000000000000000000000..1bf0e968c8986b708d8adc0906924bd655d8af35 --- /dev/null +++ b/tlatools/test/tlc2/util/CombinatoricsTest.java @@ -0,0 +1,119 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.util; + +import static org.junit.Assert.*; + +import java.math.BigInteger; + +import org.junit.Test; + +public class CombinatoricsTest { + @Test + public void testChoose() { + for (int n = 0; n < Combinatorics.MAXCHOOSENUM; n++) { + for (int k = 0; k < Combinatorics.MAXCHOOSENUM; k++) { + long choose = Combinatorics.choose(n, k); + long binomial = Combinatorics.binomial(n, k); + assertEquals(String.format("n=%s, k=%s", n, k), choose, binomial); + } + } + } + @Test + public void testChooseBigChoose() { + for (int n = 0; n < Combinatorics.MAXCHOOSENUM + 1; n++) { + for (int k = 0; k < Combinatorics.MAXCHOOSENUM + 1; k++) { + long choose = Combinatorics.choose(n, k); + long bigChoose = Combinatorics.bigChoose(n, k).longValueExact(); + assertEquals(String.format("n=%s, k=%s", n, k), choose, bigChoose); + } + } + } + @Test + public void testSlowChooseBigChoose() { + for (int n = Combinatorics.MAXCHOOSENUM + 1; n < Combinatorics.MAXCHOOSENUM << 2; n++) { + for (int k = Combinatorics.MAXCHOOSENUM + 1; k < Combinatorics.MAXCHOOSENUM << 2; k++) { + BigInteger slowBigChoose = Combinatorics.slowBigChoose(n, k); + BigInteger bigChoose = Combinatorics.bigChoose(n, k); + assertEquals(String.format("n=%s, k=%s", n, k), slowBigChoose, bigChoose); + } + } + } + @Test + public void testBigChoose50c1() { + final BigInteger bigChoose = Combinatorics.bigChoose(50, 1); + assertEquals(6, bigChoose.bitLength()); + assertEquals(50L, bigChoose.longValueExact()); + } + @Test + public void testBigChoose50c10() { + final BigInteger bigChoose = Combinatorics.bigChoose(50, 10); + assertEquals(34, bigChoose.bitLength()); + assertEquals(10272278170L, bigChoose.longValueExact()); + } + @Test + public void testBigChoose50c20() { + final BigInteger bigChoose = Combinatorics.bigChoose(50, 20); + assertEquals(46, bigChoose.bitLength()); + assertEquals(47129212243960L, bigChoose.longValueExact()); + } + @Test + public void testBigChoose50c30() { + final BigInteger bigChoose = Combinatorics.bigChoose(50, 30); + assertEquals(46, bigChoose.bitLength()); + assertEquals(47129212243960L, bigChoose.longValueExact()); + } + @Test + public void testBigChoose400c1() { + final BigInteger bigChoose = Combinatorics.bigChoose(400, 1); + assertEquals(9, bigChoose.bitLength()); + assertEquals(400L, bigChoose.longValueExact()); + } + @Test + public void testBigChoose400c50() { + final BigInteger bigChoose = Combinatorics.bigChoose(400, 50); + assertEquals(214, bigChoose.bitLength()); + assertEquals( + "17035900270730601418919867558071677342938596450600561760371485120", + bigChoose.toString()); + } + @Test + public void testBigChoose400c100() { + final BigInteger bigChoose = Combinatorics.bigChoose(400, 100); + assertEquals(321, bigChoose.bitLength()); + assertEquals( + "2241854791554337561923210387201698554845411177476295990399942258896013007429693894018935107174320", + bigChoose.toString()); + } + @Test + public void testBigChoose400c200() { + final BigInteger bigChoose = Combinatorics.bigChoose(400, 200); + assertEquals(396, bigChoose.bitLength()); + assertEquals( + "102952500135414432972975880320401986757210925381077648234849059575923332372651958598336595518976492951564048597506774120", + bigChoose.toString()); + } +} diff --git a/tlatools/test/tlc2/value/EnumerableValueTest.java b/tlatools/test/tlc2/value/EnumerableValueTest.java new file mode 100644 index 0000000000000000000000000000000000000000..553fbcbdb2df856d78a22ecd2cb2e0eb7cb7cc6f --- /dev/null +++ b/tlatools/test/tlc2/value/EnumerableValueTest.java @@ -0,0 +1,149 @@ +/******************************************************************************* + * Copyright (c) 20178 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + * Ian Morris Nieves - added support for fingerprint stack trace + ******************************************************************************/ +package tlc2.value; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.util.HashSet; +import java.util.Set; + +import org.junit.Test; + +import tlc2.value.EnumerableValue.SubsetEnumerator; + +public class EnumerableValueTest { + + @Test + public void test() { + EnumerableValue.setRandom(15041980); + + final Set<Integer> indices = new HashSet<>(); + // For the first n \in Nat+ up to 10657 show that: + for (int n = 1; n < 10657; n++) { + final SubsetEnumerator enumerator = (SubsetEnumerator) new DummyValue(n).elements(n); + + while (enumerator.hasNext()) { + final int index = enumerator.nextIndex(); + assertTrue("Index %s out of bounds.", 0 <= index && index < n); + indices.add(index); + } + assertEquals("Missing indices.", n, indices.size()); + indices.clear(); + } + } + + @SuppressWarnings("serial") + class DummyValue extends EnumerableValue { + + private final int size; + + public DummyValue(int size) { + this.size = size; + } + + @Override + public int size() { + return size; + } + + @Override + public ValueEnumeration elements(final int k) { + return new EnumerableValue.SubsetEnumerator(k) { + @Override + public Value nextElement() { + return null; + } + }; + } + + @Override + public ValueEnumeration elements() { + return null; + } + + @Override + public byte getKind() { + return 0; + } + + @Override + public int compareTo(Object val) { + return 0; + } + + @Override + public boolean member(Value elem) { + return false; + } + + @Override + public Value takeExcept(ValueExcept ex) { + return null; + } + + @Override + public Value takeExcept(ValueExcept[] exs) { + return null; + } + + @Override + public boolean isNormalized() { + return false; + } + + @Override + public Value normalize() { + return this; + } + + @Override + public boolean isFinite() { + return false; + } + + @Override + public boolean isDefined() { + return false; + } + + @Override + public Value deepCopy() { + return null; + } + + @Override + public boolean assignable(Value val) { + return false; + } + + @Override + public StringBuffer toString(StringBuffer sb, int offset) { + return null; + } + } +} diff --git a/tlatools/test/tlc2/value/IntervalValueTest.java b/tlatools/test/tlc2/value/IntervalValueTest.java new file mode 100644 index 0000000000000000000000000000000000000000..67d6ce80814ae7ab0525be8124af2ab6a2c71b35 --- /dev/null +++ b/tlatools/test/tlc2/value/IntervalValueTest.java @@ -0,0 +1,40 @@ +package tlc2.value; + +import static org.junit.Assert.*; + +import org.junit.Test; + +import util.Assert.TLCRuntimeException; + +public class IntervalValueTest { + + @Test + public void testElementAt() { + final IntervalValue iv = new IntervalValue(3, 11); + for (int i = 0; i < iv.size(); i++) { + assertEquals(IntValue.gen(i + 3), iv.elementAt(i)); + } + } + + @Test + public void testElementAtOutOfBoundsNegative() { + final IntervalValue iv = new IntervalValue(3, 11); + try { + iv.elementAt(-1); + } catch (TLCRuntimeException e) { + return; + } + fail(); + } + + @Test + public void testElementAtOutOfBoundsSize() { + final IntervalValue iv = new IntervalValue(3, 11); + try { + iv.elementAt(iv.size()); + } catch (TLCRuntimeException e) { + return; + } + fail(); + } +} diff --git a/tlatools/test/tlc2/value/SetOfFcnsValueTest.java b/tlatools/test/tlc2/value/SetOfFcnsValueTest.java new file mode 100644 index 0000000000000000000000000000000000000000..b492a81defd5c956164c8762e452f88114462e32 --- /dev/null +++ b/tlatools/test/tlc2/value/SetOfFcnsValueTest.java @@ -0,0 +1,394 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.value; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.function.Consumer; +import java.util.function.IntConsumer; +import java.util.stream.IntStream; + +import org.junit.Test; + +import tlc2.util.FP64; +import tlc2.value.SetOfFcnsValue.SubsetEnumerator; +import util.Assert.TLCRuntimeException; + +public class SetOfFcnsValueTest { + + private static final Value[] getValue(String... strs) { + final Value[] values = new Value[strs.length]; + for (int i = 0; i < strs.length; i++) { + values[i] = new StringValue(strs[i]); + } + return values; + } + + @Test + public void testRangeSubsetValue() { + final Value[] values = new Value[] { ModelValue.make("m1"), ModelValue.make("m2"), ModelValue.make("m3") }; + final SetOfFcnsValue setOfFcnsValue = new SetOfFcnsValue(new SetEnumValue(values, true), + new SubsetValue(new SetEnumValue( + new Value[] { new StringValue("a"), new StringValue("b"), new StringValue("c") }, true))); + + assertEquals(512, setOfFcnsValue.size()); + + final SetOfFcnsValue.SubsetEnumerator enumerator = (SubsetEnumerator) setOfFcnsValue.elements(512); + final SetEnumValue emptyset = new SetEnumValue(); + int i = 0; + assertEquals(new FcnRcdValue(values, new Value[] { emptyset, emptyset, emptyset }, true), + enumerator.elementAt(i++)); + assertEquals( + new FcnRcdValue(values, + new Value[] { emptyset, emptyset, + new SetEnumValue(new Value[] { new StringValue("a") }, true) }, + true), + enumerator.elementAt(i++)); + assertEquals( + new FcnRcdValue(values, + new Value[] { emptyset, emptyset, + new SetEnumValue(new Value[] { new StringValue("b") }, true) }, + true), + enumerator.elementAt(i++)); + assertEquals(new FcnRcdValue(values, + new Value[] { emptyset, emptyset, + new SetEnumValue(new Value[] { new StringValue("a"), new StringValue("b") }, true) }, + true), enumerator.elementAt(i++)); + assertEquals( + new FcnRcdValue(values, + new Value[] { emptyset, emptyset, + new SetEnumValue(new Value[] { new StringValue("c") }, true) }, + true), + enumerator.elementAt(i++)); + + // Last element + final SetEnumValue setEnumValue = new SetEnumValue( + new Value[] { new StringValue("a"), new StringValue("b"), new StringValue("c") }, true); + assertEquals(new FcnRcdValue(values, new Value[] { setEnumValue, setEnumValue, setEnumValue }, true), + enumerator.elementAt(511)); + } + + @Test + public void testDomainEmpty() { + final SetEnumValue domain = new SetEnumValue(); + final SetOfFcnsValue setOfFcnsValue = new SetOfFcnsValue(domain, + new SetEnumValue(getValue("a", "b", "c"), true)); + + // Non-subset behavior is our prototype. + assertEquals(1, setOfFcnsValue.size()); + final ValueEnumeration elements = setOfFcnsValue.elements(); + assertEquals(new FcnRcdValue(new Value[0], new Value[0], true), elements.nextElement()); + assertNull(elements.nextElement()); + + // Subset behaves similar. + final EnumerableValue subset = setOfFcnsValue.getRandomSubset(5); + final ValueEnumeration subsetElements = subset.elements(); + assertEquals(1, subset.size()); + assertEquals(new FcnRcdValue(new Value[0], new Value[0], true), subsetElements.nextElement()); + assertNull(subsetElements.nextElement()); + } + + @Test + public void testRangeEmpty() { + final IntervalValue domain = new IntervalValue(1, 2); + final SetOfFcnsValue setOfFcnsValue = new SetOfFcnsValue(domain, new SetEnumValue(new ValueVec(), true)); + + // Non-subset behavior is our prototype. + assertEquals(0, setOfFcnsValue.size()); + assertNull(setOfFcnsValue.elements().nextElement()); + + // Subset behaves similar. + final EnumerableValue subset = setOfFcnsValue.getRandomSubset(5); + assertEquals(0, subset.size()); + assertNull(subset.elements().nextElement()); + assertEquals(new SetEnumValue(), subset); + } + + @Test + public void testDomainAndRangeEmpty() { + final SetEnumValue domain = new SetEnumValue(); + final SetOfFcnsValue setOfFcnsValue = new SetOfFcnsValue(domain, new SetEnumValue()); + + // Non-subset behavior is our prototype. + assertEquals(1, setOfFcnsValue.size()); + final ValueEnumeration elements = setOfFcnsValue.elements(); + assertEquals(new FcnRcdValue(new Value[0], new Value[0], true), elements.nextElement()); + assertNull(elements.nextElement()); + + // Subset behaves similar. + final EnumerableValue subset = setOfFcnsValue.getRandomSubset(5); + final ValueEnumeration subsetElements = subset.elements(); + assertEquals(1, subset.size()); + assertEquals(new FcnRcdValue(new Value[0], new Value[0], true), subsetElements.nextElement()); + assertNull(subsetElements.nextElement()); + } + + @Test + public void testRandomSubsetAndValueEnumerator() { + final Value[] domain = new Value[] { ModelValue.make("m1"), ModelValue.make("m2"), ModelValue.make("m3") }; + final SetOfFcnsValue setOfFcnsValue = new SetOfFcnsValue(new SetEnumValue(domain, true), + new SetEnumValue(getValue("a", "b", "c"), true)); + + assertEquals(27, setOfFcnsValue.size()); + + FP64.Init(); + final Set<FcnRcdValue> enumeratorValues = new HashSet<>(27); + + final SetOfFcnsValue.SubsetEnumerator enumerator = (SubsetEnumerator) setOfFcnsValue.elements(27); + for (int i = 0; i < setOfFcnsValue.size(); i++) { + FcnRcdValue rcd = (FcnRcdValue) enumerator.elementAt(i); + assertEquals(3, rcd.domain.length); + assertEquals(3, rcd.values.length); + enumeratorValues.add(rcd); + } + + final EnumerableValue randomSubset = setOfFcnsValue.getRandomSubset(27); + final Set<FcnRcdValue> randomsubsetValues = new HashSet<>(27); + + final ValueEnumeration enumerator2 = randomSubset.elements(); + FcnRcdValue rcd; + while ((rcd = (FcnRcdValue) enumerator2.nextElement()) != null) { + assertEquals(3, rcd.domain.length); + assertEquals(3, rcd.values.length); + randomsubsetValues.add(rcd); + // Check element is in the original SetOfFcnsValue. + assertTrue(setOfFcnsValue.member(rcd)); + } + + assertEquals(enumeratorValues.size(), randomsubsetValues.size()); + assertEquals(enumeratorValues, randomsubsetValues); + } + + @Test + public void testDomainModelValue() { + final Value[] domain = new Value[] { ModelValue.make("m1"), ModelValue.make("m2"), ModelValue.make("m3") }; + final SetOfFcnsValue setOfFcnsValue = new SetOfFcnsValue(new SetEnumValue(domain, true), + new SetEnumValue(getValue("a", "b", "c"), true)); + + assertEquals(27, setOfFcnsValue.size()); + + FP64.Init(); + final Set<FcnRcdValue> enumeratorValues = new HashSet<>(27); + + final SetOfFcnsValue.SubsetEnumerator enumerator = (SubsetEnumerator) setOfFcnsValue.elements(27); + for (int i = 0; i < setOfFcnsValue.size(); i++) { + FcnRcdValue rcd = (FcnRcdValue) enumerator.elementAt(i); + assertEquals(3, rcd.domain.length); + assertEquals(3, rcd.values.length); + enumeratorValues.add(rcd); + // Check element is in the original SetOfFcnsValue. + assertTrue(setOfFcnsValue.member(rcd)); + } + assertEquals(27, enumeratorValues.size()); + + int i = 0; + assertEquals(new FcnRcdValue(domain, getValue("a", "a", "a"), true), enumerator.elementAt(i++)); + assertEquals(new FcnRcdValue(domain, getValue("a", "a", "b"), true), enumerator.elementAt(i++)); + assertEquals(new FcnRcdValue(domain, getValue("a", "a", "c"), true), enumerator.elementAt(i++)); + assertEquals(new FcnRcdValue(domain, getValue("a", "b", "a"), true), enumerator.elementAt(i++)); + assertEquals(new FcnRcdValue(domain, getValue("a", "b", "b"), true), enumerator.elementAt(i++)); + assertEquals(new FcnRcdValue(domain, getValue("a", "b", "c"), true), enumerator.elementAt(i++)); + assertEquals(new FcnRcdValue(domain, getValue("a", "c", "a"), true), enumerator.elementAt(i++)); + assertEquals(new FcnRcdValue(domain, getValue("a", "c", "b"), true), enumerator.elementAt(i++)); + assertEquals(new FcnRcdValue(domain, getValue("a", "c", "c"), true), enumerator.elementAt(i++)); + assertEquals(new FcnRcdValue(domain, getValue("b", "a", "a"), true), enumerator.elementAt(i++)); + assertEquals(new FcnRcdValue(domain, getValue("b", "a", "b"), true), enumerator.elementAt(i++)); + assertEquals(new FcnRcdValue(domain, getValue("b", "a", "c"), true), enumerator.elementAt(i++)); + assertEquals(new FcnRcdValue(domain, getValue("b", "b", "a"), true), enumerator.elementAt(i++)); + assertEquals(new FcnRcdValue(domain, getValue("b", "b", "b"), true), enumerator.elementAt(i++)); + assertEquals(new FcnRcdValue(domain, getValue("b", "b", "c"), true), enumerator.elementAt(i++)); + assertEquals(new FcnRcdValue(domain, getValue("b", "c", "a"), true), enumerator.elementAt(i++)); + assertEquals(new FcnRcdValue(domain, getValue("b", "c", "b"), true), enumerator.elementAt(i++)); + assertEquals(new FcnRcdValue(domain, getValue("b", "c", "c"), true), enumerator.elementAt(i++)); + assertEquals(new FcnRcdValue(domain, getValue("c", "a", "a"), true), enumerator.elementAt(i++)); + assertEquals(new FcnRcdValue(domain, getValue("c", "a", "b"), true), enumerator.elementAt(i++)); + assertEquals(new FcnRcdValue(domain, getValue("c", "a", "c"), true), enumerator.elementAt(i++)); + assertEquals(new FcnRcdValue(domain, getValue("c", "b", "a"), true), enumerator.elementAt(i++)); + assertEquals(new FcnRcdValue(domain, getValue("c", "b", "b"), true), enumerator.elementAt(i++)); + assertEquals(new FcnRcdValue(domain, getValue("c", "b", "c"), true), enumerator.elementAt(i++)); + assertEquals(new FcnRcdValue(domain, getValue("c", "c", "a"), true), enumerator.elementAt(i++)); + assertEquals(new FcnRcdValue(domain, getValue("c", "c", "b"), true), enumerator.elementAt(i++)); + assertEquals(new FcnRcdValue(domain, getValue("c", "c", "c"), true), enumerator.elementAt(i++)); + } + + @Test + public void testDomainIntervalRangeSetEnumValueSize9() { + final IntervalValue domain = new IntervalValue(1, 2); + final SetOfFcnsValue setOfFcnsValue = new SetOfFcnsValue(domain, + new SetEnumValue(getValue("a", "b", "c"), true)); + + assertEquals(9, setOfFcnsValue.size()); + + final SetOfFcnsValue.SubsetEnumerator enumerator = (SubsetEnumerator) setOfFcnsValue.elements(9); + for (int i = 0; i < setOfFcnsValue.size(); i++) { + FcnRcdValue rcd = (FcnRcdValue) enumerator.elementAt(i); + assertEquals(2, rcd.domain.length); + assertEquals(2, rcd.values.length); + // Check element is in the original SetOfFcnsValue. + assertTrue(setOfFcnsValue.member(rcd)); + } + + int i = 0; + assertEquals(new FcnRcdValue(domain, getValue("a", "a")), enumerator.elementAt(i++)); + assertEquals(new FcnRcdValue(domain, getValue("a", "b")), enumerator.elementAt(i++)); + assertEquals(new FcnRcdValue(domain, getValue("a", "c")), enumerator.elementAt(i++)); + assertEquals(new FcnRcdValue(domain, getValue("b", "a")), enumerator.elementAt(i++)); + assertEquals(new FcnRcdValue(domain, getValue("b", "b")), enumerator.elementAt(i++)); + assertEquals(new FcnRcdValue(domain, getValue("b", "c")), enumerator.elementAt(i++)); + assertEquals(new FcnRcdValue(domain, getValue("c", "a")), enumerator.elementAt(i++)); + assertEquals(new FcnRcdValue(domain, getValue("c", "b")), enumerator.elementAt(i++)); + assertEquals(new FcnRcdValue(domain, getValue("c", "c")), enumerator.elementAt(i++)); + } + + @Test + public void testDomainIntervalRangeSetEnumValueSize27() { + final IntervalValue domain = new IntervalValue(1, 3); + final SetOfFcnsValue setOfFcnsValue = new SetOfFcnsValue(domain, + new SetEnumValue(getValue("a", "b", "c"), true)); + + assertEquals(27, setOfFcnsValue.size()); + + final SetOfFcnsValue.SubsetEnumerator enumerator = (SubsetEnumerator) setOfFcnsValue.elements(27); + for (int i = 0; i < setOfFcnsValue.size(); i++) { + FcnRcdValue rcd = (FcnRcdValue) enumerator.elementAt(i); + assertEquals(3, rcd.domain.length); + assertEquals(3, rcd.values.length); + // Check element is in the original SetOfFcnsValue. + assertTrue(setOfFcnsValue.member(rcd)); + } + + int i = 0; + assertEquals(new FcnRcdValue(domain, getValue("a", "a", "a")), enumerator.elementAt(i++)); + assertEquals(new FcnRcdValue(domain, getValue("a", "a", "b")), enumerator.elementAt(i++)); + assertEquals(new FcnRcdValue(domain, getValue("a", "a", "c")), enumerator.elementAt(i++)); + assertEquals(new FcnRcdValue(domain, getValue("a", "b", "a")), enumerator.elementAt(i++)); + assertEquals(new FcnRcdValue(domain, getValue("a", "b", "b")), enumerator.elementAt(i++)); + assertEquals(new FcnRcdValue(domain, getValue("a", "b", "c")), enumerator.elementAt(i++)); + assertEquals(new FcnRcdValue(domain, getValue("a", "c", "a")), enumerator.elementAt(i++)); + assertEquals(new FcnRcdValue(domain, getValue("a", "c", "b")), enumerator.elementAt(i++)); + assertEquals(new FcnRcdValue(domain, getValue("a", "c", "c")), enumerator.elementAt(i++)); + assertEquals(new FcnRcdValue(domain, getValue("b", "a", "a")), enumerator.elementAt(i++)); + assertEquals(new FcnRcdValue(domain, getValue("b", "a", "b")), enumerator.elementAt(i++)); + assertEquals(new FcnRcdValue(domain, getValue("b", "a", "c")), enumerator.elementAt(i++)); + assertEquals(new FcnRcdValue(domain, getValue("b", "b", "a")), enumerator.elementAt(i++)); + assertEquals(new FcnRcdValue(domain, getValue("b", "b", "b")), enumerator.elementAt(i++)); + assertEquals(new FcnRcdValue(domain, getValue("b", "b", "c")), enumerator.elementAt(i++)); + assertEquals(new FcnRcdValue(domain, getValue("b", "c", "a")), enumerator.elementAt(i++)); + assertEquals(new FcnRcdValue(domain, getValue("b", "c", "b")), enumerator.elementAt(i++)); + assertEquals(new FcnRcdValue(domain, getValue("b", "c", "c")), enumerator.elementAt(i++)); + assertEquals(new FcnRcdValue(domain, getValue("c", "a", "a")), enumerator.elementAt(i++)); + assertEquals(new FcnRcdValue(domain, getValue("c", "a", "b")), enumerator.elementAt(i++)); + assertEquals(new FcnRcdValue(domain, getValue("c", "a", "c")), enumerator.elementAt(i++)); + assertEquals(new FcnRcdValue(domain, getValue("c", "b", "a")), enumerator.elementAt(i++)); + assertEquals(new FcnRcdValue(domain, getValue("c", "b", "b")), enumerator.elementAt(i++)); + assertEquals(new FcnRcdValue(domain, getValue("c", "b", "c")), enumerator.elementAt(i++)); + assertEquals(new FcnRcdValue(domain, getValue("c", "c", "a")), enumerator.elementAt(i++)); + assertEquals(new FcnRcdValue(domain, getValue("c", "c", "b")), enumerator.elementAt(i++)); + assertEquals(new FcnRcdValue(domain, getValue("c", "c", "c")), enumerator.elementAt(i++)); + } + + @Test + public void testDomainIntervalRangeSetEnumValueSize256() { + final IntervalValue domain = new IntervalValue(1, 4); + final SetOfFcnsValue setOfFcnsValue = new SetOfFcnsValue(domain, + new SetEnumValue(getValue("a", "b", "c", "d"), true)); + + assertEquals(256, setOfFcnsValue.size()); + + final SetOfFcnsValue.SubsetEnumerator enumerator = (SubsetEnumerator) setOfFcnsValue.elements(256); + for (int i = 0; i < setOfFcnsValue.size(); i++) { + FcnRcdValue rcd = (FcnRcdValue) enumerator.elementAt(i); + assertEquals(4, rcd.domain.length); + assertEquals(4, rcd.values.length); + // Check element is in the original SetOfFcnsValue. + assertTrue(setOfFcnsValue.member(rcd)); + } + + int i = 0; + assertEquals(new FcnRcdValue(domain, getValue("a", "a", "a", "a")), enumerator.elementAt(i++)); + assertEquals(new FcnRcdValue(domain, getValue("a", "a", "a", "b")), enumerator.elementAt(i++)); + assertEquals(new FcnRcdValue(domain, getValue("a", "a", "a", "c")), enumerator.elementAt(i++)); + assertEquals(new FcnRcdValue(domain, getValue("a", "a", "a", "d")), enumerator.elementAt(i++)); + // ... (to lazy to type them out) + assertEquals(new FcnRcdValue(domain, getValue("d", "d", "d", "b")), enumerator.elementAt(253)); + assertEquals(new FcnRcdValue(domain, getValue("d", "d", "d", "c")), enumerator.elementAt(254)); + assertEquals(new FcnRcdValue(domain, getValue("d", "d", "d", "d")), enumerator.elementAt(255)); + } + + @Test + public void testRandomSubsetFromReallyLarge() { + final List<SetOfFcnsValue> l = new ArrayList<>(); + + l.add(new SetOfFcnsValue(new IntervalValue(1, 11), + new SetEnumValue(getValue("a", "b", "c", "d", "e", "f", "g", "h", "i", "j"), true))); + l.add(new SetOfFcnsValue(new IntervalValue(1, 44), new IntervalValue(1, 20))); + l.add(new SetOfFcnsValue(new IntervalValue(1, 121), new IntervalValue(1, 19))); + l.add(new SetOfFcnsValue(new IntervalValue(1, 321), new IntervalValue(1, 29))); + + l.forEach(new Consumer<SetOfFcnsValue>() { + @Override + public void accept(final SetOfFcnsValue sofv) { + try { + sofv.size(); + } catch (TLCRuntimeException tre) { + // OK, set is huge for size to reject it. Next get a tiny subset of it. + + IntStream.of(0, 1, 2, 799, 1024, 8932, 16933/*, 109031*/).forEach(new IntConsumer() { // 109031 causes the test to take a little long to be included in the overall test suite. + @Override + public void accept(int kOutOfN) { + final EnumerableValue randomSubset = sofv.getRandomSubset(kOutOfN); + + // Check expected amount of elements. + assertEquals(kOutOfN, randomSubset.size()); + + // Check for no duplicates. + FP64.Init(); + final Set<FcnRcdValue> set = new HashSet<>(kOutOfN); + + final ValueEnumeration elements = randomSubset.elements(); + FcnRcdValue rcd; + while ((rcd = (FcnRcdValue) elements.nextElement()) != null) { + // Check element is in the original SetOfFcnsValue. + assertTrue(sofv.member(rcd)); + set.add(rcd); + } + assertEquals(kOutOfN, set.size()); + } + }); + return; + } + fail(); + } + }); + } +} diff --git a/tlatools/test/tlc2/value/SetOfRcrdValueTest.java b/tlatools/test/tlc2/value/SetOfRcrdValueTest.java new file mode 100644 index 0000000000000000000000000000000000000000..94e312cfc08a2912ff7eb6245ba14b186bf95170 --- /dev/null +++ b/tlatools/test/tlc2/value/SetOfRcrdValueTest.java @@ -0,0 +1,196 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.value; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.util.HashSet; +import java.util.Set; +import java.util.stream.IntStream; + +import org.junit.BeforeClass; +import org.junit.Test; + +import tlc2.util.FP64; +import tlc2.value.SetOfRcdsValue.SubsetEnumerator; +import util.UniqueString; + +public class SetOfRcrdValueTest { + + private static final int a = 97; + + private static final Value[] getValue(final int n, String str) { + final Value[] values = new Value[n]; + for (int i = 0; i < n; i++) { + values[i] = new StringValue(str + i); + } + return values; + } + + private static final Value[] getValue(int n, String... strs) { + final Value[] values = new Value[strs.length]; + for (int i = 0; i < values.length; i++) { + values[i] = new SetEnumValue(getValue(n, strs[i]), false); + } + return values; + } + + private static final Value[] getValue(int n, UniqueString[] names) { + // a,b,c,d,e,... + return getValue(n, IntStream.range(a, a + names.length).mapToObj(ascii -> Character.toString((char) ascii)) + .toArray(String[]::new)); + } + + private static final UniqueString[] getNames(final int n) { + final UniqueString[] names = new UniqueString[n]; + for (int i = 0; i < names.length; i++) { + names[i] = UniqueString.uniqueStringOf("N" + i); + } + return names; + } + + @BeforeClass + public static void setup() { + FP64.Init(); + } + + @Test + public void testSimple() { + final UniqueString[] names = getNames(3); + + final Value[] values = new Value[3]; + values[0] = new SetEnumValue(getValue(7, "a"), true); + values[1] = new IntervalValue(1, 2); + values[2] = new IntervalValue(1, 4); + + final SetOfRcdsValue setOfRcrdValue = new SetOfRcdsValue(names, values, true); + + checkElements(names, values, setOfRcrdValue, (SubsetEnumerator) setOfRcrdValue.elements(setOfRcrdValue.size())); + } + + private static void checkElements(final UniqueString[] names, final Value[] values, final SetOfRcdsValue set, + final SubsetEnumerator rcds) { + for (int i = 0; i < set.size(); i++) { + // Check names are stable. + final RecordValue rcd = rcds.elementAt(i); + assertArrayEquals(names, rcd.names); + // Check values are from correct range. + final Value[] rcdValues = rcd.values; + for (int j = 0; j < rcdValues.length; j++) { + assertTrue(values[j].member(rcdValues[j])); + } + } + } + + @Test + public void testRangeSubsetValue() { + final UniqueString[] names = getNames(4); + final SetOfRcdsValue setOfRcrdValue = new SetOfRcdsValue(names, getValue(2, names), true); + + final Set<Value> actual = new HashSet<>(setOfRcrdValue.elements(setOfRcrdValue.size()).all()); + assertEquals(setOfRcrdValue.size(), actual.size()); + + final Set<Value> expected = new HashSet<>(setOfRcrdValue.elements().all()); + assertEquals(expected, actual); + } + + @Test + public void testRandomSubset() { + final UniqueString[] names = getNames(4); + final SetOfRcdsValue setOfRcrdValue = new SetOfRcdsValue(names, getValue(3, names), true); + + final int size = 27; + final EnumerableValue randomSubset = setOfRcrdValue.getRandomSubset(size); + final Set<RecordValue> randomsubsetValues = new HashSet<>(size); + + final ValueEnumeration enumerator = randomSubset.elements(); + RecordValue rcd; + while ((rcd = (RecordValue) enumerator.nextElement()) != null) { + assertEquals(names.length, rcd.names.length); + assertEquals(names.length, rcd.values.length); + randomsubsetValues.add(rcd); + // Check element is in the original SetOfFcnsValue. + assertTrue(setOfRcrdValue.member(rcd)); + } + + assertEquals(size, randomsubsetValues.size()); + } + + @Test + public void testRandomSubsetVaryingParameters() { + for (int n = 1; n < 7; n++) { + final UniqueString[] names = getNames(n); + for (int m = 1; m < 5; m++) { + final SetOfRcdsValue setOfRcrdValue = new SetOfRcdsValue(names, getValue(m, names), true); + final Set<RecordValue> randomsubsetValues = new HashSet<>(); + for (int kOutOfN = 0; kOutOfN < setOfRcrdValue.size(); kOutOfN++) { + final EnumerableValue randomSubset = setOfRcrdValue.getRandomSubset(kOutOfN); + + final ValueEnumeration enumerator = randomSubset.elements(); + RecordValue rcd; + while ((rcd = (RecordValue) enumerator.nextElement()) != null) { + assertEquals(names.length, rcd.names.length); + assertEquals(names.length, rcd.values.length); + randomsubsetValues.add(rcd); + // Check element is in the original SetOfFcnsValue. + assertTrue(setOfRcrdValue.member(rcd)); + } + + assertEquals(kOutOfN, randomsubsetValues.size()); + randomsubsetValues.clear(); + } + } + } + } + + @Test + public void testRandomSubsetAstronomically() { + // RandomSubset(10000, [a1 : {k : k \in 1..50}, a2 : {k : k \in 1..50}, a3 : {k : k \in 1..50}, + // a4 : {k : k \in 1..50}, a5 : {k : k \in 1..50}, a6 : {k : k \in 1..50}, + // a7 : {k : k \in 1..50}, a8 : {k : k \in 1..50}, a9 : {k : k \in 1..50}, + // a10 : {k : k \in 1..50}]) + final UniqueString[] names = getNames(10); + final SetOfRcdsValue setOfRcrdValue = new SetOfRcdsValue(names, getValue(50, names), true); + + final int k = 10000; + final EnumerableValue randomSubset = setOfRcrdValue.getRandomSubset(k); + final Set<RecordValue> randomsubsetValues = new HashSet<>(k); + + final ValueEnumeration enumerator = randomSubset.elements(); + RecordValue rcd; + while ((rcd = (RecordValue) enumerator.nextElement()) != null) { + assertEquals(names.length, rcd.names.length); + assertEquals(names.length, rcd.values.length); + randomsubsetValues.add(rcd); + // Check element is in the original SetOfFcnsValue. + assertTrue(setOfRcrdValue.member(rcd)); + } + + assertEquals(k, randomsubsetValues.size()); + } +} diff --git a/tlatools/test/tlc2/value/SetOfTuplesValueTest.java b/tlatools/test/tlc2/value/SetOfTuplesValueTest.java new file mode 100644 index 0000000000000000000000000000000000000000..64948b79def1d3dca9d08536f455ced668d28e79 --- /dev/null +++ b/tlatools/test/tlc2/value/SetOfTuplesValueTest.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.value; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import tlc2.TLCGlobals; + +public class SetOfTuplesValueTest { + + @Test + public void testToStringLazy() { + // Force toString representation to be lazy. + TLCGlobals.enumBound = 1; + + final IntervalValue intVal = new IntervalValue(1, 2); + final SetOfTuplesValue inner = new SetOfTuplesValue(intVal, intVal); + final SetOfTuplesValue outter = new SetOfTuplesValue(inner, inner); + assertTrue(outter.toString().contains("\\X")); + assertEquals("((1..2 \\X 1..2) \\X (1..2 \\X 1..2))", outter.toString()); + } +} diff --git a/tlatools/test/tlc2/value/SubsetEnumeratorTest.java b/tlatools/test/tlc2/value/SubsetEnumeratorTest.java new file mode 100644 index 0000000000000000000000000000000000000000..acf3d31fddd05607418cacc2e0c926db9b204c7f --- /dev/null +++ b/tlatools/test/tlc2/value/SubsetEnumeratorTest.java @@ -0,0 +1,172 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + * Ian Morris Nieves - added support for fingerprint stack trace + ******************************************************************************/ +package tlc2.value; + +import static org.junit.Assert.assertEquals; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.function.DoubleConsumer; +import java.util.function.IntConsumer; +import java.util.stream.DoubleStream; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; + +import tlc2.util.FP64; + +@RunWith(Parameterized.class) +public class SubsetEnumeratorTest { + + private static final Value[] getValue(String... strs) { + final List<Value> values = new ArrayList<>(strs.length); + for (int i = 0; i < strs.length; i++) { + values.add(new StringValue(strs[i])); + } + return values.toArray(new Value[values.size()]); + } + + @Parameters + public static List<EnumerableValue> getEnumerable() { + final List<EnumerableValue> params = new ArrayList<EnumerableValue>(); + + // IntervalValue + params.add(new IntervalValue(1, 10)); + + // SetEnumValue + final ValueVec vec = new ValueVec(); + final String input = "ABCDEFGHIJ"; + input.chars().forEach(new IntConsumer() { + @Override + public void accept(final int value) { + vec.addElement(ModelValue.make(String.valueOf(value))); + } + }); + params.add(new SetEnumValue(vec, false)); + + // SetOfTuplesValue + params.add(new SetOfTuplesValue(new IntervalValue(1, 5), new IntervalValue(1, 5))); + params.add(new SetOfTuplesValue(new SetEnumValue(), new SetEnumValue())); // empty + + // UnionValue + params.add(new UnionValue( + new SetEnumValue(new Value[] { new IntervalValue(1, 5), new IntervalValue(5, 11) }, true))); + params.add(new UnionValue(new SetEnumValue())); // empty + + // SetOfFcnsValue + params.add(new SetOfFcnsValue(new IntervalValue(2, 5), + new SetEnumValue(new Value[] { new StringValue("a"), new StringValue("b"), new StringValue("c") }, true))); + params.add(new SetOfFcnsValue(new IntervalValue(3, 5), new SetEnumValue())); // empty range + + // SetOfFcnsValue with SubsetValue as range. + params.add(new SetOfFcnsValue( + new SetEnumValue(new Value[] { ModelValue.make("m1"), ModelValue.make("m2"), ModelValue.make("m3") }, + true), + new SubsetValue(new SetEnumValue( + new Value[] { new StringValue("a"), new StringValue("b"), new StringValue("c") }, true)))); + + // SetOfFcnsValue + final SetEnumValue domain = new SetEnumValue(getValue("A1", "A2", "A3"), true); + final SetEnumValue range = new SetEnumValue(getValue("v1", "v2", "v3"), true); + params.add(new SetOfFcnsValue(domain, range)); + + // SubsetValue + params.add(new SubsetValue(new SetEnumValue( + new Value[] { new StringValue("a"), new StringValue("b"), new StringValue("c") }, true))); + params.add(new SubsetValue(new SetEnumValue())); // empty + + // Adding values to Set<Value> requires fingerprinting. + FP64.Init(); + + return params; + } + + private final Enumerable enumerable; + + public SubsetEnumeratorTest(final Enumerable enumerable) { + this.enumerable = enumerable; + } + + @Test + public void testElementsInt() { + // for various fractions... + DoubleStream.of(0, .1, .2, .3, .4, .55, .625, .775, .8, .9, 1).forEach(new DoubleConsumer() { + @Override + public void accept(double fraction) { + final int k = (int) Math.ceil(enumerable.size() * fraction); + final List<Value> values = enumerable.elements(k).all(); + + // Expected size. + Assert.assertEquals(String.format("Failed for fraction: %s", fraction), k, values.size()); + + // Unique values. + Assert.assertEquals(String.format("Failed for fraction: %s", fraction), values.size(), + new HashSet<Value>(values).size()); + + // Each value is actually a member of enumerable. + for (Value v : values) { + Assert.assertTrue(String.format("Failed for fraction: %s", fraction), enumerable.member(v)); + } + } + }); + } + + @Test + public void testGetRandomSubset() { + DoubleStream.of(0, .1, .2, .3, .4, .55, .625, .775, .8, .9, 1).forEach(new DoubleConsumer() { + @Override + public void accept(final double fraction) { + final int k = (int) Math.ceil(enumerable.size() * fraction); + + final EnumerableValue enumValue = enumerable.getRandomSubset(k); + + // Expected size. + assertEquals(String.format("Failed for fraction: %s", fraction), k, enumValue.size()); + + final Set<Value> values = new HashSet<Value>(enumValue.size()); + + // Each value is actually a member of enumerable. + ValueEnumeration elements = enumValue.elements(); + Value v = null; + while ((v = elements.nextElement()) != null) { + Assert.assertTrue(String.format("Failed for fraction: %s", fraction), enumerable.member(v)); + values.add(v); + } + + // Unique values. + Assert.assertEquals(String.format("Failed for fraction: %s", fraction), enumValue.size(), + new HashSet<Value>(values).size()); + + } + }); + } +} diff --git a/tlatools/test/tlc2/value/SubsetValueTest.java b/tlatools/test/tlc2/value/SubsetValueTest.java new file mode 100644 index 0000000000000000000000000000000000000000..144ff10f5805fbdca8ad91c42c85d662879f3fb3 --- /dev/null +++ b/tlatools/test/tlc2/value/SubsetValueTest.java @@ -0,0 +1,519 @@ +/******************************************************************************* + * Copyright (c) 2018 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.value; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.TreeSet; + +import org.junit.BeforeClass; +import org.junit.Test; + +import tlc2.util.FP64; +import tlc2.value.SubsetValue.CoinTossingSubsetEnumerator; +import tlc2.value.SubsetValue.KElementEnumerator; +import tlc2.value.SubsetValue.SubsetEnumerator; +import tlc2.value.SubsetValue.Unrank; +import util.Assert; + +public class SubsetValueTest { + + private static final Value[] getValue(String... strs) { + final List<Value> values = new ArrayList<>(strs.length); + for (int i = 0; i < strs.length; i++) { + values.add(new StringValue(strs[i])); + } + Collections.shuffle(values); + return values.toArray(new Value[values.size()]); + } + + @BeforeClass + public static void setup() { + // Make test repeatable by setting random seed always to same value. + EnumerableValue.setRandom(15041980L); + // Needed to insert elements into java.util.Set (because of hashcode) later to + // detect duplicates. + FP64.Init(); + } + + private void doTest(final int expectedSize, final EnumerableValue innerSet) { + doTest(expectedSize, innerSet, expectedSize); + } + + private void doTest(final int expectedSize, final EnumerableValue innerSet, + int expectedElements) { + final SubsetValue subsetValue = new SubsetValue(innerSet); + assertEquals(expectedSize, subsetValue.size()); + + final Set<Value> s = new TreeSet<>(new Comparator<Value>() { + @Override + public int compare(Value o1, Value o2) { + // o1.normalize(); + // ((SetEnumValue) o1).elems.sort(true); + // + // o2.normalize(); + // ((SetEnumValue) o2).elems.sort(true); + + return o1.compareTo(o2); + } + }); + + final ValueEnumeration elements = subsetValue.elements(expectedElements); + assertTrue(elements instanceof SubsetEnumerator); + + SetEnumValue next = null; + while ((next = (SetEnumValue) elements.nextElement()) != null) { + final int size = next.elems.size(); + assertTrue(0 <= size && size <= innerSet.size()); + s.add(next); + } + assertEquals(expectedElements, s.size()); + } + + @Test + public void testRandomSubsetE7F1() { + final SetEnumValue innerSet = new SetEnumValue(getValue("a", "b", "c", "d", "e", "f", "g"), true); + doTest(1 << innerSet.size(), innerSet); + } + + @Test + public void testRandomSubsetE7F05() { + final SetEnumValue innerSet = new SetEnumValue(getValue("a", "b", "c", "d", "e", "f", "g"), true); + doTest(1 << innerSet.size(), innerSet, 64); + } + + @Test + public void testRandomSubsetE6F1() { + final SetEnumValue innerSet = new SetEnumValue(getValue("a", "b", "c", "d", "e", "f"), true); + doTest(1 << innerSet.size(), innerSet); + } + + @Test + public void testRandomSubsetE5F01() { + final SetEnumValue innerSet = new SetEnumValue(getValue("a", "b", "c", "d", "e"), true); + doTest(1 << innerSet.size(), innerSet, 4); + } + + @Test + public void testRandomSubsetE5F025() { + final SetEnumValue innerSet = new SetEnumValue(getValue("a", "b", "c", "d", "e"), true); + doTest(1 << innerSet.size(), innerSet, 8); + } + + @Test + public void testRandomSubsetE5F05() { + final SetEnumValue innerSet = new SetEnumValue(getValue("a", "b", "c", "d", "e"), true); + doTest(1 << innerSet.size(), innerSet, 16); + } + + @Test + public void testRandomSubsetE5F075() { + final SetEnumValue innerSet = new SetEnumValue(getValue("a", "b", "c", "d", "e"), true); + doTest(1 << innerSet.size(), innerSet, 24); + } + + @Test + public void testRandomSubsetE5F1() { + final SetEnumValue innerSet = new SetEnumValue(getValue("a", "b", "c", "d", "e"), true); + doTest(1 << innerSet.size(), innerSet); + } + + @Test + public void testRandomSubsetE32F1ENeg6() { + final IntervalValue innerSet = new IntervalValue(1, 32); + final SubsetValue subsetValue = new SubsetValue(innerSet); + + ValueEnumeration elements = subsetValue.elements(2342); + assertTrue(elements instanceof CoinTossingSubsetEnumerator); + + final Set<Value> s = new HashSet<>(); + SetEnumValue next = null; + while ((next = (SetEnumValue) elements.nextElement()) != null) { + final int size = next.elems.size(); + assertTrue(0 <= size && size <= innerSet.size()); + s.add(next); + } + + CoinTossingSubsetEnumerator tossingEnumerator = (CoinTossingSubsetEnumerator) elements; + assertTrue(tossingEnumerator.getNumOfPicks() - 100 <= s.size() && s.size() <= tossingEnumerator.getNumOfPicks()); + } + + @Test + public void testRandomSubsetE17F1ENeg3() { + final IntervalValue innerSet = new IntervalValue(1, 17); + final SubsetValue subsetValue = new SubsetValue(innerSet); + + final ValueEnumeration elements = subsetValue.elements(4223); + assertTrue(elements instanceof SubsetEnumerator); + + final Set<Value> s = new HashSet<>(); + SetEnumValue next = null; + while ((next = (SetEnumValue) elements.nextElement()) != null) { + final int size = next.elems.size(); + assertTrue(0 <= size && size <= innerSet.size()); + s.add(next); + } + + final SubsetEnumerator enumerator = (SubsetEnumerator) elements; + assertEquals(enumerator.k, s.size()); + } + + @Test + public void testRandomSubsetSubset16() { + final SetEnumValue innerSet = new SetEnumValue(getValue("a", "b"), true); + final SubsetValue innerSubset = new SubsetValue(innerSet); + final SubsetValue subsetValue = new SubsetValue(innerSubset); + + final int expectedSize = 1 << innerSubset.size(); + assertEquals(expectedSize, subsetValue.size()); + + // No duplicates + final Set<Value> s = new HashSet<>(expectedSize); + final ValueEnumeration elements = subsetValue.elements(expectedSize); + Value next = null; + while ((next = elements.nextElement()) != null) { + s.add(next); + } + assertEquals(expectedSize, s.size()); + } + + @Test + public void testRandomSubsetSubset256() { + final SetEnumValue innerSet = new SetEnumValue(getValue("a", "b", "c"), true); + final SubsetValue innerSubset = new SubsetValue(innerSet); + final SubsetValue subsetValue = new SubsetValue(innerSubset); + + final int expectedSize = 1 << innerSubset.size(); + assertEquals(expectedSize, subsetValue.size()); + + // No duplicates + final Set<Value> s = new HashSet<>(expectedSize); + final ValueEnumeration elements = subsetValue.elements(expectedSize); + Value next = null; + while ((next = elements.nextElement()) != null) { + s.add(next); + } + assertEquals(expectedSize, s.size()); + } + + @Test + public void testRandomSubsetSubset65536() { + final SetEnumValue innerSet = new SetEnumValue(getValue("a", "b", "c", "d"), true); + final SubsetValue innerSubset = new SubsetValue(innerSet); + final SubsetValue subsetValue = new SubsetValue(innerSubset); + + final int expectedSize = 1 << innerSubset.size(); + assertEquals(expectedSize, subsetValue.size()); + + // No duplicates + final Set<Value> s = new HashSet<>(expectedSize); + final ValueEnumeration elements = subsetValue.elements(expectedSize); + Value next = null; + while ((next = elements.nextElement()) != null) { + s.add(next); + } + assertEquals(expectedSize, s.size()); + } + + @Test + public void testRandomSubsetSubsetNoOverflow() { + final SetEnumValue innerSet = new SetEnumValue(getValue("a", "b", "c", "d", "e"), true); + final SubsetValue innerSubset = new SubsetValue(innerSet); + final SubsetValue subsetValue = new SubsetValue(innerSubset); + + try { + subsetValue.size(); + } catch (Assert.TLCRuntimeException e) { + final Set<Value> s = new HashSet<>(); + + final ValueEnumeration elements = subsetValue.elements(2148); + assertTrue(elements instanceof CoinTossingSubsetEnumerator); + Value next = null; + while ((next = elements.nextElement()) != null) { + s.add(next); + } + // No duplicates + assertEquals(2148, s.size()); + } + } + + @Test + public void testKSubsetEnumerator() { + final SetEnumValue innerSet = new SetEnumValue(getValue("a", "b", "c", "d"), true); + final SubsetValue subset = new SubsetValue(innerSet); + + assertEquals(1, subset.numberOfKElements(0)); + assertEquals(4, subset.numberOfKElements(1)); + assertEquals(6, subset.numberOfKElements(2)); + assertEquals(4, subset.numberOfKElements(3)); + assertEquals(1, subset.numberOfKElements(4)); + + ValueEnumeration enumerator = subset.kElements(0); + assertEquals(new SetEnumValue(), enumerator.nextElement()); + assertNull(enumerator.nextElement()); + + // Need to sort KElementEnumerator to be able to predict the order in which + // elements get returned. + enumerator = ((KElementEnumerator) subset.kElements(1)).sort(); + assertEquals(new SetEnumValue(getValue("a"), false), enumerator.nextElement()); + assertEquals(new SetEnumValue(getValue("b"), false), enumerator.nextElement()); + assertEquals(new SetEnumValue(getValue("c"), false), enumerator.nextElement()); + assertEquals(new SetEnumValue(getValue("d"), false), enumerator.nextElement()); + assertNull(enumerator.nextElement()); + + enumerator = ((KElementEnumerator) subset.kElements(2)).sort(); + assertEquals(new SetEnumValue(getValue("a", "b"), false), enumerator.nextElement()); + assertEquals(new SetEnumValue(getValue("a", "c"), false), enumerator.nextElement()); + assertEquals(new SetEnumValue(getValue("b", "c"), false), enumerator.nextElement()); + assertEquals(new SetEnumValue(getValue("a", "d"), false), enumerator.nextElement()); + assertEquals(new SetEnumValue(getValue("b", "d"), false), enumerator.nextElement()); + assertEquals(new SetEnumValue(getValue("c", "d"), false), enumerator.nextElement()); + assertNull(enumerator.nextElement()); + + enumerator = ((KElementEnumerator) subset.kElements(3)).sort(); + assertEquals(new SetEnumValue(getValue("a", "b", "c"), false), enumerator.nextElement()); + assertEquals(new SetEnumValue(getValue("a", "b", "d"), false), enumerator.nextElement()); + assertEquals(new SetEnumValue(getValue("a", "c", "d"), false), enumerator.nextElement()); + assertEquals(new SetEnumValue(getValue("b", "c", "d"), false), enumerator.nextElement()); + assertNull(enumerator.nextElement()); + + enumerator = ((KElementEnumerator) subset.kElements(4)).sort(); + assertEquals(new SetEnumValue(getValue("a", "b", "c", "d"), false), enumerator.nextElement()); + assertNull(enumerator.nextElement()); + } + + @Test + public void testKSubsetEnumeratorNegative() { + final SetEnumValue innerSet = new SetEnumValue(getValue("a", "b", "c", "d"), true); + final SubsetValue subset = new SubsetValue(innerSet); + try { + subset.kElements(-1); + } catch (IllegalArgumentException e) { + return; + } + fail(); + } + + @Test + public void testKSubsetEnumeratorGTCapacity() { + final SetEnumValue innerSet = new SetEnumValue(getValue("a", "b", "c", "d"), true); + final SubsetValue subset = new SubsetValue(innerSet); + try { + subset.kElements(innerSet.size() + 1); + } catch (IllegalArgumentException e) { + return; + } + fail(); + } + + @Test + public void testNumKSubset() { + final SetEnumValue innerSet = new SetEnumValue(getValue("a", "b", "c", "d", "e"), true); + final SubsetValue subset = new SubsetValue(innerSet); + + assertEquals(1, subset.numberOfKElements(0)); + assertEquals(5, subset.numberOfKElements(1)); + assertEquals(10, subset.numberOfKElements(2)); + assertEquals(10, subset.numberOfKElements(3)); + assertEquals(5, subset.numberOfKElements(4)); + assertEquals(1, subset.numberOfKElements(5)); + } + + @Test + public void testNumKSubset2() { + final SetEnumValue innerSet = new SetEnumValue(getValue("a", "b", "c", "d", "e", "f", "g", "h"), true); + final SubsetValue subset = new SubsetValue(innerSet); + + int sum = 0; + for (int i = 0; i <= innerSet.size(); i++) { + sum += subset.numberOfKElements(i); + } + assertEquals(1 << innerSet.size(), sum); + } + + @Test + public void testNumKSubsetNeg() { + final SetEnumValue innerSet = new SetEnumValue(getValue("a", "b", "c", "d", "e"), true); + final SubsetValue subset = new SubsetValue(innerSet); + + try { + subset.numberOfKElements(-1); + } catch (IllegalArgumentException e) { + return; + } + fail(); + } + + @Test + public void testNumKSubsetKGTN() { + final SetEnumValue innerSet = new SetEnumValue(getValue("a", "b", "c", "d", "e"), true); + final SubsetValue subset = new SubsetValue(innerSet); + + try { + subset.numberOfKElements(innerSet.size() + 1); + } catch (IllegalArgumentException e) { + return; + } + fail(); + } + + @Test + public void testNumKSubsetUpTo62() { + for (int i = 1; i < 62; i++) { + final SubsetValue subset = new SubsetValue(new IntervalValue(1, i)); + long sum = 0L; + for (int j = 0; j <= i; j++) { + sum += subset.numberOfKElements(j); + } + assertEquals(1L << i, sum); + } + } + + @Test + public void testNumKSubsetPreventsOverflow() { + final IntervalValue innerSet = new IntervalValue(1, 63); + final SubsetValue subset = new SubsetValue(innerSet); + for (int i = 0; i <= innerSet.size(); i++) { + try { + subset.numberOfKElements(i); + } catch (IllegalArgumentException e) { + continue; + } + fail(); + } + } + + @Test + public void testUnrankKSubsets() { + final SetEnumValue innerSet = new SetEnumValue(getValue("a", "b", "c", "d", "e"), true); + final SubsetValue subset = new SubsetValue(innerSet); + + final int sizeS = innerSet.size(); + for (int k = 0; k < sizeS; k++) { + final Unrank unranker = subset.getUnrank(k); + // for each k-subset... + final long numElementsInKSubset = subset.numberOfKElements(k); + final Set<Value> kSubset = new HashSet<>(); + for (int i = 0; i < numElementsInKSubset; i++) { + final Value kElementAt = unranker.subsetAt(i); + // check k-Subset is indeed k-Subset + assertEquals(k, kElementAt.size()); + kSubset.add(kElementAt); + } + // check for no duplicates. + assertEquals(numElementsInKSubset, kSubset.size()); + } + } + + @Test + public void testUnrank16viaRank() { + final IntervalValue innerSet = new IntervalValue(1, 16); + final SubsetValue subset = new SubsetValue(innerSet); + + int size = innerSet.size(); + + final long sizeS = 1L << size; // 2^innerSet.size() + final Set<Value> unranked = new HashSet<>((int)sizeS); + + for (int k = 0; k <= size; k++) { + final Unrank unranker = subset.getUnrank(k); + // for each k-subset... + final long numElementsInKSubset = subset.numberOfKElements(k); + for (int i = 0; i < numElementsInKSubset; i++) { + final Value kElementAt = unranker.subsetAt(i); + assertEquals(k, kElementAt.size()); + unranked.add(kElementAt); + } + } + assertEquals(sizeS, unranked.size()); + } + + @Test + public void testRandomSetOfSubsets() { + final IntervalValue innerSet = new IntervalValue(1, 22); + final SubsetValue subset = new SubsetValue(innerSet); + + final int maxLength = 10; + final int k = 23131; + final SetEnumValue setOfSubsets = (SetEnumValue) subset.getRandomSetOfSubsets(k, maxLength); + assertEquals(k, setOfSubsets.size()); + + final ValueEnumeration elements = setOfSubsets.elements(); + Value val = null; + while ((val = elements.nextElement()) != null) { + assertTrue(val.size() <= maxLength); + } + setOfSubsets.normalize(); + assertEquals(k, setOfSubsets.size()); + } + + @Test + public void testRandomSetOfSubsets300() { + final IntervalValue innerSet = new IntervalValue(1, 300); + final SubsetValue subset = new SubsetValue(innerSet); + + final int maxLength = 9; + final int k = 23071; + final SetEnumValue setOfSubsets = (SetEnumValue) subset.getRandomSetOfSubsets(k, maxLength); + assertEquals(k, setOfSubsets.size()); + + final ValueEnumeration elements = setOfSubsets.elements(); + Value val = null; + while ((val = elements.nextElement()) != null) { + assertTrue(val.size() <= maxLength); + } + setOfSubsets.normalize(); + assertEquals(k, setOfSubsets.size()); + } + + @Test + public void testRandomSetOfSubsets400() { + final IntervalValue innerSet = new IntervalValue(1, 400); + final SubsetValue subset = new SubsetValue(innerSet); + + final int maxLength = 9; + final int k = 23077; + final SetEnumValue setOfSubsets = (SetEnumValue) subset.getRandomSetOfSubsets(k, maxLength); + assertEquals(k, setOfSubsets.size()); + + final ValueEnumeration elements = setOfSubsets.elements(); + Value val = null; + while ((val = elements.nextElement()) != null) { + assertTrue(val.size() <= maxLength); + } + setOfSubsets.normalize(); + assertEquals(k, setOfSubsets.size()); + } +} diff --git a/tlatools/test/tlc2/value/ValueInputOutputStreamTest.java b/tlatools/test/tlc2/value/ValueInputOutputStreamTest.java new file mode 100644 index 0000000000000000000000000000000000000000..dda13c636836ca12e8ea2e8f21d7ca93e4b92c30 --- /dev/null +++ b/tlatools/test/tlc2/value/ValueInputOutputStreamTest.java @@ -0,0 +1,118 @@ +/******************************************************************************* + * Copyright (c) 2017 Microsoft Research. All rights reserved. + * + * The MIT License (MIT) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Contributors: + * Markus Alexander Kuppe - initial API and implementation + ******************************************************************************/ +package tlc2.value; + +import static org.junit.Assert.*; + +import java.io.File; +import java.io.IOException; + +import org.junit.Test; + +import tlc2.TLCGlobals; + +public class ValueInputOutputStreamTest { + + @Test + public void testWriteShort() throws IOException { + final File tempFile = File.createTempFile("ValueOutputStreamTest-testWriteShort", ".vos"); + tempFile.deleteOnExit(); + + final ValueOutputStream out = new ValueOutputStream(tempFile); + out.writeShort(Short.MAX_VALUE); + out.writeShort(Short.MIN_VALUE); + out.writeShort((short) 0); + out.close(); + + final ValueInputStream in = new ValueInputStream(tempFile); + assertEquals(Short.MAX_VALUE, in.readShort()); + assertEquals(Short.MIN_VALUE, in.readShort()); + assertEquals((short) 0, in.readShort()); + in.close(); + } + + @Test + public void testWriteInt() throws IOException { + final File tempFile = File.createTempFile("ValueOutputStreamTest-testWriteInt", ".vos"); + tempFile.deleteOnExit(); + + final ValueOutputStream out = new ValueOutputStream(tempFile); + out.writeInt(Integer.MAX_VALUE); + out.writeInt(Integer.MIN_VALUE); + out.writeInt(0); + out.close(); + + final ValueInputStream in = new ValueInputStream(tempFile); + assertEquals(Integer.MAX_VALUE, in.readInt()); + assertEquals(Integer.MIN_VALUE, in.readInt()); + assertEquals(0, in.readInt()); + in.close(); + } + + @Test + public void testWriteShortNat() throws IOException { + final File tempFile = File.createTempFile("ValueOutputStreamTest-testWriteShortNat", ".vos"); + tempFile.deleteOnExit(); + + TLCGlobals.useGZIP = true; + final ValueOutputStream out = new ValueOutputStream(tempFile); + out.writeShortNat(Short.MAX_VALUE); + out.writeShortNat((short) 0); + out.close(); + + // 20 byte header + // 2 byte Short.MAX_VALUE + // 1 byte 0 + assertEquals(20 + 2 + 1, tempFile.length()); + + final ValueInputStream in = new ValueInputStream(tempFile); + assertEquals(Short.MAX_VALUE, in.readShortNat()); + assertEquals(0, in.readShortNat()); + in.close(); + } + + @Test + public void testWriteNat() throws IOException { + final File tempFile = File.createTempFile("ValueOutputStreamTest-testWriteNat", ".vos"); + tempFile.deleteOnExit(); + + TLCGlobals.useGZIP = true; + final ValueOutputStream out = new ValueOutputStream(tempFile); + out.writeNat(Integer.MAX_VALUE); + out.writeNat(0); + out.close(); + + // 20 byte header + // 4 byte Integer.MAX_VALUE + // 2 byte 0 + assertEquals(20 + 4 + 2, tempFile.length()); + + final ValueInputStream in = new ValueInputStream(tempFile); + assertEquals(Integer.MAX_VALUE, in.readNat()); + assertEquals(0, in.readNat()); + in.close(); + } +}