Qcert.DNNRC.Typing.TDNNRCInfer


Section TDNNRCInfer.




Type inference for NNNRC when given the type of the environment


  Section helpers.
    Context {ftype:foreign_type}.
    Context {br:brand_relation}.

    Definition lift_tlocal (dτ:drtype) : option rtype :=
    match dτ with
    | Tlocal τ ⇒ Some τ
    | Tdistr _None
    end.

  Definition lift_tdistr (dτ:drtype) : option rtype :=
    match dτ with
    | Tlocal _None
    | Tdistr τ ⇒ Some (Coll τ)
    end.

  Definition drtype_join (dτ dτ:drtype) : option drtype
    := match dτ, dτ with
       | Tlocal τ, Tlocal τSome (Tlocal τ))
       | Tdistr τ, Tdistr τSome (Tdistr τ))
       | _, _None
       end.

  Record type_annotation {A:Set} : Set :=
    mkType_annotation {
        ta_base:A
        
        ; ta_inferred:drtype
        
        ; ta_required:drtype

      }.

    Definition drtype_map (f:rtypertype) (d:drtype) : drtype
    := match d with
       | Tlocal tTlocal (f t)
       | Tdistr tTdistr (f t)
       end.

    Definition drtype_omap (f:rtypeoption rtype) (d:drtype) : option drtype
    := match d with
       | Tlocal tlift Tlocal (f t)
       | Tdistr tlift Tdistr (f t)
       end.


    End helpers.

  Context {fruntime:foreign_runtime}.
  Context {ftype:foreign_type}.
  Context {m:brand_model}.
  Context {fdtyping:foreign_data_typing}.
  Context {fboptyping:foreign_binary_op_typing}.
  Context {fuoptyping:foreign_unary_op_typing}.
  Context {plug_type:Set}.
  Context {plug:AlgPlug plug_type}.

  Definition di_typeof {A} (d:dnnrc (type_annotation A) plug_type)
    := ta_inferred (dnnrc_annotation_get d).

  Definition di_required_typeof {A} (d:dnnrc (type_annotation A) plug_type)
    := ta_required (dnnrc_annotation_get d).

  Definition ta_mk {A:Set} (base:A) (dτ:drtype) : type_annotation A
    := mkType_annotation base dτ dτ.

  Definition ta_require {A} (dτ:drtype) (d:dnnrc (type_annotation A) plug_type)
    := dnnrc_annotation_update
         (fun a:type_annotation A
            mkType_annotation (ta_base a) (ta_inferred a) dτ) d.

  Definition bind_local_distr {A} (dτ:drtype) (f1:rtype A)
             (f2:rtype A) : A :=
    match dτ with
    | Tlocal τ ⇒ f1 τ
    | Tdistr τ ⇒ f2 τ
    end.

  Fixpoint infer_dnnrc_type {A} (tenv:tdbindings) (n:dnnrc A plug_type) :
    option (dnnrc (type_annotation A) plug_type)
    := match n with
       | DNNRCVar a v
         lift (fun τ ⇒ DNNRCVar (ta_mk a τ) v)
              (lookup equiv_dec tenv v)
              
       | DNNRCConst a d
         lift (fun τ ⇒ DNNRCConst (ta_mk a (Tlocal τ)) d)
              (infer_data_type (normalize_data brand_relation_brands d))
              
       | DNNRCBinop a b n1 n2
         let binf (n₁ n₂:dnnrc (type_annotation A) plug_type) : option (dnnrc (type_annotation A) plug_type)
             := let dτ := (di_typeof n₁) in
                let dτ := (di_typeof n₂) in
                olift2 (fun τ τ
                          lift (fun τs
                                  let '(τ, τ₁', τ₂') := τs in
                                  DNNRCBinop
                                    (ta_mk a (Tlocal τ))
                                    b
                                    (ta_require (Tlocal τ₁') n₁)
                                    (ta_require (Tlocal τ₂') n₂))
                          (infer_binop_type_sub b τ τ))
                       (lift_tlocal dτ) (lift_tlocal dτ)
         in
         olift2 binf (infer_dnnrc_type tenv n1) (infer_dnnrc_type tenv n2)

       | DNNRCUnop a u n1
         let unf (n₁:dnnrc (type_annotation A) plug_type) : option (dnnrc (type_annotation A) plug_type)
             := let dτ := (di_typeof n₁) in
                bind_local_distr dτ
                                 
                                 (fun τ
                                    lift (fun τs
                                            let '(τ, τ₁') := τs in
                                            DNNRCUnop
                                              (ta_mk a (Tlocal τ))
                                              u
                                              (ta_require (Tlocal τ₁') n₁))
                                         (infer_unop_type_sub u τ))
                                 
                                 
                                 (fun τ
                                    match u with
                                    | ACount
                                      lift (fun τs
                                              let '(τ, τ₁') := τs in
                                              DNNRCUnop
                                                (ta_mk a (Tlocal τ))
                                                ACount
                                                (ta_require (Tlocal τ₁') n₁))
                                           (infer_unop_type_sub ACount (Coll τ))
                                    | ASum
                                      lift (fun τs
                                              let '(τ, τ₁') := τs in
                                              DNNRCUnop
                                                (ta_mk a (Tlocal τ))
                                                ASum
                                                (ta_require (Tlocal τ₁') n₁))
                                           (infer_unop_type_sub ASum (Coll τ))
                                    | ADistinct
                                      olift (fun τs
                                              let '(τ, τ₁') := τs in
                                              lift2 (fun τc
                                                       fun τc₁'
                                                         DNNRCUnop
                                                           (ta_mk a (Tdistr τc))
                                                           ADistinct
                                                           (ta_require (Tdistr τc₁') n₁))
                                                    (tuncoll τ)
                                                    (tuncoll τ₁'))
                                           (infer_unop_type_sub ADistinct (Coll τ))
                                    | AFlatten
                                      olift (fun τs
                                              let '(τ, τ₁') := τs in
                                              lift2 (fun τc
                                                       fun τc₁'
                                                         DNNRCUnop
                                                           (ta_mk a (Tdistr τc))
                                                           AFlatten
                                                           (ta_require (Tdistr τc₁') n₁))
                                                    (tuncoll τ)
                                                    (tuncoll τ₁'))
                                           (infer_unop_type_sub AFlatten (Coll τ))
                                    | _None
                                    end
                                 )
         in
         olift unf (infer_dnnrc_type tenv n1)

       | DNNRCLet a v n1 n2
         bind (infer_dnnrc_type tenv n1)
              (fun n₁
                 let dτ := (di_typeof n₁) in
                 lift (fun n₂DNNRCLet (ta_mk a (di_typeof n₂)) v n₁ n₂)
                      (infer_dnnrc_type ((v,dτ)::tenv) n2))

       | DNNRCFor a v n1 n2
         bind (infer_dnnrc_type tenv n1)
              (fun n₁
                 bind_local_distr (di_typeof n₁)
                                  
                                  (fun τ₁l
                                     let τ₁l' := τ₁l (Coll ) in
                                     bind (tuncoll τ₁l')
                                          (fun τ
                                             bind (infer_dnnrc_type ((v,Tlocal τ)::tenv) n2)
                                                  (fun n₂
                                                     let τ := di_typeof n₂ in
                                                     lift (fun τ₂'
                                                             DNNRCFor
                                                               (ta_mk a (Tlocal (Coll τ₂')))
                                                               v
                                                               (ta_require (Tlocal τ₁l') n₁)
                                                               n₂)
                                                          (lift_tlocal τ))))
                                  
                                  (fun τ₁l
                                     let τ := τ₁l in
                                     bind (infer_dnnrc_type ((v,Tlocal τ)::tenv) n2)
                                          (fun n₂
                                             let τ := di_typeof n₂ in
                                             lift (fun τ₂'
                                                     DNNRCFor
                                                       (ta_mk a (Tdistr τ₂'))
                                                       v
                                                       (ta_require (Tlocal τ) n₁)
                                                       n₂)
                                                  (lift_tlocal τ)))
              )
       | DNNRCIf a n0 n1 n2
         bind (infer_dnnrc_type tenv n0)
              (fun n₀
                 let dτ := di_typeof n₀ in
                 if (drtype_sub_dec dτ (Tlocal Bool))
                 then
                   bind (infer_dnnrc_type tenv n1)
                        (fun n₁
                           bind (infer_dnnrc_type tenv n2)
                                (fun n₂
                                   bind (drtype_join (di_typeof n₁) (di_typeof n₂))
                                        (fun dτ ⇒
                                           Some (DNNRCIf
                                                   (ta_mk a dτ)
                                                   (ta_require (Tlocal Bool) n₀)
                                                   (ta_require dτ n₁)
                                                   (ta_require dτ n₂)
                                   
                        ))))
                 else None
              )

       | DNNRCEither a n0 v1 n1 v2 n2
         bind (infer_dnnrc_type tenv n0)
              (fun n₀
                 bind (lift_tlocal (di_typeof n₀))
                      (fun dτ₀l
                         
                         let τ₀l' := dτ₀l (Either ) in
                         bind (tuneither τ₀l')
                              (fun τlτr
                                    let '(τl, τr) := τlτr in
                                    bind (infer_dnnrc_type
                                            ((v1,Tlocal τl)::tenv) n1)
                                         (fun n₁
                                            bind (infer_dnnrc_type
                                                    ((v2,Tlocal τr)::tenv) n2)
                                                 (fun n₂
                                                    bind (drtype_join (di_typeof n₁) (di_typeof n₂))
                                        (fun dτ ⇒
                                           Some (DNNRCEither
                                                   (ta_mk a dτ)
                                                   (ta_require (Tlocal τ₀l') n₀)
                                                   v1
                                                   (ta_require dτ n₁)
                                                   v2
                                                   (ta_require dτ n₂)
                                 )
              ))))))

       | DNNRCCollect a n0
         bind (infer_dnnrc_type tenv n0)
              (fun n₀
                 bind (lift_tdistr (di_typeof n₀))
                      (fun τ
                         let τ := Tlocal τ in
                         Some (DNNRCCollect
                                 (ta_mk a τ)
                                 n₀)))

       | DNNRCDispatch a n0
         bind (infer_dnnrc_type tenv n0)
              (fun n₀
                 bind (lift_tlocal (di_typeof n₀))
                      (fun τ₀l
                         let τ₀l' := τ₀l (Coll ) in
                         bind (tuncoll τ₀l')
                              (fun τ
                                 let τ := Tdistr τ in
                                 Some (DNNRCDispatch
                                         (ta_mk a τ)
                                         (ta_require (Tlocal τ₀l') n₀
              )))))

       | DNNRCGroupBy a g sl n1
         bind (infer_dnnrc_type tenv n1)
              (fun n₁
                 bind (lift_tlocal (di_typeof n₁))
                      (fun τ₁l
                         let τ₁l' := τ₁l (Coll ) in
                         bind (tuncoll τ₁l')
                              (fun τ
                                 olift (fun τs
                                         let '(τ, τ₁') := τs in
                                         olift (fun τs₂
                                                 let '(τ, τ₂') := τs₂ in
                                                 lift (fun τs₃
                                                         let '(τ, τ₃', τ₃'') := τs₃ in
                                                         DNNRCGroupBy
                                                           (ta_mk a (Tlocal (Coll τ)))
                                                           g sl
                                                           (ta_require (Tlocal (Coll τ₁l')) n₁))
                                                      (infer_binop_type_sub AConcat τ τ)
                                               )
                                               (infer_unop_type_sub (ARec g) τ₁l'))
                                       (infer_unop_type_sub (ARecProject sl) τ))))
       | DNNRCAlg _ _ _None
       end.

  Example ex1 : dnnrc unit plug_type
    := DNNRCLet tt "x"%string (DNNRCConst tt (dnat 3)) (DNNRCBinop tt ALt (DNNRCVar tt "x"%string)
                 (DNNRCConst tt (dnat 5))).

  Example ex2 : dnnrc unit plug_type
    := DNNRCFor tt
               "x"%string
               (DNNRCConst tt (dcoll nil))
               (DNNRCIf tt
                       (DNNRCVar tt "x"%string)
                       (DNNRCConst tt (dcoll ((dbool true)::nil)))
                       (DNNRCConst tt (dcoll ((dnat 3)::nil)))).

  Example ex3 : dnnrc unit plug_type
    := DNNRCFor tt
               "x"%string
               (DNNRCConst tt (dcoll nil))
               (DNNRCEither tt
                           (DNNRCVar tt "x"%string)
                           "x1"%string
                           (DNNRCUnop tt ASum (DNNRCConst tt (dcoll (nil))))
                           "x2"%string
                           (DNNRCConst tt (dcoll ((dbool true)::nil)))).

  Example ex4 : dnnrc unit plug_type :=
    DNNRCFor tt "el"%string
            (DNNRCCollect tt (DNNRCVar tt "WORLD"%string))
            (DNNRCUnop tt AToString (DNNRCVar tt "el"%string)).

  Example ex5 : dnnrc unit plug_type :=
    DNNRCFor tt "el"%string
            (DNNRCVar tt "WORLD"%string)
            (DNNRCUnop tt AToString (DNNRCVar tt "el"%string)).

  Example ex6 : dnnrc unit plug_type :=
    DNNRCUnop tt ACount
             (DNNRCCollect tt (DNNRCVar tt "WORLD"%string)).

  Example ex7 : dnnrc unit plug_type :=
    DNNRCUnop tt ACount (DNNRCVar tt "WORLD"%string).

  Example ex8 : dnnrc unit plug_type :=
    DNNRCUnop tt ADistinct
             (DNNRCCollect tt (DNNRCVar tt "WORLD"%string)).

  Example ex9 : dnnrc unit plug_type :=
    DNNRCUnop tt ADistinct (DNNRCVar tt "WORLD"%string).

  Example ex10 : dnnrc unit plug_type :=
    DNNRCVar tt "WORLD"%string.


  Definition unwrap_pf_compute {A} n :=
    Eval vm_compute in
    match @di_typeof A n with
    | Tlocal r ⇒ (proj1_sig r)
    | Tdistr r ⇒ (proj1_sig r)
    end.

  Definition t0_rec :=
    ("age"%string,Nat)::("name"%string,String)::("partition"%string,Nat)::nil.

  Lemma t0_rec_wf :
    is_list_sorted ODT_lt_dec (domain t0_rec) = true.

  Definition t0 :=
    Tdistr (Rec Closed t0_rec t0_rec_wf).

  Example ex11 : dnnrc unit plug_type :=
    DNNRCGroupBy tt "partition"%string ("name"%string::nil)
                 (DNNRCCollect tt (DNNRCVar tt "$vConst$WORLD"%string)).


  Example ex12 : dnnrc unit plug_type :=
    DNNRCGroupBy tt "partition"%string ("age"%string::"name"%string::nil)
                 (DNNRCCollect tt (DNNRCVar tt "$vConst$WORLD"%string)).


  Example ex13 : dnnrc unit plug_type :=
    DNNRCFor tt
             "$vtmap$0"%string
             (DNNRCUnop tt AFlatten
                        (DNNRCFor tt
                                  "$vtprod$0"%string
                                  (DNNRCCollect tt (DNNRCVar tt "$vConst$WORLD"%string))
                                  (DNNRCUnop tt AColl
                                             (DNNRCBinop tt AConcat
                                                         (DNNRCVar tt "$vtprod$0"%string)
                                                         (DNNRCConst tt (drec nil))))))
             (DNNRCUnop tt (ARec "name")
                        (DNNRCUnop tt (ADot "name") (DNNRCVar tt "$vtmap$0"%string))).



End TDNNRCInfer.