Library mcertikos.layerlib.LayerCalculusLemma

Require Import Coqlib.
Require Import MemoryX.
Require Import MemWithData.
Require Import liblayers.compat.CompatGenSem.
Require Import liblayers.compat.CompatLayers.
Require Import liblayers.compcertx.Stencil.

Section LayerCalculus.

  Context `{Hstencil: Stencil}.
  Context `{Hmem: Mem.MemoryModel}.
  Context `{Hmwd: UseMemWithData mem}.

  Lemma sim_commutativity {D1: compatdata} {D2: compatdata} {R: _ D1 D2}:
     L L1 L2,
      sim R L (L1 L2) →
      sim R L (L2 L1).
  Proof.
    intros.
    rewrite commutativity.
    assumption.
  Qed.

  Lemma sim_associativity {D1: compatdata} {D2: compatdata} {R: _ D1 D2}:
     L L1 L2 L3,
      sim R L (L1 (L2 L3)) →
      sim R L ((L1 L2) L3).
  Proof.
    intros.
    rewrite associativity.
    assumption.
  Qed.

  Lemma sim_assoc_comm {D1: compatdata} {D2: compatdata} {R: _ D1 D2}:
     L L1 L2 L3,
      sim R L (L2 (L1 L3)) →
      sim R L ((L1 L2) L3).
  Proof.
    intros.
    rewrite oplus_assoc_comm_equiv.
    assumption.
  Qed.

  Lemma sim_left {D1: compatdata} {D2: compatdata} {R: _ D1 D2}:
     L L1 L2,
      sim R L L1
      sim R L (L1 L2).
  Proof.
    intros.
    rewrite <- left_upper_bound.
    assumption.
  Qed.

  Lemma sim_eq {D1: compatdata} {D2: compatdata} {R: _ D1 D2}:
     L1 L1´,
      L1 = L1´
       L,
        sim R L L1´
        sim R L L1.
  Proof.
    intros. rewrite H. assumption.
  Qed.

  Lemma sim_eq_left {D1: compatdata} {D2: compatdata} {R: _ D1 D2}:
     L1 L1´ L1´´,
      L1 = (L1´ L1´´)
       L,
        sim R L L1´
        sim R L L1.
  Proof.
    intros. eapply sim_eq; try eassumption.
    apply sim_left. assumption.
  Qed.

  Lemma le_commutativity {D: compatdata}:
     (L L1 L2: compatlayer D),
      L (L1 L2)
      L (L2 L1).
  Proof.
    intros.
    rewrite commutativity.
    assumption.
  Qed.

  Lemma le_associativity {D: compatdata}:
     (L L1 L2 L3: compatlayer D),
      L (L1 (L2 L3))
      L ((L1 L2) L3).
  Proof.
    intros.
    rewrite associativity.
    assumption.
  Qed.

  Lemma le_assoc_comm {D: compatdata}:
     (L L1 L2 L3: compatlayer D),
      L (L2 (L1 L3))
      L ((L1 L2) L3).
  Proof.
    intros.
    rewrite oplus_assoc_comm_equiv.
    assumption.
  Qed.

  Lemma le_left {D: compatdata}:
     (L L1 L2: compatlayer D),
      L L1
      L (L1 L2).
  Proof.
    intros.
    rewrite <- left_upper_bound.
    assumption.
  Qed.

  Lemma le_right {D: compatdata}:
     (L L1 L2: compatlayer D),
      L L2
      L (L1 L2).
  Proof.
    intros.
    rewrite <- right_upper_bound.
    assumption.
  Qed.

  Lemma layer_le_trans `{D: compatdata}:
     (LT LL LH: compatlayer D),
      LL LT = LH
      LL LH.
  Proof.
    intros.
    rewrite <- H.
    apply left_upper_bound.
  Qed.

  Lemma sim_monotonic8 {D1: compatdata} {D2: compatdata} {R: _ D1 D2}:
     L1 L2 L3 L4 L5 L6 L7 L8 L1´ L2´ L3´ L4´ L5´ L6´ L7´ L8´,
      sim R L1 L1´
      sim R L2 L2´
      sim R L3 L3´
      sim R L4 L4´
      sim R L5 L5´
      sim R L6 L6´
      sim R L7 L7´
      sim R L8 L8´
      sim R (L1 L2 L3 L4 L5 L6 L7 L8)
          (L1´ L2´ L3´ L4´ L5´ L6´ L7´ L8´).
  Proof.
    intros. repeat apply oplus_sim_monotonic; assumption.
  Qed.

  Lemma sim_monotonic7 {D1: compatdata} {D2: compatdata} {R: _ D1 D2}:
     L1 L2 L3 L4 L5 L6 L7 L1´ L2´ L3´ L4´ L5´ L6´ L7´,
      sim R L1 L1´
      sim R L2 L2´
      sim R L3 L3´
      sim R L4 L4´
      sim R L5 L5´
      sim R L6 L6´
      sim R L7 L7´
      sim R (L1 L2 L3 L4 L5 L6 L7)
          (L1´ L2´ L3´ L4´ L5´ L6´ L7´).
  Proof.
    intros. repeat apply oplus_sim_monotonic; assumption.
  Qed.

  Lemma sim_monotonic6 {D1: compatdata} {D2: compatdata} {R: _ D1 D2}:
     L1 L2 L3 L4 L5 L6 L1´ L2´ L3´ L4´ L5´ L6´ ,
      sim R L1 L1´
      sim R L2 L2´
      sim R L3 L3´
      sim R L4 L4´
      sim R L5 L5´
      sim R L6 L6´
      sim R (L1 L2 L3 L4 L5 L6)
          (L1´ L2´ L3´ L4´ L5´ L6´).
  Proof.
    intros. repeat apply oplus_sim_monotonic; assumption.
  Qed.

  Lemma sim_monotonic5 {D1: compatdata} {D2: compatdata} {R: _ D1 D2}:
     L1 L2 L3 L4 L5 L1´ L2´ L3´ L4´ L5´ ,
      sim R L1 L1´
      sim R L2 L2´
      sim R L3 L3´
      sim R L4 L4´
      sim R L5 L5´
      sim R (L1 L2 L3 L4 L5)
          (L1´ L2´ L3´ L4´ L5´).
  Proof.
    intros. repeat apply oplus_sim_monotonic; assumption.
  Qed.

  Lemma sim_monotonic4 {D1: compatdata} {D2: compatdata} {R: _ D1 D2}:
     L1 L2 L3 L4 L1´ L2´ L3´ L4´,
      sim R L1 L1´
      sim R L2 L2´
      sim R L3 L3´
      sim R L4 L4´
      sim R (L1 L2 L3 L4) (L1´ L2´ L3´ L4´).
  Proof.
    intros. repeat apply oplus_sim_monotonic; assumption.
  Qed.

  Lemma sim_monotonic3 {D1: compatdata} {D2: compatdata} {R: _ D1 D2}:
     L1 L2 L3 L1´ L2´ L3´,
      sim R L1 L1´
      sim R L2 L2´
      sim R L3 L3´
      sim R (L1 L2 L3 )
          (L1´ L2´ L3´).
  Proof.
    intros. repeat apply oplus_sim_monotonic; assumption.
  Qed.

  Lemma sim_monotonic2 {D1: compatdata} {D2: compatdata} {R: _ D1 D2}:
     L1 L2 L1´ L2´,
      sim R L1 L1´
      sim R L2 L2´
      sim R (L1 L2) (L1´ L2´).
  Proof.
    intros. apply oplus_sim_monotonic; assumption.
  Qed.

End LayerCalculus.

    Ltac sim_oplus_split_straight:=
      lazymatch goal with
        | |- sim _ (_ _ _ _ _ _ _ _) _
          apply sim_monotonic8; [| | | | | | | sim_oplus_split_straight]
        | |- sim _ (_ _ _ _ _ _ _) _
          apply sim_monotonic7; [| | | | | |sim_oplus_split_straight]
        | |- sim _ (_ _ _ _ _ _) _
          apply sim_monotonic6; [| | | | |sim_oplus_split_straight]
        | |- sim _ (_ _ _ _ _) _
          apply sim_monotonic5; [| | | | sim_oplus_split_straight]
        | |- sim _ (_ _ _ _) _
          apply sim_monotonic4; [| | |sim_oplus_split_straight]
        | |- sim _ (_ _ _) _
          apply sim_monotonic3; [| | sim_oplus_split_straight]
        | |- sim _ (_ _) _
          apply sim_monotonic2; [|sim_oplus_split_straight]
        | _idtac
      end.

  Ltac sim_move_to_head a :=
    match goal with
      | |- sim _ _ ?T
        match T with
          | a _idtac
          | ?A ?B
            match A with
              | context [ a ] ⇒
                match A with
                  | ?C ?D
                    match C with
                      | context [a] ⇒ apply sim_associativity;
                                      sim_move_to_head a
                      | _apply sim_assoc_comm; sim_move_to_head a
                    end
                  | _idtac
                end
              | _apply sim_commutativity; sim_move_to_head a
            end
        end
    end.

   Ltac sim_oplus_split:=
    match goal with
      | |- sim _ ?A ?B
        match A with
          | (?a _) ⇒ sim_move_to_head a;
                       match B with
                         | (_ _) ⇒ idtac
                         | _apply sim_left
                       end
          | (?a _ _ ) ⇒
            sim_move_to_head a; apply oplus_sim_monotonic; [| sim_oplus_split]
        end
      | _idtac
    end.

  Ltac le_move_to_head a :=
    match goal with
      | |- _ ?T
        match T with
          | a _idtac
          | ?A ?B
            match A with
              | context [ a ] ⇒
                match A with
                  | ?C ?D
                    match C with
                      | context [a] ⇒ apply le_associativity;
                                      le_move_to_head a
                      | _apply le_assoc_comm; le_move_to_head a
                    end
                  | _idtac
                end
              | _apply le_commutativity; le_move_to_head a
            end
        end
    end.

  Ltac le_oplus_split:=
    match goal with
      | |- ?A ?B
        match A with
          | (?a _) ⇒ le_move_to_head a;
                       match B with
                         | (_ _) ⇒ idtac
                         | _apply le_left
                       end
          | (?a _ _ ) ⇒
            le_move_to_head a; apply oplus_monotonic; [ reflexivity | le_oplus_split]
        end
      | _idtac
    end.

  Ltac le_move_to_head_quick a :=
    match goal with
      | |- _ ?T
        match T with
          | a _idtac
          | ?A ?B
            match A with
              | context [ a ] ⇒ apply le_left; le_move_to_head_quick a
              | _apply le_right; le_move_to_head_quick a
            end
        end
    end.

  Ltac le_oplus_split_quick:=
    match goal with
      | |- (?a _) ?B
        le_move_to_head_quick a; reflexivity
    end.

Recursively unfold layer definitions.

  Ltac unfold_layer t :=
    lazymatch t with
      | _ _
        idtac
      | ?L1 ?L2
        unfold_layer L1;
        unfold_layer L2
      | _
        let def := eval red in t in
        change t with def;
        unfold_layer def
      | _
        idtac
    end.

  Ltac unfold_layers :=
    match goal with
      | |- ?L1 ?L2
        unfold_layer L1;
        unfold_layer L2
      | |- sim _ ?L1 ?L2
        unfold_layer L1;
        unfold_layer L2
    end.

For (≤), we can use the pseudojoin reflection-based tactic. TODO: extend to sim and see if that's faster, for sim_oplus.

  Require Import PseudoJoinReflection.

  Ltac le_oplus :=
    match goal with
      | |- le (A := compatlayer ?D) _ _
        pose proof (sim_pseudojoin _ D);
        unfold_layers;
        unfold AST.ident;
        pjr
      | |- le _ _
        unfold_layers;
        unfold AST.ident;
        pjr
      | |- ?goal
        fail 1 "le_oplus could not prove:" goal
    end.

Final tactic: break down the inequality into components and try to solve the parts that are the same.

  Ltac construct_passthrough_layer T1 T2:=
    match T1 with
      | (?a _) ?B
        match T2 with
          | context [a ?X] ⇒
            let T2´ := (construct_passthrough_layer B T2) in
            constr : ((a X) T2´)
        end
      | (?a _)=>
        match T2 with
          | context [a ?X] ⇒
            constr : (a X)
        end
    end.

  Ltac construct_left_layer T1 T2 D:=
    match T2 with
      | ?A ?B
        let T21 := (construct_left_layer T1 A D) in
        let T22 := (construct_left_layer T1 B D) in
        match T21 with
          | T22
          | _match T22 with
                   | T21
                   | _constr : (T21 T22)
                 end
        end
      | (?a ?X) ⇒
        match T1 with
          | context [a] ⇒ constr : (@emptyset _ (layer_empty D))
          | _constr : (a X)
        end
    end.

  Ltac sim_oplus :=
    unfold_layers;
    match goal with
      | |- le (A := _ ?D) ?T1 ?T2
        change (sim id T1 T2);
        sim_oplus
      | |- simRR _ ?D _ ?T1 ?T2
        let L1 := construct_passthrough_layer T1 T2 in
        let L2 := construct_left_layer T1 T2 D in
        change T2 with (L1 L2);
          apply sim_left;
          try reflexivity;
          sim_oplus_split_straight
    end.

For backward compatibility. Calls can be replaced by sim_oplus_final, which infers D automatically and unfolds layers if needed.
  Ltac sim_oplus_split_final D :=
    sim_oplus.