Built with Alectryon, running Coq+SerAPI v8.12.0+0.12.0. Coq sources are in this panel; goals and messages will appear in the other. Bubbles () indicate interactive fragments: hover for details, tap to reveal contents. Use Ctrl+↑ Ctrl+↓ to navigate, Ctrl+🖱️ to focus.
Require Import Arith. Require Import RelationClasses. Require Import List. Require Import Helpers. Set Implicit Arguments.
Disk model.
Model of bytes.
Axiom bytes : nat -> Type. Axiom bytes_dec : forall n, EqualDec (bytes n). Existing Instance bytes_dec.
Two "initial" byte values: an all-zero array, bytes0, and
an all-ones array, bytes1. We also promise that all-zero
and all-ones arrays are different, as long as there's at least
one element.
Axiom bytes0 : forall n, bytes n. Axiom bytes1 : forall n, bytes n. Axiom bytes_differ : forall n, n > 0 -> bytes0 n <> bytes1 n. Definition bnull : bytes 0 := bytes0 0. Axiom bappend : forall n1 n2, bytes n1 -> bytes n2 -> bytes (n1+n2). Axiom bsplit : forall n1 n2, bytes (n1+n2) -> bytes n1 * bytes n2. Arguments bsplit {n1 n2} bs. Axiom bsplit_bappend : forall n1 n2 (b1 : bytes n1) (b2 : bytes n2), bsplit (bappend b1 b2) = (b1, b2). Fixpoint bsplit_list {n} {m} : bytes (n * m) -> list (bytes m) := match n with | O => fun _ => nil | S n' => fun (bs : bytes ((S n') * m)) => let (this, rest) := bsplit bs in this :: bsplit_list rest end. Extraction Language Haskell. Extract Constant bytes => "Data.ByteString.ByteString". Extract Constant bytes_dec => "(\n b1 b2 -> b1 Prelude.== b2)". Extract Constant bytes0 => "(\n -> Data.ByteString.replicate (Prelude.fromIntegral n) 0)". Extract Constant bappend => "(\_ _ bs1 bs2 -> Data.ByteString.append bs1 bs2)". Extract Constant bsplit => "(\n1 _ bs -> Data.ByteString.splitAt (Prelude.fromIntegral n1) bs)".
Model of blocks.
Definition blockbytes := 1024. Definition block := bytes blockbytes. Definition block0 : block := bytes0 _. Definition block1 : block := bytes1 _.block0 <> block1block0 <> block1blockbytes > 0lia. Qed. Hint Resolve block0_block1_differ : core.1024 > 0
Mark blockbytes as opaque so that Coq doesn't expand it too eagerly.
Opaque blockbytes.
Disk as a list of blocks.
Definition disk := list block. Definition empty_disk : disk := nil.
We define three main operations on disks:
- diskGet d a gets the contents of an address a in disk d.
It returns an option block, which is either a block value b
(represented by Some b), or None if a is past the end of
the disk.
- diskSize returns the size of the disk, which is just the length
of the list representing the disk.
- diskUpd writes to a disk. Since Gallina is a functional language, we cannot update a disk "in-place", so instead diskUpd returns a new disk reflecting the write. Specifically, diskUpd d a b returns a new disk with address a updated to block value b, if a is in-bounds, or the original disk unchanged if a is out-of-bounds.
We address into disks with addr, which is simply a nat.
Definition addr := nat. Definition diskGet (d : disk) (a : addr) : option block := nth_error d a. Definition diskSize (d : disk) : nat := length d. Fixpoint diskUpd d (a: addr) b : disk := match d with | nil => nil | db :: drest => match a with | O => b :: drest | S a' => db :: diskUpd drest a' b end end.
We define another helper operation, diskShrink, which takes
a disk and drops the last block. This will be helpful in the
bad-block-remapping lab assignment.
Definition diskShrink (d : disk) : disk :=
firstn (length d - 1) d.
We also define variants of diskGet and diskUpd that operate
on multiple blocks at a time. These may be helpful in the
logging lab assignment, but not required in any sense.
Fixpoint diskGets (d : disk) (a : addr) (count : nat) : list (option block) := match count with | O => nil | S count' => diskGet d a :: diskGets d (a+1) count' end. Fixpoint diskUpds (d : disk) (a : addr) (blocks : list block) : disk := match blocks with | nil => d | b :: blocks' => diskUpd (diskUpds d (a+1) blocks') a b end.
Finally, we prove a variety of theorems about the behavior of these
disk operations.
forall (a : nat) (d : disk), a < diskSize d -> exists b : block, diskGet d a = Some bforall (a : nat) (d : disk), a < diskSize d -> exists b : block, diskGet d a = Some bforall (a : nat) (d : disk), a < length d -> exists b : block, diskGet d a = Some ba:natd:diskH:a < length dexists b : block, diskGet d a = Some ba:natd:diskH:a < length dH0:diskGet d a = Noneexists b : block, None = Some blia. Qed.a:natd:diskH:a < length dH0:length d <= aexists b : block, None = Some bforall (a : nat) (d : disk), a < diskSize d -> diskGet d a = None -> Falseforall (a : nat) (d : disk), a < diskSize d -> diskGet d a = None -> Falseforall (a : nat) (d : disk), a < length d -> diskGet d a = None -> Falsea:natd:diskH:a < length dH0:diskGet d a = NoneFalselia. Qed.a:natd:diskH:a < length dH0:length d <= aFalseforall (a : addr) (d : disk), diskGet d a = None -> ~ a < diskSize dforall (a : addr) (d : disk), diskGet d a = None -> ~ a < diskSize da:addrd:diskH:diskGet d a = None~ a < diskSize dexfalso; eapply disk_inbounds_not_none; eauto. Qed.a:addrd:diskH:diskGet d a = Nonel:a < diskSize d~ a < diskSize dforall (d : disk) (a : nat), ~ a < diskSize d -> diskGet d a = Noneforall (d : disk) (a : nat), ~ a < diskSize d -> diskGet d a = Noneforall (d : disk) (a : nat), ~ a < length d -> diskGet d a = Nonea:natH:~ a < 0diskGet nil a = Nonea:blockd:list blockIHd:forall a : nat, ~ a < length d -> diskGet d a = Nonea0:natH:~ a0 < S (length d)diskGet (a :: d) a0 = Noneinduction a; eauto.a:natH:~ a < 0diskGet nil a = Nonea:blockd:list blockIHd:forall a : nat, ~ a < length d -> diskGet d a = Nonea0:natH:~ a0 < S (length d)diskGet (a :: d) a0 = Nonea:blockd:list blockIHd:forall a : nat, ~ a < length d -> diskGet d a = NoneH:~ 0 < S (length d)Some a = Nonea:blockd:list blockIHd:forall a : nat, ~ a < length d -> diskGet d a = Nonea0:natH:~ S a0 < S (length d)diskGet d a0 = Nonelia.a:blockd:list blockIHd:forall a : nat, ~ a < length d -> diskGet d a = NoneH:~ 0 < S (length d)Some a = Nonea:blockd:list blockIHd:forall a : nat, ~ a < length d -> diskGet d a = Nonea0:natH:~ S a0 < S (length d)diskGet d a0 = Nonelia. Qed. (* this rule allows autorewrite to simplify maybe_eq *)a:blockd:list blockIHd:forall a : nat, ~ a < length d -> diskGet d a = Nonea0:natH:~ S a0 < S (length d)~ a0 < length dT:Typev:TNone =?= v = Truereflexivity. Qed. Hint Rewrite maybe_eq_None_is_True : upd.T:Typev:TNone =?= v = TrueT:Typev:TNone =?= vexact I. Qed. Hint Resolve maybe_eq_None_holds : core.T:Typev:TNone =?= vA:Typeforall l1 l2 : list A, (forall a : nat, nth_error l1 a = nth_error l2 a) -> l1 = l2A:Typeforall l1 l2 : list A, (forall a : nat, nth_error l1 a = nth_error l2 a) -> l1 = l2A:Typel2:list AH:forall a : nat, nth_error nil a = nth_error l2 anil = l2A:Typea:Al1:list AIHl1:forall l2 : list A, (forall a : nat, nth_error l1 a = nth_error l2 a) -> l1 = l2l2:list AH:forall a0 : nat, nth_error (a :: l1) a0 = nth_error l2 a0a :: l1 = l2A:Typel2:list AH:forall a : nat, nth_error nil a = nth_error l2 anil = l2A:Typea:Al2:list AH:forall a0 : nat, nth_error nil a0 = nth_error (a :: l2) a0nil = a :: l2congruence.A:Typea:Al2:list AH:None = Some anil = a :: l2A:Typea:Al1:list AIHl1:forall l2 : list A, (forall a : nat, nth_error l1 a = nth_error l2 a) -> l1 = l2l2:list AH:forall a0 : nat, nth_error (a :: l1) a0 = nth_error l2 a0a :: l1 = l2A:Typea:Al1:list AIHl1:forall l2 : list A, (forall a : nat, nth_error l1 a = nth_error l2 a) -> l1 = l2H:forall a0 : nat, nth_error (a :: l1) a0 = nth_error nil a0a :: l1 = nilA:Typea:Al1:list AIHl1:forall l2 : list A, (forall a : nat, nth_error l1 a = nth_error l2 a) -> l1 = l2a0:Al2:list AH:forall a1 : nat, nth_error (a :: l1) a1 = nth_error (a0 :: l2) a1a :: l1 = a0 :: l2A:Typea:Al1:list AIHl1:forall l2 : list A, (forall a : nat, nth_error l1 a = nth_error l2 a) -> l1 = l2H:forall a0 : nat, nth_error (a :: l1) a0 = nth_error nil a0a :: l1 = nilcongruence.A:Typea:Al1:list AIHl1:forall l2 : list A, (forall a : nat, nth_error l1 a = nth_error l2 a) -> l1 = l2H:Some a = Nonea :: l1 = nilA:Typea:Al1:list AIHl1:forall l2 : list A, (forall a : nat, nth_error l1 a = nth_error l2 a) -> l1 = l2a0:Al2:list AH:forall a1 : nat, nth_error (a :: l1) a1 = nth_error (a0 :: l2) a1a :: l1 = a0 :: l2A:Typea:Al1:list AIHl1:forall l2 : list A, (forall a : nat, nth_error l1 a = nth_error l2 a) -> l1 = l2a0:Al2:list AH:forall a1 : nat, nth_error (a :: l1) a1 = nth_error (a0 :: l2) a1H':Some a = Some a0a :: l1 = a0 :: l2A:Typea:Al1:list AIHl1:forall l2 : list A, (forall a : nat, nth_error l1 a = nth_error l2 a) -> l1 = l2a0:Al2:list AH:forall a1 : nat, nth_error (a :: l1) a1 = nth_error (a0 :: l2) a1H':Some a = Some a0l1 = l2A:Typea:Al1:list AIHl1:forall l2 : list A, (forall a : nat, nth_error l1 a = nth_error l2 a) -> l1 = l2a0:Al2:list AH:forall a1 : nat, nth_error (a :: l1) a1 = nth_error (a0 :: l2) a1H':Some a = Some a0a1:natnth_error l1 a1 = nth_error l2 a1eauto. Qed.A:Typea:Al1:list AIHl1:forall l2 : list A, (forall a : nat, nth_error l1 a = nth_error l2 a) -> l1 = l2a0:Al2:list Aa1:natH:nth_error l1 a1 = nth_error l2 a1H':Some a = Some a0nth_error l1 a1 = nth_error l2 a1A:Typeforall l1 l2 : list A, length l1 = length l2 -> (forall a : nat, a < length l1 -> nth_error l1 a = nth_error l2 a) -> l1 = l2A:Typeforall l1 l2 : list A, length l1 = length l2 -> (forall a : nat, a < length l1 -> nth_error l1 a = nth_error l2 a) -> l1 = l2A:Typel1, l2:list AH:length l1 = length l2H0:forall a : nat, a < length l1 -> nth_error l1 a = nth_error l2 al1 = l2A:Typel1, l2:list AH:length l1 = length l2H0:forall a : nat, a < length l1 -> nth_error l1 a = nth_error l2 aa:natnth_error l1 a = nth_error l2 aA:Typel1, l2:list AH:length l1 = length l2H0:forall a : nat, a < length l1 -> nth_error l1 a = nth_error l2 aa:natn:~ a < length l1nth_error l1 a = nth_error l2 aA:Typel1, l2:list AH:length l1 = length l2H0:forall a : nat, a < length l1 -> nth_error l1 a = nth_error l2 aa:natn:~ a < length l1nth_error l1 a = nth_error l2 aA:Typel1, l2:list AH:length l1 = length l2H0:forall a : nat, a < length l1 -> nth_error l1 a = nth_error l2 aa:natn:~ a < length l1nth_error l1 a = NoneA:Typel1, l2:list AH:length l1 = length l2H0:forall a : nat, a < length l1 -> nth_error l1 a = nth_error l2 aa:natn:~ a < length l1H1:nth_error l1 a = Nonenth_error l1 a = nth_error l2 aA:Typel1, l2:list AH:length l1 = length l2H0:forall a : nat, a < length l1 -> nth_error l1 a = nth_error l2 aa:natn:~ a < length l1H1:nth_error l1 a = Nonenth_error l1 a = nth_error l2 aA:Typel1, l2:list AH:length l1 = length l2H0:forall a : nat, a < length l1 -> nth_error l1 a = nth_error l2 aa:natn:~ a < length l1H1:nth_error l1 a = Nonenth_error l2 a = NoneA:Typel1, l2:list AH:length l1 = length l2H0:forall a : nat, a < length l1 -> nth_error l1 a = nth_error l2 aa:natn:~ a < length l1H1:nth_error l1 a = NoneH2:nth_error l2 a = Nonenth_error l1 a = nth_error l2 acongruence. Qed.A:Typel1, l2:list AH:length l1 = length l2H0:forall a : nat, a < length l1 -> nth_error l1 a = nth_error l2 aa:natn:~ a < length l1H1:nth_error l1 a = NoneH2:nth_error l2 a = Nonenth_error l1 a = nth_error l2 aforall d d' : disk, (forall a : addr, diskGet d a = diskGet d' a) -> d = d'forall d d' : disk, (forall a : addr, diskGet d a = diskGet d' a) -> d = d'apply nth_error_ext_eq; auto. Qed.d, d':diskH:forall a : addr, diskGet d a = diskGet d' ad = d'forall d d' : disk, diskSize d = diskSize d' -> (forall a : nat, a < diskSize d -> diskGet d a = diskGet d' a) -> d = d'forall d d' : disk, diskSize d = diskSize d' -> (forall a : nat, a < diskSize d -> diskGet d a = diskGet d' a) -> d = d'apply nth_error_ext_inbounds_eq; auto. Qed.d, d':diskH:diskSize d = diskSize d'H0:forall a : nat, a < diskSize d -> diskGet d a = diskGet d' ad = d'
forall (d : disk) (a : addr) (b0 b : block), diskGet d a = Some b0 -> diskGet (diskUpd d a b) a = Some bforall (d : disk) (a : addr) (b0 b : block), diskGet d a = Some b0 -> diskGet (diskUpd d a b) a = Some bforall (a : addr) (b0 b : block), diskGet nil a = Some b0 -> diskGet nil a = Some ba:blockd:list blockIHd:forall (a : addr) (b0 b : block), diskGet d a = Some b0 -> diskGet (diskUpd d a b) a = Some bforall (a0 : addr) (b0 b : block), diskGet (a :: d) a0 = Some b0 -> diskGet match a0 with | 0 => b :: d | S a' => a :: diskUpd d a' b end a0 = Some bdestruct a; simpl; intros; congruence.forall (a : addr) (b0 b : block), diskGet nil a = Some b0 -> diskGet nil a = Some bdestruct a0; simpl; intros; eauto. Qed.a:blockd:list blockIHd:forall (a : addr) (b0 b : block), diskGet d a = Some b0 -> diskGet (diskUpd d a b) a = Some bforall (a0 : addr) (b0 b : block), diskGet (a :: d) a0 = Some b0 -> diskGet match a0 with | 0 => b :: d | S a' => a :: diskUpd d a' b end a0 = Some bforall (d : disk) (a : nat) (b : block), a < diskSize d -> diskGet (diskUpd d a b) a = Some bforall (d : disk) (a : nat) (b : block), a < diskSize d -> diskGet (diskUpd d a b) a = Some bd:diska:natb:blockH:a < diskSize ddiskGet (diskUpd d a b) a = Some beauto using diskUpd_eq_some. Qed.d:diska:natb, b0:blockH:diskGet d a = Some b0diskGet (diskUpd d a b) a = Some bforall (d : list block) (a : addr) (b : block), diskSize (diskUpd d a b) = diskSize dforall (d : list block) (a : addr) (b : block), diskSize (diskUpd d a b) = diskSize ddestruct a0; simpl; intros; eauto. Qed.a:blockd:list blockIHd:forall (a : addr) (b : block), diskSize (diskUpd d a b) = diskSize dforall (a0 : addr) (b : block), diskSize match a0 with | 0 => b :: d | S a' => a :: diskUpd d a' b end = S (diskSize d)forall (d : disk) (a : nat) (b : block), ~ a < diskSize d -> diskGet (diskUpd d a b) a = Noneforall (d : disk) (a : nat) (b : block), ~ a < diskSize d -> diskGet (diskUpd d a b) a = Noned:diska:natb:blockH:~ a < diskSize ddiskGet (diskUpd d a b) a = Nonerewrite diskUpd_size; auto. Qed.d:diska:natb:blockH:~ a < diskSize d~ a < diskSize (diskUpd d a b)forall (d : list block) (a : addr) (b : block) (a' : addr), a <> a' -> diskGet (diskUpd d a b) a' = diskGet d a'forall (d : list block) (a : addr) (b : block) (a' : addr), a <> a' -> diskGet (diskUpd d a b) a' = diskGet d a'a:blockd:list blockIHd:forall (a : addr) (b : block) (a' : addr), a <> a' -> diskGet (diskUpd d a b) a' = diskGet d a'a0:addrb:blocka':addrH:a0 <> a'diskGet match a0 with | 0 => b :: d | S a' => a :: diskUpd d a' b end a' = diskGet (a :: d) a'a:blockd:list blockIHd:forall (a : addr) (b : block) (a' : addr), a <> a' -> diskGet (diskUpd d a b) a' = diskGet d a'b:blocka':addrH:0 <> a'diskGet (b :: d) a' = diskGet (a :: d) a'a:blockd:list blockIHd:forall (a : addr) (b : block) (a' : addr), a <> a' -> diskGet (diskUpd d a b) a' = diskGet d a'a0:natb:blocka':addrH:S a0 <> a'diskGet (a :: diskUpd d a0 b) a' = diskGet (a :: d) a'destruct a'; simpl; try lia; auto.a:blockd:list blockIHd:forall (a : addr) (b : block) (a' : addr), a <> a' -> diskGet (diskUpd d a b) a' = diskGet d a'b:blocka':addrH:0 <> a'diskGet (b :: d) a' = diskGet (a :: d) a'destruct a'; simpl; auto. Qed.a:blockd:list blockIHd:forall (a : addr) (b : block) (a' : addr), a <> a' -> diskGet (diskUpd d a b) a' = diskGet d a'a0:natb:blocka':addrH:S a0 <> a'diskGet (a :: diskUpd d a0 b) a' = diskGet (a :: d) a'forall (d : disk) (a : addr) (b : block), diskGet d a = None -> diskUpd d a b = dforall (d : disk) (a : addr) (b : block), diskGet d a = None -> diskUpd d a b = da:blockd:list blockIHd:forall (a : addr) (b : block), diskGet d a = None -> diskUpd d a b = da0:addrb:blockH:diskGet (a :: d) a0 = Nonematch a0 with | 0 => b :: d | S a' => a :: diskUpd d a' b end = a :: drewrite IHd; eauto. Qed.a:blockd:list blockIHd:forall (a : addr) (b : block), diskGet d a = None -> diskUpd d a b = da0:natb:blockH:diskGet d a0 = Nonea :: diskUpd d a0 b = a :: dforall (d : disk) (a : addr) (b : block), diskGet d a = Some b -> diskUpd d a b = dforall (d : disk) (a : addr) (b : block), diskGet d a = Some b -> diskUpd d a b = da:blockd:list blockIHd:forall (a : addr) (b : block), diskGet d a = Some b -> diskUpd d a b = da0:addrb:blockH:diskGet (a :: d) a0 = Some bmatch a0 with | 0 => b :: d | S a' => a :: diskUpd d a' b end = a :: da:blockd:list blockIHd:forall (a : addr) (b : block), diskGet d a = Some b -> diskUpd d a b = db:blockH:Some a = Some bb :: d = a :: da:blockd:list blockIHd:forall (a : addr) (b : block), diskGet d a = Some b -> diskUpd d a b = da0:natb:blockH:diskGet d a0 = Some ba :: diskUpd d a0 b = a :: dcongruence.a:blockd:list blockIHd:forall (a : addr) (b : block), diskGet d a = Some b -> diskUpd d a b = db:blockH:Some a = Some bb :: d = a :: drewrite IHd; eauto. Qed.a:blockd:list blockIHd:forall (a : addr) (b : block), diskGet d a = Some b -> diskUpd d a b = da0:natb:blockH:diskGet d a0 = Some ba :: diskUpd d a0 b = a :: dforall (d : list block) (a : addr) (b b' : block), diskUpd (diskUpd d a b) a b' = diskUpd d a b'forall (d : list block) (a : addr) (b b' : block), diskUpd (diskUpd d a b) a b' = diskUpd d a b'a:blockd:list blockIHd:forall (a : addr) (b b' : block), diskUpd (diskUpd d a b) a b' = diskUpd d a b'a0:addrb, b':blockdiskUpd match a0 with | 0 => b :: d | S a' => a :: diskUpd d a' b end a0 b' = match a0 with | 0 => b' :: d | S a' => a :: diskUpd d a' b' enda:blockd:list blockIHd:forall (a : addr) (b b' : block), diskUpd (diskUpd d a b) a b' = diskUpd d a b'b, b':blockb' :: d = b' :: da:blockd:list blockIHd:forall (a : addr) (b b' : block), diskUpd (diskUpd d a b) a b' = diskUpd d a b'a0:natb, b':blocka :: diskUpd (diskUpd d a0 b) a0 b' = a :: diskUpd d a0 b'congruence.a:blockd:list blockIHd:forall (a : addr) (b b' : block), diskUpd (diskUpd d a b) a b' = diskUpd d a b'b, b':blockb' :: d = b' :: drewrite IHd; eauto. Qed.a:blockd:list blockIHd:forall (a : addr) (b b' : block), diskUpd (diskUpd d a b) a b' = diskUpd d a b'a0:natb, b':blocka :: diskUpd (diskUpd d a0 b) a0 b' = a :: diskUpd d a0 b'forall (d : list block) (a a' : addr) (b b' : block), a <> a' -> diskUpd (diskUpd d a b) a' b' = diskUpd (diskUpd d a' b') a bforall (d : list block) (a a' : addr) (b b' : block), a <> a' -> diskUpd (diskUpd d a b) a' b' = diskUpd (diskUpd d a' b') a ba:blockd:list blockIHd:forall (a a' : addr) (b b' : block), a <> a' -> diskUpd (diskUpd d a b) a' b' = diskUpd (diskUpd d a' b') a ba0, a':addrb, b':blockH:a0 <> a'diskUpd match a0 with | 0 => b :: d | S a' => a :: diskUpd d a' b end a' b' = diskUpd match a' with | 0 => b' :: d | S a' => a :: diskUpd d a' b' end a0 ba:blockd:list blockIHd:forall (a a' : addr) (b b' : block), a <> a' -> diskUpd (diskUpd d a b) a' b' = diskUpd (diskUpd d a' b') a bb, b':blockH:0 <> 0b' :: d = b :: da:blockd:list blockIHd:forall (a a' : addr) (b b' : block), a <> a' -> diskUpd (diskUpd d a b) a' b' = diskUpd (diskUpd d a' b') a ba':natb, b':blockH:0 <> S a'b :: diskUpd d a' b' = b :: diskUpd d a' b'a:blockd:list blockIHd:forall (a a' : addr) (b b' : block), a <> a' -> diskUpd (diskUpd d a b) a' b' = diskUpd (diskUpd d a' b') a ba0:natb, b':blockH:S a0 <> 0b' :: diskUpd d a0 b = b' :: diskUpd d a0 ba:blockd:list blockIHd:forall (a a' : addr) (b b' : block), a <> a' -> diskUpd (diskUpd d a b) a' b' = diskUpd (diskUpd d a' b') a ba0, a':natb, b':blockH:S a0 <> S a'a :: diskUpd (diskUpd d a0 b) a' b' = a :: diskUpd (diskUpd d a' b') a0 blia.a:blockd:list blockIHd:forall (a a' : addr) (b b' : block), a <> a' -> diskUpd (diskUpd d a b) a' b' = diskUpd (diskUpd d a' b') a bb, b':blockH:0 <> 0b' :: d = b :: dcongruence.a:blockd:list blockIHd:forall (a a' : addr) (b b' : block), a <> a' -> diskUpd (diskUpd d a b) a' b' = diskUpd (diskUpd d a' b') a ba':natb, b':blockH:0 <> S a'b :: diskUpd d a' b' = b :: diskUpd d a' b'congruence.a:blockd:list blockIHd:forall (a a' : addr) (b b' : block), a <> a' -> diskUpd (diskUpd d a b) a' b' = diskUpd (diskUpd d a' b') a ba0:natb, b':blockH:S a0 <> 0b' :: diskUpd d a0 b = b' :: diskUpd d a0 brewrite IHd; eauto. Qed.a:blockd:list blockIHd:forall (a a' : addr) (b b' : block), a <> a' -> diskUpd (diskUpd d a b) a' b' = diskUpd (diskUpd d a' b') a ba0, a':natb, b':blockH:S a0 <> S a'a :: diskUpd (diskUpd d a0 b) a' b' = a :: diskUpd (diskUpd d a' b') a0 bforall (d : list block) (a a' : nat) (b b' : block), a < a' -> diskUpd (diskUpd d a b) a' b' = diskUpd (diskUpd d a' b') a bforall (d : list block) (a a' : nat) (b b' : block), a < a' -> diskUpd (diskUpd d a b) a' b' = diskUpd (diskUpd d a' b') a bd:list blocka, a':natb, b':blockH:a < a'diskUpd (diskUpd d a b) a' b' = diskUpd (diskUpd d a' b') a blia. Qed.d:list blocka, a':natb, b':blockH:a < a'a <> a'forall (d : disk) (a : nat) (b : block), ~ a < diskSize d -> diskUpd d a b = dforall (d : disk) (a : nat) (b : block), ~ a < diskSize d -> diskUpd d a b = da:blockd:list blockIHd:forall (a : nat) (b : block), ~ a < diskSize d -> diskUpd d a b = da0:natb:blockH:~ a0 < S (diskSize d)match a0 with | 0 => b :: d | S a' => a :: diskUpd d a' b end = a :: da:blockd:list blockIHd:forall (a : nat) (b : block), ~ a < diskSize d -> diskUpd d a b = db:blockH:~ 0 < S (diskSize d)b :: d = a :: da:blockd:list blockIHd:forall (a : nat) (b : block), ~ a < diskSize d -> diskUpd d a b = da0:natb:blockH:~ S a0 < S (diskSize d)a :: diskUpd d a0 b = a :: dlia.a:blockd:list blockIHd:forall (a : nat) (b : block), ~ a < diskSize d -> diskUpd d a b = db:blockH:~ 0 < S (diskSize d)b :: d = a :: drewrite IHd; auto; lia. Qed.a:blockd:list blockIHd:forall (a : nat) (b : block), ~ a < diskSize d -> diskUpd d a b = da0:natb:blockH:~ S a0 < S (diskSize d)a :: diskUpd d a0 b = a :: d
forall d : disk, diskSize d <> 0 -> diskSize (diskShrink d) = diskSize d - 1forall d : disk, diskSize d <> 0 -> diskSize (diskShrink d) = diskSize d - 1d:diskH:length d <> 0length (firstn (length d - 1) d) = length d - 1rewrite min_l; lia. Qed.d:diskH:length d <> 0Init.Nat.min (length d - 1) (length d) = length d - 1forall (d : disk) (a : nat), a <> diskSize (diskShrink d) -> diskGet (diskShrink d) a = diskGet d aforall (d : disk) (a : nat), a <> diskSize (diskShrink d) -> diskGet (diskShrink d) a = diskGet d aforall (d : disk) (a : nat), a <> diskSize (firstn (length d - 1) d) -> diskGet (firstn (length d - 1) d) a = diskGet d aa:blockd:list blockIHd:forall a : nat, a <> diskSize (firstn (length d - 1) d) -> diskGet (firstn (length d - 1) d) a = diskGet d aa0:natH:a0 <> diskSize (firstn (length d - 0) (a :: d))diskGet (firstn (length d - 0) (a :: d)) a0 = diskGet (a :: d) a0a:blockIHd:forall a : nat, a <> 0 -> diskGet nil a = diskGet nil aa0:natH:a0 <> 0diskGet nil a0 = diskGet (a :: nil) a0a, b:blockd:list blockIHd:forall a : nat, a <> diskSize (firstn (length d - 0) (b :: d)) -> diskGet (firstn (length d - 0) (b :: d)) a = diskGet (b :: d) aa0:natH:a0 <> S (diskSize (firstn (length d) (b :: d)))diskGet (a :: firstn (length d) (b :: d)) a0 = diskGet (a :: b :: d) a0a:blockIHd:forall a : nat, a <> 0 -> diskGet nil a = diskGet nil aa0:natH:a0 <> 0diskGet nil a0 = diskGet (a :: nil) a0destruct a0; auto.a:blockIHd:forall a : nat, a <> 0 -> diskGet nil a = diskGet nil aa0:natH:S a0 <> 0None = diskGet nil a0a, b:blockd:list blockIHd:forall a : nat, a <> diskSize (firstn (length d - 0) (b :: d)) -> diskGet (firstn (length d - 0) (b :: d)) a = diskGet (b :: d) aa0:natH:a0 <> S (diskSize (firstn (length d) (b :: d)))diskGet (a :: firstn (length d) (b :: d)) a0 = diskGet (a :: b :: d) a0a, b:blockd:list blockIHd:forall a : nat, a <> diskSize (firstn (length d - 0) (b :: d)) -> diskGet (firstn (length d - 0) (b :: d)) a = diskGet (b :: d) aa0:natH:S a0 <> S (diskSize (firstn (length d) (b :: d)))diskGet (firstn (length d) (b :: d)) a0 = diskGet (b :: d) a0rewrite <- IHd; auto. Qed.a, b:blockd:list blockIHd:forall a : nat, a <> diskSize (firstn (length d) (b :: d)) -> diskGet (firstn (length d) (b :: d)) a = diskGet (b :: d) aa0:natH:S a0 <> S (diskSize (firstn (length d) (b :: d)))diskGet (firstn (length d) (b :: d)) a0 = diskGet (b :: d) a0forall (d : disk) (a : nat) (b : block), a >= diskSize d - 1 -> diskShrink (diskUpd d a b) = diskShrink dforall (d : disk) (a : nat) (b : block), a >= diskSize d - 1 -> diskShrink (diskUpd d a b) = diskShrink dd:diska:natb:blockH:a >= diskSize d - 1firstn (length (diskUpd d a b) - 1) (diskUpd d a b) = firstn (length d - 1) dd:diskb:blockH:diskSize d - 1 >= diskSize d - 1firstn (length (diskUpd d (diskSize d - 1) b) - 1) (diskUpd d (diskSize d - 1) b) = firstn (length d - 1) dd:diska:natb:blockH:a >= diskSize d - 1n:a <> diskSize d - 1firstn (length (diskUpd d a b) - 1) (diskUpd d a b) = firstn (length d - 1) dd:diskb:blockH:diskSize d - 1 >= diskSize d - 1firstn (length (diskUpd d (diskSize d - 1) b) - 1) (diskUpd d (diskSize d - 1) b) = firstn (length d - 1) dd:diskb:blockfirstn (length (diskUpd d (diskSize d - 1) b) - 1) (diskUpd d (diskSize d - 1) b) = firstn (length d - 1) dd:diskb:blockfirstn (length d - 1) (diskUpd d (length d - 1) b) = firstn (length d - 1) da:blockd:list blockb:blockIHd:firstn (length d - 1) (diskUpd d (length d - 1) b) = firstn (length d - 1) dfirstn (length d - 0) match length d - 0 with | 0 => b :: d | S a' => a :: diskUpd d a' b end = firstn (length d - 0) (a :: d)a, b0:blockd:list blockb:blockIHd:firstn (length d - 0) match length d - 0 with | 0 => b :: d | S a' => b0 :: diskUpd d a' b end = firstn (length d - 0) (b0 :: d)a :: firstn (length d) match length d with | 0 => b :: d | S a' => b0 :: diskUpd d a' b end = a :: firstn (length d) (b0 :: d)f_equal; auto.a, b0:blockd:list blockb:blockIHd:firstn (length d) match length d with | 0 => b :: d | S a' => b0 :: diskUpd d a' b end = firstn (length d) (b0 :: d)a :: firstn (length d) match length d with | 0 => b :: d | S a' => b0 :: diskUpd d a' b end = a :: firstn (length d) (b0 :: d)rewrite diskUpd_oob_noop by lia; auto. Qed.d:diska:natb:blockH:a >= diskSize d - 1n:a <> diskSize d - 1firstn (length (diskUpd d a b) - 1) (diskUpd d a b) = firstn (length d - 1) dforall (d : disk) (a : nat) (b : block), a < diskSize d - 1 -> diskShrink (diskUpd d a b) = diskUpd (diskShrink d) a bforall (d : disk) (a : nat) (b : block), a < diskSize d - 1 -> diskShrink (diskUpd d a b) = diskUpd (diskShrink d) a bforall (d : disk) (a : nat) (b : block), a < diskSize d - 1 -> firstn (length (diskUpd d a b) - 1) (diskUpd d a b) = diskUpd (firstn (length d - 1) d) a ba:blockd:list blockIHd:forall (a : nat) (b : block), a < diskSize d - 1 -> firstn (length (diskUpd d a b) - 1) (diskUpd d a b) = diskUpd (firstn (length d - 1) d) a ba0:natb:blockH:a0 < diskSize d - 0firstn (length match a0 with | 0 => b :: d | S a' => a :: diskUpd d a' b end - 1) match a0 with | 0 => b :: d | S a' => a :: diskUpd d a' b end = diskUpd (firstn (length d - 0) (a :: d)) a0 ba:blockd:list blockIHd:forall (a : nat) (b : block), a < diskSize d - 1 -> firstn (length (diskUpd d a b) - 1) (diskUpd d a b) = diskUpd (firstn (length d - 1) d) a bb:blockH:0 < diskSize d - 0firstn (length d - 0) (b :: d) = diskUpd (firstn (length d - 0) (a :: d)) 0 ba:blockd:list blockIHd:forall (a : nat) (b : block), a < diskSize d - 1 -> firstn (length (diskUpd d a b) - 1) (diskUpd d a b) = diskUpd (firstn (length d - 1) d) a ba0:natb:blockH:S a0 < diskSize d - 0firstn (length (diskUpd d a0 b) - 0) (a :: diskUpd d a0 b) = diskUpd (firstn (length d - 0) (a :: d)) (S a0) bdestruct d; simpl; auto.a:blockd:list blockIHd:forall (a : nat) (b : block), a < diskSize d - 1 -> firstn (length (diskUpd d a b) - 1) (diskUpd d a b) = diskUpd (firstn (length d - 1) d) a bb:blockH:0 < diskSize d - 0firstn (length d - 0) (b :: d) = diskUpd (firstn (length d - 0) (a :: d)) 0 ba:blockd:list blockIHd:forall (a : nat) (b : block), a < diskSize d - 1 -> firstn (length (diskUpd d a b) - 1) (diskUpd d a b) = diskUpd (firstn (length d - 1) d) a ba0:natb:blockH:S a0 < diskSize d - 0firstn (length (diskUpd d a0 b) - 0) (a :: diskUpd d a0 b) = diskUpd (firstn (length d - 0) (a :: d)) (S a0) ba, b0:blockd:list blockIHd:forall (a : nat) (b : block), a < diskSize d - 0 -> firstn (length match a with | 0 => b :: d | S a' => b0 :: diskUpd d a' b end - 1) match a with | 0 => b :: d | S a' => b0 :: diskUpd d a' b end = diskUpd (firstn (length d - 0) (b0 :: d)) a ba0:natb:blockH:S a0 < S (diskSize d)firstn (length match a0 with | 0 => b :: d | S a' => b0 :: diskUpd d a' b end - 0) (a :: match a0 with | 0 => b :: d | S a' => b0 :: diskUpd d a' b end) = a :: diskUpd (firstn (length d) (b0 :: d)) a0 ba, b0:blockd:list blockIHd:forall (a : nat) (b : block), a < diskSize d - 0 -> firstn (length match a with | 0 => b :: d | S a' => b0 :: diskUpd d a' b end - 1) match a with | 0 => b :: d | S a' => b0 :: diskUpd d a' b end = diskUpd (firstn (length d) (b0 :: d)) a ba0:natb:blockH:S a0 < S (diskSize d)firstn (length match a0 with | 0 => b :: d | S a' => b0 :: diskUpd d a' b end - 0) (a :: match a0 with | 0 => b :: d | S a' => b0 :: diskUpd d a' b end) = a :: diskUpd (firstn (length d) (b0 :: d)) a0 bdestruct a0; simpl; try rewrite diskUpd_size; unfold diskSize; replace (length d - 0) with (length d) by lia; auto. Qed. Hint Rewrite diskUpd_size : disk_size. Hint Rewrite diskShrink_size using solve [ auto || lia ] : disk_size.a, b0:blockd:list blockIHd:forall (a : nat) (b : block), a < diskSize d - 0 -> firstn (length match a with | 0 => b :: d | S a' => b0 :: diskUpd d a' b end - 1) match a with | 0 => b :: d | S a' => b0 :: diskUpd d a' b end = diskUpd (firstn (length d) (b0 :: d)) a ba0:natb:blockH:S a0 < S (diskSize d)firstn (length match a0 with | 0 => b :: d | S a' => b0 :: diskUpd d a' b end - 0) (a :: match a0 with | 0 => b :: d | S a' => b0 :: diskUpd d a' b end) = a :: firstn (length match a0 with | 0 => b :: d | S a' => b0 :: diskUpd d a' b end - 1) match a0 with | 0 => b :: d | S a' => b0 :: diskUpd d a' b end
forall (blocks : list block) (d : disk) (a a' : nat), a' < a \/ a' >= a + length blocks -> diskGet (diskUpds d a blocks) a' = diskGet d a'forall (blocks : list block) (d : disk) (a a' : nat), a' < a \/ a' >= a + length blocks -> diskGet (diskUpds d a blocks) a' = diskGet d a'a:blockblocks:list blockIHblocks:forall (d : disk) (a a' : nat), a' < a \/ a' >= a + length blocks -> diskGet (diskUpds d a blocks) a' = diskGet d a'd:diska0, a':natH:a' < a0 \/ a' >= a0 + S (length blocks)diskGet (diskUpd (diskUpds d (a0 + 1) blocks) a0 a) a' = diskGet d a'a:blockblocks:list blockIHblocks:forall (d : disk) (a a' : nat), a' < a \/ a' >= a + length blocks -> diskGet (diskUpds d a blocks) a' = diskGet d a'd:diska0, a':natH:a' < a0 \/ a' >= a0 + S (length blocks)diskGet (diskUpds d (a0 + 1) blocks) a' = diskGet d a'lia. Qed.a:blockblocks:list blockIHblocks:forall (d : disk) (a a' : nat), a' < a \/ a' >= a + length blocks -> diskGet (diskUpds d a blocks) a' = diskGet d a'd:diska0, a':natH:a' < a0 \/ a' >= a0 + S (length blocks)a' < a0 + 1 \/ a' >= a0 + 1 + length blocksforall (blocks : list block) (d : disk) (a : addr), diskSize (diskUpds d a blocks) = diskSize dforall (blocks : list block) (d : disk) (a : addr), diskSize (diskUpds d a blocks) = diskSize drewrite diskUpd_size; auto. Qed.a:blockblocks:list blockIHblocks:forall (d : disk) (a : addr), diskSize (diskUpds d a blocks) = diskSize dd:diska0:addrdiskSize (diskUpd (diskUpds d (a0 + 1) blocks) a0 a) = diskSize dforall (blocks : list block) (d : disk) (a a' : nat) (b : block), a' < a \/ a' >= a + length blocks -> diskUpd (diskUpds d a blocks) a' b = diskUpds (diskUpd d a' b) a blocksforall (blocks : list block) (d : disk) (a a' : nat) (b : block), a' < a \/ a' >= a + length blocks -> diskUpd (diskUpds d a blocks) a' b = diskUpds (diskUpd d a' b) a blocksa:blockblocks:list blockIHblocks:forall (d : disk) (a a' : nat) (b : block), a' < a \/ a' >= a + length blocks -> diskUpd (diskUpds d a blocks) a' b = diskUpds (diskUpd d a' b) a blocksd:diska0, a':natb:blockH:a' < a0 \/ a' >= a0 + S (length blocks)diskUpd (diskUpd (diskUpds d (a0 + 1) blocks) a0 a) a' b = diskUpd (diskUpds (diskUpd d a' b) (a0 + 1) blocks) a0 aa:blockblocks:list blockIHblocks:forall (d : disk) (a a' : nat) (b : block), a' < a \/ a' >= a + length blocks -> diskUpd (diskUpds d a blocks) a' b = diskUpds (diskUpd d a' b) a blocksd:diska0, a':natb:blockH:a' < a0 \/ a' >= a0 + S (length blocks)diskUpd (diskUpd (diskUpds d (a0 + 1) blocks) a' b) a0 a = diskUpd (diskUpds (diskUpd d a' b) (a0 + 1) blocks) a0 alia. Qed.a:blockblocks:list blockIHblocks:forall (d : disk) (a a' : nat) (b : block), a' < a \/ a' >= a + length blocks -> diskUpd (diskUpds d a blocks) a' b = diskUpds (diskUpd d a' b) a blocksd:diska0, a':natb:blockH:a' < a0 \/ a' >= a0 + S (length blocks)a' < a0 + 1 \/ a' >= a0 + 1 + length blocksforall (blocks : list block) (d : disk) (a : addr) (b : block), diskUpd (diskUpds d a blocks) (a + length blocks) b = diskUpds d a (blocks ++ b :: nil)forall (blocks : list block) (d : disk) (a : addr) (b : block), diskUpd (diskUpds d a blocks) (a + length blocks) b = diskUpds d a (blocks ++ b :: nil)d:diska:addrb:blockdiskUpd d (a + 0) b = diskUpd d a ba:blockblocks:list blockIHblocks:forall (d : disk) (a : addr) (b : block), diskUpd (diskUpds d a blocks) (a + length blocks) b = diskUpds d a (blocks ++ b :: nil)d:diska0:addrb:blockdiskUpd (diskUpd (diskUpds d (a0 + 1) blocks) a0 a) (a0 + S (length blocks)) b = diskUpd (diskUpds d (a0 + 1) (blocks ++ b :: nil)) a0 areplace (a + 0) with a; auto.d:diska:addrb:blockdiskUpd d (a + 0) b = diskUpd d a ba:blockblocks:list blockIHblocks:forall (d : disk) (a : addr) (b : block), diskUpd (diskUpds d a blocks) (a + length blocks) b = diskUpds d a (blocks ++ b :: nil)d:diska0:addrb:blockdiskUpd (diskUpd (diskUpds d (a0 + 1) blocks) a0 a) (a0 + S (length blocks)) b = diskUpd (diskUpds d (a0 + 1) (blocks ++ b :: nil)) a0 aa:blockblocks:list blockIHblocks:forall (d : disk) (a : addr) (b : block), diskUpd (diskUpds d a blocks) (a + length blocks) b = diskUpds d a (blocks ++ b :: nil)d:diska0:addrb:blockdiskUpd (diskUpd (diskUpds d (a0 + 1) blocks) (a0 + S (length blocks)) b) a0 a = diskUpd (diskUpds d (a0 + 1) (blocks ++ b :: nil)) a0 aa:blockblocks:list blockIHblocks:forall (d : disk) (a : addr) (b : block), diskUpd (diskUpds d a blocks) (a + length blocks) b = diskUpds d a (blocks ++ b :: nil)d:diska0:addrb:blockdiskUpd (diskUpd (diskUpds d (a0 + 1) blocks) (a0 + S (length blocks)) b) a0 a = diskUpd (diskUpd (diskUpds d (a0 + 1) blocks) (a0 + 1 + length blocks) b) a0 areflexivity. Qed.a:blockblocks:list blockIHblocks:forall (d : disk) (a : addr) (b : block), diskUpd (diskUpds d a blocks) (a + length blocks) b = diskUpds d a (blocks ++ b :: nil)d:diska0:addrb:blockdiskUpd (diskUpd (diskUpds d (a0 + 1) blocks) (a0 + 1 + length blocks) b) a0 a = diskUpd (diskUpd (diskUpds d (a0 + 1) blocks) (a0 + 1 + length blocks) b) a0 aforall (blocks : list block) (d : disk) (a : nat) (b : block), diskUpd (diskUpds d (a + 1) blocks) a b = diskUpds d a (b :: blocks)reflexivity. Qed.forall (blocks : list block) (d : disk) (a : nat) (b : block), diskUpd (diskUpds d (a + 1) blocks) a b = diskUpds d a (b :: blocks)
forall (count : nat) (d : disk) (a : addr), diskGets d a (count + 1) = diskGet d a :: diskGets d (a + 1) countforall (count : nat) (d : disk) (a : addr), diskGets d a (count + 1) = diskGet d a :: diskGets d (a + 1) countcount:natd:diska:addrdiskGets d a (count + 1) = diskGet d a :: diskGets d (a + 1) countreflexivity. Qed.count:natd:diska:addrdiskGets d a (S count) = diskGet d a :: diskGets d (a + 1) countforall (count : nat) (d : disk) (a : addr), diskGets d a (count + 1) = diskGets d a count ++ diskGet d (a + count) :: nilforall (count : nat) (d : disk) (a : addr), diskGets d a (count + 1) = diskGets d a count ++ diskGet d (a + count) :: nild:diska:addrdiskGet d a :: nil = diskGet d (a + 0) :: nilcount:natIHcount:forall (d : disk) (a : addr), diskGets d a (count + 1) = diskGets d a count ++ diskGet d (a + count) :: nild:diska:addrdiskGet d a :: diskGets d (a + 1) (count + 1) = diskGet d a :: diskGets d (a + 1) count ++ diskGet d (a + S count) :: nilreplace (a+0) with a by lia; auto.d:diska:addrdiskGet d a :: nil = diskGet d (a + 0) :: nilcount:natIHcount:forall (d : disk) (a : addr), diskGets d a (count + 1) = diskGets d a count ++ diskGet d (a + count) :: nild:diska:addrdiskGet d a :: diskGets d (a + 1) (count + 1) = diskGet d a :: diskGets d (a + 1) count ++ diskGet d (a + S count) :: nilreplace (a+1+count) with (a+S count) by lia; auto. Qed.count:natIHcount:forall (d : disk) (a : addr), diskGets d a (count + 1) = diskGets d a count ++ diskGet d (a + count) :: nild:diska:addrdiskGet d a :: diskGets d (a + 1) count ++ diskGet d (a + 1 + count) :: nil = diskGet d a :: diskGets d (a + 1) count ++ diskGet d (a + S count) :: nilforall (count0 count1 : nat) (d : disk) (a : addr), diskGets d a (count0 + count1) = diskGets d a count0 ++ diskGets d (a + count0) count1forall (count0 count1 : nat) (d : disk) (a : addr), diskGets d a (count0 + count1) = diskGets d a count0 ++ diskGets d (a + count0) count1count0:natIHcount0:forall (count1 : nat) (d : disk) (a : addr), diskGets d a (count0 + count1) = diskGets d a count0 ++ diskGets d (a + count0) count1count1:natd:diska:addrdiskGet d a :: diskGets d (a + 1) (count0 + count1) = diskGet d a :: diskGets d (a + 1) count0 ++ diskGets d (a + S count0) count1count0:natIHcount0:forall (count1 : nat) (d : disk) (a : addr), diskGets d a (count0 + count1) = diskGets d a count0 ++ diskGets d (a + count0) count1count1:natd:diska:addrdiskGet d a :: diskGets d (a + 1) count0 ++ diskGets d (a + 1 + count0) count1 = diskGet d a :: diskGets d (a + 1) count0 ++ diskGets d (a + S count0) count1auto. Qed.count0:natIHcount0:forall (count1 : nat) (d : disk) (a : addr), diskGets d a (count0 + count1) = diskGets d a count0 ++ diskGets d (a + count0) count1count1:natd:diska:addrdiskGet d a :: diskGets d (a + 1) count0 ++ diskGets d (a + S count0) count1 = diskGet d a :: diskGets d (a + 1) count0 ++ diskGets d (a + S count0) count1forall (d : disk) (a : addr) (count : nat), length (diskGets d a count) = countforall (d : disk) (a : addr) (count : nat), length (diskGets d a count) = countd:diska:addrcount:natlength (diskGets d a count) = countinduction count; simpl; auto. Qed.d:diskcount:natforall a : addr, length (diskGets d a count) = countforall (d : disk) (a : addr) (count i : nat), i < count -> nth_error (diskGets d a count) i = Some (diskGet d (a + i))forall (d : disk) (a : addr) (count i : nat), i < count -> nth_error (diskGets d a count) i = Some (diskGet d (a + i))d:diska:addrcount, i:natH:i < countnth_error (diskGets d a count) i = Some (diskGet d (a + i))d:diska:addrcount:natforall i : nat, i < count -> nth_error (diskGets d a count) i = Some (diskGet d (a + i))d:diskcount:natforall (a : addr) (i : nat), i < count -> nth_error (diskGets d a count) i = Some (diskGet d (a + i))d:diska:addri:natH:i < 0nth_error nil i = Some (diskGet d (a + i))d:diskcount:natIHcount:forall (a : addr) (i : nat), i < count -> nth_error (diskGets d a count) i = Some (diskGet d (a + i))a:addri:natH:i < S countnth_error (diskGet d a :: diskGets d (a + 1) count) i = Some (diskGet d (a + i))lia.d:diska:addri:natH:i < 0nth_error nil i = Some (diskGet d (a + i))d:diskcount:natIHcount:forall (a : addr) (i : nat), i < count -> nth_error (diskGets d a count) i = Some (diskGet d (a + i))a:addri:natH:i < S countnth_error (diskGet d a :: diskGets d (a + 1) count) i = Some (diskGet d (a + i))d:diskcount:natIHcount:forall (a : addr) (i : nat), i < count -> nth_error (diskGets d a count) i = Some (diskGet d (a + i))a:addrH:0 < S countSome (diskGet d a) = Some (diskGet d (a + 0))d:diskcount:natIHcount:forall (a : addr) (i : nat), i < count -> nth_error (diskGets d a count) i = Some (diskGet d (a + i))a:addri:natH:S i < S countnth_error (diskGets d (a + 1) count) i = Some (diskGet d (a + S i))d:diskcount:natIHcount:forall (a : addr) (i : nat), i < count -> nth_error (diskGets d a count) i = Some (diskGet d (a + i))a:addri:natH:S i < S countnth_error (diskGets d (a + 1) count) i = Some (diskGet d (a + S i))replace (a+1+i) with (a+S i) by lia; auto. Qed. Hint Rewrite diskGets_length : disk_size. Section diskGets_proof. Hint Rewrite nth_error_app1 using (autorewrite with disk_size in *; lia) : upd. Hint Rewrite nth_error_app2 using (autorewrite with disk_size in *; lia) : upd. Hint Rewrite diskGets_index using lia : upd.d:diskcount:natIHcount:forall (a : addr) (i : nat), i < count -> nth_error (diskGets d a count) i = Some (diskGet d (a + i))a:addri:natH:S i < S countSome (diskGet d (a + 1 + i)) = Some (diskGet d (a + S i))forall (d1 d2 : list block) (a count : nat), count >= length d1 - a -> a < length d1 -> diskGets (d1 ++ d2) a count = diskGets d1 a (length d1 - a) ++ diskGets d2 0 (count - (length d1 - a))forall (d1 d2 : list block) (a count : nat), count >= length d1 - a -> a < length d1 -> diskGets (d1 ++ d2) a count = diskGets d1 a (length d1 - a) ++ diskGets d2 0 (count - (length d1 - a))d1, d2:list blocka, count:natH:count >= length d1 - aH0:a < length d1diskGets (d1 ++ d2) a count = diskGets d1 a (length d1 - a) ++ diskGets d2 0 (count - (length d1 - a))d1, d2:list blocka, count:natH:count >= length d1 - aH0:a < length d1length (diskGets (d1 ++ d2) a count) = length (diskGets d1 a (length d1 - a) ++ diskGets d2 0 (count - (length d1 - a)))d1, d2:list blocka, count:natH:count >= length d1 - aH0:a < length d1forall a0 : nat, a0 < length (diskGets (d1 ++ d2) a count) -> nth_error (diskGets (d1 ++ d2) a count) a0 = nth_error (diskGets d1 a (length d1 - a) ++ diskGets d2 0 (count - (length d1 - a))) a0d1, d2:list blocka, count:natH:count >= length d1 - aH0:a < length d1length (diskGets (d1 ++ d2) a count) = length (diskGets d1 a (length d1 - a) ++ diskGets d2 0 (count - (length d1 - a)))lia.d1, d2:list blocka, count:natH:count >= length d1 - aH0:a < length d1count = length d1 - a + (count - (length d1 - a))d1, d2:list blocka, count:natH:count >= length d1 - aH0:a < length d1forall a0 : nat, a0 < length (diskGets (d1 ++ d2) a count) -> nth_error (diskGets (d1 ++ d2) a count) a0 = nth_error (diskGets d1 a (length d1 - a) ++ diskGets d2 0 (count - (length d1 - a))) a0d1, d2:list blocka, count:natH:count >= length d1 - aH0:a < length d1i:natH1:i < length (diskGets (d1 ++ d2) a count)nth_error (diskGets (d1 ++ d2) a count) i = nth_error (diskGets d1 a (length d1 - a) ++ diskGets d2 0 (count - (length d1 - a))) id1, d2:list blocka, count:natH:count >= length d1 - aH0:a < length d1i:natH1:i < countnth_error (diskGets (d1 ++ d2) a count) i = nth_error (diskGets d1 a (length d1 - a) ++ diskGets d2 0 (count - (length d1 - a))) id1, d2:list blocka, count:natH:count >= length d1 - aH0:a < length d1i:natH1:i < countSome (diskGet (d1 ++ d2) (a + i)) = nth_error (diskGets d1 a (length d1 - a) ++ diskGets d2 0 (count - (length d1 - a))) id1, d2:list blocka, count:natH:count >= length d1 - aH0:a < length d1i:natH1:i < countl:i < length d1 - aSome (nth_error d1 (a + i)) = Some (diskGet d1 (a + i))d1, d2:list blocka, count:natH:count >= length d1 - aH0:a < length d1i:natH1:i < countn:~ i < length d1 - aSome (nth_error d2 (a + i - length d1)) = Some (diskGet d2 (0 + (i - (length d1 - a))))auto.d1, d2:list blocka, count:natH:count >= length d1 - aH0:a < length d1i:natH1:i < countl:i < length d1 - aSome (nth_error d1 (a + i)) = Some (diskGet d1 (a + i))d1, d2:list blocka, count:natH:count >= length d1 - aH0:a < length d1i:natH1:i < countn:~ i < length d1 - aSome (nth_error d2 (a + i - length d1)) = Some (diskGet d2 (0 + (i - (length d1 - a))))d1, d2:list blocka, count:natH:count >= length d1 - aH0:a < length d1i:natH1:i < countn:~ i < length d1 - aSome (nth_error d2 (a + i - length d1)) = Some (nth_error d2 (0 + (i - (length d1 - a))))lia. Qed. End diskGets_proof.d1, d2:list blocka, count:natH:count >= length d1 - aH0:a < length d1i:natH1:i < countn:~ i < length d1 - aa + i - length d1 = 0 + (i - (length d1 - a))forall (d1 : list block) (a : nat) (x : block) (count : nat), a < length d1 -> a + count = S (length d1) -> diskGets (d1 ++ x :: nil) a count = diskGets d1 a (length d1 - a) ++ Some x :: nilforall (d1 : list block) (a : nat) (x : block) (count : nat), a < length d1 -> a + count = S (length d1) -> diskGets (d1 ++ x :: nil) a count = diskGets d1 a (length d1 - a) ++ Some x :: nild1:list blocka:natx:blockcount:natH:a < length d1H0:a + count = S (length d1)diskGets (d1 ++ x :: nil) a count = diskGets d1 a (length d1 - a) ++ Some x :: nilreplace (count - (length d1 - a)) with 1 by lia; simpl; auto. Qed.d1:list blocka:natx:blockcount:natH:a < length d1H0:a + count = S (length d1)diskGets d1 a (length d1 - a) ++ diskGets (x :: nil) 0 (count - (length d1 - a)) = diskGets d1 a (length d1 - a) ++ Some x :: nilforall (count : nat) (d : list block) (a a0 : nat) (v0 : block), a0 < a \/ a0 > a + count -> diskGets (diskUpd d a0 v0) a count = diskGets d a countforall (count : nat) (d : list block) (a a0 : nat) (v0 : block), a0 < a \/ a0 > a + count -> diskGets (diskUpd d a0 v0) a count = diskGets d a countcount:natIHcount:forall (d : list block) (a a0 : nat) (v0 : block), a0 < a \/ a0 > a + count -> diskGets (diskUpd d a0 v0) a count = diskGets d a countd:list blocka, a0:natv0:blockH:a0 < a \/ a0 > a + S countdiskGet (diskUpd d a0 v0) a :: diskGets (diskUpd d a0 v0) (a + 1) count = diskGet d a :: diskGets d (a + 1) countcount:natIHcount:forall (d : list block) (a a0 : nat) (v0 : block), a0 < a \/ a0 > a + count -> diskGets (diskUpd d a0 v0) a count = diskGets d a countd:list blocka, a0:natv0:blockH:a0 < a \/ a0 > a + S countdiskGet d a :: diskGets (diskUpd d a0 v0) (a + 1) count = diskGet d a :: diskGets d (a + 1) countauto. Qed.count:natIHcount:forall (d : list block) (a a0 : nat) (v0 : block), a0 < a \/ a0 > a + count -> diskGets (diskUpd d a0 v0) a count = diskGets d a countd:list blocka, a0:natv0:blockH:a0 < a \/ a0 > a + S countdiskGet d a :: diskGets d (a + 1) count = diskGet d a :: diskGets d (a + 1) countforall (count : nat) (d : disk) (a a0 : nat) (vs : list block), a0 + length vs < a \/ a0 >= a + count -> diskGets (diskUpds d a0 vs) a count = diskGets d a countforall (count : nat) (d : disk) (a a0 : nat) (vs : list block), a0 + length vs < a \/ a0 >= a + count -> diskGets (diskUpds d a0 vs) a count = diskGets d a countcount:natIHcount:forall (d : disk) (a a0 : nat) (vs : list block), a0 + length vs < a \/ a0 >= a + count -> diskGets (diskUpds d a0 vs) a count = diskGets d a countd:diska, a0:natvs:list blockH:a0 + length vs < a \/ a0 >= a + S countdiskGet (diskUpds d a0 vs) a :: diskGets (diskUpds d a0 vs) (a + 1) count = diskGet d a :: diskGets d (a + 1) countcount:natIHcount:forall (d : disk) (a a0 : nat) (vs : list block), a0 + length vs < a \/ a0 >= a + count -> diskGets (diskUpds d a0 vs) a count = diskGets d a countd:diska, a0:natvs:list blockH:a0 + length vs < a \/ a0 >= a + S countdiskGet d a :: diskGets (diskUpds d a0 vs) (a + 1) count = diskGet d a :: diskGets d (a + 1) countauto. Qed.count:natIHcount:forall (d : disk) (a a0 : nat) (vs : list block), a0 + length vs < a \/ a0 >= a + count -> diskGets (diskUpds d a0 vs) a count = diskGets d a countd:diska, a0:natvs:list blockH:a0 + length vs < a \/ a0 >= a + S countdiskGet d a :: diskGets d (a + 1) count = diskGet d a :: diskGets d (a + 1) countforall (vs : list block) (d : disk) (a : nat), a + length vs <= diskSize d -> diskGets (diskUpds d a vs) a (length vs) = map Some vsforall (vs : list block) (d : disk) (a : nat), a + length vs <= diskSize d -> diskGets (diskUpds d a vs) a (length vs) = map Some vsa:blockvs:list blockIHvs:forall (d : disk) (a : nat), a + length vs <= diskSize d -> diskGets (diskUpds d a vs) a (length vs) = map Some vsd:diska0:natH:a0 + S (length vs) <= diskSize ddiskGet (diskUpd (diskUpds d (a0 + 1) vs) a0 a) a0 :: diskGets (diskUpd (diskUpds d (a0 + 1) vs) a0 a) (a0 + 1) (length vs) = Some a :: map Some vsa:blockvs:list blockIHvs:forall (d : disk) (a : nat), a + length vs <= diskSize d -> diskGets (diskUpds d a vs) a (length vs) = map Some vsd:diska0:natH:a0 + S (length vs) <= diskSize dSome a :: diskGets (diskUpd (diskUpds d (a0 + 1) vs) a0 a) (a0 + 1) (length vs) = Some a :: map Some vsa:blockvs:list blockIHvs:forall (d : disk) (a : nat), a + length vs <= diskSize d -> diskGets (diskUpds d a vs) a (length vs) = map Some vsd:diska0:natH:a0 + S (length vs) <= diskSize da0 < diskSize (diskUpds d (a0 + 1) vs)a:blockvs:list blockIHvs:forall (d : disk) (a : nat), a + length vs <= diskSize d -> diskGets (diskUpds d a vs) a (length vs) = map Some vsd:diska0:natH:a0 + S (length vs) <= diskSize dSome a :: diskGets (diskUpd (diskUpds d (a0 + 1) vs) a0 a) (a0 + 1) (length vs) = Some a :: map Some vsa:blockvs:list blockIHvs:forall (d : disk) (a : nat), a + length vs <= diskSize d -> diskGets (diskUpds d a vs) a (length vs) = map Some vsd:diska0:natH:a0 + S (length vs) <= diskSize dSome a :: diskGets (diskUpds d (a0 + 1) vs) (a0 + 1) (length vs) = Some a :: map Some vsauto.a:blockvs:list blockIHvs:forall (d : disk) (a : nat), a + length vs <= diskSize d -> diskGets (diskUpds d a vs) a (length vs) = map Some vsd:diska0:natH:a0 + S (length vs) <= diskSize dSome a :: map Some vs = Some a :: map Some vsa:blockvs:list blockIHvs:forall (d : disk) (a : nat), a + length vs <= diskSize d -> diskGets (diskUpds d a vs) a (length vs) = map Some vsd:diska0:natH:a0 + S (length vs) <= diskSize da0 < diskSize (diskUpds d (a0 + 1) vs)lia. Qed.a:blockvs:list blockIHvs:forall (d : disk) (a : nat), a + length vs <= diskSize d -> diskGets (diskUpds d a vs) a (length vs) = map Some vsd:diska0:natH:a0 + S (length vs) <= diskSize da0 < diskSize dforall d1 d2 : list block, diskSize (d1 ++ d2) = diskSize d1 + diskSize d2apply app_length. Qed. Hint Rewrite append_size : disk_size. Hint Rewrite diskUpds_size : disk_size.forall d1 d2 : list block, diskSize (d1 ++ d2) = diskSize d1 + diskSize d2forall (d1 d2 : list block) (a : nat) (v : block), a < length d1 -> diskUpd (d1 ++ d2) a v = diskUpd d1 a v ++ d2forall (d1 d2 : list block) (a : nat) (v : block), a < length d1 -> diskUpd (d1 ++ d2) a v = diskUpd d1 a v ++ d2d2:list blocka:natv:blockH:a < 0diskUpd d2 a v = d2a:blockd1:list blockIHd1:forall (d2 : list block) (a : nat) (v : block), a < length d1 -> diskUpd (d1 ++ d2) a v = diskUpd d1 a v ++ d2d2:list blocka0:natv:blockH:a0 < S (length d1)match a0 with | 0 => v :: d1 ++ d2 | S a' => a :: diskUpd (d1 ++ d2) a' v end = match a0 with | 0 => v :: d1 | S a' => a :: diskUpd d1 a' v end ++ d2lia.d2:list blocka:natv:blockH:a < 0diskUpd d2 a v = d2a:blockd1:list blockIHd1:forall (d2 : list block) (a : nat) (v : block), a < length d1 -> diskUpd (d1 ++ d2) a v = diskUpd d1 a v ++ d2d2:list blocka0:natv:blockH:a0 < S (length d1)match a0 with | 0 => v :: d1 ++ d2 | S a' => a :: diskUpd (d1 ++ d2) a' v end = match a0 with | 0 => v :: d1 | S a' => a :: diskUpd d1 a' v end ++ d2rewrite IHd1 by lia; auto. Qed.a:blockd1:list blockIHd1:forall (d2 : list block) (a : nat) (v : block), a < length d1 -> diskUpd (d1 ++ d2) a v = diskUpd d1 a v ++ d2d2:list blocka0:natv:blockH:S a0 < S (length d1)a :: diskUpd (d1 ++ d2) a0 v = a :: diskUpd d1 a0 v ++ d2forall (d1 d2 : list block) (a : nat) (v : block), a >= length d1 -> diskUpd (d1 ++ d2) a v = d1 ++ diskUpd d2 (a - length d1) vforall (d1 d2 : list block) (a : nat) (v : block), a >= length d1 -> diskUpd (d1 ++ d2) a v = d1 ++ diskUpd d2 (a - length d1) vd2:list blocka:natv:blockH:a >= 0diskUpd d2 a v = diskUpd d2 (a - 0) va:blockd1:list blockIHd1:forall (d2 : list block) (a : nat) (v : block), a >= length d1 -> diskUpd (d1 ++ d2) a v = d1 ++ diskUpd d2 (a - length d1) vd2:list blocka0:natv:blockH:a0 >= S (length d1)match a0 with | 0 => v :: d1 ++ d2 | S a' => a :: diskUpd (d1 ++ d2) a' v end = a :: d1 ++ diskUpd d2 (a0 - S (length d1)) vreplace (a-0) with a by lia; auto.d2:list blocka:natv:blockH:a >= 0diskUpd d2 a v = diskUpd d2 (a - 0) va:blockd1:list blockIHd1:forall (d2 : list block) (a : nat) (v : block), a >= length d1 -> diskUpd (d1 ++ d2) a v = d1 ++ diskUpd d2 (a - length d1) vd2:list blocka0:natv:blockH:a0 >= S (length d1)match a0 with | 0 => v :: d1 ++ d2 | S a' => a :: diskUpd (d1 ++ d2) a' v end = a :: d1 ++ diskUpd d2 (a0 - S (length d1)) vrewrite IHd1 by lia; auto. Qed.a:blockd1:list blockIHd1:forall (d2 : list block) (a : nat) (v : block), a >= length d1 -> diskUpd (d1 ++ d2) a v = d1 ++ diskUpd d2 (a - length d1) vd2:list blocka0:natv:blockH:S a0 >= S (length d1)a :: diskUpd (d1 ++ d2) a0 v = a :: d1 ++ diskUpd d2 (a0 - length d1) vforall (d1 d2 : list block) (n : nat) (v : list block), n + length v < length d1 -> diskUpds (d1 ++ d2) n v = diskUpds d1 n v ++ d2forall (d1 d2 : list block) (n : nat) (v : list block), n + length v < length d1 -> diskUpds (d1 ++ d2) n v = diskUpds d1 n v ++ d2d1, d2:list blockn:natv:list blockH:n + length v < length d1diskUpds (d1 ++ d2) n v = diskUpds d1 n v ++ d2d1, d2, v:list blockforall n : nat, n + length v < length d1 -> diskUpds (d1 ++ d2) n v = diskUpds d1 n v ++ d2d1, d2:list blocka:blockv:list blockIHv:forall n : nat, n + length v < length d1 -> diskUpds (d1 ++ d2) n v = diskUpds d1 n v ++ d2n:natH:n + S (length v) < length d1diskUpd (diskUpds (d1 ++ d2) (n + 1) v) n a = diskUpd (diskUpds d1 (n + 1) v) n a ++ d2d1, d2:list blocka:blockv:list blockIHv:forall n : nat, n + length v < length d1 -> diskUpds (d1 ++ d2) n v = diskUpds d1 n v ++ d2n:natH:n + S (length v) < length d1diskUpd (diskUpds d1 (n + 1) v ++ d2) n a = diskUpd (diskUpds d1 (n + 1) v) n a ++ d2d1, d2:list blocka:blockv:list blockIHv:forall n : nat, n + length v < length d1 -> diskUpds (d1 ++ d2) n v = diskUpds d1 n v ++ d2n:natH:n + S (length v) < length d1n < length (diskUpds d1 (n + 1) v)unfold diskSize; lia. Qed.d1, d2:list blocka:blockv:list blockIHv:forall n : nat, n + length v < length d1 -> diskUpds (d1 ++ d2) n v = diskUpds d1 n v ++ d2n:natH:n + S (length v) < length d1n < diskSize d1forall (d1 d2 : list block) (n : nat) (v : list block), length d1 <= n -> diskUpds (d1 ++ d2) n v = d1 ++ diskUpds d2 (n - length d1) vforall (d1 d2 : list block) (n : nat) (v : list block), length d1 <= n -> diskUpds (d1 ++ d2) n v = d1 ++ diskUpds d2 (n - length d1) vd1, d2:list blockn:natv:list blockH:length d1 <= ndiskUpds (d1 ++ d2) n v = d1 ++ diskUpds d2 (n - length d1) vd1, d2, v:list blockforall n : nat, length d1 <= n -> diskUpds (d1 ++ d2) n v = d1 ++ diskUpds d2 (n - length d1) vd1, d2:list blocka:blockv:list blockIHv:forall n : nat, length d1 <= n -> diskUpds (d1 ++ d2) n v = d1 ++ diskUpds d2 (n - length d1) vn:natH:length d1 <= ndiskUpd (diskUpds (d1 ++ d2) (n + 1) v) n a = d1 ++ diskUpd (diskUpds d2 (n - length d1 + 1) v) (n - length d1) ad1, d2:list blocka:blockv:list blockIHv:forall n : nat, length d1 <= n -> diskUpds (d1 ++ d2) n v = d1 ++ diskUpds d2 (n - length d1) vn:natH:length d1 <= ndiskUpd (d1 ++ diskUpds d2 (n + 1 - length d1) v) n a = d1 ++ diskUpd (diskUpds d2 (n - length d1 + 1) v) (n - length d1) areplace (n + 1 - length d1) with (n - length d1 + 1) by lia; auto. Qed.d1, d2:list blocka:blockv:list blockIHv:forall n : nat, length d1 <= n -> diskUpds (d1 ++ d2) n v = d1 ++ diskUpds d2 (n - length d1) vn:natH:length d1 <= nd1 ++ diskUpd (diskUpds d2 (n + 1 - length d1) v) (n - length d1) a = d1 ++ diskUpd (diskUpds d2 (n - length d1 + 1) v) (n - length d1) aforall (A : Type) (l : list A) (n : nat) (r : A), nth_error l n = Some r -> firstn (S n) l = firstn n l ++ r :: nilforall (A : Type) (l : list A) (n : nat) (r : A), nth_error l n = Some r -> firstn (S n) l = firstn n l ++ r :: nilA:Typel:list An:natr:AH:nth_error l n = Some rfirstn (S n) l = firstn n l ++ r :: nilA:Typen:natr:Aforall l : list A, nth_error l n = Some r -> firstn (S n) l = firstn n l ++ r :: nilA:Typen:natr:AIHn:forall l : list A, nth_error l n = Some r -> match l with | nil => nil | a :: l0 => a :: firstn n l0 end = firstn n l ++ r :: nila:Al:list AH:nth_error l n = Some ra :: match l with | nil => nil | a :: l => a :: firstn n l end = a :: firstn n l ++ r :: nilrewrite IHn; auto. Qed.A:Typen:natr:AIHn:forall l : list A, nth_error l n = Some r -> match l with | nil => nil | a :: l0 => a :: firstn n l0 end = firstn n l ++ r :: nila:Al:list AH:nth_error l n = Some rmatch l with | nil => nil | a :: l => a :: firstn n l end = firstn n l ++ r :: nilforall (log : list block) (n : addr) (r : block), diskGet log n = Some r -> firstn (S n) log = firstn n log ++ r :: nilforall (log : list block) (n : addr) (r : block), diskGet log n = Some r -> firstn (S n) log = firstn n log ++ r :: nillog:list blockn:addrr:blockH:diskGet log n = Some rfirstn (S n) log = firstn n log ++ r :: niln:addrr:blockforall log : list block, diskGet log n = Some r -> firstn (S n) log = firstn n log ++ r :: niln:natr:blockIHn:forall log : list block, diskGet log n = Some r -> match log with | nil => nil | a :: l => a :: firstn n l end = firstn n log ++ r :: nilb:blocklog:list blockH:diskGet log n = Some rb :: match log with | nil => nil | a :: l => a :: firstn n l end = b :: firstn n log ++ r :: nilrewrite IHn; auto. Qed.n:natr:blockIHn:forall log : list block, diskGet log n = Some r -> match log with | nil => nil | a :: l => a :: firstn n l end = firstn n log ++ r :: nilb:blocklog:list blockH:diskGet log n = Some rmatch log with | nil => nil | a :: l => a :: firstn n l end = firstn n log ++ r :: nil
We combine all of the above theorems into a hint database called "upd".
This means that, when you type autorewrite with upd in some Coq proof,
Coq will try to rewrite using all of the hints in that database.
The using part of the hint tells Coq that all of the side conditions
associated with the rewrite must be solved using the tactic specified
in the using clause. This prevents Coq from applying a rewrite rule
if some side condition (like an address being out-of-bounds) cannot be
immediately proven.
Ltac solve_disk_size := solve [ autorewrite with disk_size; (auto || lia) ]. Hint Rewrite diskUpd_eq using solve_disk_size : upd. Hint Rewrite disk_oob_eq using solve_disk_size : upd. Hint Rewrite diskUpd_oob_eq using solve_disk_size : upd. Hint Rewrite diskUpd_size : upd. Hint Rewrite diskUpd_neq using (solve [ auto ]) : upd. Hint Rewrite diskUpd_comm_lt using solve_disk_size : upd. Hint Rewrite diskUpd_none using (solve [ auto ]) : upd. Hint Rewrite diskUpd_same using (solve [ auto ]) : upd. Hint Rewrite diskUpd_oob_noop using solve_disk_size : upd. Hint Rewrite diskUpd_twice : upd. Hint Rewrite diskUpds_neq using solve_disk_size : upd. Hint Rewrite diskUpds_diskUpd_comm using solve_disk_size : upd. Hint Rewrite diskUpds_size : upd. Hint Rewrite diskUpd_diskGets_neq using solve_disk_size : upd. Hint Rewrite diskUpds_diskGets_neq using solve_disk_size : upd. Hint Rewrite diskUpds_diskGets_eq using solve_disk_size : upd. Hint Rewrite diskShrink_size using solve_disk_size : upd. Hint Rewrite diskShrink_preserves using solve_disk_size : upd. Hint Rewrite diskShrink_diskUpd_last using solve_disk_size : upd. Hint Rewrite diskShrink_diskUpd_notlast using solve_disk_size : upd.