aboutsummaryrefslogtreecommitdiff
path: root/src/Reflection/Z/Bounds/InterpretationLemmas.v
blob: 11a6ea91e71812af608c69b31869af756392c46a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
Require Import Coq.ZArith.ZArith.
Require Import Coq.micromega.Psatz.
Require Import Crypto.Reflection.Z.Syntax.
Require Import Crypto.Reflection.Z.Syntax.Util.
Require Import Crypto.Reflection.Syntax.
Require Import Crypto.Reflection.Z.Bounds.Interpretation.
Require Import Crypto.Reflection.SmartMap.
Require Import Crypto.Util.ZUtil.
Require Import Crypto.Util.Bool.
Require Import Crypto.Util.FixedWordSizesEquality.
Require Import Crypto.Util.Option.
Require Import Crypto.Util.Tactics.BreakMatch.
Require Import Crypto.Util.Tactics.DestructHead.
Require Import Crypto.Util.Tactics.SpecializeBy.
Require Import Crypto.Util.Tactics.SplitInContext.
Require Import Crypto.Util.Tactics.UniquePose.

Local Notation pick_typeb := Bounds.bounds_to_base_type (only parsing).
Local Notation pick_type v := (SmartFlatTypeMap (fun _ => pick_typeb) v).

Local Open Scope Z_scope.

Local Ltac break_t_step :=
  first [ progress destruct_head'_and
        | progress destruct_head'_or
        | progress destruct_head'_prod
        | progress split_andb
        | break_innermost_match_step ].

Local Ltac fin_t :=
  first [ reflexivity
        | assumption
        | match goal with
          | [ |- and _ _ ]
            => first [ split; [ | solve [ fin_t ] ]
                     | split; [ solve [ fin_t ] | ] ];
               try solve [ fin_t ]
          end
        | omega ].

Local Ltac specializer_t_step :=
  first [ progress specialize_by_assumption
        | progress specialize_by fin_t ].

Local Ltac Zarith_t_step :=
  first [ match goal with
          | [ H : (?x <= ?y)%Z, H' : (?y <= ?x)%Z |- _ ]
            => assert (x = y) by omega; clear H H'
          end
        | progress Z.ltb_to_lt_in_context ].
Local Ltac Zarith_land_lor_t_step :=
  match goal with
  | [ |- _ <= Z.lor _ _ <= _ ]
    => split; etransitivity; [ | apply Z.lor_bounds; omega | apply Z.lor_bounds; omega | ]
  | [ |- 2^Z.log2_up (?x + 1) - 1 <= 2^Z.log2_up (?y + 1) - 1 ]
    => let H := fresh in assert (H : x <= y) by omega; rewrite H; reflexivity
  end.
Local Ltac word_arith_t :=
  match goal with
  | [ |- (0 <= FixedWordSizes.wordToZ ?w <= 2^2^Z.of_nat ?logsz - 1)%Z ]
    => clear; pose proof (@wordToZ_range logsz w); autorewrite with push_Zof_nat zsimplify_const in *; try omega
  end.

Local Ltac revert_min_max :=
  repeat match goal with
         | [ H : context[Z.min _ _] |- _ ] => revert H
         | [ H : context[Z.max _ _] |- _ ] => revert H
         end.
Local Ltac split_min_max :=
  repeat match goal with
         | [ H : (?a <= ?b)%Z |- context[Z.max ?a ?b] ]
           => rewrite (Z.max_r a b) by omega
         | [ H : (?b <= ?a)%Z |- context[Z.max ?a ?b] ]
           => rewrite (Z.max_l a b) by omega
         | [ H : (?a <= ?b)%Z |- context[Z.min ?a ?b] ]
           => rewrite (Z.min_l a b) by omega
         | [ H : (?b <= ?a)%Z |- context[Z.min ?a ?b] ]
           => rewrite (Z.min_r a b) by omega
         | [ |- context[Z.max ?a ?b] ]
           => first [ rewrite (Z.max_l a b) by omega
                    | rewrite (Z.max_r a b) by omega ]
         | [ |- context[Z.min ?a ?b] ]
           => first [ rewrite (Z.min_l a b) by omega
                    | rewrite (Z.min_r a b) by omega ]
         | _ => revert_min_max; progress repeat apply Z.min_case_strong; intros
         | _ => revert_min_max; progress repeat apply Z.max_case_strong; intros
         end.

Local Ltac case_Zvar_nonneg_on x :=
  is_var x;
  lazymatch type of x with
  | Z => lazymatch goal with
         | [ H : (0 <= x)%Z |- _ ] => fail
         | [ H : (x < 0)%Z |- _ ] => fail
         | _ => destruct (Z_lt_le_dec x 0); try omega
         end
  end.
Local Ltac case_Zvar_nonneg_step :=
  match goal with
  | [ |- context[?x] ]
    => case_Zvar_nonneg_on x
  end.
Local Ltac case_Zvar_nonneg := repeat case_Zvar_nonneg_step.

Local Ltac remove_binary_operation_le_hyps_step :=
  match goal with
  | [ H : (?f ?x ?y <= ?f ?x ?y')%Z |- _ ]
    => assert ((y = y') \/ (y < y' /\ 0 <= x))%Z by (assert (y <= y')%Z by omega; nia);
       clear H
  | [ H : (?f ?y ?x <= ?f ?y' ?x)%Z |- _ ]
    => assert ((y = y') \/ (y < y' /\ 0 <= x))%Z by (assert (y <= y')%Z by omega; nia);
       clear H
  | [ H : (?f ?x ?y <= ?f ?x ?y')%Z |- _ ]
    => assert ((y = y') \/ (y' < y /\ x <= 0))%Z by (assert (y' <= y)%Z by omega; nia);
       clear H
  | [ H : (?f ?y ?x <= ?f ?y' ?x)%Z |- _ ]
    => assert ((y = y') \/ (y' < y /\ x <= 0))%Z by (assert (y' <= y)%Z by omega; nia);
       clear H
  | [ H : ?T, H' : ?T |- _ ] => clear H'
  | [ H : ?A \/ (~?A /\ ?B), H' : ?A \/ (~?A /\ ?C) |- _ ]
    => assert (A \/ (~A /\ (B /\ C))) by (clear -H H'; tauto); clear H H'
  | _ => progress destruct_head' or; destruct_head' and; subst; try omega
  | [ |- (_ <= _ <= _)%Z ] => split
  | _ => case_Zvar_nonneg_step
  end.

Local Ltac saturate_with_shift_facts :=
  repeat match goal with
         | [ H : ?x <= ?y, H' : ?x' <= ?y' |- context[?x << ?x'] ]
           => unique assert (x << x' <= y << y') by (apply Z.shiftl_le_mono; omega)
         | [ H : ?x <= ?y, H' : ?x' <= ?y' |- context[?y << ?y'] ]
           => unique assert (x << x' <= y << y') by (apply Z.shiftl_le_mono; omega)
         | [ H : ?x <= ?y, H' : ?x' <= ?y' |- context[?x >> ?x'] ]
           => unique assert (x >> x' <= y >> y') by (apply Z.shiftr_le_mono; omega)
         | [ H : ?x <= ?y, H' : ?x' <= ?y' |- context[?y >> ?y'] ]
           => unique assert (x >> x' <= y >> y') by (apply Z.shiftr_le_mono; omega)
         end.
Local Ltac saturate_with_all_shift_facts :=
  repeat match goal with
         | _ => progress saturate_with_shift_facts
         | [ H : ?x <= ?y, H' : ?x' <= ?y' |- context[Z.shiftl _ _] ]
           => unique assert (x << x' <= y << y') by (apply Z.shiftl_le_mono; omega)
         | [ H : ?x <= ?y, H' : ?x' <= ?y' |- context[Z.shiftr _ _] ]
           => unique assert (x >> x' <= y >> y') by (apply Z.shiftr_le_mono; omega)
         end.
Local Ltac saturate_land_lor_facts :=
  repeat match goal with
         | [ |- context[Z.land ?x ?y] ]
           => let H := fresh in
              let H' := fresh in
              assert (H : 0 <= x) by omega;
              assert (H' : 0 <= y) by omega;
              unique pose proof (Z.land_upper_bound_r x y H H');
              unique pose proof (Z.land_upper_bound_l x y H H')
         | [ |- context[Z.land ?x ?y] ]
           => unique assert (0 <= Z.land x y) by (apply Z.land_nonneg; omega)
         | [ |- context[Z.land ?x ?y] ]
           => case_Zvar_nonneg_on x; case_Zvar_nonneg_on y
         | [ |- context[Z.lor ?x ?y] ]
           => let H := fresh in
              let H' := fresh in
              assert (H : 0 <= x) by omega;
              assert (H' : 0 <= y) by omega;
              unique pose proof (proj1 (Z.lor_bounds x y H H'));
              unique pose proof (proj2 (Z.lor_bounds x y H H'))
         | [ |- context[Z.lor ?x ?y] ]
           => unique assert (0 <= Z.lor x y) by (apply Z.lor_nonneg; omega)
         | [ |- context[Z.lor ?x ?y] ]
           => case_Zvar_nonneg_on x; case_Zvar_nonneg_on y
         end.
Local Ltac clean_neg :=
  repeat match goal with
         | [ H : (-?x) < 0 |- _ ] => assert (0 <= x) by omega; assert (x <> 0) by omega; clear H
         | [ H : -?x <= -?y |- _ ] => apply Z.opp_le_mono in H
         | [ |- -?x <= -?y ] => apply Z.opp_le_mono
         | _ => progress rewrite <- Z.opp_le_mono in *
         end.
Local Ltac replace_with_neg x :=
  assert (x = -(-x)) by omega; generalize dependent (-x);
  let x' := fresh in
  rename x into x'; intro x; intros; subst x';
  clean_neg.
Local Ltac replace_all_neg_with_pos :=
  repeat match goal with
         | [ H : ?x < 0 |- _ ] => replace_with_neg x
         end.
Local Ltac handle_shift_neg :=
  repeat first [ rewrite !Z.shiftr_opp_r
               | rewrite !Z.shiftl_opp_r ].

Local Ltac handle_four_corners_step_fast :=
  first [ progress destruct_head Bounds.t
        | progress cbv [Bounds.four_corners] in *
        | progress subst
        | Zarith_t_step
        | progress split_min_max
        | omega
        | nia ].
Local Ltac handle_four_corners_step :=
  first [ handle_four_corners_step_fast
        | remove_binary_operation_le_hyps_step ].
Local Ltac handle_four_corners :=
  lazymatch goal with
  | [ |- (ZRange.lower (Bounds.four_corners _ _ _) <= _ <= _)%Z ]
    => idtac
  end;
  repeat handle_four_corners_step.

Local Ltac rewriter_t :=
  first [ rewrite !Bool.andb_true_iff
        | rewrite !Bool.andb_false_iff
        | rewrite !Bool.orb_true_iff
        | rewrite !Bool.orb_false_iff
        | rewrite !Z.abs_opp
        | rewrite !Z.max_log2_up
        | rewrite !Z.add_max_distr_r
        | rewrite !Z.add_max_distr_l
        | rewrite wordToZ_ZToWord by (autorewrite with push_Zof_nat zsimplify_const; omega)
        | match goal with
          | [ H : _ |- _ ]
            => first [ rewrite !Bool.andb_true_iff in H
                     | rewrite !Bool.andb_false_iff in H
                     | rewrite !Bool.orb_true_iff in H
                     | rewrite !Bool.orb_false_iff in H ]
          end ].

Local Arguments Bounds.is_bounded_by' !_ _ _ / .

Lemma is_bounded_by_truncation_bounds Tout bs v
      (H : Bounds.is_bounded_by (T:=Tbase TZ) bs v)
  : Bounds.is_bounded_by (T:=Tbase Tout)
                         (Bounds.truncation_bounds (Bounds.bit_width_of_base_type Tout) bs)
                         (ZToInterp v).
Proof.
  destruct bs as [l u]; cbv [Bounds.truncation_bounds Bounds.is_bounded_by Bounds.is_bounded_by' Bounds.bit_width_of_base_type ZRange.is_bounded_by'] in *; simpl in *.
  repeat first [ break_t_step
               | fin_t
               | progress simpl in *
               | Zarith_t_step
               | rewriter_t
               | word_arith_t ].
Qed.

Local Arguments Z.pow : simpl never.
Local Arguments Z.add !_ !_.
Local Existing Instances Z.add_le_Proper Z.log2_up_le_Proper Z.pow_Zpos_le_Proper Z.sub_le_eq_Proper.
Lemma is_bounded_by_interp_op t tR (opc : op t tR)
      (bs : interp_flat_type Bounds.interp_base_type _)
      (v : interp_flat_type interp_base_type _)
      (H : Bounds.is_bounded_by bs v)
  : Bounds.is_bounded_by (Bounds.interp_op opc bs) (Syntax.interp_op _ _ opc v).
Proof.
  destruct opc; apply is_bounded_by_truncation_bounds;
    repeat first [ progress simpl in *
                 | progress cbv [interp_op lift_op cast_const Bounds.interp_base_type Bounds.is_bounded_by' ZRange.is_bounded_by'] in *
                 | progress destruct_head'_prod
                 | progress destruct_head'_and
                 | omega
                 | match goal with
                   | [ |- context[interpToZ ?x] ]
                     => generalize dependent (interpToZ x); clear x; intros
                   | [ |- _ /\ True ] => split; [ | tauto ]
                   end ].
  { handle_four_corners. }
  { handle_four_corners. }
  { handle_four_corners. }
  { destruct_head Bounds.t.
    case_Zvar_nonneg; replace_all_neg_with_pos; handle_shift_neg;
      autorewrite with Zshift_to_pow;
      rewrite ?Z.div_opp_l_complete by auto with zarith;
      autorewrite with Zpow_to_shift.
    16:split_min_max; saturate_with_shift_facts; omega.
    all:admit. }
  { destruct_head Bounds.t.
    case_Zvar_nonneg; replace_all_neg_with_pos; handle_shift_neg; admit. }
  { repeat first [ progress destruct_head Bounds.t
                 | progress simpl in *
                 | break_t_step
                 | Zarith_t_step
                 | rewriter_t
                 | progress replace_all_neg_with_pos
                 | progress saturate_land_lor_facts
                 | split_min_max; omega ];
      admit. }
  { repeat first [ progress destruct_head Bounds.t
                 | progress simpl in *
                 | break_t_step
                 | Zarith_t_step
                 | rewriter_t
                 | progress replace_all_neg_with_pos
                 | progress saturate_land_lor_facts
                 | progress Zarith_land_lor_t_step
                 | solve [ split_min_max; try omega; try Zarith_land_lor_t_step ] ];
      admit. }
  { repeat first [ progress destruct_head Bounds.t
                 | progress simpl in *
                 | progress split_min_max
                 | omega ]. }
Admitted.

Local Arguments lift_op : simpl never.
Local Arguments cast_back_flat_const : simpl never.
Local Arguments unzify_op : simpl never.
Local Arguments Z.pow : simpl never.
Local Arguments Z.add !_ !_.
Local Existing Instance Z.pow_Zpos_le_Proper.
Lemma pull_cast_genericize_op t tR (opc : op t tR)
      (bs : interp_flat_type Bounds.interp_base_type t)
      (v : interp_flat_type interp_base_type (pick_type bs))
      (H : Bounds.is_bounded_by bs
                                (SmartFlatTypeMapUnInterp
                                   (fun (t1 : base_type) (b0 : Bounds.interp_base_type t1) => cast_const) v))
  : interp_op t tR opc (cast_back_flat_const v)
    = cast_back_flat_const (interp_op (pick_type bs) (pick_type (Bounds.interp_op opc bs)) (genericize_op opc) v).
Proof.
  pose proof (is_bounded_by_interp_op t tR opc bs).
  unfold interp_op in *.
  rewrite Zinterp_op_genericize_op.
  generalize dependent (Zinterp_op t tR opc).
  generalize dependent (Bounds.interp_op opc bs); clear opc; simpl; intros.
  revert dependent t; induction tR as [tR| |]; intros;
    [
    | repeat first [ match goal with
                     | [ |- ?x = ?y ]
                       => transitivity tt; destruct x, y; reflexivity
                     end
                   | reflexivity
                   | progress simpl @Bounds.is_bounded_by in *
                   | rewrite !lift_op_prod_dst
                   | rewrite !cast_back_flat_const_prod
                   | progress split_and
                   | match goal with
                     | [ H : _ |- _ ] => first [ setoid_rewrite lift_op_prod_dst in H
                                               | setoid_rewrite cast_back_flat_const_prod in H ]
                     end
                   | setoid_rewrite lift_op_prod_dst
                   | match goal with
                     | [ H : _ |- _ ] => erewrite H by eassumption
                     end ].. ].
  revert dependent tR; induction t as [t| |]; intros;
    [
    | repeat first [ match goal with
                     | [ |- ?x = ?y ]
                       => transitivity tt; destruct x, y; reflexivity
                     end
                   | reflexivity
                   | progress simpl @Bounds.is_bounded_by in *
                   | rewrite !lift_op_prod_dst
                   | rewrite !cast_back_flat_const_prod
                   | progress split_and
                   | match goal with
                     | [ H : _ |- _ ] => first [ setoid_rewrite lift_op_prod_dst in H
                                               | setoid_rewrite cast_back_flat_const_prod in H ]
                     end
                   | setoid_rewrite lift_op_prod_dst
                   | match goal with
                     | [ H : _ |- _ ] => erewrite H by eassumption
                     end ].. ].
  { simpl in *; unfold unzify_op, cast_back_flat_const, SmartFlatTypeMap, Bounds.interp_base_type, cast_const, Bounds.is_bounded_by', lift_op, SmartFlatTypeMapUnInterp, SmartFlatTypeMapInterp2, cast_const in *; simpl in *.
    unfold Bounds.is_bounded_by', cast_const, ZToInterp, interpToZ, Bounds.bounds_to_base_type, ZRange.is_bounded_by' in *; simpl in *.
    destruct_head base_type; break_innermost_match; Z.ltb_to_lt; destruct_head Bounds.t;
      repeat match goal with
             | _ => progress destruct_head'_and
             | _ => reflexivity
             | [ H : forall v, _ /\ True -> _ |- _ ] => specialize (fun v pf => H v (conj pf I))
             | [ H : forall v, _ -> _ /\ True |- _ ] => pose proof (fun v pf => proj1 (H v pf)); clear H
             | [ H : True |- _ ] => clear H
             | [ H : ?T, H' : ?T |- _ ] => clear H
             | [ H : forall v, _ -> _ <= ?f v <= _ |- ?f ?v' = _ ]
               => specialize (H v')
             | [ H : forall v, _ -> _ <= ?f (?g v) <= _ |- ?f (?g ?v') = _ ]
               => specialize (H v')
             | [ H : forall v, _ -> _ <= ?f (?g (?h v)) <= _ /\ _ /\ _ |- context[?h ?v'] ]
               => specialize (H v')
             | [ H : forall v, _ -> _ <= ?f (?g (?h (?i v))) <= _ /\ _ /\ _ |- context[?h (?i ?v')] ]
               => specialize (H v')
             | _ => progress specialize_by omega
             | _ => rewrite wordToZ_ZToWord
                 by repeat match goal with
                           | [ |- and _ _ ] => split
                           | [ |- ?x < ?y ] => cut (1 + x <= y); [ omega | ]
                           | _ => omega
                           | _ => progress autorewrite with push_Zof_nat zsimplify_const
                           | _ => rewrite Z2Nat.id by auto with zarith
                           | _ => rewrite <- !Z.log2_up_le_full
                           end
             | _ => rewrite wordToZ_ZToWord in *
                 by repeat match goal with
                           | [ |- and _ _ ] => split
                           | [ |- ?x < ?y ] => cut (1 + x <= y); [ omega | ]
                           | _ => omega
                           | _ => progress autorewrite with push_Zof_nat zsimplify_const
                           | _ => rewrite Z2Nat.id by auto with zarith
                           | _ => rewrite <- !Z.log2_up_le_full
                           end
             | _ => rewrite wordToZ_ZToWord_wordToZ
                 by (rewrite Nat2Z.inj_le, Z2Nat.id, <- !Z.log2_up_le_pow2_full by auto with zarith; omega)
             | _ => rewrite wordToZ_ZToWord_wordToZ in *
                 by (rewrite Nat2Z.inj_le, Z2Nat.id, <- !Z.log2_up_le_pow2_full by auto with zarith; omega)
             end.
    all:admit. }
  { simpl in *.
    specialize (H0 tt I).
    simpl in *.
    hnf in H0.
    unfold cast_back_flat_const, lift_op, unzify_op in *; simpl in *.
    unfold interpToZ in *.
    unfold Bounds.bounds_to_base_type in *.
    destruct_head base_type; simpl in *.
    split_andb.
    Z.ltb_to_lt.
    all:destruct_head' and.
    all:simpl in *.
    all:break_innermost_match; break_match_hyps; split_andb; Z.ltb_to_lt; try reflexivity.
    all:try (simpl in *;
    rewrite wordToZ_ZToWord
      by (autorewrite with push_Zof_nat zsimplify_const;
        rewrite Z2Nat.id by auto with zarith;
        split; try omega;
        match goal with
        | [ |- (?x < ?y)%Z ]
          => apply (Z.lt_le_trans x (x + 1) y); [ omega | ]
        end;
        rewrite <- !Z.log2_up_le_full;
        omega)).
    all:try reflexivity.
    unfold interpToZ, cast_const.
    simpl.
    rewrite ZToWord_wordToZ_ZToWord; [ reflexivity | ].
    apply Nat2Z.inj_le.
    rewrite Z2Nat.id by auto with zarith.

Admitted.