Lazy Cache Implements Complete Cache Draft Version^{1}

P. B. Ladkin

Universität Bielefeld, Technische Fakultät

D-33501 Bielefeld, Germany

ladkin@techfak.uni-bielefeld.de

Sun 7 Jan 1996 [18:49]

1The author will be very grateful for notification of any errors!

Abstract

I provide a formal proof in TLA that the Lazy Cache algorithm of Afek, Brown and Merritt implements an abstraction called a Complete Cache. This proof is part of a verification in TLA that the Lazy Cache is sequentially consistent. I explain how the invariant was chosen, and comment the proof to allow it more easily to be read.

1 What’s the Problem?

Rob Gerth set the challenge problem to verify formally that the Lazy Caching algorithm of Afek, Brown and Merritt [ABM93] is sequentially consistent [Ger96]. We undertook to verify the algorithm completely formally in TLA. The description of our proof appears in [LLRO96], which contains the TLA specifications and the approach on which the work described here is based. I present here part of the formal proof, namely the proof that the lazy caching algorithm implements an intermediate specification called the complete cache.

To find out how one goes about formulating specification and algorithm descriptions and verifying one against the other in TLA, see the report [Lam94]. I assume knowledge of TLA procedures.

2 How’s It Solved?

The proof here, that the lazy cache implements the complete cache, is part of the entire proof that the lazy cache is sequentially consistent. The lazy caching algorithm works roughly as follows. There is a state machine corresponding to the picture in Fig. 3. Each processor writes a ⟨datum, address ⟩ pair to an out queue (action Write). The Heads of these queues are nondeterministically selected for writing simultaneously and atomically to main memory and to all of the in queues, in[i] for i ∈ Proc (action MemWrite). The in queues hold the pending updates for the caches c[i]. A write from processor i is specially designated in in[i], the cache-write queue for processor i itself. The caches c[i] are updated from the queues in[i] by a CacheUpdate, which takes the Head of queue in[i] and writes it into the cache. There is no requirement that the caches remain coherent. Caches may lose values (via a CacheInval) operation) and may refresh (through MemRead). The ‘trick’ is in the processor read requests. Processor i may read from its cache c[i] only when its out queue out[i] is empty and there are no writes from processor i itself pending on its in[i] queue. This ensures that reads and writes from processor i are sequentially ordered in time, but yet there is no guarantee of time-like interleaving with other actions from other processors – a read from processor i may be executed before a timewise-previous write from processor j has been written from the queue in[i] into i’s cache c[i]. Sequential consistency and not time-like interleaving is the goal. Figures 1 and 2 contain the TLA specification of LazyCache.

For a part of the proof that Lazy Cache is sequentially consistent, we constructed an intermediate machine, called the Complete Cache, or CCache, pictured in Figure 4. CCache has no main memory, but each cache cc[i] itself contains entries for the entire memory address space. Thus the memory is “virtual” in that it may be constructed out of any cc[i], together with the updates contained in in[i]. Thus we may eliminate one variable (mem), and two actions (MemRead and CacheInval), absolving us from worrying about cache operations inessential for the proof of sequential consistency. The TLA specification for CCache appears in Figure 5.

In TLA, algorithms and specifications are both described by state machines. I must thus prove that the Lazy Cache machine implements the Complete Cache machine. Figure 6 states the correctness theorem to prove, along with correctness theorems for other parts of the proof. History variables are adequate to prove LCimplCC , which requires a non-trivial invariant for the safety part. (Proving sequential consistency from CCache requires prophecy variables also.) How this invariant arose is explained below. I don’t claim that this is the “best” invariant, or the mathematically most slick. In fact, it seems rather messy. But this is engineering–everything should follow from method and rely less on mathematical insight. The invariant works, and it was developed from straightforward considerations as to how LazyCache must relate to CCache, so it suffices.

Various parts of the proof use the mathematics of Sequences, described in the module in Figure 7.

module LazyCache

import MemParams, ChannelInterface, Sequences, Naturals

parameters c, in, out, mem : variable

⊥ =^{Δ} choose i : i ∉ Data Restrict(f ) =^{Δ} {g ∈ [Addr → Data ∪ {⊥}] : ∀ a ∈ Addr : g[a] ∈ {f [a], ⊥}}

Init =^{Δ} ∧ mem ∈ [Addr → InitData] ∧ c ∈ [Proc → Restrict(mem)] ∧ in = [i ∈ Proc ↦ ⟨ ⟩] ∧ out = [i ∈ Proc ↦ ⟨ ⟩]

Read(i, d, a) =^{Δ} ∧ out[i] = ⟨ ⟩ ∧ ∀ j ∈ 1 . . Len(in[i]) : Len(in[i][j ]) = 2 ∧ c[i][a] = d ∧ ChanOp(ch[i], ⟨i, “Rd”, d, a ⟩) ∧ ∀ j ∈ Proc \{i} : unchanged ch[j ] ∧ unchanged ⟨c, in, out, mem ⟩

Write(i, d, a) =^{Δ} ∧ ChanOp(ch[i], ⟨i, “Wr”, d, a ⟩) ∧ out′ = [out except ![i] = out[i] ∘ ⟨⟨d, a ⟩⟩] ∧ ∀ j ∈ Proc \{i} : unchanged ch[j ] ∧ unchanged ⟨c, in, mem ⟩

MemWrite(i) =^{Δ} ∧ out[i] ≠ ⟨ ⟩ ∧ out′ = [out except ![i] = Tail(out[i])] ∧ in′ = [j ∈ Proc ↦ in[j ] ∘ if j = i then ⟨Head(out[i]) ∘ ⟨“∗”⟩⟩ else ⟨Head(out[i])⟩ ]

∧ mem′ = [mem except ![Head(out[i])[2]] = Head(out[i])[1] ] ∧ unchanged ⟨c, ch ⟩

CacheUpdate(i) =^{Δ} ∧ in[i] ≠ ⟨ ⟩ ∧ in′ = [in except ![i] = Tail(in[i])] ∧ c′ = [c except ![i][Head(in[i])[2]] = Head(in[i])[1] ] ∧ unchanged ⟨out, ch, mem ⟩

Figure 1: The lazy caching algorithm (beginning).

Another module describes the operations Chan on the processor channels, but since these operations play the role of atomic formulae in the proof, I didn’t include this module or its related modules here.

3 How’s It All Work?

CCache turns cache refreshes (MemRead) and invalidations into things of the past. How may this happen? MemRead(i) pushes a cache refresh ⟨data, address ⟩ pair on the end of the in[i] queue. If this is to be a no-op, the new item must be invisible. MemWrite pushes a pair on the end of in[i], too, but these pairs are not invisible. So ‘visible’ and ‘invisible’ writes must be distinguished. We MemRead(i) =^{Δ} ∧ ∃ a ∈ Addr : in′ = [in except ![i] = in[i] ∘ ⟨⟨mem[a], a ⟩⟩] ∧ unchanged ⟨out, c, mem, ch ⟩

CacheInval(i) =^{Δ} ∧ c′ ∈ {[c except ![i] ∈ Restrict(c[i])]} ∧ unchanged ⟨in, out, mem, ch ⟩

Next(i) =^{Δ} ∨ ∃ d ∈ Data, a ∈ Addr : Read(i, d, a) ∨ Write(i, d, a) ∨ MemWrite(i) ∨ CacheUpdate(i) ∨ MemRead(i) ∨ CacheInval(i)

vars =^{Δ} ⟨c, in, out, mem, ch ⟩ Spec =^{Δ} ∧ Init ∧ □[∃ i ∈ Proc : Next(i)]_{vars} ∧ ∀ i ∈ Proc : WF_{vars}(CacheUpdate(i)) ∧ WF_{vars}(MemWrite(i))

Figure 2: The lazy caching algorithm (continued).

[figure: mem; …; in[1]; out[1]; c[1]; ch[1]; Processor 1; Processor N; in[N ]; out[N ]; c[N ]; ch[N ]]

Figure 3: The state machine describing the lazy caching algorithm, where c[i] is a cache, out[i] is a queue of ⟨data, address⟩ pairs for writes by processor i that have not yet been performed to memory, and in[i] is a queue of ⟨data, address⟩ pairs and ⟨data, address, “∗”⟩ triples of pending writes to c[i], a “∗” indicating that the write was issued by processor i.

[figure: cin[1]; cout[1]; cc[1]; ch[1]; Processor 1; Processor N; cin[N ]; cout[N ]; cc[N ]; ch[N ]]

Figure 4: The state machine CCache describing the complete cache algorithm, where cc[i] is a complete cache, and cout[i] and cin[i] are queues of ⟨processor, operation, data, address⟩ tuples.

simply add a field to the pair, telling us “who wrote me?” (Processor i if a refresh), and “how did I get here?” (“Rd” from a MemRead, “Wr” from a MemWrite). Thus the history variable hin has four-element entries instead of two-element entries. The effect of the operations MemWrite and MemRead on in[i], and the virtual counterparts HMemWrite and HMemRead on hin[i], is shown in Figures 8, 9, and 12.

How do we filter invisible writes from visible ones to form cin[i]? The SelectSeq function from Sequences is used with a predicate that distinguishes the two kinds of writes to filter the hin[i] queue to form cin[i]. SelectSeq filters hin entries on the second element, “Rd” or “Wr”.

When one of these to-be-filtered items (a “Rd”) appears at the Head of hin[i], the lazy-cache CacheUpdate that writes it into c[i] must be a no-op for CCache. Thus cc[i] must not change, hence it must contain the pair ⟨datum, address ⟩ already. It certainly contains ⟨something, address ⟩, since cc[i] contains entries for all addresses. Thus, for this CacheUpdate of a refresh to be invisible, something had better already be datum. Figures 10 and 11 show the CacheUpdate and HCacheUpdate operations. What must not occur is shown in Figure 13.

Before constucting the invariant or proceeding with the machine simulation, I add the history variable vc for the complete cache, as well as other history variables. Hence, they may be explicitly mentioned in the invariant. The predicate NotRefresh identifies those ‘real’ items in an in queue, shown in Figure 14.

To rule out the ‘bad’ situation in Figure 13, I construct the predicate FirstIsVC . The predicate FirstIsVC (a, i) says that all items in in[i] with address a up to the first ‘real’ write are repeats of what’s in the virtual cache vc[i] already (vc will implement cc). FirstIsVC belongs to the invariant.

But that is not enough. The vc[i] item ⟨d, a ⟩ in Figure 13 got there somehow. It passed through the hin[i] queue as a NotRefresh element. So, when there is a NotRefresh for address a in hin[i], say in position m, then all refreshes of address a that follow it, up to the next NotRefresh of address a in hin[i] in position n, must contain simply the repeated data value. This is expressed in the predicate MemWritesFromTo(m, n, i), illustrated in Figure 15. The predicate BetweenMemWrites(i) is simply the quantification of MemWritesFromTo(m, n, i) over all m, n in Len(in[i]).

Figure 16 shows that the situation must also be avoided at the other end–all refreshes of address a following the last NotRefresh of a in hin[i] must contain the same value as mem. If not, this

module CCache

import MemParams, ChannelInterface, Sequences, Naturals

parameters cc, cin, cout : variable

Init =^{Δ} ∧ cc ∈ [Proc → [Addr → InitData]] ∧ ∀ i, j ∈ Proc : cc[i] = cc[j ] ∧ cin = [i ∈ Proc ↦ ⟨ ⟩] ∧ cout = [i ∈ Proc ↦ ⟨ ⟩]

Read(i, d, a) =^{Δ} ∧ cout[i] = ⟨ ⟩ ∧ ∀ j ∈ (1 . . Len(cin[i])) : cin[i][j ][1] ≠ i ∧ cc[i][a] = d ∧ ChanOp(ch[i], ⟨i, “Rd”, d, a ⟩) ∧ ∀ j ∈ Proc \{i} : unchanged ch[j ] ∧ unchanged ⟨cc, cin, cout ⟩

Write(i, d, a) =^{Δ} ∧ ChanOp(ch[i], ⟨i, “Wr”, d, a ⟩) ∧ cout′ = [cout except ![i] = cout[i] ∘ ⟨⟨i, “Wr”, d, a ⟩⟩] ∧ ∀ j ∈ Proc \{i} : unchanged ch[j ] ∧ unchanged ⟨cc, cin ⟩

MemWrite(i) =^{Δ} ∧ cout[i] ≠ ⟨ ⟩ ∧ cout′ = [cout except ![i] = Tail(cout[i])] ∧ cin′ = [j ∈ Proc ↦ cin[j ] ∘ ⟨Head(cout[i])⟩] ∧ unchanged ⟨cc, ch ⟩

CacheUpdate(i) =^{Δ} ∧ cin[i] ≠ ⟨ ⟩ ∧ cin′ = [cin except ![i] = Tail(cin[i])] ∧ cc′ = [cc except ![i][Head(cin[i])[4]] = Head(cin[i])[3]] ∧ unchanged ⟨cout, ch ⟩

Next(i) =^{Δ} ∨ ∃ d ∈ Data, a ∈ Addr : Read(i, d, a) ∨ Write(i, d, a) ∨ MemWrite(i) ∨ CacheUpdate(i)

vars =^{Δ} ⟨cc, cin, cout, ch ⟩ Spec =^{Δ} ∧ Init ∧ □[∃ i ∈ Proc : Next(i)]_{vars} ∧ ∀ i ∈ Proc : WF_{vars}(CacheUpdate(i)) ∧ WF_{vars}(MemWrite(i))

Figure 5: The complete cache algorithm.

module CacheCorrectness

import MemParams

parameters c, in, out, mem : variable

include LazyCache as LC

POp =^{Δ} [i ∈ Proc ↦ {i} × {“Rd”, “Wr”} × Data × Addr] OKOp(o, old, new) =^{Δ} ∨ ∧ o[2] = “Rd” ∧ o[3] = old[o[4]] ∧ new = old ∨ ∧ o[2] = “Wr” ∧ new = [old except ![o[4]] = o[3] ]

InitDB =^{Δ} [Addr → InitData] include SeqDB1 as DB1 theorem LCimpliesDB1 =^{Δ} LC .Spec ⇒ DB1.Spec

include CCache as CC (cc, cin, cout) theorems

LCimpliesCC =^{Δ} LC .Spec ⇒ (∃ ∃ ∃ ∃ ∃ ∃ cc, cin, cout : CC (cc, cin, cout).Spec) CCimpliesDB1 =^{Δ} ∀ ∀ ∀ ∀ ∀ ∀ cc, cin, cout : CC (cc, cin, cout).Spec ⇒ DB1.Spec

include ACCache as ACC (cc, cin, cout, vcq, vrq, vdch) theorems

CCequivACC =^{Δ}

∀ ∀ ∀ ∀ ∀ ∀ cc, cin, cout : CC (cc, cin, cout).Spec ≡

(∃ ∃ ∃ ∃ ∃ ∃ vcq, vrq, vdch : ACC (cc, cin, cout, vcq, vrq, vdch).ASpec) ACCimpliesDB1 =^{Δ}

∀ ∀ ∀ ∀ ∀ ∀ cc, cin, cout, vcq, vrq, vdch :

ACC (cc, cin, cout, vcq, vrq, vdch).ASpec ⇒ DB1.Spec

Figure 6: The theorems constituting the correctness proof.

module Sequences

import Naturals

m . . n =^{Δ} {i ∈ Nat : (m ≤ i) ∧ (i ≤ n)} Len(s) =^{Δ} choose n : (n ∈ Nat) ∧ ((Domain s) = (1 . . n))

Head(s) =^{Δ} s[1]

Tail(s) =^{Δ} [i ∈ 1 . .(Len(s) − 1) ↦ s[i + 1]]

s ∘ t  =^{Δ} [i ∈ 1 . .(Len(s) + Len(t)) ↦ if i ≤ Len(s) then s[i] else t[i − Len(s)]]

Seq(S) =^{Δ} union {[(1 . . n) → S] : n ∈ Nat} SelectSeq(s, test( )) =^{Δ} let F [ t : Seq({s[i] : i ∈ 1 . . Len(s)}) ] =^{Δ} if t = ⟨ ⟩ then ⟨ ⟩ else if test(Head(t)) then ⟨Head(t)⟩ ∘ F [Tail(t)] else F [Tail(t)] in F [s]

SubSeq(s, m, n) =^{Δ} [i ∈ 1 . .(1 + n − m) ↦ s[i + m − 1]]

Figure 7: Module Sequences

[figure: ⟨d_{1}, a_{1}, ∗⟩; ⟨d_{2}, a_{2}⟩; ⟨d_{3}, a_{3}⟩; in[i]; c[i]; ⇒; ⟨d, a⟩; ⟨d_{1}, a_{1}, ∗⟩; ⟨d_{2}, a_{2}⟩; ⟨d_{3}, a_{3}⟩; in′[i]; c′[i]]

Figure 8: The actions MemWrite and MemRead both add to in[i]

[figure: ⟨i, “Wr”, d_{1}, a_{1}⟩; ⟨j , “Wr”, d_{2}, a_{2}⟩; ⟨j , “Wr”, d_{3}, a_{3}⟩; hin[i]; vc[i]; ⇒; ⟨i, “Wr”, d, a⟩; ⟨i, “Wr”, d_{1}, a_{1}⟩; ⟨j , “Wr”, d_{2}, a_{2}⟩; ⟨j , “Wr”, d_{3}, a_{3}⟩; hin′[i]; vc′[i]]

Figure 9: The virtual MemWrite

[figure: ⟨d_{1}, a_{1}, ∗⟩; ⟨d_{2}, a_{2}⟩; ⟨d_{3}, a_{3}⟩; ⟨d, a⟩; in[i]; c[i]; ⇒; ⟨d_{1}, a_{1}, ∗⟩; ⟨d_{2}, a_{2}⟩; ⟨d_{3}, a_{3}⟩; in′[i]; ⟨d, a⟩; c′[i]]

Figure 10: CacheUpdate

[figure: ⟨i, “Wr”, d_{1}, a_{1}, ⟩; ⟨j , “Wr”, d_{2}, a_{2}⟩; ⟨p, “Wr”, d_{3}, a_{3}⟩; ⟨j , “Wr”, d, a⟩; hin[i]; ⟨d_{4}, a⟩; vc[i]; ⇒; ⟨i, “Wr”, d_{1}, a_{1}, ⟩; ⟨j , “Wr”, d_{2}, a_{2}, ⟩; ⟨p, “Wr”, d_{3}, a_{3}⟩; hin′[i]; ⟨d, a⟩; vc′[i]]

Figure 11: HCacheUpdate

[figure: ⟨i, “Wr”, d_{1}, a_{1}, ⟩; ⟨j , “Wr”, d_{2}, a_{2}⟩; ⟨j , “Wr”, d_{3}, a_{3}⟩; hin[i]; vc[i]; ⇒; ⟨i, “Rd”, d, a⟩; ⟨i, “Wr”, d_{1}, a_{1}, ⟩; ⟨j , “Wr”, d_{2}, a_{2}⟩; ⟨j , “Wr”, d_{3}, a_{3}⟩; hin′[i]; vc′[i]]

Figure 12: HMemRead

[figure: ⟨i, “Rd”, d_{2}, a⟩; ⟨j , “Wr”, d_{2}, a⟩; ⟨i, “Rd”, d_{2}, a⟩; ⟨i, “Rd”, d_{2}, a⟩; d_{2} ≠ d; hin[i]; ⟨d, a⟩; vc[i]]

Figure 13: What must not happen

⟨i, “Wr”, d_{1}, a⟩ ⟨i, “Rd”, d_{3}, a⟩ ⟨i, “Wr”, d_{3}, a⟩ ⟨i, “Rd”, d_{2}, a⟩ hin[i] vc[i]  NotRefresh_{i} NotRefresh_{i} ¬NotRefresh_{i} ¬NotRefresh_{i}

Figure 14: Illustrating NotRefresh_{i}

[figure: ⟨i, “Wr”, d_{1}, a⟩; ⟨i, “Rd”, d, a⟩; ⟨i, “Rd”, d, a⟩; ⟨i, “Wr”, d, a⟩; ⟨i, “Rd”, d_{2}, a⟩; hin[i]; vc[i]]

Figure 15: MemWritesFromTo(2, 7, i)

[figure: ⟨d, a⟩; mem; ⟨i, “Rd”, d_{2}, a⟩; ⟨i, “Rd”, d_{2}, a⟩; ⟨i, “Rd”, d_{2}, a⟩; ⟨i, “Rd”, d_{2}, a⟩; hin[i]; ⟨d_{2}, a⟩; vc[i]]

Figure 16: Also to be avoided

[figure: ⟨d, a⟩; mem; ⟨i, “Rd”, d, a⟩; ⟨i, “Rd”, d, a⟩; ⟨i, “Rd”, d, a⟩; ⟨i, “Rd”, d, a⟩; hin[i]; ⟨d, a⟩; vc[i]]

Figure 17: That’s better!

situation would also eventually lead to the bad situation excluded by FirstIsVC . Finally, if there are only cache refreshes of address a in in[i], and no NotRefreshes, then both vc[i] and all the refreshes must contain the same datum as mem for that address a. This situation is illustrated in Figure 17, and described by the predicate NoMemWrite(i) in the invariant.

Putting this all together, the invariant is that

• Refreshes between adjacent NotRefresh writes must be the same as the first such;

• When there are only refreshes in in[i], they must contain the same data value as held for that address in vc[i] and in mem;

• Otherwise, refreshes must have the same value as vc[i] until the first “Wr”-write, and as mem beyond the last one.

This is expressed by the formula CCInv.3(p) =^{Δ} ∧ BetweenMemWrites(p) ∧ ∀ a ∈ Addr : ∨ NoMemWrite(a, p) ∨ ∧ LastIsMem(a, p) ∧ FirstIsVC (a, p)

As usual, there are a couple of other minor ‘type-conditions’ that must be stated in the invariant. The entire invariant is described within the proof. The intuition of how the situation in the queue hin[i] evolves is crucial to decomposing the proof of the invariant into proofs of its individual clauses.

4 The Proof

The true taste of success for any invariant comes when we successfully use it to prove the safety property of CCache. This is straightforward. The harder part is to prove that the invariant is truly invariant.

The liveness properties of the algorithm are trivial (not our fault–they were imposed by Gerth), and so the liveness part of the proof is routine and mathematically almost empty. One piece, the weak fairness of the cache update operation in CCache, is formally similar to the proof of the weak fairness of an abstract buffer pop operation in [Lad95]. The abstract operation is enabled before the concrete operation is, and the concrete operation must be performed, invisibly to the specification, on “Rd”-writes numerous times in order to bring the “Wr”-write to the Head of hin[i], thus enabling the concrete update of vc[i] which corresponds to the abstract update CC (cc, cin, cout).CacheUpdate. This proof thus requires the use of TLA rule WF2, of which the fourth premiss is justified by a temporal logic rule called the Bridge Rule ([Lad95, Page 46]), one of whose hypotheses is the conclusion of the Lattice Rule, of which the premiss is justified in turn by WF1, of which the premises are directly proved. In contrast to the proof in [Lad95], the safety proof of LCimplCC is not trivial, although it is straightforward, as we have seen from our justification of the invariant. Now to the proof. Have fun!

⟨1⟩1. LC .Spec ⇒ (∃ ∃ ∃ ∃ ∃ ∃ cc, cin, cout : CC (cc, cin, cout).Spec)

Proof:

Let: We add history variables: vc is the virtual cache; hout is out, with more information carried along as required by CCache(cc, cin, cout); hin contains not only the writes from in but also whether the writes were the result of a MemWrite(i) for some i ∈ Proc (the second entry of this element of hin[p] is “Wr”), or the result of a cache refresh, MemRead(a, p) (the second entry of this element of hin[p] is “Rd”).

We define new operations which are identical to the LazyCache operations for the LazyCache variables, but which alter the history variables as we wish.

vc, hin, hout : variable

hvars =^{Δ} LC .vars ∘ ⟨vc, hin, hout ⟩

new.hin =^{Δ} case ∃ i ∈ Proc, d ∈ Data, a ∈ Addr : Read(i, d, a) → hin, ∃ i ∈ Proc, d ∈ Data, a ∈ Addr : Write(i, d, a) → hin, ∃ i ∈ Proc : MemWrite(i) → [hin except ![i] = hin[i] ∘ ⟨⟨i, “Wr”⟩ ∘ Head(out[i])⟩], ∃ i ∈ Proc : CacheUpdate(i) → [hin except ![i] = Tail(hin[i])], ∃ i ∈ Proc : MemRead(i) → [hin except ![i] = hin[i] ∘ ⟨⟨i, “Rd”, ⊥, ⊥⟩⟩], ∃ i ∈ Proc : CacheInval(i) → hin

new.vc =^{Δ} case ∃ i ∈ Proc, d ∈ Data, a ∈ Addr : Read(i, d, a) → vc, ∃ i ∈ Proc, d ∈ Data, a ∈ Addr : Write(i, d, a) → vc, ∃ i ∈ Proc : MemWrite(i) → vc, ∃ i ∈ Proc : CacheUpdate(i) →, [vc except ![i][Head(in[i])[2]] = Head(in[i])[1]], ∃ i ∈ Proc : MemRead(i) → vc, ∃ i ∈ Proc : CacheInval(i) → vc new.hout =^{Δ} case ∃ i ∈ Proc, d ∈ Data, a ∈ Addr : Read(i, d, a) → hout, ∃ i ∈ Proc, d ∈ Data, a ∈ Addr : Write(i, d, a) → [hout except ![i] = hout[i] ∘ ⟨⟨i, “Wr”, d, a ⟩⟩], ∃ i ∈ Proc : MemWrite(i) → [hout except ![i] = Tail(hout[i])], ∃ i ∈ Proc : CacheUpdate(i) → hout, ∃ i ∈ Proc : MemRead(i) → hout, ∃ i ∈ Proc : CacheInval(i) → hout

HInit =^{Δ} ∧ LC .Init ∧ vc ∈ [Proc → InitDB] ∧ ∀ i ∈ Proc : vc[i] = mem ∧ hin = [i ∈ Proc ↦ ⟨ ⟩] ∧ hout = [i ∈ Proc ↦ ⟨ ⟩]

i, d, a : constant HRead(i, d, a) =^{Δ} LC .Read(i, d, a) ∧ unchanged ⟨vc, hin, hout ⟩ HWrite(i, d, a) =^{Δ} ∧ LC .Write(i, d, a) ∧ hout′ = [hout except ![i] = hout[i] ∘ ⟨⟨i, “Wr”, d, a ⟩⟩] ∧ unchanged ⟨vc, hin ⟩

HMemWrite(i) =^{Δ} ∧ LC .MemWrite(i) ∧ hin′ = [j ∈ Proc ↦ hin[j ] ∘ ⟨⟨i, “Wr”⟩⟩] ∧ hout′ = [hout except ![i] = Tail(hout[i])] ∧ unchanged vc

HCacheUpdate(i) =^{Δ} ∧ LC .CacheUpdate(i) ∧ hin′ = [hin except ![i] = Tail(hin[i])] ∧ vc′ = [vc except ![i][Head(in[i])[2]] = Head(in[i])[1]] ∧ unchanged hout

HMemRead(i) =^{Δ} ∧ LC .MemRead(i) ∧ hin′ = [hin except ![i] = hin[i] ∘ ⟨⟨i, “Rd”⟩⟩] ∧ unchanged vc, hout

HCacheInval(i) =^{Δ} LC .CacheInval(i) ∧ unchanged ⟨vc, hin, hout ⟩ HOp(i) =^{Δ} ∨ ∃ d ∈ Data, a ∈ Addr : HRead(i, d, a) ∨ ∃ d ∈ Data, a ∈ Addr : HWrite(i, d, a) ∨ HMemWrite(i) ∨ HCacheUpdate(i) ∨ HMemRead(i) ∨ HCacheInval(i)

HSpec =^{Δ} ∧ HInit ∧ □[∃ i ∈ Proc : HOp(i)]_{hvars} ∧ ∀ i : ∈ Proc : WF_{hvars}(HCacheUpdate(i)) ∧ ∀ i : ∈ Proc : WF_{hvars}(HMemWrite(i))

We show, using Proposition 1 (History Variable), that the specification with history variables is logically equivalent to the LazyCache specification.

⟨2⟩1. LC .Spec ≡ ∃ ∃ ∃ ∃ ∃ ∃ vc, hin, hout : HSpec Proof:

In order to unpack the case statement unambiguously, we show first that all the LazyCache operations are mutually exclusive. The step will then follow directly from the History Variable theorem.

⟨3⟩1. LC .Read(i, d, a) ⇒ ∧ ¬LC .Write(i, d, a) ∧ ¬LC .MemWrite(i) ∧ ¬LC .CacheUpdate(i) ∧ ¬LC .MemRead(i) ∧ ¬LC .CacheInval(i)

Proof: ⟨4⟩1. LC .Read(i, d, a) ⇒ ¬LC .Write(i, d, a)

⟨5⟩1. LC .Read(i, d, a) ⇒ ChanOp(ch[i], ⟨i, “Rd”, d, a ⟩)

Proof: Immediate from the definition. ⟨5⟩2. ChanOp(ch[i], ⟨i, “Rd”, d, a ⟩) ⇒ ¬ChanOp(ch[i], ⟨i, “Wr”, d, a ⟩)

Proof: Immediate from the definition in ChannelInterface. ⟨5⟩3. ¬ChanOp(ch[i], ⟨i, “Wr”, d, a ⟩) ⇒ ¬LC .Write(i, d, a)

Proof: Immediate from the definition of LC .Write, by contraposition. ⟨5⟩4. Q.E.D.

By Boolean logic from ⟨5⟩1, ⟨5⟩2, and ⟨5⟩3. ⟨4⟩2. LC .Read(i, d, a) ⇒ ¬LC .MemWrite(i)

⟨5⟩1. LC .Read(i, d, a) ⇒ in′ = in

Proof: Immediate from the definition of LC .Read(i, d, a). ⟨5⟩2. in′ = in ⇒ ¬(in′ = [j ∈ Proc ↦ in[j ] ∘ \begin{matrix}if j = i & then & ⟨Head(out[i]) ∘ ⟨“∗”⟩⟩ \\ & else & ⟨Head(out[i])⟩ ] \end{matrix})

Proof: Immediate from properties of ∘. ⟨5⟩3. ¬(in′ = [j ∈ Proc ↦ in[j ] ∘ \begin{matrix}if j = i & then & ⟨Head(out[i]) ∘ ⟨“∗”⟩⟩ \\ & else & ⟨Head(out[i])⟩ ] \end{matrix})

⇒ ¬LC .MemWrite(i) Proof: Immediate from the definition of LC .MemWrite.

⟨5⟩4. Q.E.D.

Proof: Follows by Boolean logic from ⟨5⟩1, ⟨5⟩2, and ⟨5⟩3. ⟨4⟩3. LC .Read(i, d, a) ⇒ ¬LC .CacheUpdate(i)

⟨5⟩1. LC .Read(i, d, a) ⇒ in′ = in

Proof: Immediate from the definition of LC .Read(i, d, a). ⟨5⟩2. in′ = in ⇒ ¬(in′ = [in except ![i] = Tail(in[i])])

Proof: Immediate. ⟨5⟩3. ¬(in′ = [in except ![i] = Tail(in[i])]) ⇒ ¬LC .CacheUpdate(i)

Proof: Immediate from the definition of LC .CacheUpdate. ⟨5⟩4. Q.E.D.

Proof: Follows by Boolean logic from ⟨5⟩1, ⟨5⟩2, and ⟨5⟩3. ⟨4⟩4. LC .Read(i, d, a) ⇒ ¬LC .MemRead(i)

⟨5⟩1. LC .Read(i, d, a) ⇒ in′ = in

Proof: Immediate from the definition of LC .Read(i, d, a). ⟨5⟩2. in′ = in ⇒ ¬(∃ a ∈ Addr : in′ = [in except ![i] = in[i] ∘ ⟨⟨mem[a], a ⟩⟩])

Proof: Immediate.

⟨5⟩3. ¬(∃ a ∈ Addr :

in′ = [in except ![i] = in[i] ∘ ⟨⟨mem[a], a ⟩⟩])

⇒ ¬LC .MemRead(i) Proof: Immediate from the definition of LC .MemRead.

⟨5⟩4. Q.E.D.

Proof: Follows by Boolean logic from ⟨5⟩1, ⟨5⟩2, and ⟨5⟩3. ⟨4⟩5. LC .Read(i, d, a) ⇒ ¬LC .CacheInval(i)

⟨5⟩1. LC .Read(i, d, a) ⇒ ChanOp(ch[i], ⟨i, “Rd”, d, a ⟩)

Proof: Immediate from the definition of LC .Read(i, d, a). ⟨5⟩2. ChanOp(ch[i], ⟨i, “Rd”, d, a ⟩) ⇒ ¬unchanged ch

Proof: Immediate from the definition of ChanOp.

⟨5⟩3. ¬unchanged ch ⇒ ¬LC .CacheInval(i)

Proof: Immediate from the definition of LC .CacheInval. ⟨5⟩4. Q.E.D.

Proof: Follows by Boolean logic from ⟨5⟩1, ⟨5⟩2, and ⟨5⟩3. ⟨4⟩6. Q.E.D.

Follows by Boolean Logic from ⟨4⟩1, ⟨4⟩2, ⟨4⟩3, ⟨4⟩4, ⟨4⟩5. ⟨3⟩2. LC .Write(i, d, a) ⇒ ∧ ¬LC .Read(i, d, a) ∧ ¬LC .MemWrite(i) ∧ ¬LC .CacheUpdate(i) ∧ ¬LC .MemRead(i) ∧ ¬LC .CacheInval(i)

Proof: Similar to that of ⟨3⟩1. ⟨3⟩3. LC .MemWrite(i, d, a) ⇒ ∧ ¬LC .Read(i, d, a) ∧ ¬LC .Write(i, d, a) ∧ ¬LC .CacheUpdate(i) ∧ ¬LC .MemRead(i) ∧ ¬LC .CacheInval(i)

Proof: Similar to that of ⟨3⟩1. ⟨3⟩4. LC .CacheUpdate(i) ⇒ ∧ ¬LC .Read(i, d, a) ∧ ¬LC .Write(i, d, a) ∧ ¬LC .MemWrite(i) ∧ ¬LC .MemRead(i) ∧ ¬LC .CacheInval(i)

Proof: Similar to that of ⟨3⟩1. ⟨3⟩5. LC .MemRead(i) ⇒ ∧ ¬LC .Read(i, d, a) ∧ ¬LC .Write(i, d, a) ∧ ¬LC .MemWrite(i) ∧ ¬LC .CacheUpdate(i) ∧ ¬LC .CacheInval(i)

Proof: Similar to that of ⟨3⟩1. ⟨3⟩6. LC .CacheInval(i) ⇒ ∧ ¬LC .Read(i, d, a) ∧ ¬LC .Write(i, d, a) ∧ ¬LC .MemWrite(i) ∧ ¬LC .CacheUpdate(i) ∧ ¬LC .MemRead(i)

Proof: Similar to that of ⟨3⟩1. ⟨3⟩7. Q.E.D.

Proof: Follows directly from the conclusion of Proposition 1 (History Variable) with B_{1} =^{Δ} A_{1} = ∃ i : LC .MemWrite(i), B_{2} =^{Δ} A_{2} = ∃ i : LC .CacheUpdate(i), B_{3} =^{Δ} A_{3} = ∃ i : LC .MemRead(i), A_{4} =^{Δ} ∃ i, d, a : LC .Read(i, d, a), A_{5} =^{Δ} ∃ i, d, a : LC .Write(i, d, a), A_{6} =^{Δ} ∃ i : LC .CacheInval(i), h =^{Δ} ⟨vc, hin, hout ⟩, g =^{Δ} ⟨new.vc, new.hin, new.hout ⟩. Steps 1 and 2 of the theorem follow immediately from the binding just given, and Step 3 follows with Inv = true from ⟨3⟩1, ⟨3⟩2, ⟨3⟩5, ⟨3⟩3, ⟨3⟩4, and ⟨3⟩6. The theorem follows finally by using the definition of tuples to select the elements of the tuple h where required.

We show that the LazyCache-with-history specification implies the CCache specification. (The theorem that LazyCache implements CCache then will follow immediately using ⟨2⟩1, the next step and the transitivity of implication.)

⟨2⟩2. ∃ c, in, out, mem, ch, vc, hin, hout : ∧ HInit ∧ □[∃ i ∈ Proc : HOp(i)]_{hvars} ∧ ∀ i : ∈ Proc : WF_{hvars}(HCacheUpdate(i)) ∧ ∀ i : ∈ Proc : WF_{hvars}(HMemWrite(i)))

⇒ ∃ cc, cin, cout, ch : ∧ CC (cc, cin, cout).Init ∧ □[∃ i ∈ Proc : CC (cc, cin, cout).Next(i)]_{⟨cc,cin,cout,ch ⟩} ∧ ∀ i : ∈ Proc : WF_{⟨cc,cin,cout,ch ⟩}(CC (cc, cin, cout).CacheUpdate(i)) ∧ ∀ i : ∈ Proc : WF_{⟨cc,cin,cout,ch ⟩}(CC (cc, cin, cout).MemWrite(i)))

Proof:

Let: The refinement mapping is

\overline{cc} ← vc \overline{cin} ← [i ∈ Proc ↦ SelectSeq(hin[i], P[2] ≠ “Rd”)] \overline{cout} ← hout \overline{ch} ← ch

j , p : constant

The following predicate is needed to state the invariant CCInv.3(p)

∀ i ∈ Proc : NotRefresh_{i}(j ) =^{Δ} ∧ j ∈ 1 . . Len(hin[i]) ∧ hin[i][j ][2] ≠ “Rd”

The first two conjuncts of the invariant are routine:

CCInv.1(p) =^{Δ} ∧ Len(hin[p]) = Len(in[p]) ∧ Len(hout[p]) = Len(out[p]) ∧ ∀ a ∈ Addr, d ∈ Data, j ∈ 1 . . Len(in[i]) : Len(in[i][j ]) = 3 ≡ ∧ hin[i][j ][1] = i ∧ hin[i][j ][2] = “Wr”

CCInv.2(p) =^{Δ} c[p] ∈ Restrict(vc[p])

The third conjunct requires some auxiliary definitions. First, NoMemWrite asserts that there’s no element in the in[p] queue that is a write of address a.

NoMemWrite(a, p) =^{Δ} ∧ p ∈ Proc ∧ vc[p][a] = mem[a] ∧ ∀ k ∈ 1 . . Len(in[p]) : ∨ in[p][k][2] ≠ a ∨ in[p][k][1] = mem[a]

But suppose there is an element in the queue in[p] that is a write of address a. The following predicate asserts that the last element in the in[p] queue that is the result of a MemWrite of address a contains the same data value as mem.

LastIsMem(a, p) =^{Δ} ∧ p ∈ Proc ∧ ∃ k ∈ 1 . . Len(in[p]) : ∧ NotRefresh_{p}(k) ∧ in[p][k][1] = mem[a] ∧ in[p][k][2] = a ∧ ∀ j ∈ k + 1 . . Len(in[p]) : ∨ in[p][j ][2] ≠ a ∨ in[p][j ][1] = mem[a]

The following predicate asserts that all elements in in[p] with address a that occur before the first element that is a MemWrite of address a must have the same data value as lies in the cache vc[p]. (Note always vc[p][a] ∈ Data for all a ∈ Addr.)

FirstIsVC (a, p) =^{Δ} ∧ p ∈ Proc ∧ ∃ k ∈ 1 . . Len(in[p]) : ∧ NotRefresh_{p}(k) ∧ in[p][k][2] = a ∧ ∀ j ∈ 1 . . k − 1 : ∨ in[p][j ][2] ≠ a ∨ in[p][j ][1] = vc[p][a]

Between two MemWrites of address a in in[p], say in[p][m] and in[p][n], every element with address a has the same data value as in[p][m].

m, n : constant

MemWritesFromTo(m, n, p) =^{Δ} ∧ p ∈ Proc ∧ m ∈ 1 . . Len(in[p]) ∧ n ∈ 1 . . Len(in[p]) ∧ m < n ∧ NotRefresh_{p}(m) ∧ NotRefresh_{p}(n) ∧ ∀ j ∈ m + 1 . . n − 1 : ¬NotRefresh_{p}(j ) ⇒

∀ j ∈ m + 1 . . n − 1 : ∨ in[p][j ][2] ≠ in[p][m][2] ∨ in[p][j ][1] = in[p][m][1]

.... and the invariant will assert this be true for all m and n.

BetweenMemWrites(p) =^{Δ} ∀ m, n ∈ 1 . . Len(in[p]) : MemWritesFromTo(m, n, p)

Finally, here is the third component of the invariant for process p.

CCInv.3(p) =^{Δ} ∧ BetweenMemWrites(p) ∧ ∀ a ∈ Addr : ∨ NoMemWrite(a, p) ∨ ∧ LastIsMem(a, p) ∧ FirstIsVC (a, p)

The definition of CCInv(p), the invariant for process p is:

CCInv(p) =^{Δ} CCInv.1(p) ∧ CCInv.2(p) ∧ CCInv.3(p)

The definition of the complete invariant is

CCInv.1 =^{Δ} ∀ p ∈ Proc : CCInv.1(p) CCInv.2 =^{Δ} ∀ p ∈ Proc : CCInv.2(p) CCInv.3 =^{Δ} ∀ p ∈ Proc : CCInv.3(p) CCInv =^{Δ} CCInv.1 ∧ CCInv.2 ∧ CCInv.3

First, some straightforward logical observations concerning the invariant.

Everything but an HMemWrite(i) leaves data structures for all other processes but i alone, as also mem.

Proof: ⟨3⟩1. HOp(i) ∧ ¬HMemWrite(i) ⇒

∀ p ∈ Proc \{i} : unchanged ⟨c[p], in[p], out[p], mem, ch[p], vc[p], hin[p], hout[p]⟩ Proof: Immediate from the definitions of HRead, HWrite, HMemWrite, HCacheUpdate, HMemRead, and HCacheInval.

A HMemWrite(i) leaves c[p], out[p], ch[p], vc[p] and hout[p] alone, for all p ∈ Proc such that p ≠ i.

⟨3⟩2. HMemWrite(i) ⇒ ∀ p ∈ Proc \{i} : unchanged ⟨c[p], out[p], ch[p], vc[p], hout[p]⟩ Proof: Immediate from the definitions of HRead, HWrite, HMemWrite, HCacheUpdate, HMemRead, and HCacheInval.

Thus everything except an HMemWrite(i) leaves the variables in CCInv(p) alone, hence CCInv(p)′ is equivalent to CCInv(p).

⟨3⟩3. HOp(i) ∧ ¬HMemWrite(i) ⇒

∀ p ∈ Proc \{i} : CCInv(p) ≡ CCInv′(p) Proof: Immediate from ⟨3⟩1 and the definition of CCInv(p).

The initial state of LazyCache implies the initial state of CCache.

⟨3⟩4. HInit ⇒ \overline{CC (cc, cin, cout).Init} Proof: ⟨4⟩1.

∧ c ∈ [Proc → InitDB] ∧ mem ∈ InitDB ∧ ∀ i ∈ Proc : ∧ c[i] ∈ Restrict(mem) ∧ in[i] = ⟨ ⟩ ∧ out[i] = ⟨ ⟩

∧ vc ∈ [Proc → InitDB] ∧ ∀ i ∈ Proc : vc[i] = mem ∧ hin = [i ∈ Proc ↦ ⟨ ⟩] ∧ hout = [i ∈ Proc ↦ ⟨ ⟩]

⇒ ∧ vc ∈ [Proc → InitDB] ∧ ∀ i, j ∈ Proc : vc[i] = vc[j ] ∧ \overline{cin} = [i ∈ Proc ↦ ⟨ ⟩] ∧ \overline{cout} = [i ∈ Proc ↦ ⟨ ⟩]

Proof: ⟨5⟩1. ∀ i ∈ Proc : (vc[i] = mem)

⇒ ∀ i, j ∈ Proc : vc[i] = vc[j ] Proof: Immediate from the logic of equality.

⟨5⟩2. (∀ i ∈ Proc : hin = [i ∈ Proc ↦ ⟨ ⟩]) ⇒ (∀ i ∈ Proc : cin = [i ∈ Proc ↦ ⟨ ⟩]) Proof: Follows immediately from the definition of cin[i], and that SelectSeq(⟨ ⟩, P[2] ≠ “Rd”) = ⟨ ⟩.

⟨5⟩3. (∀ i ∈ Proc : out[i] = ⟨ ⟩) ⇒ \overline{cout} = [i ∈ Proc ↦ ⟨ ⟩]

Proof: Immediate from the definition of hout[i]. ⟨5⟩4. Q.E.D.

Proof: Immediate by propositional logic from ⟨5⟩1, ⟨5⟩2, and ⟨5⟩3. ⟨4⟩2. Q.E.D.

Proof: Immediate from ⟨4⟩1 and the definitions of HInit, \overline{CC (cc, cin, cout).Init}.

The invariant follows from the initial conditions and the safety property.

⟨3⟩5. HInit ∧ □[∃ i ∈ Proc : HOp(i)]_{hvars} ⇒ □CCInv

The invariant follows from the initial conditions.

⟨4⟩1. HInit ⇒ CCInv Proof: ⟨5⟩1. HInit ⇒ ∧ ∀ i ∈ Proc : Len(hin[i]) = 0 ∧ ∀ i ∈ Proc : Len(in[i]) = 0 ∧ ∀ i ∈ Proc : Len(hout[i]) = 0 ∧ ∀ i ∈ Proc : Len(out[i]) = 0

Proof: Immediate by definition of HInit. ⟨5⟩2. HInit ⇒ CCInv.1

Proof: Immediate from ⟨5⟩1. ⟨5⟩3. HInit ⇒ ∀ i ∈ Proc : (vc[i] = mem) ∧ (c[i] = Restrict(mem))

Proof: The consequent is part of the definition of HInit. ⟨5⟩4. HInit ⇒ CCInv.2

Proof: Immediate from ⟨5⟩3. ⟨5⟩5. HInit ⇒ CCInv.3

Proof:

⟨6⟩1. ∧ HInit ; ∧ p ∈ Proc

⇒ ∧ BetweenMemWrites(p) ∧ ∀ a ∈ Addr : NoMemWrite(a, p)

Proof:

⟨7⟩1. ∧ HInit ; ∧ p ∈ Proc
⇒ 1 . . Len(in[p]) = ∅

Proof: Immediate from in[p] = ⟨ ⟩. ⟨7⟩2. Q.E.D.

Proof: BetweenMemWrites(p) follows trivially from ⟨7⟩1 since both universal quantifiers in the prefix range over 1 . . Len(in[p]), as does the second conjunct of NoMemWrite(a, p). The first conjunct of NoMemWrite(a, p) follows immediately from ⟨5⟩3.

⟨6⟩2. Q.E.D.

Proof: Immediate from ⟨6⟩1 and ⟨3⟩3. ⟨5⟩6. Q.E.D.

Proof: Follows by propositional logic from ⟨5⟩2, ⟨5⟩4, ⟨5⟩5 and definition of CCInv.

The invariant is preserved by the steps of LazyCache.

⟨4⟩2. CCInv ∧ □[∃ i ∈ Proc : HOp(i))]_{hvars} ⇒ □CCInv′ Proof: ⟨5⟩1. CCInv ∧ [∃ i ∈ Proc : HOp(i))]_{hvars} ⇒ CCInv′

Proof: ⟨6⟩1. CCInv ∧ hvars′ = hvars ⇒ CCInv′

Proof: Immediate since all the variables of CCInv are in hvars.

First, a general fact from logic and set theory that we shall use without further proof. Let ψ be a TLA formula:

Let: x, y : constant

⟨6⟩2. ∧ (x ∈ S ⇒ ψ) ≡ (x ∈ S \{y} ⇒ ψ) ∧ ψ(y/x)

∧ (x ∈ S ∧ ψ) ≡ (x ∈ S \{y} ∧ ψ) ∨ ψ(y/x) Proof: Follows from logic and elementary set theory.

We split the proof of the invariant into separate steps for each disjunct of HOp.

The invariant is preserved by HRead.

⟨6⟩3. ∧ i ∈ Proc

∧ CCInv

∧ (∃ d ∈ Data, a ∈ Addr : HRead(i, d, a))

⇒ CCInv′ Proof:

⟨7⟩1. ∧ i ∈ Proc

∧ CCInv

∧ HRead(i, d, a)

⇒ CCInv′ Proof: The free variables in, vc, hin, mem, c of invariant CCInv are HRead-unchanged variables by the definition of HRead(i). CCInv′ follows by the logical laws of equality.

⟨7⟩2. Q.E.D.

Proof: ⟨6⟩3 follows by existential quantification over a and d.

The invariant is preserved by a HWrite

⟨6⟩4. ∧ i ∈ Proc

∧ CCInv

∧ (∃ d ∈ Data, a ∈ Addr : HWrite(i, d, a))

⇒ CCInv′ Proof:

⟨7⟩1. ∧ i ∈ Proc

∧ CCInv

∧ HWrite(i, d, a)

⇒ CCInv′ Proof: ⟨8⟩1. i ∈ Proc ∧ HWrite(i, d, a) ⇒ ∧ Len(out′[i]) = Len(out[i]) + 1 ∧ Len(hout′[i]) = Len(hout[i]) + 1

Proof: Immediate from the definition of HWrite. ⟨8⟩2. Q.E.D.

Proof: The conjuncts for out and hout in CCInv.1 are preserved by ⟨8⟩1. The free variables in, vc, hin, mem, c of invariant CCInv are a subset of the HWrite-unchanged

variables by the definition of HWrite. CCInv′ follows by the logical laws of equality. ⟨7⟩2. Q.E.D.

Proof: ⟨6⟩4 follows by existential quantification over a and d.

The invariant is preserved by a HMemWrite

⟨6⟩5. ∧ i ∈ Proc

∧ CCInv ∧ HMemWrite(i) ⇒ CCInv′

Proof:

First, some steps that we’ll make use of in various places in this proof.

⟨7⟩1. ∧ i ∈ Proc

∧ HMemWrite(i) ∧ p ∈ Proc ⇒ ∧ Len(hin′[p]) = Len(hin[p]) + 1 ∧ Len(in′[p]) = Len(in[p]) + 1 ∧ Len(hout′[p]) = Len(hout[p]) − 1 ∧ Len(out′[p]) = Len(out[p]) − 1

Proof: Immediate from the definition of HMemWrite and the definition of Tail.

⟨7⟩2. ∧ i ∈ Proc

∧ HMemWrite(i) ∧ p ∈ Proc ∧ k ∈ 1 . . Len(in′[p]) ∧ j ∈ 1 . . k − 1 ⇒ j ∈ 1 . . Len(in[p])

Proof: Immediate from ⟨7⟩1. ⟨7⟩3. i ∈ Proc ∧ HMemWrite(i) ∧ p ∈ Proc

⇒ 1 . . Len(in′[p]) \{Len(in′[p])} = 1 . . Len(in[p]) Proof: Immediate from ⟨7⟩1 and definition of 1 . . t.

⟨7⟩4. ∧ i ∈ Proc

∧ HMemWrite(i) ∧ p ∈ Proc ∧ CCInv.1(p) ∧ a ∈ Addr ∧ k ∈ 1 . . Len(in[p]) ⇒ ∧ in′[p][k] = in[p][k] ∧ hin′[p][k] = hin[p][k] ∧ vc′[p][a] = vc[p][a]

Proof: Immediate from the definition of HMemWrite.

⟨7⟩5. ∧ i ∈ Proc

∧ HMemWrite(i) ∧ a ∈ Addr \{Head(out[i])[2]}

⇒ mem′[a] = mem[a] Proof: Immediate from the definition of HMemWrite.

⟨7⟩6. ∧ i ∈ Proc

∧ HMemWrite(i) ∧ p ∈ Proc ∧ k = Len(in′[p])

⇒ NotRefresh′_{p}(k) Proof: Immediate from the definition of HMemWrite.

The first two conjuncts of the invariant, CCInv.1 and CCInv.2, are easily seen to be preserved.

⟨7⟩7. ∧ i ∈ Proc

∧ HMemWrite(i) ∧ p ∈ Proc ∧ CCInv.1(p)

⇒ CCInv.1′(p) Proof: The first two conjuncts of CCInv.1(p) follow by equality manipulation from ⟨7⟩1, and the third conjunct by ⟨6⟩2 and the definition of HMemWrite.

⟨7⟩8. ∧ i ∈ Proc

∧ HMemWrite(i) ∧ p ∈ Proc

⇒ CCInv.2(p) ≡ CCInv.2′(p) Proof: Follows immediately by the definition of HMemWrite since c and vc are unchanged .

The proof of the third invariant from HMemWrite.

⟨7⟩9. ∧ i ∈ Proc

∧ HMemWrite(i) ∧ p ∈ Proc ∧ CCInv(p)

⇒ CCInv.3′(p) Proof:

BetweenMemWrites is preserved. A weakened form of CCInv.3(p) is used as a hypothesis in the proof.

⟨8⟩1.

∧ i ∈ Proc ∧ HMemWrite(i)

∧ p ∈ Proc

∧ CCInv.1(p)

∧ BetweenMemWrites(p)

∧ ∀ a ∈ Addr : ∨ LastIsMem(a, p) ∨ NoMemWrite(a, p)

⇒ BetweenMemWrites′(p) Proof:

The proof is split into two: One proof for m < n ≤ Len(in[p]) and one for m ≤ Len(in[p]) and n = Len(in′[p]). First, the split.

⟨9⟩1.

∧ i ∈ Proc ∧ HMemWrite(i)

∧ p ∈ Proc ⇒

BetweenMemWrites′(p) ≡ ∧ ∀ m, n ∈ 1 . . Len(in[p]) : MemWritesFromTo′(m, n, p) ∧ ∀ m ∈ 1 . . Len(in[p]) : MemWritesFromTo′(m, Len(in′[p]), p)

Proof: Follows immediately by ⟨7⟩1 and ⟨6⟩2 from definition of 1 . . Len(in[p]) and properties of <.

The step for m < n ≤ Len(in[p]).

⟨9⟩2.

∧ i ∈ Proc ∧ HMemWrite(i) ∧ p ∈ Proc ∧ CCInv.1(p) ∧ m ∈ 1 . . Len(in[p]) ∧ n ∈ 1 . . Len(in[p]) ∧ MemWritesFromTo(m, n, p)

⇒ MemWritesFromTo′(m, n, p) Proof: ⟨10⟩1.

∧ i ∈ Proc ∧ HMemWrite(i) ∧ CCInv.1(p) ∧ p ∈ Proc ∧ m ∈ 1 . . Len(in[p]) ∧ n ∈ 1 . . Len(in[p]) ∧ m < n ∧ NotRefresh_{p}(m) ∧ NotRefresh_{p}(n) ∧ ∀ j ∈ m + 1 . . n − 1 : ¬NotRefresh_{p}(j ) ⇒ ∀ j ∈ m + 1 . . n − 1 : ∨ in[p][j ][2] ≠ in[p][m][2] ∨ in[p][j ][1] = in[p][m][1]

⇒ ∀ j ∈ m + 1 . . n − 1 : ¬NotRefresh′_{p}(j )

⇒ ∀ j ∈ m + 1 . . n − 1 : ∨ in′[p][j ][2] ≠ in′[p][m][2] ∨ in′[p][j ][1] = in′[p][m][1]

Proof:

The proof is split into two parts which are propositionally combined to yield the proof.

⟨11⟩1.

∧ i ∈ Proc ∧ HMemWrite(i)

∧ CCInv.1(p)

∧ p ∈ Proc

∧ m ∈ 1 . . Len(in[p])

∧ n ∈ 1 . . Len(in[p])

∧ m < n

∧ NotRefresh_{p}(m)

∧ NotRefresh_{p}(n)

∧ ∀ j ∈ m + 1 . . n − 1 : ∨ in[p][j ][2] ≠ in[p][m][2] ∨ in[p][j ][1] = in[p][m][1]

⇒ ∀ j ∈ m + 1 . . n − 1 : ∨ in′[p][j ][2] ≠ in′[p][m][2] ∨ in′[p][j ][1] = in′[p][m][1]

Proof: ⟨12⟩1.

∧ i ∈ Proc ∧ HMemWrite(i)

∧ CCInv.1(p) ∧ p ∈ Proc ∧ m ∈ 1 . . Len(in[p]) ∧ n ∈ 1 . . Len(in[p]) ∧ m < n ∧ NotRefresh_{p}(m) ∧ NotRefresh_{p}(n) ∧ j ∈ m + 1 . . n − 1 ∧ ∨ in[p][j ][2] ≠ in[p][m][2] ∨ in[p][j ][1] = in[p][m][1]

⇒ ∧ j ∈ m + 1 . . n − 1 ∧ ∨ in′[p][j ][2] ≠ in′[p][m][2] ∨ in′[p][j ][1] = in′[p][m][1]

Proof: Follows directly from ⟨7⟩4, using propositional logic. ⟨12⟩2. Q.E.D.

Proof: Immediate by universal generalisation over j and quantifier rules. ⟨11⟩2.

∧ i ∈ Proc ∧ HMemWrite(i) ∧ CCInv.1(p) ∧ p ∈ Proc ∧ m ∈ 1 . . Len(in[p]) ∧ n ∈ 1 . . Len(in[p]) ∧ m < n ∧ NotRefresh_{p}(m) ∧ NotRefresh_{p}(n) ∧ ∃ j ∈ m + 1 . . n − 1 : NotRefresh_{p}(j ) ⇒

∃ j ∈ m + 1 . . n − 1 : NotRefresh′_{p}(j ) Proof: ⟨12⟩1.

∧ i ∈ Proc ∧ HMemWrite(i) ∧ CCInv.1(p) ∧ p ∈ Proc ∧ m ∈ 1 . . Len(in[p]) ∧ n ∈ 1 . . Len(in[p]) ∧ m < n ∧ NotRefresh_{p}(m) ∧ NotRefresh_{p}(n) ∧ j ∈ m + 1 . . n − 1 ∧ NotRefresh_{p}(j ) ⇒

∧ j ∈ m + 1 . . n − 1

∧ NotRefresh′_{p}(j ) Proof: ⟨13⟩1.

∧ i ∈ Proc ∧ HMemWrite(i)

∧ CCInv.1(p)

∧ p ∈ Proc

∧ m ∈ 1 . . Len(in[p])

∧ n ∈ 1 . . Len(in[p])

∧ m < n

∧ NotRefresh_{p}(m)

∧ NotRefresh_{p}(n)

∧ j ∈ m + 1 . . n − 1

∧ j ∈ 1 . . Len(hin[p])

∧ hin[p][j ][2] ≠ “Rd” ⇒

∧ j ∈ 1 . . Len(hin′[p]) ∧ hin′[p][j ][2] ≠ “Rd”

Proof: The first conjunct of the conclusion follows by set theory and ⟨7⟩1 and the second by ⟨7⟩4.

⟨13⟩2. Q.E.D.

Proof: Immediate by propositional logic and definition of NotRefresh. ⟨12⟩2. Q.E.D.

Proof: Immediate by existential generalisation over j . ⟨11⟩3. Q.E.D.

Proof: Follows from ⟨11⟩1 and ⟨11⟩2 by propositional logic: ((A ∧ (D ⇒ E)) ⇒

(F ⇒ G)) follows from (A ∧ E ⇒ G) ∧ (A ∧ ¬D ⇒ ¬F ). ⟨10⟩2. Q.E.D.

Proof: Immediate from ⟨10⟩1 using definition of MemWritesFromTo and propositional logic: the consequent of ⟨10⟩1 is the consequent of MemWritesFromTo′(m, n, p).

The second part of the proof for m < n = Len(in′[i]) uses other clauses of CCInv.3(p).

⟨9⟩3.

∧ i ∈ Proc ∧ HMemWrite(i) ∧ p ∈ Proc ∧ m ∈ 1 . . Len(in[p]) ∧ ∀ a ∈ Addr : ∨ LastIsMem(a, p) ∨ NoMemWrite(a, p)

⇒ ∧ p ∈ Proc ∧ m ∈ 1 . . Len(in′[p]) ∧ Len(in′[p]) ∈ 1 . . Len(in′[p]) ∧ m < Len(in′[p]) ∧ NotRefresh_{p}(m) ∧ NotRefresh_{p}(Len(in′[p])) ∧ ∀ j ∈ m + 1 . . Len(in′[p]) − 1 : ¬NotRefresh_{p}(j ) ⇒ ∀ j ∈ m + 1 . . Len(in′[p]) − 1 : ∨ in[p][j ][2] ≠ in[p][m][2] ∨ in[p][j ][1] = in[p][m][1]

Proof: ⟨10⟩1.

∧ i ∈ Proc ∧ HMemWrite(i) ∧ p ∈ Proc ∧ m ∈ 1 . . Len(in[p]) ∧ NotRefresh_{p}(m) ∧ ∀ j ∈ m + 1 . . Len(in′[p]) − 1 : ¬NotRefresh_{p}(j ) ∧ ∀ a ∈ Addr : ∨ LastIsMem(a, p) ∨ NoMemWrite(a, p)

⇒ ∀ j ∈ m + 1 . . Len(in′[p]) − 1 : ∨ in[p][j ][2] ≠ in[p][m][2] ∨ in[p][j ][1] = in[p][m][1]

Proof: ⟨11⟩1.

∧ i ∈ Proc ∧ HMemWrite(i)

∧ p ∈ Proc

∧ m ∈ 1 . . Len(in[p])

∧ NotRefresh_{p}(m)

∧ ∀ j ∈ m + 1 . . Len(in′[p]) − 1 : ¬NotRefresh_{p}(j )

∧ ∨ LastIsMem(in[p][m][2], p) ∨ NoMemWrite(in[p][m][2], p)

⇒ ∀ j ∈ m + 1 . . Len(in′[p]) − 1 : ∨ in[p][j ][2] ≠ in[p][m][2] ∨ in[p][j ][1] = in[p][m][1]

Proof: ⟨12⟩1.

∧ i ∈ Proc ∧ HMemWrite(i)

∧ p ∈ Proc

∧ m ∈ 1 . . Len(in[p])

∧ NoMemWrite(in[p][m][2], p)

⇒ ∀ j ∈ m + 1 . . Len(in[p]) : ∨ in[p][j ][2] ≠ in[p][m][2] ∨ in[p][j ][1] = in[p][m][1]

Proof: The consequent follows by restricting the quantifier in the third con-

junct of NoMemWrite(in[p][m][2], p) to m+1 . . Len(in[p]) instead of 1 . . Len(in[p]) ⟨12⟩2.

∧ i ∈ Proc ∧ HMemWrite(i) ∧ p ∈ Proc ∧ m ∈ 1 . . Len(in[p]) ∧ NotRefresh_{p}(m) ∧ LastIsMem(in[p][m][2], p) ∧ ∀ j ∈ m + 1 . . Len(in[p]) : ¬NotRefresh_{p}(j ) ⇒

∀ j ∈ m + 1 . . Len(in[p]) : ∨ in[p][j ][2] ≠ in[p][m][2] ∨ in[p][j ][1] = in[p][m][1]

Proof: Let: k : constant ⟨13⟩1.

∧ i ∈ Proc ∧ HMemWrite(i) ∧ p ∈ Proc ∧ m ∈ 1 . . Len(in[p]) ∧ NotRefresh_{p}(m) ∧ k ∈ 1 . . Len(in[p]) ∧ NotRefresh_{p}(k) ∧ in[p][k][1] = mem[in[p][m][2]] ∧ in[p][k][2] = in[p][m][2] ∧ ∀ j ∈ k + 1 . . Len(in[p]) : ∨ in[p][j ][2] ≠ in[p][m][2] ∨ in[p][j ][1] = mem[in[p][m][2]]

∧ ∀ j ∈ m + 1 . . Len(in[p]) : ¬NotRefresh_{p}(j ) ⇒

∀ j ∈ m + 1 . . Len(in[p]) : ∨ in[p][j ][2] ≠ in[p][m][2] ∨ in[p][j ][1] = in[p][m][1]

Proof:

We split into three cases: k < m, k = m, k > m. The latter can’t hold, which we show first.

⟨14⟩1.

∧ i ∈ Proc ∧ HMemWrite(i)

∧ p ∈ Proc

∧ m ∈ 1 . . Len(in[p])

∧ NotRefresh_{p}(m)

∧ k ∈ 1 . . Len(in[p])

∧ NotRefresh_{p}(k)

∧ ∀ j ∈ m + 1 . . Len(in[p]) : ¬NotRefresh_{p}(j )

⇒ k ≤ m Proof: ⟨15⟩1.

∧ i ∈ Proc ∧ HMemWrite(i)

∧ p ∈ Proc

∧ m ∈ 1 . . Len(in[p]) ∧ NotRefresh_{p}(m) ∧ k ∈ 1 . . Len(in[p]) ∧ NotRefresh_{p}(k) ∧ k > m ⇒ ∃ j ∈ m + 1 . . Len(in[p]) : NotRefresh_{p}(j )

Proof:

⟨16⟩1.

∧ i ∈ Proc ∧ HMemWrite(i)

∧ p ∈ Proc

∧ m ∈ 1 . . Len(in[p]) ∧ NotRefresh_{p}(m) ∧ k ∈ 1 . . Len(in[p]) ∧ NotRefresh_{p}(k) ∧ k > m ⇒ ∧ k ∈ m + 1 . . Len(in[p]) ∧ NotRefresh_{p}(k)

Proof: Immediate from properties of >. ⟨16⟩2. Q.E.D.

Proof: Immediate by existential generalisation over k. ⟨15⟩2. Q.E.D.

Proof: Immediate from ⟨15⟩1 by contraposition of k > m with the consequent, and properties of <.

Now the k = m case.

⟨14⟩2.

∧ i ∈ Proc ∧ HMemWrite(i) ∧ p ∈ Proc ∧ m ∈ 1 . . Len(in[p]) ∧ NotRefresh_{p}(m) ∧ k ∈ 1 . . Len(in[p]) ∧ NotRefresh_{p}(k) ∧ k = m ∧ in[p][k][1] = mem[in[p][m][2]] ∧ in[p][k][2] = in[p][m][2] ∧ ∀ j ∈ k + 1 . . Len(in[p]) : ∨ in[p][j ][2] ≠ in[p][m][2] ∨ in[p][j ][1] = mem[in[p][m][2]]

∧ ∀ j ∈ m + 1 . . Len(in[p]) : ¬NotRefresh_{p}(j ) ⇒

∀ j ∈ m + 1 . . Len(in[p]) : ∨ in[p][j ][2] ≠ in[p][m][2] ∨ in[p][j ][1] = in[p][m][1]

Proof: Follows immediately by substitution of in[p][k][1] for mem[in[p][m][2]] and m for k.

Now the k < m case.

⟨14⟩3.

∧ i ∈ Proc ∧ HMemWrite(i) ∧ p ∈ Proc ∧ m ∈ 1 . . Len(in[p]) ∧ NotRefresh_{p}(m) ∧ k ∈ 1 . . Len(in[p]) ∧ NotRefresh_{p}(k) ∧ k < m ∧ in[p][k][1] = mem[in[p][m][2]] ∧ in[p][k][2] = in[p][m][2] ∧ ∀ j ∈ k + 1 . . Len(in[p]) : ∨ in[p][j ][2] ≠ in[p][m][2] ∨ in[p][j ][1] = mem[in[p][m][2]]

∧ ∀ j ∈ m + 1 . . Len(in[p]) : ¬NotRefresh_{p}(j ) ⇒ ∀ j ∈ m + 1 . . Len(in[p]) :

∨ in[p][j ][2] ≠ in[p][m][2] ∨ in[p][j ][1] = in[p][m][1]

Proof: ⟨15⟩1.

∧ i ∈ Proc ∧ HMemWrite(i) ∧ p ∈ Proc ∧ m ∈ 1 . . Len(in[p]) ∧ NotRefresh_{p}(m) ∧ k ∈ 1 . . Len(in[p]) ∧ NotRefresh_{p}(k) ∧ k < m ∧ in[p][k][1] = mem[in[p][m][2]] ∧ in[p][k][2] = in[p][m][2] ∧ ∀ j ∈ k + 1 . . Len(in[p]) : ∨ in[p][j ][2] ≠ in[p][m][2] ∨ in[p][j ][1] = mem[in[p][m][2]]

∧ ∀ j ∈ m + 1 . . Len(in[p]) : ¬NotRefresh_{p}(j ) ⇒ in[p][m][1] = mem[in[p][m][2]]

Proof: It follows from hypothesis k < m that m ≥ k +1. Instantianting j to m in the quantifier ∀ j ∈ k + 1 . . Len(in[p]) in the hypothesis yields the conclusion, since one disjunct, in[p][m][2] ≠ in[p][m][2], is a contradiction.

⟨15⟩2.

∧ i ∈ Proc ∧ HMemWrite(i) ∧ p ∈ Proc ∧ m ∈ 1 . . Len(in[p]) ∧ NotRefresh_{p}(m) ∧ k ∈ 1 . . Len(in[p]) ∧ NotRefresh_{p}(k) ∧ k < m ∧ in[p][k][1] = mem[in[p][m][2]] ∧ in[p][k][2] = in[p][m][2] ∧ ∀ j ∈ k + 1 . . Len(in[p]) : ∨ in[p][j ][2] ≠ in[p][m][2] ∨ in[p][j ][1] = mem[in[p][m][2]]

∧ ∀ j ∈ m + 1 . . Len(in[p]) : ¬NotRefresh_{p}(j ) ⇒

∀ j ∈ m + 1 . . Len(in[p]) : ∨ in[p][j ][2] ≠ in[p][m][2] ∨ in[p][j ][1] = mem[in[p][m][2]]

Proof: The consequent follows immediately from the similar hypothesis by restricting the quantifier.

⟨15⟩3. Q.E.D.

Proof: Follows from ⟨15⟩2 by substituting in[p][m][1]] for mem[in[p][m][2]] in the conclusion, according to the conclusion of ⟨15⟩1.

⟨14⟩4. Q.E.D.

Proof: Immediate from ⟨14⟩1, ⟨14⟩2, ⟨14⟩3, and the truth k < m ∨ k = m ∨ m < k, which follows from axioms in the Naturals module.

⟨13⟩2. Q.E.D.

Proof: Follows immediately from ⟨13⟩1 by existential generalisation on k. ⟨12⟩3. Q.E.D.

Proof: Follows directly by propositional logic from ⟨12⟩1 and ⟨12⟩2. ⟨11⟩2. Q.E.D.

Proof: Follows by propositional logic from ⟨11⟩1 since the disjunctive hypothesis in ⟨10⟩1 is strengthened by the universal quantification.

⟨10⟩2. Q.E.D.

Proof: Immediate by propositional logic from ⟨10⟩1, by weakening the consequent.

⟨9⟩4. Q.E.D.

Proof: Follows from ⟨9⟩2 and ⟨9⟩3 using universal generalisation over m, n, and then by ⟨9⟩1.

We now show that all the other components, FirstIsVC , LastIsMem, and NoMemWrite, are preserved.

We first show that LastIsMem is preserved for a = Head(out[i])[2].

⟨8⟩2.

∧ i ∈ Proc ∧ HMemWrite(i) ∧ p ∈ Proc ⇒ LastIsMem′(Head(out[i])[2], p)

Proof: ⟨9⟩1.

∧ i ∈ Proc ∧ HMemWrite(i)

∧ p ∈ Proc ⇒

∧ NotRefresh_{p}′(Len(in′[p])

∧ in′[p][Len(in′[p])][1] = mem′[Head(out[i])[2]] ∧ in′[p][Len(in′[p])][2] = Head(out[i])[2]

Proof: ⟨10⟩1. hin′[p][Len(hin′[p])][2] = “Wr”

Proof: Immediate from the definition of HMemWrite. ⟨10⟩2. i ∈ Proc ∧ HMemWrite(i) ⇒ mem′[Head(out[i])[2]] = Head(out[i])[1]

Proof: Immediate from the definition of HMemWrite. ⟨10⟩3. Q.E.D.

Proof: The first conjunct follows immediately from ⟨10⟩1, and the second and third from ⟨10⟩2 using the definition of HMemWrite.

⟨9⟩2. Q.E.D.

Proof: Immediate from the definition of LastIsMem and ⟨9⟩1.

Second, FirstIsVC is preserved. This is split into two pieces. The hypotheses are used to prove the consequent conjuncts except for NotRefresh′; and then they are used to show NotRefresh′.

⟨8⟩3. ∧ i ∈ Proc

∧ HMemWrite(i) ∧ p ∈ Proc ∧ CCInv.1(p) ∧ a ∈ Addr ∧ FirstIsVC (a, p)

⇒ FirstIsVC′(a, p) Proof: Let: k : constant

⟨9⟩1. ∧ i ∈ Proc

∧ HMemWrite(i) ∧ p ∈ Proc ∧ CCInv.1(p) ∧ a ∈ Addr ∧ k ∈ 1 . . Len(in[p]) ∧ NotRefresh_{p}(k) ∧ in[p][k][2] = a ∧ ∀ j ∈ 1 . . k − 1 : ∨ in[p][j ][2] ≠ a ∨ in[p][j ][1] = vc[p][a]

⇒ ∧ p ∈ Proc ∧ k ∈ 1 . . Len(in′[p]) ∧ in′[p][k][2] = a ∧ ∀ j ∈ 1 . . k − 1 : ∨ in′[p][j ][2] ≠ a ∨ in′[p][j ][1] = vc′[p][a]

Proof: ⟨10⟩1.

∧ i ∈ Proc ∧ HMemWrite(i) ∧ p ∈ Proc ∧ CCInv.1(p) ∧ a ∈ Addr ∧ k ∈ 1 . . Len(in[p]) ∧ NotRefresh_{p}(k) ∧ in[p][k][2] = a ∧ j ∈ 1 . . k − 1

∧  ∨ in[p][j ][2] ≠ a ∨ in[p][j ][1] = vc[p][a]

⇒ ∧ p ∈ Proc ∧ k ∈ 1 . . Len(in′[p]) ∧ in′[p][k][2] = a ∧ j ∈ 1 . . k − 1 ∧ ∨ in′[p][j ][2] ≠ a ∨ in′[p][j ][1] = vc′[p][a]

Proof:

⟨11⟩1. ∧ i ∈ Proc

∧ HMemWrite(i)

∧ p ∈ Proc

∧ k ∈ 1 . . Len(in[p]) ⇒ k ∈ 1 . . Len(in′[p])

Proof: Immediate from ⟨7⟩1 and elementary set theory. ⟨11⟩2. Q.E.D.

Proof: Immediate from ⟨7⟩4 and ⟨11⟩1. ⟨10⟩2. Q.E.D.

Proof: Follows by universal generalisation over j and predicate logic from ⟨10⟩1.

⟨9⟩2.

∧ i ∈ Proc ∧ HMemWrite(i) ∧ p ∈ Proc ∧ CCInv.1(p) ∧ a ∈ Addr ∧ k ∈ 1 . . Len(in[p]) ∧ NotRefresh_{p}(k) ∧ in[p][k][2] = a ∧ ∀ j ∈ 1 . . k − 1 : ∨ in[p][j ][2] ≠ a ∨ in[p][j ][1] = vc[p][a]

⇒ NotRefresh_{p}′(k) Proof:

⟨10⟩1. ∧ i ∈ Proc

∧ HMemWrite(i)

∧ p ∈ Proc

∧ k ∈ 1 . . Len(hin[p]) ⇒ k ∈ 1 . . Len(hin′[p])

Proof: Immediate from ⟨7⟩1 and elementary set theory.

⟨10⟩2. ∧ i ∈ Proc

∧ HMemWrite(i)

∧ p ∈ Proc

∧ NotRefresh_{p}(k)

⇒ k ∈ 1 . . Len(hin[p])

Proof: Immediate from the definition of NotRefresh. ⟨10⟩3. Q.E.D.

Immediate by propositional logic from ⟨10⟩1 and ⟨10⟩2, and then using ⟨7⟩4. ⟨9⟩3. Q.E.D.

Proof: Immediate, by propositional logic from ⟨9⟩1 and ⟨9⟩2, and then existential generalisation over k.

Third, NoMemWrite is preserved, for all a ∈ Addr except for a = Head(out[i])[2].

⟨8⟩4.

∧ i ∈ Proc ∧ HMemWrite(i) ∧ p ∈ Proc ∧ a ∈ Addr \{Head(out[i])[2]} ∧ NoMemWrite(a, p)

⇒ NoMemWrite′(a, p) Proof:

The substep is simply a substitution of the definition of HMemWrite.

⟨9⟩1.

∧ i ∈ Proc ∧ HMemWrite(i) ∧ p ∈ Proc ∧ a ∈ Addr \{Head(out[i])[2]} ∧ vc[p][a] = mem[a] ∧ ∀ k ∈ 1 . . Len(in[p]) : ∨ in[p][k][2] ≠ a ∨ in[p][k][1] = mem[a]

⇒ ∧ vc′[p][a] = mem′[a] ∧ ∀ k ∈ 1 . . Len(in′[p]) : ∨ in′[p][k][2] ≠ a ∨ in′[p][k][1] = mem′[a]

Proof:

⟨10⟩1.

∧ i ∈ Proc ∧ HMemWrite(i)

∧ p ∈ Proc

∧ a ∈ Addr \{Head(out[i])[2]} ∧ k ∈ 1 . . Len(in[p]) ∧ ∨ in[p][k][2] ≠ a ∨ in[p][k][1] = mem[a]

⇒ ∧ k ∈ 1 . . Len(in′[p]) ∧ ∨ in′[p][k][2] ≠ a ∨ in′[p][k][1] = mem′[a]

Proof:

We split the proof into two: k ∈ 1 . . Len(in[p]) and k = Len(in′[p]). First, k ∈ 1 . . Len(in[p]).

⟨11⟩1.

∧ i ∈ Proc ∧ HMemWrite(i)

∧ p ∈ Proc

∧ a ∈ Addr \{Head(out[i])[2]} ∧ k ∈ 1 . . Len(in[p]) ∧ ∨ in[p][k][2] ≠ a ∨ in[p][k][1] = mem[a]

⇒ ∧ k ∈ 1 . . Len(in[p]) : ∧ ∨ in′[p][k][2] ≠ a ∨ in′[p][k][1] = mem′[a]

Proof: Immediate from ⟨7⟩5, ⟨7⟩4, and propositional logic.

Next, k = Len(in′[p]).

⟨11⟩2.

∧ i ∈ Proc ∧ HMemWrite(i)

∧ p ∈ Proc

∧ a ∈ Addr \{Head(out[i])[2]} ⇒ in′[p][Len(in′[p])][2] ≠ a

Proof:

⟨12⟩1.

∧ i ∈ Proc ∧ HMemWrite(i)

∧ p ∈ Proc

⇒ in′[p][Len(in′[p])][2] = Head(out[i])[2] Proof: Immediate from the definition of HMemWrite.

⟨12⟩2. Q.E.D.

Proof: Immediate by equality reasoning and set theory definitions from ⟨12⟩1. ⟨11⟩3. Q.E.D.

Proof: Follows from ⟨11⟩1 and ⟨11⟩2 by ⟨7⟩3 and propositional logic. ⟨10⟩2. Q.E.D.

Proof: Immediate from ⟨10⟩1 by universal generalisation over k and predicate logic, and by adding the premis vc[p][a] = mem[a] and conclusion vc′[p][a] = mem′[a] and using ⟨7⟩4 and ⟨7⟩5.

⟨9⟩2. Q.E.D. Proof: Immediate from ⟨9⟩1 by substitution for the definition of NoMemWrite.

Fourth, NoMemWrite is not quite preserved for a = Head(out[i])[2].

⟨8⟩5.

∧ i ∈ Proc ∧ HMemWrite(i) ∧ p ∈ Proc ∧ CCInv.1(p) ∧ NoMemWrite(Head(out[i])[2], p)

⇒ ∨ NoMemWrite′(Head(out[i])[2], p) ∨ ∧ LastIsMem′(Head(out[i])[2], p) ∧ FirstIsVC′(Head(out[i])[2], p)

Proof: ⟨9⟩1.

∧ i ∈ Proc ∧ HMemWrite(i) ∧ p ∈ Proc ∧ CCInv.1(p) ∧ NoMemWrite(Head(out[i])[2], p) ⇒ ∨ NoMemWrite′(Head(out[i])[2], p) ∨ FirstIsVC′(Head(out[i])[2], p)

Proof: ⟨10⟩1.

∧ i ∈ Proc ∧ HMemWrite(i) ∧ p ∈ Proc ∧ CCInv.1(p) ∧ vc[p][Head(out[i])[2]] = mem[Head(out[i])[2]] ∧ ∀ k ∈ 1 . . Len(in[p]) : ∨ in[p][k][2] ≠ Head(out[i])[2] ∨ in[p][k][1] = mem[Head(out[i])[2]]

⇒ ∨ ∧ p ∈ Proc ∧ vc′[p][Head(out[i])[2]] = mem′[Head(out[i])[2]] ∧ ∀ k ∈ 1 . . Len(in′[p]) : ∨ in′[p][k][2] ≠ Head(out[i])[2] ∨ in′[p][k][1] = mem′[Head(out[i])[2]] ∨ ∧ p ∈ Proc ∧ ∃ k ∈ 1 . . Len(in′[p]) : ∧ NotRefresh′_{p}(k) ∧ in′[p][k][2] = Head(out′[i])[2] ∧ ∀ j ∈ 1 . . k − 1 : ∨ in′[p][j ][2] ≠ Head(out′[i])[2] ∨ in′[p][j ][1] = vc′[p][Head(out′[i])[2]]

Proof:

We split into two cases, first mem[Head(out[i])[2]] = mem′[Head(out[i])[2]] and second mem[Head(out[i])[2]] ≠ mem′[Head(out[i])[2]].

⟨11⟩1.

∧ i ∈ Proc ∧ HMemWrite(i) ∧ p ∈ Proc ∧ CCInv.1(p) ∧ vc[p][Head(out[i])[2]] = mem[Head(out[i])[2]] ∧ mem[Head(out[i])[2]] = mem′[Head(out[i])[2]] ∧ ∀ k ∈ 1 . . Len(in[p]) : ∨ in[p][k][2] ≠ Head(out[i])[2] ∨ in[p][k][1] = mem[Head(out[i])[2]]

⇒ ∧ p ∈ Proc ∧ vc′[p][Head(out[i])[2]] = mem′[Head(out[i])[2]] ∧ ∀ k ∈ 1 . . Len(in′[p]) : ∨ in′[p][k][2] ≠ Head(out[i])[2] ∨ in′[p][k][1] = mem′[Head(out[i])[2]]

Proof: Follows directly by substitution of mem[Head(out[i])[2]] for mem′[Head(out[i])[2]], of vc[p][Head(out[i])[2]] for vc′[p][Head(out[i])[2]] by ⟨7⟩4, and using ⟨6⟩2 on the set 1 . . Len(in′[p]) by ⟨7⟩3.

⟨11⟩2.

∧ i ∈ Proc ∧ HMemWrite(i) ∧ p ∈ Proc ∧ CCInv.1(p) ∧ vc[p][Head(out[i])[2]] = mem[Head(out[i])[2]] ∧ mem[Head(out[i])[2]] ≠ mem′[Head(out[i])[2]] ∧ ∀ k ∈ 1 . . Len(in[p]) : ∨ in[p][k][2] ≠ Head(out[i])[2] ∨ in[p][k][1] = mem[Head(out[i])[2]]

⇒ ∧ p ∈ Proc ∧ ∃ k ∈ 1 . . Len(in′[p]) : ∧ NotRefresh′_{p}(k) ∧ in′[p][k][2] = Head(out′[i])[2] ∧ ∀ j ∈ 1 . . k − 1 : ∨ in′[p][j ][2] ≠ Head(out[i])[2] ∨ in′[p][j ][1] = vc′[p][Head(out[i])[2]]

Proof: ⟨12⟩1.

∧ i ∈ Proc ∧ HMemWrite(i) ∧ p ∈ Proc ∧ CCInv.1(p) ∧ vc[p][Head(out[i])[2]] = mem[Head(out[i])[2]] ∧ mem[Head(out[i])[2]] ≠ mem′[Head(out[i])[2]] ∧ ∀ k ∈ 1 . . Len(in[p]) : ∨ in[p][k][2] ≠ Head(out[i])[2] ∨ in[p][k][1] = mem[Head(out[i])[2]]

⇒ ∧ p ∈ Proc ∧ NotRefresh′_{p}(Len(in′[p])) ∧ in′[p][Len(in′[p])][2] = Head(out[i])[2] ∧ ∀ j ∈ 1 . . Len(in[p])\begin{matrix}∨ in′[p][j ][2] ≠ Head(out[i])[2] \\ ∨ in′[p][j ][1] = vc′[p][Head(out[i])[2]] \end{matrix}

Proof: The first conjunct of the consequent is trivial, the second follows from the definition of NotRefresh and HMemWrite, the third by definition of HMemWrite and Len(in′[p]), and the last by the last hypothesis, noting that vc′[p][Head(out[i])[2]] = vc[p][Head(out[i])[2]], and that ∀ j ∈ 1 . . Len(in[p]) : in′[p][j ] = in[p][j ], both by ⟨7⟩4 and substituting.

⟨12⟩2. Q.E.D.

Proof: Follows immediately from ⟨12⟩1 by substitution of k −1 for Len(in[p]) by ⟨7⟩1, by existential generalisation on k, and propositional logic.

⟨11⟩3. Q.E.D.

Proof: By propositional logic from ⟨11⟩1 and ⟨11⟩1. ⟨10⟩2. Q.E.D.

Proof: ⟨10⟩1 is simply a rewrite of ⟨9⟩1. ⟨9⟩2. Q.E.D.

Proof: Follows by propositional logic from ⟨9⟩1 and ⟨8⟩2, which says that LastIsMem is preserved for this value of a.

Fifth, LastIsMem is preserved.

⟨8⟩6.

∧ i ∈ Proc ∧ HMemWrite(i) ∧ p ∈ Proc ∧ LastIsMem(a, p)

⇒ LastIsMem′(a, p) Proof:

Since this follows directly from ⟨8⟩2 for a = Head(out[i])[2], we need to show it for the other values of a.

⟨9⟩1.

∧ i ∈ Proc ∧ HMemWrite(i) ∧ p ∈ Proc ∧ a ∈ Addr \{Head(out[i])[2]} ∧ LastIsMem(a, p)

⇒ LastIsMem′(a, p) Proof:

The substep is simply to expand the definition of LastIsMem.

⟨10⟩1.

∧ i ∈ Proc ∧ HMemWrite(i) ∧ p ∈ Proc ∧ a ∈ Addr \{Head(out[i])[2]} ∧ ∃ k ∈ 1 . . Len(in[p]) : ∧ NotRefresh_{p}(k) ∧ in[p][k][1] = mem[a] ∧ in[p][k][2] = a ∧ ∀ j ∈ k + 1 . . Len(in[p]) : ∨ in[p][j ][2] ≠ a ∨ in[p][j ][1] = mem[a]

⇒

∃ k ∈ 1 . . Len(in′[p]) :

∧ NotRefresh_{p}′(k)

∧ in′[p][k][1] = mem′[a]

∧ in′[p][k][2] = a

∧ ∀ j ∈ k + 1 . . Len(in′[p]) : ∨ in′[p][j ][2] ≠ a ∨ in′[p][j ][1] = mem′[a]

Proof:

The substep is to instantiate k. The same k will witness both hypothesis and consequent, since it can’t be Len(in′[p]) in the consequent by the hypothesis on the value of a.

Let: k : constant ⟨11⟩1.

∧ i ∈ Proc ∧ HMemWrite(i) ∧ p ∈ Proc ∧ a ∈ Addr \{Head(out[i])[2]} ∧ k ∈ 1 . . Len(in[p]) ∧ NotRefresh_{p}(k) ∧ in[p][k][1] = mem[a] ∧ in[p][k][2] = a ∧ ∀ j ∈ k + 1 . . Len(in[p]) : ∨ in[p][j ][2] ≠ a ∨ in[p][j ][1] = mem[a]

⇒ ∧ k ∈ 1 . . Len(in′[p]) ∧ NotRefresh_{p}′(k) ∧ in′[p][k][1] = mem′[a] ∧ in′[p][k][2] = a ∧ ∀ j ∈ k + 1 . . Len(in[p]) : ∨ in′[p][j ][2] ≠ a ∨ in′[p][j ][1] = mem′[a]

∧ in′[p][Len(in′[p])][2] ≠ a

Proof: Immediate from ⟨7⟩1, ⟨7⟩5 and ⟨7⟩4. ⟨11⟩2. Q.E.D.

Proof: Immediate by predicate logic from ⟨11⟩1 by using ⟨7⟩3 and ⟨6⟩2 to combine the last two conjuncts of the consequent, and by existentially quantifying over k in antecedent and consequent and predicate logic.

⟨10⟩2. Q.E.D.

Proof: Immediate from ⟨10⟩1 by definition of LastIsMem. ⟨9⟩2. Q.E.D.

Proof: Immediate from ⟨8⟩2 and ⟨9⟩1 using ⟨6⟩2.

That completes the sequence of steps showing the preservation of components of CCInv.3(p) under HMemWrite. We conclude thus:- ⟨8⟩7. Q.E.D.

Proof: Follows by propositional logic using ⟨8⟩1, ⟨8⟩3,⟨8⟩6,and using ⟨6⟩2 on ⟨8⟩4 and ⟨8⟩5.

We may now conclude that all components of CCInv are preserved under HMemWrite:-

⟨7⟩10. Q.E.D.

Proof: Follows by propositional logic and quantifier rules from ⟨7⟩7, ⟨7⟩8, and ⟨7⟩9.

The invariant is preserved by a HCacheUpdate

⟨6⟩6. CCInv ∧ i ∈ Proc ∧ HCacheUpdate(i) ⇒ CCInv′ Proof:

First, two logical properties of sequence operations and a general logical property.

Let: k : constant ⟨7⟩1. k ∈ 2 . . Len(s) ⇒ ϕ(s[k]) ≡ ϕ(Tail(s)[k − 1])

Proof: Logical property of Tail, assumed without further proof. ⟨7⟩2. ∀ k ∈ 2 . . Len(s) : ϕ(s[k]) ≡ ∀ p ∈ 1 . . Len(Tail(s)) : ϕ(Tail(s)[p])

Proof: Follows from ⟨7⟩1 by properties of the sets q . . r and universal generalisation. ⟨7⟩3. ∀ x ∈ S : ϕ ∧ T ⊂ S ⇒ ∀ x ∈ T : ϕ

Proof: This is general logic and set theory, which we assume without further proof.

Some general properties of HCacheUpdate.

⟨7⟩4. i ∈ Proc ∧ HCacheUpdate(i) ⇒ ∧ Len(in′[i]) = Len(in[i]) − 1 ∧ Len(hin′[i]) = Len(hin[i]) − 1 ∧ unchanged ⟨out, hout ⟩

Proof: Immediate from the definitions of HCacheUpdate and Tail.

⟨7⟩5. ∧ i ∈ Proc

∧ HCacheUpdate(i) ∧ (k ∈ 2 . . Len(in[i])) ⇒ ∧ NotRefresh_{i}(k) ≡ NotRefresh_{i}′(k − 1) ∧ in[i][k] = in′[i][k − 1]

Proof: Follows from the definition of HCacheUpdate, and ⟨7⟩1.

CCInv(i) is preserved under HCacheUpdate(i).

⟨7⟩6. ∧ i ∈ Proc

∧ CCInv(i)

∧ HCacheUpdate(i)

⇒ CCInv′(i) Proof:

First, CCInv.1(i) is preserved under HCacheUpdate(i).

⟨8⟩1. ∧ i ∈ Proc

∧ CCInv.1(i)

∧ HCacheUpdate(i) ⇒ CCInv.1′(i)

Proof: Follows immediately from the definition of HCacheUpdate by ⟨7⟩4 for the first two conjuncts of CCInv.1, and by ⟨7⟩3 for the third conjunct.

CCInv.2(i) is preserved under HCacheUpdate(i).

⟨8⟩2. ∧ i ∈ Proc

∧ CCInv(i)

∧ HCacheUpdate(i) ⇒ CCInv.2′(i)

Proof: Follows immediately from logical equality rules since the new values of c and vc are defined by the same terms in the definition of HCacheUpdate.

CCInv.3(i) is preserved under HCacheUpdate(i).

⟨8⟩3. ∧ i ∈ Proc

∧ CCInv(i) ∧ HCacheUpdate(i) ⇒ CCInv.3′(i)

Proof:

We show that each of the components of CCInv.3(i) is preserved. First, BetweenMemWrites.

⟨9⟩1. ∧ i ∈ Proc

∧ HCacheUpdate(i) ∧ BetweenMemWrites(i) ⇒ BetweenMemWrites′(i)

Proof: Immediate from restricting the universal quantifiers in the definition of BetweenMemWrites, and using ⟨7⟩2.

Next, NoMemWrite is preserved.

⟨9⟩2. ∧ i ∈ Proc

∧ a ∈ Addr ∧ HCacheUpdate(i) ∧ NoMemWrite(a, i) ⇒ NoMemWrite′(a, i)

Proof:

This is split into two steps: a = Head(in[i])[2] and a ∈ Addr \{Head(in[i])[2]}

⟨10⟩1. ∧ i ∈ Proc

∧ a ∈ Addr

∧ HCacheUpdate(i)

∧ NoMemWrite(Head(in[i])[2], i)

⇒ NoMemWrite′(Head(in[i])[2], i) Proof:

We expand the definition of NoMemWrite.

⟨11⟩1.

∧ i ∈ Proc ∧ HCacheUpdate(i)

∧ a ∈ Addr

∧ vc[i][Head(in[i])[2]] = mem[Head(in[i])[2]]

∧ ∀ k ∈ 1 . . Len(in[i]) : ∨ in[i][k][2] ≠ Head(in[i])[2] ∨ in[i][k][1] = mem[Head(in[i])[2]]

⇒ ∧ vc′[i][Head(in[i])[2]] = mem′[Head(in[i])[2]] ∧ ∀ k ∈ 1 . . Len(in′[i]) : ∨ in′[i][k][2] ≠ Head(in[i])[2] ∨ in′[i][k][1] = mem′[Head(in[i])[2]]

Proof: ⟨12⟩1.

∧ i ∈ Proc ∧ HCacheUpdate(i)

∧ a ∈ Addr

∧ vc[i][Head(in[i])[2]] = mem[Head(in[i])[2]]

∧ in[i][1][1] = mem[Head(in[i])[2]]

∧ ∀ k ∈ 2 . . Len(in[i]) : ∨ in[i][k][2] ≠ Head(in[i])[2] ∨ in[i][k][1] = mem[Head(in[i])[2]]

⇒ ∧ vc′[i][Head(in[i])[2]] = mem′[Head(in[i])[2]] ∧ ∀ k ∈ 1 . . Len(in′[i]) : ∨ in′[i][k][2] ≠ Head(in[i])[2] ∨ in′[i][k][1] = mem′[Head(in[i])[2]]

Proof: First, substitute mem for mem′, since mem is unchanged by definition of HCacheUpdate. The first clause of the consequent follows by substituting mem[Head(in[i])[2]] for Head(in[i])[1] = in[i][1][1] in the definition of HCacheUpdate. The second clause follows from the corresponding clause of the antecedent by ⟨7⟩2.

⟨12⟩2. Q.E.D.

Proof: Follows from ⟨12⟩1 using ⟨6⟩2 on the last two clauses of the antecedent, and the definition of s . . t.

⟨11⟩2. Q.E.D.

Proof: ⟨11⟩1 is a rewrite of ⟨10⟩1 using the definition of NoMemWrite.

Next, NoMemWrite is preserved for a ∈ Addr \{Head(in[i])[2]}.

⟨10⟩2.

∧ i ∈ Proc ∧ HCacheUpdate(i) ∧ a ∈ Addr \{Head(in[i])[2]} ∧ NoMemWrite(a, i) ⇒ NoMemWrite′(a, i)

Proof:

We expand the definition of NoMemWrite.

⟨11⟩1.

∧ i ∈ Proc ∧ HCacheUpdate(i)

∧ a ∈ Addr \{Head(in[i])[2]}

∧ vc[i][a] = mem[a]

∧ ∀ k ∈ 1 . . Len(in[i]) : ∨ in[i][k][2] ≠ a ∨ in[i][k][1] = mem[a]

⇒ ∧ vc′[i][a] = mem′[a] ∧ ∀ k ∈ 1 . . Len(in′[i]) : ∨ in′[i][k][2] ≠ a ∨ in′[i][k][1]mem′[a]

Proof:

We weaken the hypothesis quantifier ∀ k ∈ 1 . . Len(in′[i]) to ∀ k ∈ 2 . . Len(in′[i]), and use ⟨7⟩2 to obtain the conclusion. vc[i] and mem are unchanged for this address value.

⟨12⟩1.

∧ i ∈ Proc ∧ HCacheUpdate(i) ∧ a ∈ Addr \{Head(in[i])[2]} ∧ vc[i][a] = mem[a] ∧ ∀ k ∈ 2 . . Len(in[i]) : ∨ in[i][k][2] ≠ a ∨ in[i][k][1] = mem[a]

⇒ ∧ vc′[i][a] = mem′[a] ∧ ∀ k ∈ 1 . . Len(in′[i]) : ∨ in′[i][k][2] ≠ a ∨ in′[i][k][1]mem′[a]

Proof: First, substitute vc[i][a] for vc′[i][a] and mem[a] for mem′[a] since both are unchanged by definition of HCacheUpdate and a ≠ Head(in[i])[2]. The first conjunct of the consequent now follows from the identical conjunct of the antecedent. The second conjunct of the consequent follows from the final hypothesis by ⟨7⟩2.

⟨12⟩2. Q.E.D.

Proof: Immediate from ⟨12⟩1 by strengthening the quantified hypothesis using the definition of s . . t.

⟨11⟩2. Q.E.D.

Proof: Immediate from ⟨11⟩1 by substituting the definition of NoMemWrite. ⟨10⟩3. Q.E.D.

Proof: Immediate from ⟨10⟩1 and ⟨10⟩2 using ⟨6⟩2.

Next, LastIsMem is preserved.

⟨9⟩3.

∧ i ∈ Proc ∧ HCacheUpdate(i) ∧ a ∈ Addr ∧ LastIsMem(a, i)

⇒ LastIsMem′(a, i)

Proof:

This is split into two steps: a = Head(in[i])[2] and a ∈ Addr \{Head(in[i])[2]}. First, a ∈ Addr \{Head(in[i])[2]}.

⟨10⟩1.

∧ i ∈ Proc ∧ HCacheUpdate(i) ∧ a ∈ Addr \{Head(in[i])[2]} ∧ LastIsMem(a, i)

⇒ LastIsMem′(a, i)

Proof:

We expand the definition of LastIsMem.

⟨11⟩1.

∧ i ∈ Proc ∧ HCacheUpdate(i) ∧ a ∈ Addr \{Head(in[i])[2]} ∧ ∃ k ∈ 1 . . Len(in[i]) : ∧ NotRefresh_{i}(k) ∧ in[i][k][1] = mem[a] ∧ in[i][k][2] = a ∧ ∀ j ∈ k + 1 . . Len(in[i]) : ∨ in[i][j ][2] ≠ a ∨ in[i][j ][1] = mem[a]

⇒ ∃ k ∈ 1 . . Len(in′[i]) : ∧ NotRefresh_{i}′(k) ∧ in′[i][k][1] = mem′[a] ∧ in′[i][k][2] = a ∧ ∀ j ∈ k + 1 . . Len(in′[i]) : ∨ in′[i][j ][2] ≠ a ∨ in′[i][j ][1] = mem′[a]

Proof:

We split the quantifier in the antecedent into k = 1 and k ∈ 2 . . Len(in[i]).

⟨12⟩1.

∧ i ∈ Proc ∧ HCacheUpdate(i) ∧ a ∈ Addr \{Head(in[i])[2]} ∧ ∨ ∧ NotRefresh_{i}(1) ∧ in[i][1][1] = mem[a] ∧ in[i][1][2] = a ∧ ∀ j ∈ 2 . . Len(in[i]) : ∨ in[i][j ][2] ≠ a ∨ in[i][j ][1] = mem[a] ∨ ∃ k ∈ 2 . . Len(in[i]) : ∧ NotRefresh_{i}(k) ∧ in[i][k][1] = mem[a] ∧ in[i][k][2] = a ∧ ∀ j ∈ k + 1 . . Len(in[i]) : ∨ in[i][j ][2] ≠ a ∨ in[i][j ][1] = mem[a]

⇒ ∃ k ∈ 1 . . Len(in′[i]) : ∧ NotRefresh_{i}′(k) ∧ in′[i][k][1] = mem′[a] ∧ in′[i][k][2] = a ∧ ∀ j ∈ k + 1 . . Len(in′[i]) : ∨ in′[i][j ][2] ≠ a ∨ in′[i][j ][1] = mem′[a]

Proof:

We discard the k = 1 case, since it contains a conjunct in[i][1][2] = a that contradicts the hypothesis a ∈ Addr \{Head(in[i])[2]}.

⟨13⟩1.

∧ i ∈ Proc ∧ HCacheUpdate(i) ∧ a ∈ Addr \{Head(in[i])[2]} ∧ ∃ k ∈ 2 . . Len(in[i]) : ∧ NotRefresh_{i}(k) ∧ in[i][k][1] = mem[a] ∧ in[i][k][2] = a ∧ ∀ j ∈ k + 1 . . Len(in[i]) : ∨ in[i][j ][2] ≠ a ∨ in[i][j ][1] = mem[a]

⇒ ∃ k ∈ 1 . . Len(in′[i]) : ∧ NotRefresh_{i}′(k) ∧ in′[i][k][1] = mem′[a] ∧ in′[i][k][2] = a ∧ ∀ j ∈ k + 1 . . Len(in′[i]) : ∨ in′[i][j ][2] ≠ a ∨ in′[i][j ][1] = mem′[a]

Proof:

We prove it without the k quantifiers, so we can use existential generalisation to obtain the quantifiers. We are careful to use the right value, namely k −1, in the consequent.

Let: k : constant ⟨14⟩1.

∧ i ∈ Proc ∧ HCacheUpdate(i) ∧ a ∈ Addr \{Head(in[i])[2]} ∧ k ∈ 2 . . Len(in[i]) ∧ NotRefresh_{i}(k) ∧ in[i][k][1] = mem[a] ∧ in[i][k][2] = a ∧ ∀ j ∈ k + 1 . . Len(in[i]) : ∨ in[i][j ][2] ≠ a ∨ in[i][j ][1] = mem[a]

⇒ ∧ (k − 1) ∈ 1 . . Len(in′[i]) ∧ NotRefresh_{i}′(k − 1) ∧ in′[i][k − 1][1] = mem′[a] ∧ in′[i][k − 1][2] = a ∧ ∀ j ∈ k . . Len(in′[i]) : ∨ in′[i][j ][2] ≠ a ∨ in′[i][j ][1] = mem′[a]

Proof:

We fiddle with the quantifier ∀ j ∈ k . . Len(in′[i]) in the consequent to get it into the right form.

⟨15⟩1.

∧ i ∈ Proc ∧ HCacheUpdate(i) ∧ a ∈ Addr \{Head(in[i])[2]} ∧ k ∈ 2 . . Len(in[i]) ∧ NotRefresh_{i}(k) ∧ in[i][k][1] = mem[a] ∧ in[i][k][2] = a ∧ ∀ j ∈ k + 1 . . Len(in[i]) : ∨ in[i][j ][2] ≠ a ∨ in[i][j ][1] = mem[a]

⇒ ∧ (k − 1) ∈ 1 . . Len(in′[i]) ∧ NotRefresh_{i}′(k − 1) ∧ in′[i][k − 1][1] = mem′[a] ∧ in′[i][k − 1][2] = a ∧ ∀ l ∈ k + 1 . . Len(in[i]) : ∨ in[i][l][2] ≠ a ∨ in[i][l][1] = mem[a]

Proof: The first conjunct of the consequent follows by arithmetic and the definition of s . . t, the second, third and fourth by ⟨7⟩5, along with mem′[a] = mem[a]. The final is simply α-equivalent to the last hypothesis.

⟨15⟩2. Q.E.D.

Proof: Follows immediately from ⟨15⟩1 by using ⟨7⟩5 to substitute in′[i][l − 1]for in[i][l], the definition of HCacheUpdate to substitute mem′[a] for mem[a], recalculating the range of l − 1, and finally substituting j for l − 1.

⟨14⟩2. Q.E.D.

Proof: Follows from ⟨14⟩1 by existential generalisation over k − 1 in the consequent, and k in the antecedent, and by predicate logic.

⟨13⟩2. Q.E.D.

Proof: Follows directly from ⟨13⟩1 by adding a disjunct that contradicts other hypotheses (by asserting in[i][1][2] = a) to the last conjunct of the antecedent.

⟨12⟩2. Q.E.D.

Proof: Follows directly from ⟨12⟩1 using ⟨6⟩2. ⟨11⟩2. Q.E.D.

Proof: Immediate from ⟨11⟩1 by substituting “LastIsMem” and “LastIsMem′” for their definiens.

Second, the proof for a = Head(in[i])[2]

⟨10⟩2. ∧ i ∈ Proc

∧ HCacheUpdate(i) ∧ LastIsMem(Head(in[i])[2], i)

⇒ ∨ LastIsMem′(Head(in[i])[2], i) ∨ NoMemWrite(Head(in[i])[2], i) Proof: We expand the definition of LastIsMem and NoMemWrite. ⟨11⟩1.

∧ i ∈ Proc ∧ HCacheUpdate(i)

∧ ∃ k ∈ 1 . . Len(in[i]) : ∧ NotRefresh_{i}(k) ∧ in[i][k][1] = mem[Head(in[i])[2]]] ∧ in[i][k][2] = Head(in[i])[2] ∧ ∀ j ∈ k + 1 . . Len(in[i]) : ∨ in[i][j ][2] ≠ Head(in[i])[2] ∨ in[i][j ][1] = mem[Head(in[i])[2]]

⇒ ∨ ∧ i ∈ Proc ∧ vc′[i][Head(in[i])[2]] = mem′[Head(in[i])[2]] ∧ ∀ k ∈ 1 . . Len(in′[i]) : ∨ in′[i][k][2] ≠ Head(in[i])[2] ∨ in′[i][k][1] = mem′[Head(in[i])[2]]

∨ ∧ i ∈ Proc ∧ ∃ k ∈ 1 . . Len(in′[i]) : ∧ NotRefresh_{i}′(k) ∧ in′[i][k][1] = mem′[Head(in[i])[2]]] ∧ in′[i][k][2] = Head(in[i])[2] ∧ ∀ j ∈ k + 1 . . Len(in′[i]) : ∨ in′[i][j ][2] ≠ Head(in[i])[2] ∨ in′[i][j ][1] = mem′[Head(in[i])[2]]

Proof:

We split the k quantifier into the k = 1 and k = 2 . . Len(in[i]) cases.

⟨12⟩1.

∧ i ∈ Proc ∧ HCacheUpdate(i)

∧ ∨ ∧ NotRefresh_{i}(1) ∧ in[i][1][1] = mem[Head(in[i])[2]]] ∧ in[i][1][2] = Head(in[i])[2] ∧ ∀ j ∈ 2 . . Len(in[i]) : ∨ in[i][j ][2] ≠ Head(in[i])[2] ∨ in[i][j ][1] = mem[Head(in[i])[2]] ∨ ∃ k ∈ 2 . . Len(in[i]) : ∧ NotRefresh_{i}(k) ∧ in[i][k][1] = mem[Head(in[i])[2]]] ∧ in[i][k][2] = Head(in[i])[2] ∧ ∀ j ∈ k + 1 . . Len(in[i]) : ∨ in[i][j ][2] ≠ Head(in[i])[2] ∨ in[i][j ][1] = mem[Head(in[i])[2]]

⇒ ∨ ∧ i ∈ Proc ∧ vc′[i][Head(in[i])[2]] = mem′[Head(in[i])[2]] ∧ ∀ k ∈ 1 . . Len(in′[i]) : ∨ in′[i][k][2] ≠ Head(in[i])[2] ∨ in′[i][k][1] = mem′[Head(in[i])[2]]

∨ ∧ i ∈ Proc ∧ ∃ k ∈ 1 . . Len(in′[i]) : ∧ NotRefresh_{i}′(k) ∧ in′[i][k][1] = mem′[Head(in[i])[2]]] ∧ in′[i][k][2] = Head(in[i])[2] ∧ ∀ j ∈ k + 1 . . Len(in′[i]) : ∨ in′[i][j ][2] ≠ Head(in[i])[2] ∨ in′[i][j ][1] = mem′[Head(in[i])[2]]

Proof:

We split the proof into two parts, according to the disjunction in the antecedent, to which cases the disjuncts in the consequent correspond. First, the case k = 1.

⟨13⟩1.

∧ i ∈ Proc ∧ HCacheUpdate(i) ∧ NotRefresh_{i}(1) ∧ in[i][1][1] = mem[Head(in[i])[2]]] ∧ in[i][1][2] = Head(in[i])[2] ∧ ∀ j ∈ 2 . . Len(in[i]) : ∨ in[i][j ][2] ≠ Head(in[i])[2] ∨ in[i][j ][1] = mem[Head(in[i])[2]]

⇒ ∧ i ∈ Proc ∧ vc′[i][Head(in[i])[2]] = mem′[Head(in[i])[2]] ∧ ∀ k ∈ 1 . . Len(in′[i]) : ∨ in′[i][k][2] ≠ Head(in[i])[2] ∨ in′[i][k][1] = mem′[Head(in[i])[2]]

Proof: The first conjunct of the consequent follows from the first of the antecedent; the second from the third, using that mem is unchanged by HCacheUpdate; the third from mem being unchanged, and by ⟨7⟩2 with a variable change, as in ⟨9⟩2.

Now the case k ∈ 2 . . Len(in[i]).

⟨13⟩2.

∧ i ∈ Proc ∧ HCacheUpdate(i) ∧ ∃ k ∈ 2 . . Len(in[i]) : ∧ NotRefresh_{i}(k) ∧ in[i][k][1] = mem[Head(in[i])[2]]] ∧ in[i][k][2] = Head(in[i])[2] ∧ ∀ j ∈ k + 1 . . Len(in[i]) : ∨ in[i][j ][2] ≠ Head(in[i])[2] ∨ in[i][j ][1] = mem[Head(in[i])[2]]

⇒ ∧ i ∈ Proc ∧ ∃ k ∈ 1 . . Len(in′[i]) : ∧ NotRefresh_{i}′(k) ∧ in′[i][k][1] = mem′[Head(in[i])[2]]] ∧ in′[i][k][2] = Head(in[i])[2] ∧ ∀ j ∈ k + 1 . . Len(in′[i]) : ∨ in′[i][j ][2] ≠ Head(in[i])[2] ∨ in′[i][j ][1] = mem′[Head(in[i])[2]]

Proof:

We instantiate the quantifiers in the antecedent with k and the consequent with k − 1, as before.

Let: k : constant ⟨14⟩1.

∧ i ∈ Proc ∧ HCacheUpdate(i)

∧ k ∈ 2 . . Len(in[i])

∧ NotRefresh_{i}(k)

∧ in[i][k][1] = mem[Head(in[i])[2]]]

∧ in[i][k][2] = Head(in[i])[2]

∧ ∀ j ∈ k + 1 . . Len(in[i]) : ∨ in[i][j ][2] ≠ Head(in[i])[2] ∨ in[i][j ][1] = mem[Head(in[i])[2]]

⇒ ∧ i ∈ Proc ∧ (k − 1) ∈ 1 . . Len(in′[i]) ∧ NotRefresh_{i}′(k − 1) ∧ in′[i][k − 1][1] = mem′[Head(in[i])[2]]] ∧ in′[i][k − 1][2] = Head(in[i])[2] ∧ ∀ j ∈ k . . Len(in′[i]) : ∨ in′[i][j ][2] ≠ Head(in[i])[2] ∨ in′[i][j ][1] = mem′[Head(in[i])[2]]

Proof:

The conjuncts in the consequent all follow from the corresponding ones in the antecedent using ⟨7⟩4 with arithmetic calculation on 2 . . Len(in[i]), and ⟨7⟩5. We handle the quantifiers in this substep.

⟨15⟩1.

∧ i ∈ Proc ∧ HCacheUpdate(i)

∧ k ∈ 2 . . Len(in[i]) ∧ NotRefresh_{i}(k) ∧ in[i][k][1] = mem[Head(in[i])[2]]] ∧ in[i][k][2] = Head(in[i])[2] ∧ j ∈ k + 1 . . Len(in[i]) ∧ ∨ in[i][j ][2] ≠ Head(in[i])[2] ∨ in[i][j ][1] = mem[Head(in[i])[2]]

⇒ ∧ i ∈ Proc ∧ (k − 1) ∈ 1 . . Len(in′[i]) ∧ NotRefresh_{i}′(k − 1) ∧ in′[i][k − 1][1] = mem′[Head(in[i])[2]]] ∧ in′[i][k − 1][2] = Head(in[i])[2] ∧ (j − 1) ∈ k . . Len(in′[i]) ∧ ∨ in′[i][j − 1][2] ≠ Head(in[i])[2] ∨ in′[i][j − 1][1] = mem′[Head(in[i])[2]]

Proof: Conjuncts in the consequent all follow from the corresponding conjuncts in the antecedent using some arithmetic, and ⟨7⟩4 and ⟨7⟩5.

⟨15⟩2. Q.E.D.

Proof: Immediate from ⟨15⟩1 by universal generalisation over j , then substituting a new variable l for j − 1 in the consequent, and then by α-equivalence.

⟨14⟩2. Q.E.D.

Proof: Immediate by existential generalisation over k in the antecedent and over a variable in the consequent that is substituted first for k − 1, in ⟨13⟩2.

⟨13⟩3. Q.E.D.

Proof: Follows by propositional logic from ⟨13⟩1 and ⟨13⟩1. ⟨12⟩2. Q.E.D.

Proof: Follows from ⟨12⟩1 by ⟨6⟩2 on the hypothesis. ⟨11⟩2. Q.E.D.

Proof: ⟨10⟩2 is a rewrite of ⟨11⟩1. ⟨10⟩3. Q.E.D.

Proof: Immediate from ⟨10⟩1 and ⟨10⟩2 using ⟨6⟩2.

Next, FirstIsVC is preserved. But it isn’t always. Also, we need the hypotheses BetweenMemWrites and LastIsMem.

⟨9⟩4.

∧ i ∈ Proc ∧ HCacheUpdate(i) ∧ BetweenMemWrites(i) ∧ LastIsMem(a, i) ∧ FirstIsVC (a, i) ⇒ ∨ FirstIsVC′(a, i) ∨ NoMemWrite′(a, i))

Proof:

This is split into two steps: a = Head(in[i])[2] and a ∈ Addr \{Head(in[i])[2]}. First, a ∈ Addr \{Head(in[i])[2]}

⟨10⟩1.

∧ i ∈ Proc ∧ HCacheUpdate(i)

∧ a ∈ Addr \{Head(in[i])[2]} ∧ FirstIsVC (a, i)

⇒ FirstIsVC′(a, i)

Proof:

We unpack the definitions of FirstIsVC (a, i) and FirstIsVC′(a, i).

⟨11⟩1.

∧ i ∈ Proc ∧ HCacheUpdate(i) ∧ a ∈ Addr \{Head(in[i])[2]} ∧ ∃ k ∈ 1 . . Len(in[i]) : ∧ NotRefresh_{i}(k) ∧ in[i][k][2] = a ∧ ∀ j ∈ 1 . . k − 1 : ∨ in[i][j ][2] ≠ a ∨ in[i][j ][1] = vc[i][a]

⇒ ∃ k ∈ 1 . . Len(in′[i]) : ∧ NotRefresh′_{i}(k) ∧ in′[i][k][2] = a ∧ ∀ j ∈ 1 . . k − 1 : ∨ in′[i][j ][2] ≠ a ∨ in′[i][j ][1] = vc′[i][a]

Proof:

We split the quantifier in the hypothesis into k = 1 and k ∈ 2 . . Len(in[i]).

⟨12⟩1.

∧ i ∈ Proc ∧ HCacheUpdate(i) ∧ a ∈ Addr \{Head(in[i])[2]} ∧ ∨ ∧ NotRefresh_{i}(1) ∧ in[i][1][2] = a ∧ ∀ j ∈ 1 . . k − 1 : ∨ in[i][j ][2] ≠ a ∨ in[i][j ][1] = vc[i][a] ∨ ∃ k ∈ 2 . . Len(in[i]) : ∧ NotRefresh_{i}(k) ∧ in[i][k][2] = a ∧ ∀ j ∈ 1 . . k − 1 : ∨ in[i][j ][2] ≠ a ∨ in[i][j ][1] = vc[i][a]

⇒ ∃ k ∈ 1 . . Len(in′[i]) : ∧ NotRefresh′_{i}(k) ∧ in′[i][k][2] = a ∧ ∀ j ∈ 1 . . k − 1 : ∨ in′[i][j ][2] ≠ a ∨ in′[i][j ][1] = vc′[i][a]

Proof:

The hypothesis in[i][1][2] = a for the case k = 1 is inconsistent with the hypothesis HCacheUpdate(i)∧a ∈ Addr \{Head(in[i])[2]} so we consider only the disjunct k ∈ 2 . . Len(in[i]).

⟨13⟩1.

∧ i ∈ Proc ∧ HCacheUpdate(i) ∧ a ∈ Addr \{Head(in[i])[2]} ∧ ∃ k ∈ 2 . . Len(in[i]) : ∧ NotRefresh_{i}(k) ∧ in[i][k][2] = a ∧ ∀ j ∈ 1 . . k − 1 : ∨ in[i][j ][2] ≠ a ∨ in[i][j ][1] = vc[i][a]

⇒ ∃ k ∈ 1 . . Len(in′[i]) : ∧ NotRefresh′_{i}(k) ∧ in′[i][k][2] = a ∧ ∀ j ∈ 1 . . k − 1 : ∨ in′[i][j ][2] ≠ a ∨ in′[i][j ][1] = vc′[i][a]

Proof:

We instantiate the existential quantifier k in the antecedent and cunningly instantiate the quantifier k in the consequent with k − 1.

Let: k : constant ⟨14⟩1.

∧ i ∈ Proc ∧ HCacheUpdate(i) ∧ a ∈ Addr \{Head(in[i])[2]} ∧ k ∈ 2 . . Len(in[i]) : ∧ NotRefresh_{i}(k) ∧ in[i][k][2] = a ∧ ∀ j ∈ 1 . . k − 1 : ∨ in[i][j ][2] ≠ a ∨ in[i][j ][1] = vc[i][a]

⇒ ∧ (k − 1) ∈ 1 . . Len(in′[i]) ∧ NotRefresh′_{i}(k − 1) ∧ in′[i][k − 1][2] = a ∧ ∀ j ∈ 1 . . k − 2 : ∨ in′[i][j ][2] ≠ a ∨ in′[i][j ][1] = vc′[i][a]

Proof:

We change the variable l = (j + 1) in the consequent.

⟨15⟩1.

∧ i ∈ Proc ∧ HCacheUpdate(i) ∧ a ∈ Addr \{Head(in[i])[2]} ∧ k ∈ 2 . . Len(in[i]) : ∧ NotRefresh_{i}(k) ∧ in[i][k][2] = a ∧ ∀ j ∈ 1 . . k − 1 : ∨ in[i][j ][2] ≠ a ∨ in[i][j ][1] = vc[i][a]

⇒ ∧ (k − 1) ∈ 1 . . Len(in′[i]) ∧ NotRefresh′_{i}(k − 1) ∧ in′[i][k − 1][2] = a ∧ ∀ l ∈ 2 . . k − 1 : ∨ in′[i][l − 1][2] ≠ a ∨ in′[i][l − 1][1] = vc′[i][a]

Proof: Conjuncts in the consequent follow from corresponding conjuncts in the antecedent, using some arithmetic, and ⟨7⟩4 and ⟨7⟩5, and weakening the quantifier in the consequent.

⟨15⟩2. Q.E.D.

Proof: Follows directly from ⟨15⟩1 by the substitution j = (l − 1) in the quantifier in the consequent.

⟨14⟩2. Q.E.D.

Proof: Follows by existential generalisation over k − 1 in the consequent of ⟨14⟩1, and universal generalisation over k in the antecedent.

⟨13⟩2. Q.E.D.

Proof: Follows by propositional logic from ⟨13⟩1 by adding a disjunct to the antecedent which is inconsistent with the antecedent.

⟨12⟩2. Q.E.D.

Proof: Follows directly from ⟨6⟩2 on the disjunct in the antecedent of ⟨12⟩1. ⟨11⟩2. Q.E.D.

Proof: Follows substituting the symbols “FirstIsVC ” and “FirstIsVC′” for their definiens in ⟨11⟩1.

Second, the proof for a = Head(in[i])[2]. This requires all the hypotheses.

⟨10⟩2. ∧ i ∈ Proc

∧ HCacheUpdate(i) ∧ BetweenMemWrites(Head(in[i])[2]) ∧ FirstIsVC (Head(in[i])[2], i) ∧ LastIsMem(Head(in[i])[2], i) ⇒ ∨ FirstIsVC′(Head(in[i])[2], i) ∨ NoMemWrite′(Head(in[i])[2], i))

Proof:

We case-split on ∀ h ∈ 2 . . Len(in[i]) : ¬NotRefresh_{i}(h) and ∃ h ∈ 2 . . Len(in[i]) : NotRefresh_{i}(h). First, ∀ h ∈ 2 . . Len(in[i]) : ¬NotRefresh_{i}(h)

⟨11⟩1. ∧ i ∈ Proc

∧ HCacheUpdate(i) ∧ ∀ h ∈ 2 . . Len(in[i]) : ¬NotRefresh_{i}(h) ∧ LastIsMem(Head(in[i])[2], i) ⇒ NoMemWrite(Head(in[i])[2], i)

Proof:

We unpack the definition of LastIsMem.

⟨12⟩1. ∧ i ∈ Proc

∧ HCacheUpdate(i)

∧ ∀ h ∈ 2 . . Len(in[i]) : ¬NotRefresh_{i}(h)

∧ ∃ k ∈ 1 . . Len(in[i]) : NotRefresh_{i}(k) in[i][k][1] = mem[in[i][1][2]] in[i][k][2] = in[i][1][2] ∀ j ∈ (k + 1) . . Len(in[i]) : ∨ in[i][j ][2] ≠ Head(in[i])[2] ∨ in[i][j ][1] = mem[Head(in[i])[2]]

⇒ NoMemWrite(Head(in[i])[2], i) Proof:

We remove the quantifier from k, observe and instantiate k = 1 because all other values are ¬NotRefresh by hypothesis, and drop all the hypotheses we don’t need.

⟨13⟩1. ∧ i ∈ Proc

∧ HCacheUpdate(i)

∧ in[i][1][1] = mem[Head(in[i])[2]]

∧ ∀ j ∈ 2 . . Len(in[i]) : ∨ in[i][j ][2] ≠ Head(in[i])[2] ∨ in[i][j ][1] = mem[Head(in[i])[2]]

⇒ ∧ i ∈ Proc ∧ vc′[i][Head(in[i])[2]] = mem[Head(in[i])[2]] ∧ ∀ j ∈ 1 . . Len(in′[i]) : ∨ in′[i][j ][2] ≠ Head(in[i])[2] ∨ in′[i][j ][1] = mem′[Head(in[i])[2]]

Proof: Follows directly by substitution of vc′[i][Head(in[i])[2]] for in[i][1][1] using the definitions of Head and HCacheUpdate, and by substitution of the variable j ← (j − 1) and ⟨7⟩5 within the quantifier ∀ j to obtain the equivalent quantified expression in the conclusion.

⟨13⟩2. Q.E.D.

Proof: Direct from ⟨12⟩1 by adding hypotheses, and by substituting “NoMemwrite” for its definiens.

⟨12⟩2. Q.E.D.

Proof: By universal generalisation over k from ⟨11⟩1.

Second, ∃ h ∈ 2 . . Len(in[i]) : NotRefresh_{i}(h).

⟨11⟩2. ∧ i ∈ Proc

∧ HCacheUpdate(i)

∧ ∃ h ∈ 2 . . Len(in[i]) : NotRefresh_{i}(h)

∧ FirstIsVC (Head(in[i])[2], i)

∧ BetweenMemWrites(i)

⇒ FirstIsVC′(Head(in[i])[2], i)

Proof:

We use the choose function to select the least such h.

Let: l =^{Δ} choose h : ∧ h ∈ 2 . . Len(in[i]) ∧ NotRefresh_{i}(h) ∧ ∀ m ∈ 2 . . Len(in[i]) : NotRefresh_{i}(m) ⇒ h ≤ m ⟨12⟩1. ∃ h ∈ 2 . . Len(in[i]) : NotRefresh_{i}(h)

⇒ ∧ l ∈ 2 . . Len(in[i]) ∧ NotRefresh_{i}(l) ∧ ∀ m ∈ 2 . . Len(in[i]) : NotRefresh_{i}(m) ⇒ l ≤ m

Proof: Immediate from the definition of choose and the well-founded property of the Naturals, that there is a least Natural satisfying any non-empty predicate of Naturals.

⟨12⟩2. ∧ i ∈ Proc

∧ HCacheUpdate(i) ∧ l ∈ 2 . . Len(in[i]) ∧ NotRefresh_{i}(h) ∧ ∀ m ∈ 2 . . Len(in[i]) : NotRefresh_{i}(m) ⇒ l ≤ m ∧ FirstIsVC (Head(in[i])[2], i) ∧ BetweenMemWrites(i) ⇒ FirstIsVC′(Head(in[i])[2], i)

Proof:

We case split on NotRefresh_{i}(1). First, NotRefresh_{i}(1). We instantiate BetweenMemWrites as MemWritesFromTo(1, l, i).

⟨13⟩1. ∧ i ∈ Proc

∧ HCacheUpdate(i) ∧ l ∈ 2 . . Len(in[i]) ∧ NotRefresh_{i}(l) ∧ ∀ m ∈ 2 . . Len(in[i]) : NotRefresh_{i}(m) ⇒ l ≤ m ∧ NotRefresh_{i}(1) ∧ MemWritesFromTo(1, l, i) ⇒ ∧ NotRefresh′_{i}(l − 1) ∧ ∀ j ∈ 1 . . l − 1∨ in′[i][j ][2] ≠ Head(in[i])[2] ∨ in′[i][j ][1] = vc′[i][Head(in[i])[2]]

Proof: Immediate from ⟨7⟩5 and the definition of HCacheUpdate, by expanding the definition of MemWritesFromTo(1, l, i), using Modus Ponens, then substituting vc′[i][Head(in[i])[2]] for in[i][1][1] in the consequent, and renaming the quantified variable.

The second part for ¬NotRefresh_{i}(1) follows from FirstIsVC .

⟨13⟩2. ∧ i ∈ Proc

∧ HCacheUpdate(i) ∧ l ∈ 2 . . Len(in[i]) ∧ NotRefresh_{i}(l) ∧ ∀ m ∈ 2 . . Len(in[i]) : NotRefresh_{i}(m) ⇒ l ≤ m ∧ ¬NotRefresh_{i}(1) ∧ FirstIsVC (Head(in[i])[2], i) ⇒ ∧ NotRefresh′_{i}(l − 1) ∧ ∀ j ∈ 1 . . l − 1∨ in′[i][j ][2] ≠ Head(in[i])[2] ∨ in′[i][j ][1] = vc′[i][Head(in[i])[2]]

Proof: Immediate from ⟨7⟩5 by renaming the quantified variable. ⟨13⟩3. Q.E.D.

Proof: Immediate from ⟨13⟩1 and ⟨13⟩2 by propositional logic and then substituting “FirstIsVC′” for its definiens in the conclusion.

⟨12⟩3. Q.E.D.

Proof: Immediate from ⟨12⟩1 and ⟨12⟩2 by propositional logic. ⟨11⟩3. Q.E.D.

Proof: Immediate from ⟨11⟩1 ⟨11⟩2 by propositional logic, using the case-split which is a theorem of predicate logic.

⟨10⟩3. Q.E.D.

Proof: Immediate from ⟨10⟩1 and ⟨10⟩2 using ⟨6⟩2. ⟨9⟩5. Q.E.D.

Proof: Follows by propositional logic from ⟨9⟩1, ⟨9⟩2, ⟨9⟩3, and ⟨9⟩4.

Finally, the invariant CCInv(p) holds trivially for any process p ≠ i.

⟨8⟩4.

∧ i ∈ Proc ∧ HCacheUpdate(i)

∧ p ∈ Proc ∧ p ≠ i ∧ CCInv(p)

⇒ CCInv′(p) Proof: It is immediate from the definition of HCacheUpdate that in[p], vc[p], hin[p] and c[p] are unchanged by HCacheUpdate(i).

Hence we conclude that CCInv holds under HCacheUpdate(i), having shown the three components of CCInv(i), and CCInv(p) for p ≠ i.

⟨8⟩5. Q.E.D.

Proof: Follows immediately by propositional logic from ⟨8⟩1, ⟨8⟩2, ⟨8⟩3 and ⟨8⟩4. ⟨7⟩7. Q.E.D.

Proof: Immediate from ⟨3⟩3, ⟨7⟩6 and universal quantification.

The invariant is preserved by a HMemRead

⟨6⟩7. i ∈ Proc ∧ CCInv ∧ HMemRead(i) ⇒ CCInv′ Proof:

⟨7⟩1. ∧ i ∈ Proc

∧ HMemRead(i)

∧ p ∈ Proc

∧ p ≠ i

∧ CCInv(p)

⇒ CCInv′(p) Proof: By the definition of HMemRead, in[p], hin[p], vc, mem are all unchanged .

⟨7⟩2. i ∈ Proc ∧ CCInv(i) ∧ HMemRead(i) ⇒ CCInv′(i) Proof: ⟨8⟩1. i ∈ Proc∧HMemRead(i) ⇒ ∧ c′ = c ∧ vc′ = vc ∧ mem′ = mem ∧ out′ = out ∧ hout′ = out ∧ ∀ j ∈ Proc \{i} : hin′[j ] = hin[j ] ∧ ∀ j ∈ Proc \{i} : in′[j ] = in[j ] ∧ Len(hin′[i]) = Len(hin[i]) + 1 ∧ Len(in′[i]) = Len(in[i]) + 1 ∧ ∀ j ∈ 1 . . Len(in[i]) : in′[i][j ] = in[i][j ] ∧ in′[i][Len(in′[i])][1] = mem′[in′[i][Len(in′[i])][2]] ∧ ∀ j ∈ 1 . . Len(in[i]) : NotRefresh_{i}′(j ) ≡ NotRefresh_{i}(j ) ∧ ¬NotRefresh_{i}′(Len(in′[i])) ∧ Len(Len(in′[i])) = 2 ∧ hin′[Len(hin′[i])][2] ≠ “Wr”

Proof: Immediate from the definition of HMemRead. ⟨8⟩2. i ∈ Proc ∧ CCInv(i) ∧ HMemRead(i) ⇒ CCInv.1′(i)

Proof: Follows by logic from ⟨8⟩1. ⟨8⟩3. i ∈ Proc ∧ CCInv(i) ∧ HMemRead(i) ⇒ CCInv.2′(i)

Proof: Immediate from ⟨8⟩1. ⟨8⟩4. i ∈ Proc ∧ CCInv(i) ∧ HMemRead(i) ⇒ CCInv.3′(i)

Proof:

⟨9⟩1. i ∈ Proc ∧ HMemRead(i) ⇒

∀ j ∈ 1 . . Len(in′[i]) : ϕ(j ) ≡ (∀ j ∈ 1 . . Len(in[i]) : ϕ(j ) ∧ ϕ(Len(in′[i])) Proof: This is the quantifier-split property, as in the safety part of the proof, using Len(in′[i]) = Len(in[i]) + 1 from ⟨8⟩1.

⟨9⟩2. ∧ i ∈ Proc

∧ HMemRead(i)

∧ BetweenMemWrites(i)

⇒ BetweenMemWrites′(i) Proof:

We unpack the definition of BetweenMemWrites.

⟨10⟩1. ∧ i ∈ Proc

∧ HMemRead(i)

∧ MemWritesFromTo(m, n, i)

⇒ MemWritesFromTo′(m, n, i) Proof: Follows immediately by ⟨8⟩1 and the definition of 1 . . Len(in[i])

⟨10⟩2. ∧ i ∈ Proc

∧ HMemRead(i)

∧ m ∈ 1 . . Len(in′[i])

⇒ MemWritesFromTo′(m, Len(in′[i]), i) Proof: Follows immediately since the antecedent of MemWritesFromTo′ is false by ⟨8⟩1.

⟨10⟩3. Q.E.D.

Proof: Follows from ⟨10⟩1 and ⟨10⟩2 using ⟨9⟩1 and quantifying over m, n. ⟨9⟩3.

∧ HMemRead(i) ∧ a ∈ Addr ∧ LastIsMem(a, i)

⇒ LastIsMem′(a, i) Proof: Immediate from ⟨8⟩1 using ⟨9⟩1.

⟨9⟩4.

∧ HMemRead(i) ∧ a ∈ Addr ∧ FirstIsVC (a, i)

⇒ FirstIsVC′(a, i) Proof: Immediate from ⟨8⟩1 using ⟨9⟩1.

⟨9⟩5.

∧ HMemRead(i) ∧ a ∈ Addr ∧ NoMemWrite(a, i)

⇒ NoMemWrite′(a, i) Proof: Immediate from ⟨8⟩1 using ⟨9⟩1.

⟨9⟩6. Q.E.D.

Proof: Immediate from ⟨9⟩2, ⟨9⟩3, ⟨9⟩4 and ⟨9⟩5 using propositional logic and quantification over a.

⟨8⟩5. Q.E.D.

Proof: Immediate from ⟨8⟩2, ⟨8⟩3, and ⟨8⟩4 by propositional logic. ⟨7⟩3. Q.E.D.

Proof: Immediate from ⟨7⟩1 and ⟨7⟩2.

The invariant is preserved by a HCacheInval

⟨6⟩8. CCInv ∧ HCacheInval(i) ⇒ CCInv′ Proof: ⟨7⟩1. CCInv(i) ∧ HCacheInval(i) ⇒ CCInv′(i)

Proof: ⟨8⟩1. CCInv(i) ∧ HCacheInval(i) ⇒ CCInv.1′(i)

Proof: Immediate from the definition of HCacheInval since in, hin, out, hout are unchanged . ⟨8⟩2. CCInv(i) ∧ HCacheInval(i) ⇒ CCInv.2′(i)

Proof:

⟨9⟩1. x ∈ Restrict(y) ∧ y ∈ Restrict(z) ⇒ x ∈ Restrict(z)

Proof: Property of Restrict assumed without further proof. ⟨9⟩2. Q.E.D.

Follows from the definition of HCacheInval and ⟨9⟩1 with x ← c′[i], y ← c[i] and z = vc′[i] = vc[i] from the definition of HCacheInval.

⟨8⟩3. CCInv(i) ∧ HCacheInval(i) ⇒ CCInv.3′(i)

Proof: Immediate from the definition of HCacheInval since in, hin, mem, vc are unchanged . ⟨8⟩4. Q.E.D.

Proof: Immediate from ⟨8⟩1,⟨8⟩2 and ⟨8⟩3. ⟨7⟩2.

∧ HCacheInval(i)

∧ p ∈ Proc

∧ p ≠ i

∧ CCInv(p)

⇒ CCInv′(p) Proof: Immediate from the definition of HCacheInval, since in, hin, mem, vc, c[p] are unchanged .

⟨7⟩3. Q.E.D.

Proof: Immediate from ⟨7⟩1 and ⟨7⟩2.

That completes the proof of the invariant action by action.

⟨6⟩9. Q.E.D.

Proof: ⟨5⟩1 follows by propositional logic and existential quantification over i from ⟨6⟩3, ⟨6⟩4, ⟨6⟩5, ⟨6⟩6, ⟨6⟩7, and ⟨6⟩8.

So one may use TLA rule INV1 to infer the □ conclusion.

⟨5⟩2. Q.E.D.

Proof: Immediate from ⟨5⟩1 by TLA rule INV1.

And finally, trivial propositional logic to conclude the invariant holds.

⟨4⟩3. Q.E.D.

Proof: Follows by propositional logic from ⟨4⟩1 and ⟨4⟩2.

We now use the invariant and the safety property of LazyCache (actually, of the version with history variables) to prove the safety property of CCache. First, a general logical property of sets.

⟨3⟩6. ∀ x ∈ S : ϕ ∧ T ⊂ S ⇒ ∀ x ∈ T : ϕ

Proof: This is general logic and set theory, which we assume without further proof.

⟨3⟩7. ∧ □CCInv

∧ □[∃ i ∈ Proc : HOp(i)]_{hvars} ⇒ □[\overline{∃ i ∈ Proc : CC (cc, cin, cout).Next(i)}]\overline{⟨cc,cin,cout,ch ⟩}

Proof: ⟨4⟩1. □CCInv ⇒ □[∃ i ∈ Proc : HOp(i)]_{hvars} ≡ □[∃ i ∈ Proc : HOp(i) ∧ CCInv ∧ CCInv′]_{hvars}

Proof: Immediate from TLA rule INV2. ⟨4⟩2. □[\begin{matrix}∧ ∃ i ∈ Proc : HOp(i) \\ ∧ CCInv \\ ∧ CCInv′]_{hvars} \end{matrix}

⇒ □[\overline{∃ i ∈ Proc : CC (cc, cin, cout).Next(i)}]\overline{⟨cc,cin,cout,ch ⟩} Proof: ⟨5⟩1. [\begin{matrix}∧ ∃ i ∈ Proc : HOp(i) \\ ∧ CCInv \\ ∧ CCInv′]_{hvars} \end{matrix}

⇒ [\overline{∃ i ∈ Proc : CC (cc, cin, cout).Next(i)}]\overline{⟨cc,cin,cout,ch ⟩} Proof: ⟨6⟩1. hvars′ = hvars ⇒ \overline{⟨cc, cin, cout, ch ⟩}′ = \overline{⟨cc, cin, cout, ch ⟩}

Proof: Immediate since the latter are state functions of the former variables.

HRead simulates \overline{CC (cc, cin, cout).Read}.

⟨6⟩2. ∧ i ∈ Proc

∧ HRead(i, d, a) ∧ CCInv ∧ CCInv′ ⇒ \overline{CC (cc, cin, cout).Read}(i, d, a)

Proof:

We expand the definitions.

⟨7⟩1. ∧ i ∈ Proc

∧ CCInv ∧ CCInv′ ∧ out[i] = ⟨ ⟩ ∧ ∀ j ∈ 1 . . Len(in[i]) : Len(in[i][j ]) = 2 ∧ c[i][a] = d ∧ ChanOp(ch[i], ⟨i, “Rd”, d, a ⟩) ∧ ∀ j ∈ Proc \{i} : unchanged ch[j ] ∧ unchanged ⟨c, in, out, mem, hin, hout, vc ⟩ ⇒ ∧ hout[i] = ⟨ ⟩ ∧ ∀ j ∈ (1 . . Len(\overline{cin}[i])) : \overline{cin}[i][j ][1] ≠ i ∧ vc[i][a] = d ∧ ChanOp(ch[i], ⟨i, “Rd”, d, a ⟩) ∧ ∀ j ∈ Proc \\{i\} : unchanged ch[j ] ∧ unchanged ⟨vc, \overline{cin}, hout ⟩

Proof: It follows from out[i] = ⟨ ⟩ that Len(out[i]) = 0 and by CCInv.1 that thus Len(hout[i]) = 0 and so that hout[i] = ⟨ ⟩. From ∀ j ∈ 1 . . Len(in[i]) : Len(in[i][j ]) = 2 it follows that ∀ j ∈ 1 . . Len(hin[i]) : hin[i][j ][1] = i ⇒ hin[i][j ][2] ≠ “Wr” and thus from ⟨3⟩6 and the definition of SelectSeq and the definition of \overline{cin} that ∀ j ∈ 1 . . Len(\overline{cin}[i]) : \overline{cin}[i][j ][1] ≠ i. The other conjuncts of the consequent all follow directly from hypotheses.

⟨7⟩2. Q.E.D. Proof: Immediate from ⟨7⟩1.

HWrite simulates \overline{CC (cc, cin, cout).Write}.

⟨6⟩3. i ∈ Proc ∧ HWrite(i) ⇒ \overline{CC (cc, cin, cout).Write}(i) Proof:

⟨7⟩1. ∧ i ∈ Proc

∧ ChanOp(ch[i], ⟨i, “Wr”, d, a ⟩) ∧ out′ = [out except ![i] = out[i] ∘ ⟨⟨d, a ⟩⟩] ∧ ∀ j ∈ Proc \{i} : unchanged ch[j ] ∧ unchanged ⟨c, in, mem ⟩ ∧ hout′ = [hout except ![i] = hout[i] ∘ ⟨⟨i, “Wr”, d, a ⟩⟩] ∧ unchanged ⟨vc, hin ⟩ ⇒ ∧ ChanOp(ch[i], ⟨i, “Wr”, d, a ⟩) ∧ hout′ = [hout except ![i] = hout[i] ∘ ⟨⟨i, “Wr”, d, a ⟩⟩] ∧ ∀ j ∈ Proc \\{i\} : unchanged ch[j ] ∧ unchanged ⟨vc, \overline{cin} ⟩

Proof: Immediate, observing that since \overline{cin} is a state function of hin, unchanged hin ⇒ unchanged \overline{cin}.

⟨7⟩2. Q.E.D. Proof: Immediate from ⟨7⟩1.

HMemWrite simulates \overline{CC (cc, cin, cout).MemWrite}.

⟨6⟩4. ∧ i ∈ Proc

∧ HMemWrite(i) ∧ CCInv ∧ CCInv′ ⇒ \overline{CC (cc, cin, cout).MemWrite}(i)

Proof:

⟨7⟩1. ∧ CCInv.1(i)

∧ CCInv.1′(i) ∧ out[i] ≠ ⟨ ⟩ ∧ out′ = [out except ![i] = Tail(out[i])] ∧ in′ = [j ∈ Proc ↦ in[j ] ∘ if j = i then ⟨Head(out[i]) ∘ ⟨“∗”⟩⟩ else ⟨Head(out[i])⟩ ]

∧ mem′ = [mem except ![Head(out[i])[2]] = Head(out[i])[1] ] ∧ unchanged ⟨c, ch ⟩ ∧ hin′ = [j ∈ Proc ↦ hin[j ] ∘ ⟨⟨i, “Wr”⟩ ∘ Head(out[i])⟩] ∧ hout′ = [hout except ![i] = Tail(hout[i])] ∧ unchanged vc ⇒ ∧ hout[i] ≠ ⟨ ⟩ ∧ hout′ = [hout except ![i] = Tail(hout[i])] ∧ \overline{cin}′ = [j ∈ Proc ↦ \overline{cin}[j ] ∘ ⟨Head(hout[i])⟩] ∧ unchanged ⟨vc, ch ⟩

Proof: From the hypotheses, in′[i] = in[i]∘⟨Head(out[i])∘⟨“∗”⟩⟩ thus Len(Len(in′[i])) = 3 thus by CCInv.1′, hin′[i][Len(hin′[i])][2] = “Wr” thus by definition of SelectSeq, \overline{cin}′ = \overline{cin} ∘ ⟨Head(hout[i])⟩. The other clauses follow directly from the hypotheses.

⟨7⟩2. Q.E.D. Proof: Immediate from ⟨7⟩1.

HCacheUpdate simulates either \overline{CC (cc, cin, cout).CacheUpdate}, in case that Head(in[i]) is not a cache refresh, or a no-op in case it is.

⟨6⟩5. ∧ i ∈ Proc

∧ HCacheUpdate(i) ∧ CCInv ∧ CCInv′ ⇒ [\overline{CC (cc, cin, cout).CacheUpdate}(i)]\overline{⟨cc,cin,cout,ch ⟩}

Proof:

⟨7⟩1. ∧ i ∈ Proc

∧ CCInv ∧ CCInv′ ∧ in[i] ≠ ⟨ ⟩ ∧ in′ = [in except ![i] = Tail(in[i])] ∧ c′ = [c except ![i][Head(in[i])[2]] = Head(in[i])[1] ] ∧ unchanged ⟨out, ch, mem ⟩ ∧ hin′ = [hin except ![i] = Tail(hin[i])] ∧ vc′ = [vc except ![i][Head(in[i])[2]] = Head(in[i])[1]] ∧ unchanged hout ⇒ ∧ ∨ ∧ \overline{cin}[i] ≠ ⟨ ⟩ ∧ \overline{cin}′ = [\overline{cin} except ![i] = Tail(\overline{cin}[i])] ∧ vc′ = [vc except ![i][Head(\overline{cin}[i])[4]] = Head(\overline{cin}[i])[3]] ∨ unchanged ⟨\overline{cin}, vc ⟩ ∧ unchanged ⟨hout, ch ⟩

Proof:

We case-split on NotRefresh(Head(in[i])). First, the case in which NotRefresh(Head(in[i])).

⟨8⟩1. ∧ i ∈ Proc

∧ CCInv ∧ CCInv′ ∧ in[i] ≠ ⟨ ⟩ ∧ NotRefresh(Head(in[i])) ∧ in′ = [in except ![i] = Tail(in[i])] ∧ c′ = [c except ![i][Head(in[i])[2]] = Head(in[i])[1] ] ∧ unchanged ⟨out, ch, mem ⟩ ∧ hin′ = [hin except ![i] = Tail(hin[i])] ∧ vc′ = [vc except ![i][Head(in[i])[2]] = Head(in[i])[1]] ∧ unchanged hout ⇒ ∧ \overline{cin}[i] ≠ ⟨ ⟩ ∧ \overline{cin}′ = [\overline{cin} except ![i] = Tail(\overline{cin}[i])] ∧ vc′ = [vc except ![i][Head(\overline{cin}[i])[4]] = Head(\overline{cin}[i])[3]] ∧ unchanged ⟨hout, ch ⟩

Proof: Immediate from the definition of SelectSeq that \overline{cin} = Head(in[i])∘SelectSeq(Tail(hin[i]), P[2] ≠ “Rd”) and the consequent follows by equality manipulation.

Second, the case in which ¬NotRefresh(Head(in[i])).

⟨8⟩2. ∧ i ∈ Proc

∧ CCInv ∧ CCInv′ ∧ in[i] ≠ ⟨ ⟩ ∧ ¬NotRefresh(Head(in[i])) ∧ in′ = [in except ![i] = Tail(in[i])] ∧ c′ = [c except ![i][Head(in[i])[2]] = Head(in[i])[1] ] ∧ unchanged ⟨out, ch, mem ⟩ ∧ hin′ = [hin except ![i] = Tail(hin[i])] ∧ vc′ = [vc except ![i][Head(in[i])[2]] = Head(in[i])[1]] ∧ unchanged hout ⇒ ∧ unchanged ⟨\overline{cin}, vc ⟩ ∧ unchanged ⟨hout, ch ⟩

Proof: By FirstIsVC , vc[Head(in[i])[2]] = Head(in[i])[1] = vc′[Head(in[i])[2]] by definition of HCacheUpdate. By NoMemWrite, the same follows with a little equality reasoning. By case-splitting on these two cases of the invariant, it follows that unchanged vc. It follows from definition of SelectSeq and ¬NotRefresh(Head(in[i])) that SelectSeq(hin[i], P[2] ≠ “Rd”) = SelectSeq(Tail(hin[i]), P[2] ≠ “Rd”) and thus unchanged \overline{cin}.

⟨8⟩3. Q.E.D.

Proof: Follows by propositional logic from ⟨8⟩1 and ⟨8⟩2. ⟨7⟩2. Q.E.D.

Proof: Immediate from ⟨7⟩1.

HMemRead simulates a no-op.

⟨6⟩6. ∧ i ∈ Proc

∧ HMemRead(i) ∧ CCInv ∧ CCInv′ ⇒ unchanged \overline{⟨cc, cin, cout, ch ⟩}

Proof:

⟨7⟩1. ∧ i ∈ Proc

∧ ∃ a ∈ Addr : in′ = [in except ![i] = in[i] ∘ ⟨⟨mem[a], a ⟩⟩]

∧ unchanged ⟨out, c, mem, ch ⟩ ∧ hin′ = [hin except ![i] = hin[i] ∘ ⟨⟨i, “Rd”⟩⟩] ∧ unchanged vc, hout ⇒ unchanged ⟨ch, vc, hout, \overline{cin} ⟩

Proof: Since hin′[i][Len(hin′[i])][2] = “Rd”, by definition of \overline{cin}, hin′[i][Len(hin′[i])] is not appended to \overline{cin} by HMemRead(i) and thus unchanged \overline{cin}. The other unchanged variables are so stated in the antecedent.

⟨7⟩2. Q.E.D. Proof: Immediate from ⟨7⟩1.

HCacheInval simulates a no-op.

⟨6⟩7. ∧ i ∈ Proc

∧ HCacheInval(i) ∧ CCInv ∧ CCInv′ ⇒ unchanged \overline{⟨cc, cin, cout, ch ⟩}

Proof:

⟨7⟩1. ∧ i ∈ Proc

∧ c′ ∈ {[c except ![i] ∈ Restrict(c[i])]} ∧ unchanged ⟨in, out, mem, ch ⟩ ∧ unchanged ⟨vc, hin, hout ⟩ ⇒ unchanged ⟨ch, vc, hout, \overline{cin} ⟩

Proof: Immediate. The variables ch, vc, hout are unchanged by hypothesis, and \overline{cin} is a state function of hin, which is unchanged by the hypothesis.

⟨7⟩2. Q.E.D.

Proof: Immediate from ⟨7⟩1.

From the individual step simulations, we conclude that the machine step-simulation is valid.

⟨6⟩8. Q.E.D.

Proof: Immediate from ⟨6⟩1, ⟨6⟩2, ⟨6⟩3, ⟨6⟩4, ⟨6⟩5, ⟨6⟩6, and ⟨6⟩7 by propositional logic.

This has shown the core mathematical part of the safety proof. Now we may apply TLA rules and propositional logic to show the safety assertion ⟨3⟩7.

⟨5⟩2. Q.E.D.

Proof: Immediate by TLA rule STL4. ⟨4⟩3. Q.E.D.

Proof: Follows by propositional logic from ⟨4⟩1 and ⟨4⟩2.

We show the liveness properties by use of the TLA rule WF2.

⟨3⟩8.

∧ HInit ∧ □[∃ i ∈ Proc : HOp(i)]_{hvars} ∧ ∀ i ∈ Proc : WF_{hvars}(HCacheUpdate(i)) ∧ ∀ i ∈ Proc : WF_{hvars}(HMemWrite(i)) ⇒ ∧ ∀ i ∈ Proc : \overline{WF_{⟨cc,cin,cout,ch ⟩}(CC (cc, cin, cout).CacheUpdate(i))} ∧ ∀ i ∈ Proc : \overline{WF_{⟨cc,cin,cout,ch ⟩}(CC (cc, cin, cout).MemWrite(i))}

Proof:

Liveness of \overline{CC (cc, cin, cout).MemWrite} is easy, since it is direcly simulated by HMemWrite, and since the Enabled conditions of both are the same. First, a general trivial lemma.

⟨4⟩1. CCInv ∧ CCInv′ ∧ ¬unchanged hvars ⇒ ¬unchanged ⟨cc, cin, cout, ch ⟩ Proof: This is immediate from the definitions of the variables, and also that hin, hout, vc change when in, out, c change, from CCInv ∧ CCInv′.

⟨4⟩2.

∧ HInit ∧ □[∃ i ∈ Proc : HOp(i)]_{hvars} ∧ ∀ i ∈ Proc : WF_{hvars}(HMemWrite(i)) ⇒ ∀ i ∈ Proc : \overline{WF_{⟨cc,cin,cout,ch ⟩}(CC (cc, cin, cout).MemWrite(i))}

Proof:

First, we instantiate the quantifier

⟨5⟩1.

∧ HInit ∧ □[∃ i ∈ Proc : HOp(i)]_{hvars} ∧ WF_{hvars}(HMemWrite(p)) ∧ p ∈ Proc ⇒ ∧ p ∈ Proc ∧ \overline{WF_{⟨cc,cin,cout,ch ⟩}(CC (cc, cin, cout).MemWrite(p))}

Proof:

⟨6⟩1. ∧ p ∈ Proc

∧ CCInv ∧ CCInv′ ∧ ⟨HMemWrite(p)⟩_{hvars} ⇒ ⟨\overline{CC (cc, cin, cout).MemWrite(p)}⟩\overline{⟨cc,cin,cout,ch ⟩}

Proof: The substance of this was shown already in the step simulation in ⟨3⟩7, and the variable change follows from ⟨4⟩1.

⟨6⟩2. ∧ p ∈ Proc

∧ CCInv ∧ CCInv′ ∧ ⟨HMemWrite(p)⟩_{hvars} ∧ \overline{Enabled⟨CC (cc, cin, cout).MemWrite(p)⟩_{⟨cc,cin,cout,ch ⟩}} ⇒ ∧ ⟨HMemWrite(p)⟩_{hvars} ∧ p ∈ Proc ∧ CCinv ∧ CCInv′

Proof: Immediate by propositional logic.

⟨6⟩3. ∧ CCInv

∧ \overline{Enabled⟨CC (cc, cin, cout).MemWrite(p)⟩_{⟨cc,cin,cout,ch ⟩}} ⇒ Enabled⟨HMemWrite(p)⟩_{hvars}

Proof:

⟨7⟩1. ∧ CCInv

∧ ∃ x, y : ∧ hout[p] ≠ ⟨ ⟩ ∧ x = [hout except ![p] = Tail(hout[p])] ∧ y = [j ∈ Proc ↦ \overline{cin}[j ] ∘ ⟨Head(hout[p])⟩] ∧ unchanged ⟨vc, ch ⟩

∧ ¬unchanged ⟨vc, \overline{cin}, hout, ch ⟩ ⇒ ∧ ∃ x, v, z, w, u : ∧ out[p] ≠ ⟨ ⟩ ∧ v = [out except ![p] = Tail(out[p])] ∧ z = [j ∈ Proc ↦ in[j ] ∘ if j = p then ⟨Head(out[p]) ∘ ⟨“∗”⟩⟩ else ⟨Head(out[p])⟩ ] ∧ w = [mem except ![Head(out[p])[2]] = Head(out[p])[1] ] ∧ unchanged ⟨c, ch ⟩ ∧ u = [j ∈ Proc ↦ hin[j ] ∘ ⟨⟨p, “Wr”⟩⟩] ∧ x = [hout except ![p] = Tail(hout[p])] ∧ unchanged vc ∧ hvars′ ≠ hvars

Proof: All the values of the new variables are functions of the values of state variables, so they exist. The ¬unchanged clause follows from the similar one in the hypothesis, and out[i] ≠ ⟨ ⟩ follows from hout[i] ≠ ⟨ ⟩.

⟨7⟩2. Q.E.D.

Proof: Immediate from ⟨7⟩1. ⟨6⟩4. □CCInv ⇒ ◇□CCInv

Proof: Immediate by the contraposition of STL2. ⟨6⟩5. Q.E.D.

Proof: For fixed p, immediate by TLA rule WF2 from ⟨6⟩1, ⟨6⟩2, and ⟨6⟩3 with A =^{Δ} HMemWrite(p),

f =^{Δ} hvars,

B =^{Δ} p ∈ Proc ∧ A ∧ CCInv ∧ CCInv′, M =^{Δ} CC (cc, cin, cout, ch).MemWrite(p), g =^{Δ} ⟨cc, cin, cout, ch ⟩, P =^{Δ} p ∈ Proc ∧ CCInv.

⟨5⟩2. Q.E.D.

Proof: Immediate by quantification over p from ⟨5⟩1.

Liveness of \overline{CC (cc, cin, cout).CacheUpdate} is a little more involved, since its Enabled condition and that of HCacheUpdate differ.

⟨4⟩3.

∧ HInit ∧ □[∃ i ∈ Proc : HOp(i)]_{hvars} ∧ ∀ i ∈ Proc : WF_{hvars}(HCacheUpdate(i)) ⇒ ∀ i ∈ Proc : \overline{WF_{⟨cc,cin,cout,ch ⟩}(CC (cc, cin, cout).CacheUpdate(i))}

Proof:

First, we instantiate the quantifier.

⟨5⟩1.

∧ HInit ∧ □[∃ i ∈ Proc : HOp(i)]_{hvars} ∧ WF_{hvars}(HCacheUpdate(p)) ∧ p ∈ Proc ⇒ ∧ p ∈ Proc ∧ \overline{WF_{⟨cc,cin,cout,ch ⟩}(CC (cc, cin, cout).CacheUpdate(p))}

Proof:

First, a general formula that follows by obvious calculation. The other substeps are the four premisses of an instance of WF2 to which ⟨5⟩1 is the conclusion.

⟨6⟩1.

∧ p ∈ Proc ∧ \overline{Enabled⟨CC (cc, cin, cout).CacheUpdate(p)⟩_{⟨cc,cin,cout,ch ⟩}} ≡ p ∈ Proc ∧ ∃ c ∈ 1 . . Len(in[i]) : NotRefresh_{p}(c)

∧ p ∈ Proc ∧ Enabled⟨HCacheUpdate(p)⟩_{hvars} ≡ p ∈ Proc ∧ NotRefresh_{p}(1) Proof: This follows by direct calculation.

Now, the first three premisses of WF2.

⟨6⟩2. ∧ p ∈ Proc

∧ ⟨NotRefresh_{p}(1) ∧ HCacheUpdate(p)⟩_{hvars} ⇒ ⟨\overline{CC (cc, cin, cout).CacheUpdate(p)}⟩\overline{⟨cc,cin,cout,ch ⟩}

Proof: The substance of this was shown already in the step simulation in ⟨3⟩7, and the variable change follows from ⟨4⟩1.

⟨6⟩3. ∧ p ∈ Proc

∧ NotRefresh_{p}(1) ∧ ⟨HCacheUpdate(p)⟩_{hvars} ∧ \overline{Enabled⟨CC (cc, cin, cout).CacheUpdate(p)⟩_{⟨cc,cin,cout,ch ⟩}} ⇒ ∧ ⟨HCacheUpdate(p)⟩_{hvars} ∧ p ∈ Proc ∧ NotRefresh_{p}(1)

Proof: Immediate by propositional logic. ⟨6⟩4.

∧ NotRefresh_{p}(1) ∧ \overline{Enabled⟨CC (cc, cin, cout).CacheUpdate(p)⟩_{⟨cc,cin,cout,ch ⟩}} ⇒ Enabled⟨HCacheUpdate(p)⟩_{hvars}

Proof: Immediate by ⟨6⟩1 and propositional logic.

The fourth premiss of WF2 is now proved, first by a manipulation in temporal logic, and then as the conclusion of an instance of the Lattice Rule.

⟨6⟩5.

∧ □[∃ i ∈ Proc : HOp(i) ∧ ¬(\begin{matrix}∧ p ∈ Proc \\ ∧ HCacheUpdate(p) \\ ∧ NotRefresh_{p}(1))]_{hvars} \end{matrix}

∧ WF_{hvars}(HCacheUpdate_{p}) ∧ ◇□\overline{Enabled⟨CC (cc, cin, cout).CacheUpdate(p)⟩_{⟨cc,cin,cout,ch ⟩}} ⇒ ◇□(p ∈ Proc ∧ NotRefresh_{p}(1))

Proof:

We first reduce the consequent by temporal logic, then consider it as the conclusion of the Lattice Rule to reduce it further to the Lattice Rule premiss which we prove using WF1. The Bridge Rule from [Lad95] is used to obtain ⟨6⟩5 from the conclusion of the Lattice Rule below. The Bridge Rule is strictly not a TLA proof, since it is not a valid TLA statement. It is rather a meta-statement that a certain rule of proof is a valid derived TLA inference rule. It’s thus technically a meta-step, not a proof step. I argued in [Lad95] that such meta-steps were appropriate in a TLA proof.

First, the statement of the Bridge Rule.

Let: X , Y , Z : propositional variable

⟨7⟩1. \frac{\begin{matrix}□X ∧ Y ⇒ □Y \\ □X ⇒ □(Z ⇒ ◇Y ) \end{matrix}}{□X ∧ ◇□Z ⇒ ◇□Y}

Proof sketch: See [Lad95, Page 46] for the proof.

We prove the first Bridge-rule premiss, that NotRefresh is invariant under the hypotheses. This uses TLA rule INV1.

⟨7⟩2.

∧ □[∃ i ∈ Proc : HOp(i) ∧ ¬(\begin{matrix}∧ p ∈ Proc \\ ∧ HCacheUpdate(p) \\ ∧ NotRefresh_{p}(1))]_{hvars} \end{matrix}

∧ WF_{hvars}(HCacheUpdate_{p}) ∧ (p ∈ Proc ∧ NotRefresh_{p}(1)) ⇒ □(p ∈ Proc ∧ NotRefresh_{p}(1))

Proof: ⟨8⟩1.

∧ [∃ i ∈ Proc : HOp(i) ∧ ¬(\begin{matrix}∧ p ∈ Proc \\ ∧ HCacheUpdate(p) \\ ∧ NotRefresh_{p}(1))]_{hvars} \end{matrix}

∧ (p ∈ Proc ∧ NotRefresh_{p}(1))

⇒

(p ∈ Proc ∧ NotRefresh′_{p}(1)) Proof: Immediate from the definitions of HOp, since HCacheUpdate is the only operation which changes hin[p][1], and it follows by trivial propositional logic from the hypotheses that HCacheUpdate is false. Hence hin[p][1] is unchanged .

⟨8⟩2. Q.E.D.

Proof: Immediate by INV1 from ⟨8⟩1, and then strengthening the hypothesis. ⟨7⟩3.

∧ □[∃ i ∈ Proc : HOp(i) ∧ ¬(\begin{matrix}∧ p ∈ Proc \\ ∧ HCacheUpdate(p) \\ ∧ NotRefresh_{p}(1))]_{hvars} \end{matrix}

∧ WF_{hvars}(HCacheUpdate_{p}) ⇒ \overline{Enabled⟨CC (cc, cin, cout).CacheUpdate(p)⟩_{⟨cc,cin,cout,ch ⟩}} ⇝ (p ∈ Proc∧NotRefresh_{p}(1))

Proof:

The substep is the premiss of the Lattice Rule.

Let: c : constant ⟨8⟩1.

∧ □[∃ i ∈ Proc : HOp(i) ∧ ¬(\begin{matrix}∧ p ∈ Proc \\ ∧ HCacheUpdate(p) \\ ∧ NotRefresh_{p}(1))]_{hvars} \end{matrix}

∧ WF_{hvars}(HCacheUpdate_{p})

∧ c ∈ 1 . . Len(in[i]) ⇒

NotRefresh_{p}(c) ⇝ ∨ ∃ d ∈ 1 . . Len(in[i]) : d < c ∧ NotRefresh_{p}(d) ∨ p ∈ Proc ∧ NotRefresh_{p}(1)

Proof:

The three substeps are the three premises of an instance of WF1 to which ⟨8⟩1 is the conclusion.

⟨9⟩1. ∧ p ∈ Proc

∧ NotRefresh_{p}(c) ∧ [∃ i ∈ Proc : HOp(i) ∧ ¬(\begin{matrix}∧ p ∈ Proc \\ ∧ HCacheUpdate(p) \\ ∧ NotRefresh_{p}(1))]_{hvars} \end{matrix}

⇒ p ∈ Proc ∧ ∨ NotRefresh′_{p}(c) ∨ ∃ d ∈ 1 . . Len(in′[i]) : d < c ∧ NotRefresh′_{p}(d) ∨ NotRefresh′_{p}(1)

Proof:

⟨10⟩1. ∧ p ∈ Proc

∧ NotRefresh_{p}(c)

∧ [∃ i ∈ Proc : HOp(i) ∧ ¬HCacheUpdate(p)]_{hvars} ⇒ p ∈ Proc ∧ NotRefresh′_{p}(c)

Proof: Immediate from definitions of the operations, and results about HCacheUpdate in ⟨3⟩7.

⟨10⟩2. ∧ p ∈ Proc

∧ NotRefresh_{p}(c) ∧ ¬HCacheUpdate(p) ∧ ¬NotRefresh_{p}(1) ⇒ ∧ c ∈ 2 . . Len(in[i]) ∧ NotRefresh′_{p}(c − 1)

Proof: Immediate from propositional logic, and results about HCacheUpdate in ⟨3⟩7.

⟨10⟩3. Q.E.D.

Proof: Follows by propositional logic from ⟨10⟩1 and ⟨10⟩2. ⟨9⟩2. NotRefresh_{p}(c)

⟨\begin{matrix}∧ ∃ i ∈ Proc : HOp(i) \\ ∧ ¬(\begin{matrix}∧ p ∈ Proc \\ ∧ HCacheUpdate(p) \\ ∧ NotRefresh_{p}(1)) \end{matrix} \\ ∧ HCacheUpdate(p)⟩_{hvars} \end{matrix}

⇒ ∨ ∃ d ∈ 1 . . Len(in′[i]) : d < c ∧ NotRefresh′_{p}(d) ∨ p ∈ Proc ∧ NotRefresh′_{p}(1)

Proof:

First, we reduce the premiss.

⟨10⟩1. ∧ NotRefresh_{p}(c) ∧ p ∈ Proc ∧ HCacheUpdate(p) ∧ ¬NotRefresh_{p}(1) ∧ ¬unchanged hvars ⇒ ∨ ∃ d ∈ 1 . . Len(in′[i]) : d < c ∧ NotRefresh′_{p}(d) ∨ p ∈ Proc ∧ NotRefresh′_{p}(1)

Proof:

Then, everything follows easily by what’s known for HCacheUpdate from ⟨3⟩7.

⟨11⟩1. ∧ NotRefresh_{p}(c) ∧ p ∈ Proc ∧ HCacheUpdate(p) ∧ ¬NotRefresh_{p}(1) ∧ ¬unchanged hvars ⇒ ∧ p ∈ Proc ∧ NotRefresh_{p}(c) ∧ c ∈ 2 . . Len(in[i]) ∧ HCacheUpdate(p)

Proof: Immediate by propositional logic and quantifier-case-splitting.

⟨11⟩2. ∧ p ∈ Proc ∧ NotRefresh_{p}(c) ∧ c ∈ 2 . . Len(in[i]) ∧ HCacheUpdate(p) ⇒ NotRefresh′_{p}(c − 1)

Proof: Immediate from results in ⟨3⟩7. ⟨11⟩3. Q.E.D.

Proof: Immediate from ⟨11⟩1 and ⟨11⟩2 and existential generalisation over c −1 and propositional logic.

⟨10⟩2. Q.E.D.

Proof: Immediate by propositional logic. ⟨9⟩3. p ∈ Proc ∧ NotRefresh_{p}(c) ⇒ p ∈ Proc ∧ ∃ d ∈ 1 . . Len(in[i]) : NotRefresh_{p}(d)

Proof: Immediate by existential generalisation. ⟨9⟩4. Q.E.D.

Proof: (Almost) immediate from WF1 with the obvious substitution. Observe that c ∈ 1 . . Len(in[p]) is a conjunct of NotRefresh_{P}(c) which is a conjunct of the consequent. Thus we have added c ∈ 1 . . Len(in[p]) to the hypotheses and retained an equivalent formula to the conclusion of WF2 from ⟨9⟩1, ⟨9⟩2 and ⟨9⟩3.

⟨8⟩2. Q.E.D.

Proof: Follows immediately from ⟨8⟩1 by the Lattice Rule with

G =^{Δ} NotRefresh_{p}(1) H_{c} =^{Δ} NotRefresh_{p}(c) ≻ =^{Δ} >, S =^{Δ} 1 . . Len(in[p]), F =^{Δ} the other hypotheses and using ⟨6⟩1.

⟨7⟩4. Q.E.D.

Proof: Follows by the Bridge Rule, ⟨7⟩1, from ⟨7⟩2 and ⟨7⟩3 with substitutions □X =^{Δ} ∧ □[∃ i ∈ Proc : HOp(i) ∧ ¬(\begin{matrix}∧ p ∈ Proc \\ ∧ HCacheUpdate(p) \\ ∧ NotRefresh_{p}(1))]_{hvars} \end{matrix} ∧ WF_{hvars}(HCacheUpdate_{p})

Y =^{Δ} (p ∈ Proc ∧ NotRefresh_{p}(1))

Z =^{Δ} \overline{Enabled⟨CC (cc, cin, cout).CacheUpdate(p)⟩_{⟨cc,cin,cout,ch ⟩}}. ⟨6⟩6. Q.E.D.

Proof: For fixed p, immediate by TLA rule WF2 from ⟨6⟩2, ⟨6⟩3, and ⟨6⟩4 with A =^{Δ} HCacheUpdate(p),

f =^{Δ} hvars,

B =^{Δ} p ∈ Proc ∧ A ∧ NotRefresh_{p}(1), M =^{Δ} CC (cc, cin, cout, ch).CacheUpdate(p), g =^{Δ} ⟨cc, cin, cout, ch ⟩, P =^{Δ} p ∈ Proc ∧ NotRefresh_{p}(1).

⟨5⟩2. Q.E.D.

Proof: Immediate by quantification over p from ⟨5⟩1. ⟨4⟩4. Q.E.D.

Proof: Immediate by propositional logic from ⟨4⟩2 and ⟨4⟩3.

⟨3⟩9. ∧ HInit

∧ □[∃ i ∈ Proc : HOp(i)]_{hvars} ∧ Live ⇒ ∧ \overline{CC (cc, cin, cout).Init} ∧ □[\overline{∃ i ∈ Proc : CC (cc, cin, cout).Next(i)}]\overline{⟨cc,cin,cout,ch ⟩} ∧ \overline{Live}

Proof: ⟨3⟩9 follows from ⟨3⟩4, ⟨3⟩5, ⟨3⟩7 and ⟨3⟩8 by propositional logic. ⟨3⟩10. Q.E.D.

The theorem follows by existential quantification over the free variables in ⟨3⟩9.

Acknowledgements

Many thanks (and honorary membership of the Schadenfreude Society of Palo Alto) to Leslie Lamport, for showing me how to do TLA proofs and insisting I practice on this one. Thankyou also to Denis Roegel for reviewing my first versions of this proof and suggested necessary changes.

References

[ABM93] Yehuda Afek, Geoffrey Brown, and Michael Merritt. Lazy caching. ACM Transactions on Programming Languages and Systems, 15(1):182–205, January 1993.

[Ger96] Rob Gerth. Introduction to sequential consistency and the lazy caching algorithm. Distributed Computing, 1996. To appear.

[Lad95] Peter B. Ladkin. Formal but lively buffers in TLA+. 1995. Submitted for publication.

[Lam94] Leslie Lamport. The temporal logic of actions. ACM Transactions on Programming Languages and Systems, 16(3):872–923, May 1994.

[LLRO96] Peter Ladkin, Leslie Lamport, Denis Roegel, and Brian Olivier. Lazy caching in TLA. Distributed Computing, 1996. To appear.