Theory WPO_Approx

section ‹An Approximation of WPO›

text ‹We define an approximation of WPO. 

  It replaces the bounded lexicographic comparison by an unbounded one.
  Hence, no runtime check on lenghts are required anymore, but instead the arities of the inputs
  have to be bounded via an assumption.

  Moreover, instead of checking that terms are strictly or non-strictly decreasing w.r.t. the
  algebra (i.e., the input reduction pair), we just demand that there are sufficient criteria to
  ensure a strict- or non-strict decrease.›

theory WPO_Approx
imports
  Weighted_Path_Order.WPO
begin

definition compare_bools :: "bool × bool  bool × bool  bool"
  where
    "compare_bools p1 p2  (fst p1  fst p2)  (snd p1  snd p2)"

notation compare_bools ((_/ cb _) [51, 51] 50)

lemma lex_ext_unbounded_cb:
  assumes " i. i < length xs  i < length ys  f (xs ! i) (ys ! i) cb g (xs ! i) (ys ! i)"
  shows "lex_ext_unbounded f xs ys cb lex_ext_unbounded g xs ys"
  unfolding compare_bools_def
  by (rule lex_ext_unbounded_mono,
  insert assms[unfolded compare_bools_def], auto)

lemma mul_ext_cb:
  assumes " x y. x  set xs  y  set ys  f x y cb g x y"
  shows "mul_ext f xs ys cb mul_ext g xs ys"
  unfolding compare_bools_def
  by (intro conjI impI; rule mul_ext_mono) (insert assms, auto simp: compare_bools_def)

context
  fixes pr :: "('f × nat  'f × nat  bool × bool)"
    and prl :: "'f × nat  bool"
    and ssimple :: bool
    and large :: "'f × nat  bool"
    and cS cNS :: "('f,'v)term  ('f,'v)term  bool" ― ‹sufficient criteria›
    and σ :: "'f status"
    and c :: "'f × nat  order_tag"
begin

fun wpo_ub  :: "('f, 'v) term  ('f, 'v) term  bool × bool" 
  where
    "wpo_ub s t = (if cS s t then (True, True) else if cNS s t then (case s of
      Var x  (False,
        (case t of
          Var y  x = y
        | Fun g ts  status σ (g, length ts) = []  prl (g, length ts)))
    | Fun f ss 
        let ff = (f, length ss); sf = status σ ff in
          if ( i  set sf. snd (wpo_ub (ss ! i) t)) then (True, True)
          else
            (case t of
              Var _  (False, ssimple  large ff)
            | Fun g ts 
              let gg = (g, length ts); sg = status σ gg in
              (case pr ff gg of (prs, prns) 
                if prns  ( j  set sg. fst (wpo_ub s (ts ! j))) then
                  if prs then (True, True)
                  else 
                    let ss' = map (λ i. ss ! i) sf;
                        ts' = map (λ i. ts ! i) sg;
                        cf = c ff;
                        cg = c gg in
                     if cf = Lex  cg = Lex then lex_ext_unbounded wpo_ub ss' ts'
                     else if cf = Mul  cg = Mul then mul_ext wpo_ub ss' ts'
                     else if ts' = [] then (ss'  [], True) else (False, False)
                else (False, False)))
        ) else (False, False))"

declare wpo_ub.simps [simp del]

abbreviation "wpo_orig n S NS  wpo.wpo n S NS pr prl σ c ssimple large" 

text ‹soundness of approximation: @{const wpo_ub} can be simulated by @{const wpo_orig}
  if the arities are small (usually the length of the status of f is smaller than the arity of f).›

lemma wpo_ub:
  assumes " si tj. s  si  t  tj  (cS si tj, cNS si tj) cb ((si, tj)  S, (si, tj)  NS)"
    and " f. f  funas_term t  length (status σ f)  n"
  shows "wpo_ub s t cb wpo_orig n S NS s t" 
  using assms
proof (induct s t rule: wpo.wpo.induct [of S NS σ _ n pr prl c ssimple large])
  case (1 s t) 
  note IH = 1(1-4)
  note cb = 1(5)
  note n = 1(6)
  note cbd = compare_bools_def
  note simps = wpo_ub.simps[of s t] wpo.wpo.simps[of n S NS pr prl σ c ssimple large s t]
  let ?wpo = "wpo_orig n S NS"
  let ?cb = "λ s t. (cS s t, cNS s t) cb ((s, t)  S, (s, t)  NS)"
  let ?goal = "λ s t. wpo_ub s t cb ?wpo s t"
  from cb[of s t] have cb_st: "?cb s t" by auto
  show ?case
  proof (cases "(s,t)  S  ¬ cNS s t")
    case True
    with cb_st show ?thesis unfolding simps unfolding cbd by auto
  next
    case False
    with cb_st have *: "(s,t)  S" "(s,t)  NS" "((s,t)  S) = True" "((s, t)  S) = False" 
      "((s,t)  NS) = True" "cS s t = False" "cNS s t = True"
      unfolding cbd by auto
    note simps = simps[unfolded * if_False if_True]
    note IH = IH[OF *(1-2)]
    show ?thesis
    proof (cases s)
      case (Var x) note s = this
      show ?thesis
      proof (cases t)
        case (Var y) note t = this
        show ?thesis unfolding simps unfolding s t cbd by simp
      next
        case (Fun g ts) note t = this
        show ?thesis unfolding simps unfolding s t cbd by auto
      qed
    next
      case s: (Fun f ss)
      let ?f = "(f,length ss)"
      let ?sf = "status σ ?f"
      let ?s = "Fun f ss"
      note IH = IH[OF s]
      show ?thesis
      proof (cases "( i  set ?sf. snd (?wpo (ss ! i) t))")
        case True
        then show ?thesis unfolding simps using True * unfolding s cbd by auto
      next
        case False
        {
          fix i
          assume i: "i  set ?sf"
          from status_aux[OF i] 
          have "?goal (ss ! i) t"
            by (intro IH(1)[OF i cb n], auto simp: s)
        }
        with False have sub: "( i  set ?sf. snd (wpo_ub (ss ! i) t)) = False" unfolding cbd by auto
        note IH = IH(2-4)[OF False]
        show ?thesis
        proof (cases "wpo_ub s t = (False,False)")
          case True
          then show ?thesis unfolding cbd by auto
        next
          case False note noFF = this
          note False = False[unfolded simps * Let_def, unfolded s term.simps sub, simplified]
          show ?thesis
          proof (cases t)
            case t: (Var y)
            from False[unfolded t, simplified]
            show ?thesis unfolding s t unfolding cbd
              using * s simps sub t by auto
          next
            case t: (Fun g ts)
            let ?g = "(g,length ts)"
            let ?sg = "status σ ?g"
            let ?t = "Fun g ts"
            obtain ps pns where p: "pr ?f ?g = (ps, pns)" by force
            note IH = IH[OF t p[symmetric]]
            note False = False[unfolded t p split term.simps]
            from False have pns: "pns = True" by (cases pns, auto)
            {
              fix j
              assume j: "j  set ?sg"
              from status_aux[OF j] 
              have cb: "?goal s (ts ! j)"
                by (intro IH(1)[OF j cb n], auto simp: t)
              from j False have "fst (wpo_ub s (ts ! j))" unfolding s by (auto split: if_splits)
              with cb have "fst (?wpo s (ts ! j))" unfolding cbd by auto
            }
            then have cond: "pns  ( j  set ?sg. fst (?wpo s (ts ! j)))" using pns by auto
            note IH = IH(2-3)[OF cond]
            from cond have cond: "(pns  ( j  set ?sg. fst (?wpo ?s (ts ! j)))) = True" unfolding s by simp
            note simps = simps[unfolded * Let_def, unfolded s t term.simps if_False if_True sub[unfolded t] p split cond]
            show ?thesis 
            proof (cases ps)
              case True
              then show ?thesis unfolding s t unfolding simps cbd by auto
            next
              case False
              note IH = IH[OF this refl refl refl refl]
              let ?msf = "map ((!) ss) ?sf"
              let ?msg = "map ((!) ts) ?sg"
              have set_msf: "set ?msf  set ss" using status[of σ f "length ss"]
                unfolding set_conv_nth by force
              have set_msg: "set ?msg  set ts" using status[of σ g "length ts"]
                unfolding set_conv_nth by force
              {
                fix i
                assume "i < length ?msf"
                then have "?msf ! i  set ?msf" unfolding set_conv_nth by blast
                with set_msf have "?msf ! i  set ss" by auto
              } note msf = this
              {
                fix i
                assume "i < length ?msg"
                then have "?msg ! i  set ?msg" unfolding set_conv_nth by blast
                with set_msg have "?msg ! i  set ts" by auto
              } note msg = this
              show ?thesis
              proof (cases "c ?f = Lex  c ?g = Lex")
                case Lex: True
                note IH = IH(1)[OF Lex _ _ cb n, unfolded s t length_map]
                from n[of ?g, unfolded t] have "length (?msg)  n" by auto
                then have ub: "lex_ext_unbounded ?wpo ?msf ?msg =
                  lex_ext ?wpo n ?msf ?msg" 
                  unfolding lex_ext_unbounded_iff lex_ext_iff by auto
                from Lex False simps noFF  
                have wpo_ub: "wpo_ub s t = lex_ext_unbounded wpo_ub ?msf ?msg"
                  unfolding s t using False by (auto split: if_splits)
                also have " cb lex_ext_unbounded ?wpo ?msf ?msg"
                  by (rule lex_ext_unbounded_cb, rule IH) (insert msf msg, auto)
                finally show ?thesis unfolding ub s t simps(2) cbd using Lex by auto
              next
                case nLex: False
                show ?thesis
                proof (cases "c ?f = Mul  c ?g = Mul")
                  case Mul: True
                  note IH = IH(2)[OF nLex Mul _ _ cb n, unfolded s t]
                  from Mul nLex False simps noFF  
                  have wpo_ub: "wpo_ub s t = mul_ext wpo_ub ?msf ?msg"
                    unfolding s t using False by (auto split: if_splits)
                  also have " cb mul_ext ?wpo ?msf ?msg"
                    by (rule mul_ext_cb, rule IH) (insert set_msf set_msg, auto)
                  finally show ?thesis unfolding s t simps(2) cbd using nLex Mul by auto
                next
                  case nMul: False
                  thus ?thesis unfolding s t simps cbd using nLex nMul noFF False
                    by auto
                qed
              qed
            qed
          qed
        qed
      qed
    qed
  qed
qed

end
end