|
1 | | -import CoreModels.Funs |
| 1 | +import CoreModels.Core.Funs |
2 | 2 | import CoreModels.Spec.Aeneas |
3 | 3 |
|
4 | 4 | namespace CoreModels |
@@ -34,3 +34,78 @@ uscalar @[spec] theorem «%S».Core_modelsCmpPartialEqArray.eq_spec {N : Std.Usi |
34 | 34 | · convert h; grind |
35 | 35 |
|
36 | 36 | end CoreModels |
| 37 | + |
| 38 | + |
| 39 | + |
| 40 | +/-! ### Helper Triple: Array index by `Range Usize`. |
| 41 | +
|
| 42 | +Array variant of `core_models_Slice_Insts_index_RangeUsize_spec` |
| 43 | +(SliceSpecs.lean). The Array index reduces to the Slice index via |
| 44 | +`Array.to_slice`. -/ |
| 45 | + |
| 46 | +@[spec] |
| 47 | +theorem core_models_Array_Insts_index_RangeUsize_spec |
| 48 | + {T : Type} {N : Std.Usize} (arr : Std.Array T N) |
| 49 | + (r : CoreModels.core.ops.range.Range Std.Usize) |
| 50 | + (h0 : r.start.val ≤ r.end.val) (h1 : r.end.val ≤ N.val) : |
| 51 | + ⦃ ⌜ True ⌝ ⦄ |
| 52 | + CoreModels.core.Array.Insts.CoreOpsIndexIndex.index |
| 53 | + (CoreModels.core.ops.range.RangeUsize.Insts.CoreSliceIndexSliceIndexSliceSlice T) arr r |
| 54 | + ⦃ ⇓ r' => ⌜ r'.val = arr.val.slice r.start.val r.end.val ∧ |
| 55 | + r'.val.length = r.end.val - r.start.val ⌝ ⦄ := by |
| 56 | + -- Reduce to the slice version via `Array.to_slice`. |
| 57 | + unfold CoreModels.core.Array.Insts.CoreOpsIndexIndex.index |
| 58 | + -- Body: `core.slice.index.Slice.index inst (Array.to_slice arr) i`. |
| 59 | + have h1' : r.end.val ≤ (Std.Array.to_slice arr).val.length := by |
| 60 | + rw [Std.Array.val_to_slice] |
| 61 | + have : arr.val.length = N.val := arr.property |
| 62 | + omega |
| 63 | + have h_slice_val : (Std.Array.to_slice arr).val = arr.val := |
| 64 | + Std.Array.val_to_slice arr |
| 65 | + -- Use the existing slice spec. |
| 66 | + have h_slice := |
| 67 | + core_models_Slice_Insts_index_RangeUsize_spec (Std.Array.to_slice arr) r h0 h1' |
| 68 | + -- The slice version uses `CoreModels.core.Slice.Insts.CoreOpsIndexIndex.index`, |
| 69 | + -- which unfolds to the same `core.slice.index.Slice.index` we need here. |
| 70 | + -- Convert the slice spec's post (in terms of `arr.to_slice.val`) into one |
| 71 | + -- in terms of `arr.val`. |
| 72 | + obtain ⟨v, hv_eq, hv_val, hv_len⟩ := triple_exists_ok_sb h_slice |
| 73 | + refine triple_of_ok_sb (v := v) ?_ ?_ |
| 74 | + · -- Equality: `core.slice.index.Slice.index inst (Array.to_slice arr) r = .ok v`. |
| 75 | + have := hv_eq |
| 76 | + unfold CoreModels.core.Slice.Insts.CoreOpsIndexIndex.index at this |
| 77 | + exact this |
| 78 | + · refine ⟨?_, ?_⟩ |
| 79 | + · rw [hv_val, h_slice_val] |
| 80 | + · rw [hv_len] |
| 81 | + |
| 82 | + |
| 83 | +/-- **Generic pure-closure `[spec]` for `core_models.array.from_fn`.** |
| 84 | +
|
| 85 | +For any closure whose `call_mut` is pure (doesn't mutate state), |
| 86 | +`from_fn N inst c` succeeds and its `i`-th cell is `f i`. `hpure` is a |
| 87 | +Triple over each `call_mut` so `hax_mvcgen` can recurse through it via |
| 88 | +per-closure `@[spec]` lemmas. -/ |
| 89 | +@[spec] |
| 90 | +theorem from_fn_pure_spec |
| 91 | + {T F : Type} [Inhabited T] (N : Std.Usize) |
| 92 | + (inst : core_models.ops.function.FnMut F Std.Usize T) (c : F) (f : Nat → T) |
| 93 | + (hpure : ∀ k : Nat, k < N.val → |
| 94 | + ⦃ ⌜ True ⌝ ⦄ |
| 95 | + inst.call_mut c ⟨BitVec.ofNat _ k⟩ |
| 96 | + ⦃ ⇓ r => ⌜ r = (f k, c) ⌝ ⦄) : |
| 97 | + ⦃ ⌜ True ⌝ ⦄ |
| 98 | + core_models.array.from_fn N inst c |
| 99 | + ⦃ ⇓ a => ⌜ ∀ i : Nat, i < N.val → a.val[i]! = f i ⌝ ⦄ := by |
| 100 | + have hpure_eq : ∀ k : Nat, k < N.val → |
| 101 | + inst.call_mut c ⟨BitVec.ofNat _ k⟩ = .ok (f k, c) := |
| 102 | + fun k hk => result_eq_of_triple (hpure k hk) |
| 103 | + have heq := from_fn_pure_eq N inst c f hpure_eq |
| 104 | + rw [heq] |
| 105 | + simp only [Triple, WP.wp] |
| 106 | + apply SPred.pure_intro |
| 107 | + intro i hi |
| 108 | + show ((List.range N.val).map f)[i]! = f i |
| 109 | + rw [List.getElem!_eq_getElem?_getD, List.getElem?_map, |
| 110 | + List.getElem?_range hi] |
| 111 | + rfl |
0 commit comments