Require Import String.
Require Import List.
Require Import Lia.
Require Import Utils.
Require Import DataRuntime.
Require Import NRARuntime.
Require Import CAMPRuntime.
  
Section CAMPtoNRA.
  
Local Open Scope string_scope.
  
Local Open Scope list_scope.
  
Context {
fruntime:
foreign_runtime}.
  
Definition lift_failure d :=
    
match d with
      | 
TerminalError => 
None
      | 
RecoverableError => 
Some (
dcoll nil)
      | 
Success d' => 
Some (
dcoll (
d'::
nil))
    
end.
Translation from CAMP to NRA 
  Fixpoint nra_of_camp (
p:
camp) : 
nra :=
    
match p with
    | 
pconst d' => 
nra_match (
NRAConst d')
    | 
punop uop p₁ => 
NRAMap (
NRAUnop uop NRAID) (
nra_of_camp p₁)
    | 
pbinop bop p₁ 
p₂ =>
      
NRAMap (
NRABinop bop (
NRAUnop (
OpDot "
a1") 
NRAID) (
NRAUnop (
OpDot "
a2") 
NRAID))
             (
NRAProduct (
NRAMap (
NRAUnop (
OpRec "
a1") 
NRAID) (
nra_of_camp p₁))
                         (
NRAMap (
NRAUnop (
OpRec "
a2") 
NRAID) (
nra_of_camp p₂)))
    | 
pmap p₁ =>
      
nra_match
        (
NRAUnop OpFlatten
                 (
NRAMap
                    (
nra_of_camp p₁)
                    (
unnest_two
                       "
a1"
                       "
PDATA"
                       (
NRAUnop OpBag (
nra_wrap_a1 (
NRAUnop (
OpDot "
PDATA") 
NRAID))))))
    | 
passert p₁ => 
NRAMap (
NRAConst (
drec nil)) (
NRASelect NRAID (
nra_of_camp p₁))
    | 
porElse p₁ 
p₂ => 
NRADefault (
nra_of_camp p₁) (
nra_of_camp p₂)
    | 
pit => 
nra_match nra_data
    | 
pletIt p₁ 
p₂ =>
      
NRAUnop OpFlatten
              (
NRAMap (
nra_of_camp p₂)
                      (
unnest_two
                         "
a1"
                         "
PDATA"
                         (
NRAUnop OpBag
                                  (
nra_wrap_a1 (
nra_of_camp p₁)))))
    | 
pgetConstant s => 
nra_match (
NRAGetConstant s)
    | 
penv => 
nra_match nra_bind
    | 
pletEnv p₁ 
p₂ =>
      
NRAUnop OpFlatten
              (
NRAMap
                 (
nra_of_camp p₂)
                 (
unnest_two 
                    "
PBIND1"
                    "
PBIND"
                    (
NRAMap (
NRABinop OpRecConcat
                                      (
NRAUnop (
OpRec "
PDATA") (
NRAUnop (
OpDot "
PDATA") 
NRAID))
                                      (
NRAUnop (
OpRec "
PBIND1") (
NRABinop OpRecMerge
                                                                          (
NRAUnop (
OpDot "
PBIND") 
NRAID)
                                                                          (
NRAUnop (
OpDot "
PBIND1") 
NRAID))))
                            (
unnest_two
                               "
a1"
                               "
PBIND1"
                               (
NRAUnop OpBag
                                        (
NRABinop OpRecConcat
                                                  NRAID
                                                  (
NRAUnop (
OpRec "
a1") (
nra_of_camp p₁))))))))
    | 
pleft =>
      
NRAApp (
NRAEither (
nra_match NRAID) (
nra_fail)) 
nra_data
    | 
pright =>
      
NRAApp (
NRAEither (
nra_fail) (
nra_match NRAID)) 
nra_data
    end.
top level version sets up the appropriate input 
      (with an empty context) 
  
  Definition nra_of_camp_top p :=
    
NRAUnop OpFlatten
          (
NRAMap (
nra_of_camp p)
                (
NRAUnop OpBag
                       (
nra_context (
NRAConst (
drec nil)) 
NRAID))).
Auxiliary lemmas -- all used inside pmap proof 
  Lemma lift_map_lift (
l:
list data) :
    
lift_map (
fun x : 
data => 
Some (
drec (("
PDATA", 
x) :: 
nil))) 
l =
    
Some (
map (
fun x => (
drec (("
PDATA", 
x) :: 
nil))) 
l).
Proof.
    induction l; simpl. reflexivity.
    rewrite IHl.
    reflexivity.
  Qed.
  Lemma lift_map_lift2 bind (
l l':
list data):
    (
lift_map
       (
fun x : 
data =>
          
match x with
            | 
drec r1 =>
              
Some
                (
drec
                   (
rec_concat_sort
                      (("
PBIND", 
drec bind)
                         :: ("
a1", 
dcoll l') :: 
nil) 
r1))
            | 
_ => 
None
          end)
       (
map (
fun x : 
data => 
drec (("
PDATA", 
x) :: 
nil)) 
l)) =
    
Some (
map (
fun x :
data => (
drec
                   (
rec_concat_sort
                      (("
PBIND", 
drec bind)
                         :: ("
a1", 
dcoll l') :: 
nil) (("
PDATA", 
x) :: 
nil)))) 
l). 
Proof.
    induction l; simpl.
    reflexivity.
    rewrite IHl.
    simpl.
    reflexivity.
  Qed.
  Lemma lift_map_lift3 bind (
l l':
list data):
    
lift_map
      (
fun x : 
data =>
         
match x with
           | 
drec r => 
Some (
drec (
rremove r "
a1"))
           | 
_ => 
None
         end)
      (
map
         (
fun x : 
data =>
            
drec
              (
rec_concat_sort
                 (("
PBIND", 
drec bind)
                    :: ("
a1", 
dcoll l') :: 
nil)
                 (("
PDATA", 
x) :: 
nil))) 
l ++ 
nil)
    =
    
Some (
map (
fun x : 
data =>
                 
drec
                   (
rec_concat_sort
                      (("
PBIND", 
drec bind) :: 
nil)
                      (("
PDATA", 
x) :: 
nil))) 
l ++ 
nil).
Proof.
    induction l; simpl.
    reflexivity.
    simpl.
    rewrite IHl.
    simpl.
    reflexivity.
  Qed.
  Lemma oflatten_lift1 (
l:
option (
list data)):
    (
olift
       (
fun d1 : 
data =>
          
lift_oncoll (
fun l0 : 
list data => 
lift dcoll (
oflatten l0)) 
d1)
       (
lift dcoll
             (
lift (
fun t' : 
list data => 
dcoll nil :: 
t') 
l))) =
     (
olift
       (
fun d1 : 
data =>
          
lift_oncoll (
fun l0 : 
list data => 
lift dcoll (
oflatten l0)) 
d1)
       (
lift dcoll l)).
Proof.
    destruct l; 
try reflexivity.
    
induction l; 
simpl; 
try reflexivity.
    
simpl.
    
unfold oflatten; 
simpl.
    
assert (
forall d, 
lift (
fun t':
list data => 
t') 
d = 
d).
    
intros.
    
destruct d; 
try reflexivity.
    
rewrite H.
    
reflexivity.
  Qed.
 
Theorem 4.2: lemma of translation correctness for campterns 
  Theorem camp_trans_correct {
h:
brand_relation_t} 
c p bind d:
    
lift_failure (
camp_eval h c p bind d) = 
nra_eval h c (
nra_of_camp p) (
nra_context_data (
drec bind) 
d).
Proof.
    revert d bind;
    
camp_cases (
induction p) 
Case; 
simpl; 
intros.
    - 
Case "
pconst"%
string.
      
reflexivity.
    - 
Case "
punop"%
string.
      
rewrite <- 
IHp; 
clear IHp; 
simpl.
      
destruct (
camp_eval h c p bind d); 
try reflexivity.
      
simpl; 
destruct (
unary_op_eval h u res); 
reflexivity.
    - 
Case "
pbinop"%
string.
      
rewrite <- 
IHp1; 
rewrite <- 
IHp2; 
clear IHp1 IHp2.
      
destruct (
camp_eval h c p1 bind d); 
try reflexivity.
      
destruct (
camp_eval h c p2 bind d); 
try reflexivity.
      
simpl; 
destruct (
binary_op_eval h b res res0); 
reflexivity.
    - 
Case "
pmap"%
string.
      
destruct d; 
try reflexivity.
      
unfold omap_product in *; 
simpl.
      
unfold oncoll_map_concat in *; 
simpl.
      
rewrite lift_map_lift; 
simpl.
      
unfold omap_concat in *; 
simpl.
      
rewrite lift_map_lift2; 
simpl.
      
rewrite lift_map_lift3; 
simpl.
      
induction l; 
simpl; 
try reflexivity.
      
unfold nra_context_data in IHp.
      
assert ((
rec_concat_sort (("
PBIND", 
drec bind) :: 
nil)
                   (("
PDATA", 
a) :: 
nil)) =
              ("
PBIND", 
drec bind) :: ("
PDATA", 
a) :: 
nil).
      
reflexivity.
      
rewrite H; 
clear H.
      
rewrite <- (
IHp a bind).
      
clear IHp.
      
destruct (
camp_eval h c p bind a); 
try reflexivity; 
simpl.
      
rewrite IHl; 
simpl.
      
rewrite oflatten_lift1.
      
reflexivity.
      
revert IHl.
      
destruct ((
lift_map (
nra_eval h c (
nra_of_camp p))
              (
map
                 (
fun x : 
data =>
                  
drec
                    (
rec_concat_sort (("
PBIND", 
drec bind) :: 
nil)
                       (("
PDATA", 
x) :: 
nil))) 
l ++ 
nil))).
      * 
simpl. 
intros.
        
unfold oflatten in *.
        
simpl.
        
revert IHl.
        
destruct ((
lift_flat_map
              (
fun x : 
data =>
               
match x with
               | 
dcoll y => 
Some y
               | 
_ => 
None
               end) 
l0)); 
simpl; 
intros;
        
revert IHl;
        
destruct (
gather_successes (
map (
camp_eval h c p bind) 
l)); 
intros; 
simpl in *; 
try reflexivity; 
congruence.
      * 
simpl.
        
destruct ((
gather_successes (
map (
camp_eval h c p bind) 
l))); 
simpl; 
intros.
        
reflexivity.
        
congruence.
        
congruence.
    - 
Case "
passert"%
string.
      
rewrite <- 
IHp; 
clear IHp; 
simpl.
      
destruct (
camp_eval h c p bind d); 
try reflexivity.
      
destruct res; 
try reflexivity; 
simpl.
      
destruct b; 
reflexivity.
    - 
Case "
porElse"%
string.
      
rewrite <- 
IHp1; 
clear IHp1; 
simpl.
      
destruct (
camp_eval h c p1 bind d); 
simpl; 
auto.
    - 
Case "
pit"%
string.
      
reflexivity.
    - 
Case "
pletIt"%
string.
      
rewrite <- 
IHp1; 
clear IHp1; 
simpl.
      
destruct (
camp_eval h c p1 bind d); 
try reflexivity.
      
simpl.
      
specialize (
IHp2 res).
      
unfold nra_context_data in IHp2.
      
rewrite <- 
IHp2; 
clear IHp2.
      
destruct (
camp_eval h c p2 bind res); 
reflexivity.      
    - 
Case "
pgetConstant"%
string.
      
destruct (
edot c s); 
simpl; 
trivial.
    - 
Case "
penv"%
string.
      
eauto. 
    - 
Case "
pletEnv"%
string.
      
rewrite <- 
IHp1; 
clear IHp1; 
simpl.
      
destruct (
camp_eval h c p1 bind d); 
try reflexivity.
      
destruct res; 
try reflexivity.
      
simpl.
      
destruct (
merge_bindings bind l); 
try reflexivity.
      
specialize (
IHp2 d l0).
      
unfold nra_context_data in *.
      
simpl.
      
rewrite <- 
IHp2; 
clear IHp2; 
simpl.
      
destruct (
camp_eval h c p2 l0 d); 
try reflexivity.
    - 
Case "
pleft"%
string.
      
unfold lift_failure. 
destruct d; 
simpl; 
trivial.
    - 
Case "
pright"%
string.
      
unfold lift_failure. 
destruct d; 
simpl; 
trivial.
  Qed.
 
  Lemma camp_trans_yields_coll {
h:
brand_relation_t} 
c p d d0:
    
Forall (
fun x => 
data_normalized h (
snd x)) 
c ->
    
nra_eval h c (
nra_of_camp p) 
d = 
Some d0 ->
    {
x | 
d0 = 
dcoll x}.
Proof.
    Ltac findcol := 
      
repeat match goal with
        | [
H:
context [ 
olift _ ?
x] |- 
_ ] => 
          (
case_eq x;  [
intros ?|
idtac]; 
intros eq; 
rewrite eq in H;
           
simpl in *; 
try discriminate)
        | [
H:
context [ 
olift2 _ ?
x ?
y] |- 
_ ] => 
          (
case_eq x; 
           [
intros ?|
idtac]; 
intros eq; 
rewrite eq in H;
           
simpl in *; 
try discriminate);
            (
case_eq y; 
             [
intros ?|
idtac]; 
intros eq2; 
rewrite eq2 in H;
             
simpl in *; 
try discriminate)
        | [
H:
lift_oncoll _ ?
d = 
Some _ |- 
_] => 
          
destruct d; 
simpl in *; 
try discriminate
        | [
H:
lift _ _ = 
Some _ |- 
_ ] =>
          
apply some_lift in H; 
destruct H; 
try subst
        | [
H:
Some _ = 
Some _ |- 
_ ] => 
inversion H; 
clear H; 
try subst
      end; 
eauto.
    
revert d d0; 
induction p; 
simpl; 
intros; 
try findcol.
    
destruct (
IHp1 _ _ H eq). 
subst.
    
destruct x; 
findcol.
    
destruct d; 
try congruence.
    
destruct (
edot l "
PDATA"); 
try congruence.
    
findcol.
    
destruct d1; 
try congruence;
    [ 
exists (
d1::
nil); 
congruence | 
exists (
nil); 
congruence].
    
destruct d1; 
try congruence;
    [ 
exists nil; 
congruence | 
exists (
d1::
nil); 
congruence].
  Qed.
 
  Lemma camp_trans_top_nra_context {
h:
brand_relation_t} 
c p d:
    
Forall (
fun x => 
data_normalized h (
snd x)) 
c ->
    
nra_eval h c (
nra_of_camp_top p) 
d 
    = 
nra_eval h c (
nra_of_camp p) (
nra_context_data (
drec nil) 
d).
Proof.
  Lemma camp_trans_top_correct {
h:
brand_relation_t} 
c p d:
    
Forall (
fun x => 
data_normalized h (
snd x)) 
c ->
    
lift_failure (
camp_eval h c p nil d) = 
nra_eval h c (
nra_of_camp_top p) 
d.
Proof.
  Definition lift_camp_failure (
d : 
option data) :=
    
match d with
      | 
Some (
dcoll nil) => 
RecoverableError
      | 
Some (
dcoll (
l::
nil)) => 
Success l
      | 
_ => 
TerminalError
    end.
  
Lemma camp_trans_correct_r {
h:
brand_relation_t} 
c p bind d:
      
camp_eval h c p bind d =
      
lift_camp_failure (
nra_eval h c (
nra_of_camp p) (
nra_context_data (
drec bind) 
d)).
Proof.
  Lemma camp_trans_top_correct_r {
h:
brand_relation_t} 
c p d:
    
Forall (
fun x => 
data_normalized h (
snd x)) 
c ->
      
camp_eval h c p nil d =
      
lift_camp_failure (
nra_eval h c (
nra_of_camp_top p) 
d).
Proof.
  Section size.
Proof showing linear size translation 
    Lemma camp_trans_size p :
      
nra_size (
nra_of_camp p) <= 41 * 
camp_size p.
Proof.
      induction p; simpl; lia.
    Qed.
  End size.
  
Section sugar.
  
    
Definition nra_of_pand (
p1 p2:
camp) : 
nra :=
      
nra_of_camp (
pand p1 p2).
    
Definition nra_for_pand (
q1 q2:
nra) : 
nra :=
      (♯
flatten(χ⟨
q2
                 ⟩( 
unnest_two "
PBIND1" "
PBIND"
                               (χ⟨‵[| ("
PDATA", (
ID) · "
PDATA")|]
                                   ⊕ ‵[| ("
PBIND1", (
ID) · "
PBIND" ⊗ (
ID) · "
PBIND1")|]
                                 ⟩( 
unnest_two "
a1" "
PBIND1"
                                               (‵{|
ID
                                                     ⊕ ‵[| ("
a1",
                                                            χ⟨‵[||] ⟩( σ⟨
ID ⟩( 
q1)))|]|}))))))%
nra.
    
Lemma nra_of_pand_works (
p1 p2:
camp) :
      
nra_of_camp (
pand p1 p2) = 
nra_for_pand (
nra_of_camp p1) (
nra_of_camp p2).
Proof.
      simpl.
      reflexivity.
    Qed.
  
    
    Definition nra_of_WW (
p:
camp) :=
      
nra_of_camp (
WW p).
  
End sugar.
  
Section Top.
    
Context (
h:
brand_relation_t).
    
Definition camp_to_nra_top (
q:
camp) : 
nra :=
      
NRAApp (
nra_of_camp q) (
nra_context (
NRAConst (
drec nil)) (
NRAConst dunit)).
    
Theorem camp_to_nra_top_correct :
      
forall q:
camp, 
forall global_env:
bindings,
          
camp_eval_top h q global_env =
          
nra_eval_top h (
camp_to_nra_top q) 
global_env.
Proof.
      
  End Top.
  
End CAMPtoNRA.