[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [tlaplus] Proving eventualities with TLAPS (1.5.0)



Hi Ramon,

not entirely sure what you mean when you say you proved everything except for the final theorem (whose QED proof was included in yesterday's message). For what it's worth, here is the proof of the first of the intermediate steps, the two others are similar:

LEMMA RedBlue == Spec => []((x = "red") => <>(~(x = "red") /\ (x = "blue")))
<1>1. x = "red" => ENABLED <<Next>>_x
  BY ExpandENABLED DEF Next
<1>2. x = "red" /\ [Next]_x => (x = "red")' \/ (~(x = "red") /\ (x = "blue"))'
  BY DEF Next
<1>3. x = "red" /\ <<Next>>_x => (~(x = "red") /\ (x = "blue"))'
  BY DEF Next
<1>. QED  BY <1>1, <1>2, <1>3, PTL DEF Spec

About validity checking for temporal logic, there used to be a number of online tools for LTL that could help you with that. A quick search brought up Owl [1], a tool that converts LTL formulas to different forms of automata. For example, you can paste the formula "!(G(a -> b) -> (G a -> G b))" into the input box (note that you need to negate the formula for validity checking) and generate an NBA (non-deterministic Büchi automaton). You'll see that the automaton is trivial and has no acceptance cycle (marked in green), which means that the formula is unsatisfiable, therefore the formula without the outermost negation is valid.

Concerning your question: the "updated_enabled_cdot" branch contains two more proof primitives for reasoning about ENABLED that have not yet made it into the main branch:

- ENABLEDrewrites applies simplification rules such as

ENABLED (A \/ B) <=> (ENABLED A) \/ (ENABLED B)
ENABLED (A /\ B) <=> (ENABLED A) /\ (ENABLED B)  if A and B do not share primed variables
ENABLED (x' = e) <=> TRUE  if e is a state function

with the purpose of simplifying an ENABLED _expression_ before applying ExpandENABLED (which introduces existential quantification that may be difficult for the backends to prove).

- ENABLEDRules allows reasoning about monotonicity of ENABLED:

ASSUME A => B  PROVE (ENABLED A) => (ENABLED B)
ASSUME A <=> B  PROVE (ENABLED A) <=> (ENABLED B)

For example, this is useful to reduce ENABLED <<A>>_v to ENABLED A if A is an action that cannot stutter (as is often the case), since the latter is easier to reason about.

These additional primitives sometimes make proofs easier but they are not essential.

Stephan

[1] https://owl.model.in.tum.de


On 25 Nov 2023, at 18:52, Ramon Snir <r@xxxxxxx> wrote:

Thank you, Stephan!

I followed your email and I managed to prove everything except for the final theorem. I started reading the "coalescing" paper. I can't say yet that I understand what the decision procedure would decide as valid, but I'm still working through it, so crossing my fingers and I'll write here afterward.

One question that I had so far:

I saw in EWD998 a reference to ENABLEDRules. I don't see it defined anywhere, and neither does my installed version of TLAPM. It says "Unknown operator ENABLEDRules".

<1>2. (ENABLED <<System>>_vars) <=> (ENABLED System)
  BY <1>1, ENABLEDrules

Is it coming from a side library? I'm not sure how to use it and I don't know when I would choose to use it versus ExpandENABLED.

On Sat, Nov 25, 2023 at 3:52 AM Stephan Merz <stephan.merz@xxxxxxxxx> wrote:
Hi Ramon,

thank you for your question and indeed, documentation for the more recent features of the prover is sorely lacking. The only examples using the ENABLED backends that I am aware of are

- module SimpleExampleWF in the examples_draft directory of the tlapm repository (https://github.com/tlaplus/tlapm/tree/main/examples_draft)

- the termination proof of the termination detection algorithm described in EWD998 at https://github.com/tlaplus/Examples/blob/master/specifications/ewd998/EWD998_proof.tla (that proof uses some features beyond the elementary ExpandENABLED primitive)

In order to answer your question, the PTL backend is not based on axioms but on a decision procedure for propositional temporal logic. The details are described in our "coalescing" paper [1]. This has two fundamental consequences:

1. In first approximation, PTL does not handle sequents (ASSUME / PROOF constructs), except for constant-level assumptions [2]. I recommend only invoking it in such contexts. The "non-[]" warnings that you see in the proof output are an indication of this: they tell you that these ASSUME / PROOF steps should be rewritten as plain implications.

2. PTL only handles propositions and does not perform even trivial first-order reasoning. It will abstract atomic formulas such as `x = "red"' into a proposition, but sometimes it may be helpful to introduce propositional abstractions yourself, and it won't know that trivialities such as

x = "red" => ~(x = "blue")

holds. (I believe it doesn't even know that `x # "red"' is equivalent to `~(x = "red")'.)

Below is your proof rewritten with these caveats in mind, and an outline of your "main" theorem whose QED step is checked by PTL. Note in particular that it is really necessary in that proof to write

<1>1. Spec => []((x = "red") => <>(~(x = "red") /\ (x = "blue")))

due to observation (2) above, otherwise PTL won't know that the step from red to blue cannot just be a stuttering step. The missing proofs for steps <1>1 to <1>3 should be similar to the proof of your lemma that x will eventually be blue. (I'd actually recommend setting up the lemma in the way that it fits the steps required in the main proof so that you can use lemmas there.)

In the proof of your first real liveness theorem, besides rewriting ASSUME / PROOF to implications I also had to add the step

<1>4. Init /\ [Next]_x => Init' \/ (x = "blue")'
  BY DEF Init, Next

Without it, the conclusion wouldn't hold: weak fairness ensures that a <<Next>>_x transition will be taken only if it remains enabled, not if it just happens to be enabled at some point.

Besides, I made a few cosmetic changes to your proofs, in particular by reformulating the type-correctness lemma so that it can be used within the liveness proof.

I do hope this helps you to make progress: feel free to come back with further questions that will invariably arise.

Best,
Stephan

[2] More generally, all assumptions of lemmas should be "boxed" formulas, i.e., trivially equivalent to []F for some F.

--------------------------- MODULE RingEventually ---------------------------
EXTENDS TLAPS

VARIABLE x
Init == x = "red"
Next ==
  \/ (x = "red" /\ x' = "blue")
  \/ (x = "blue" /\ x' = "green")
  \/ (x = "green" /\ x' = "blue")

Spec == Init /\ [][Next]_x /\ WF_x(Next)

TypeOK == x \in {"red", "green", "blue"}

LEMMA TypeSafety == Init /\ [][Next]_x => []TypeOK
PROOF
<1> USE DEF TypeOK
<1>1. Init => TypeOK
  BY DEF Init
<1>2. ASSUME TypeOK /\ [Next]_x
      PROVE TypeOK'
  BY <1>2 DEF Next
<1> QED
  BY <1>1, <1>2, PTL DEF Spec

LEMMA EventuallyRed == Spec => <>(x = "red")
PROOF BY PTL DEF Spec, Init

THEOREM Spec => <>(x = "blue")
PROOF
<1>2. TypeOK /\ Init => ENABLED <<Next>>_x
  BY ExpandENABLED DEF Init, Next
<1>3. Init /\ <<Next>>_x => (x = "blue")'
  BY DEF Init, Next
<1>4. Init /\ [Next]_x => Init' \/ (x = "blue")'
  BY DEF Init, Next
<1> QED
  BY <1>2, <1>3, <1>4, TypeSafety, PTL DEF Spec


\* And my actual goal: how should _this_ proof be structured?
THEOREM Spec => []<>(x = "red")
<1>1. Spec => []((x = "red") => <>(~(x = "red") /\ (x = "blue")))
<1>2. Spec => []((x = "blue") => <>(~(x = "blue") /\ (x = "green")))
<1>3. Spec => []((x = "green") => <>(~(x = "green") /\ (x = "red")))
<1>. QED  BY <1>1, <1>2, <1>3, EventuallyRed, PTL

=============================================================================


On 24 Nov 2023, at 17:17, Ramon Snir <ramonsnir@xxxxxxxxx> wrote:

Hi,

I am trying to overcome some property-checking limitations of TLC by learning TLAPS, specifically using the unreleased features regarding ENABLED and \cdot.

I am using TLAPM built from source from this commit: https://github.com/tlaplus/tlapm/tree/dc344b6d6e92332ba4a54f4cc86c577a9a137ecd (From the master branch, but not the latest commit)

I have experience with Coq and I think I understand the general idea of how to use TLAPS, up to the PTL/sl4 solver. I'm not sure what proof rules and axioms it has access to and most results I found online are 2+ years old so they focus on proving safety, without ENABLED usage.


--------------------------- MODULE RingEventually ---------------------------
EXTENDS TLAPS

VARIABLE x
Init == x = "red"
Next ==
  \/ (x = "red" /\ x' = "blue")
  \/ (x = "blue" /\ x' = "green")
  \/ (x = "green" /\ x' = "blue")

Spec == Init /\ [][Next]_x /\ WF_x(Next)

TypeOK == x \in {"red", "green", "blue"}

LEMMA TypeSafety == Spec => []TypeOK
PROOF
<1> USE DEF TypeOK
<1>1. Init => TypeOK
  BY DEF Init
<1>2. ASSUME TypeOK /\ [Next]_x
      PROVE TypeOK'
  BY <1>2 DEF Next
<1> QED
  BY <1>1, <1>2, PTL DEF Spec

LEMMA Spec => <>(x = "red")
PROOF BY PTL DEF Spec, Init

\* The QED step fails
THEOREM Spec => <>(x = "blue")
PROOF
<1>1. (Init /\ [][Next]_x) => []TypeOK
  <2>1. Init => TypeOK
    BY DEF Init, TypeOK
  <2>2. ASSUME TypeOK /\ [Next]_x
        PROVE TypeOK'
    BY <2>2 DEF TypeOK, Next
  <2> QED
    BY <2>1, <2>2, PTL
<1>2. ASSUME TypeOK /\ Init
      PROVE ENABLED <<Next>>_x
  BY <1>2, ExpandENABLED DEF Init, Next
<1>3. ASSUME Init /\ <<Next>>_x
      PROVE (x = "blue")'
  BY <1>3 DEF Init, Next
<1> QED \* failed
  BY <1>1, <1>2, <1>3, PTL DEF Spec, Init
 
(*
The proof state at the failing QED:

ASSUME NEW VARIABLE x,
       x = "red" /\ [][Next]_x => []TypeOK ,
       ASSUME TypeOK /\ x = "red" (* non-[] *)
       PROVE  ENABLED <<Next>>_x ,
       ASSUME x = "red" /\ <<Next>>_x (* non-[] *)
       PROVE  (x = "blue")' ,
       TRUE
PROVE  x = "red" /\ [][Next]_x /\ (WF_(x) (Next)) => <>(x = "blue")
*)

\* How should this proof be structured?
THEOREM Spec => <>(x = "green")
PROOF OMITTED

\* And my actual goal: how should _this_ proof be structured?
THEOREM Spec => []<>(x = "red")
PROOF OMITTED

=============================================================================


There are three theorems that I think are within reach for TLAPS but I don't know what PTL would need to prove them.

THEOREM Spec => <>(x = "blue") \* Witness: after one non-stuttering action, it will be blue
THEOREM Spec => <>(x = "green") \* Witness: after two non-stuttering actions, it will be green
THEOREM Spec => []<>(x = "red") \* Depending on the current state, the witness would be zero/one/two non-stuttering actions

Any hints on how I could approach these?

--
You received this message because you are subscribed to the Google Groups "tlaplus" group.
To unsubscribe from this group and stop receiving emails from it, send an email to tlaplus+unsubscribe@xxxxxxxxxxxxxxxx.
To view this discussion on the web visit https://groups.google.com/d/msgid/tlaplus/0d5368ca-6221-404a-a144-362e874a1431n%40googlegroups.com.


--
You received this message because you are subscribed to a topic in the Google Groups "tlaplus" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/tlaplus/JNXR9DaJH2Q/unsubscribe.
To unsubscribe from this group and all its topics, send an email to tlaplus+unsubscribe@xxxxxxxxxxxxxxxx.
To view this discussion on the web visit https://groups.google.com/d/msgid/tlaplus/6883916B-8B2D-426C-90C9-E7AC3781E981%40gmail.com.

--
You received this message because you are subscribed to the Google Groups "tlaplus" group.
To unsubscribe from this group and stop receiving emails from it, send an email to tlaplus+unsubscribe@xxxxxxxxxxxxxxxx.
To view this discussion on the web visit https://groups.google.com/d/msgid/tlaplus/CAGNViOMZFg-7EEeH9xFMHGdoqiwVgXPq%3DkJ33d324Xm4T%2BGHHw%40mail.gmail.com.

--
You received this message because you are subscribed to the Google Groups "tlaplus" group.
To unsubscribe from this group and stop receiving emails from it, send an email to tlaplus+unsubscribe@xxxxxxxxxxxxxxxx.
To view this discussion on the web visit https://groups.google.com/d/msgid/tlaplus/6178623B-7D82-4711-854B-26091E6EF685%40gmail.com.