Theory Matching

theory Matching
imports Semantics
begin

subsection‹Boolean Matcher Algebra›

lemma MatchOr: "matches γ (MatchOr m1 m2) p  matches γ m1 p  matches γ m2 p"
  by(simp add: MatchOr_def)

lemma opt_MatchAny_match_expr_correct: "matches γ (opt_MatchAny_match_expr m) = matches γ m"
 proof -
  have "matches γ (opt_MatchAny_match_expr_once m) = matches γ m" for m
   apply(simp add: fun_eq_iff)
   by(induction m rule: opt_MatchAny_match_expr_once.induct) (simp_all)
   thus ?thesis
    apply(simp add: opt_MatchAny_match_expr_def)
    apply(rule repeat_stabilize_induct)
     by(simp)+
 qed
    

lemma matcheq_matchAny: "¬ has_primitive m  matcheq_matchAny m  matches γ m p"
  by(induction m) simp_all

lemma matcheq_matchNone: "¬ has_primitive m  matcheq_matchNone m  ¬ matches γ m p"
  by(auto dest: matcheq_matchAny matachAny_matchNone)

lemma matcheq_matchNone_not_matches: "matcheq_matchNone m  ¬ matches γ m p"
  by(induction m rule: matcheq_matchNone.induct) auto


text‹Lemmas about matching in the @{const iptables_bigstep} semantics.›

lemma matches_rule_iptables_bigstep:
  assumes "matches γ m p  matches γ m' p"
  shows "Γ,γ,p [Rule m a], s  t  Γ,γ,p [Rule m' a], s  t" (is "?l ?r")
proof -
  {
    fix m m'
    assume "Γ,γ,p [Rule m a], s  t" "matches γ m p  matches γ m' p"
    hence "Γ,γ,p [Rule m' a], s  t"
      by (induction "[Rule  m a]" s t rule: iptables_bigstep_induct)
         (auto intro: iptables_bigstep.intros simp: Cons_eq_append_conv dest: skipD)
  }
  with assms show ?thesis by blast
qed

lemma matches_rule_and_simp_help:
  assumes "matches γ m p"
  shows "Γ,γ,p [Rule (MatchAnd m m') a'], Undecided  t  Γ,γ,p [Rule m' a'], Undecided  t" (is "?l ?r")
proof
  assume ?l thus ?r
    by (induction "[Rule (MatchAnd m m') a']" Undecided t rule: iptables_bigstep_induct)
       (auto intro: iptables_bigstep.intros simp: assms Cons_eq_append_conv dest: skipD)
next
  assume ?r thus ?l
    by (induction "[Rule m' a']" Undecided t rule: iptables_bigstep_induct)
       (auto intro: iptables_bigstep.intros simp: assms Cons_eq_append_conv dest: skipD)
qed

lemma matches_MatchNot_simp: 
  assumes "matches γ m p"
  shows "Γ,γ,p [Rule (MatchNot m) a], Undecided  t  Γ,γ,p [], Undecided  t" (is "?l  ?r")
proof
  assume ?l thus ?r
    by (induction "[Rule (MatchNot m) a]" "Undecided" t rule: iptables_bigstep_induct)
       (auto intro: iptables_bigstep.intros simp: assms Cons_eq_append_conv dest: skipD)
next
  assume ?r
  hence "t = Undecided"
    by (metis skipD)
  with assms show ?l
    by (fastforce intro: nomatch)
qed

lemma matches_MatchNotAnd_simp:
  assumes "matches γ m p"
  shows "Γ,γ,p [Rule (MatchAnd (MatchNot m) m') a], Undecided  t  Γ,γ,p [], Undecided  t" (is "?l  ?r")
proof
  assume ?l thus ?r
    by (induction "[Rule (MatchAnd (MatchNot m) m') a]" "Undecided" t rule: iptables_bigstep_induct)
       (auto intro: iptables_bigstep.intros simp add: assms Cons_eq_append_conv dest: skipD)
next
  assume ?r
  hence "t = Undecided"
    by (metis skipD)
  with assms show ?l
    by (fastforce intro: nomatch)
qed
  
lemma matches_rule_and_simp:
  assumes "matches γ m p"
  shows "Γ,γ,p [Rule (MatchAnd m m') a'], s  t  Γ,γ,p [Rule m' a'], s  t"
proof (cases s)
  case Undecided
  with assms show ?thesis
    by (simp add: matches_rule_and_simp_help)
next
  case Decision
  thus ?thesis by (metis decision decisionD)
qed

lemma iptables_bigstep_MatchAnd_comm:
  "Γ,γ,p [Rule (MatchAnd m1 m2) a], s  t  Γ,γ,p [Rule (MatchAnd m2 m1) a], s  t"
proof -
  { fix m1 m2
    have "Γ,γ,p [Rule (MatchAnd m1 m2) a], s  t  Γ,γ,p [Rule (MatchAnd m2 m1) a], s  t"
      proof (induction "[Rule (MatchAnd m1 m2) a]" s t rule: iptables_bigstep_induct)
        case Seq thus ?case
          by (metis Nil_is_append_conv append_Nil butlast_append butlast_snoc seq)
      qed (auto intro: iptables_bigstep.intros)
  }
  thus ?thesis by blast
qed


subsection‹Add match›

definition add_match :: "'a match_expr  'a rule list  'a rule list" where
  "add_match m rs = map (λr. case r of Rule m' a'  Rule (MatchAnd m m') a') rs"

lemma add_match_split: "add_match m (rs1@rs2) = add_match m rs1 @ add_match m rs2"
  unfolding add_match_def
  by (fact map_append)

lemma add_match_split_fst: "add_match m (Rule m' a' # rs) = Rule (MatchAnd m m') a' # add_match m rs"
  unfolding add_match_def
  by simp


lemma add_match_distrib:
  "Γ,γ,p add_match m1 (add_match m2 rs), s  t  Γ,γ,p add_match m2 (add_match m1 rs), s  t"
proof -
  {
    fix m1 m2
    have "Γ,γ,p add_match m1 (add_match m2 rs), s  t  Γ,γ,p add_match m2 (add_match m1 rs), s  t"
      proof (induction rs arbitrary: s)
        case Nil thus ?case by (simp add: add_match_def)
        next
        case (Cons r rs)
        from Cons obtain m a where r: "r = Rule m a" by (cases r) simp
        with Cons.prems obtain ti where 1: "Γ,γ,p [Rule (MatchAnd m1 (MatchAnd m2 m)) a], s  ti" and 2: "Γ,γ,p add_match m1 (add_match m2 rs), ti  t"
          apply(simp add: add_match_split_fst)
          apply(erule seqE_cons)
          by simp
        from 1 r have base: "Γ,γ,p [Rule (MatchAnd m2 (MatchAnd m1 m)) a], s  ti"
           by (metis matches.simps(1) matches_rule_iptables_bigstep)
        from 2 Cons.IH have IH: "Γ,γ,p add_match m2 (add_match m1 rs), ti  t" by simp
        from base IH seq'_cons have "Γ,γ,p Rule (MatchAnd m2 (MatchAnd m1 m)) a # add_match m2 (add_match m1 rs), s  t" by fast
        thus ?case using r by(simp add: add_match_split_fst[symmetric])
      qed
  }
  thus ?thesis by blast
qed

lemma add_match_split_fst': "add_match m (a # rs) = add_match m [a] @ add_match m rs"
  by (simp add: add_match_split[symmetric])



lemma matches_add_match_simp:
  assumes m: "matches γ m p"
  shows "Γ,γ,p add_match m rs, s  t  Γ,γ,p rs, s  t" (is "?l  ?r")
  proof
    assume ?l with m show ?r
      proof (induction rs)
        case Nil
        thus ?case
          unfolding add_match_def by simp
      next
        case (Cons r rs)
        hence IH: "Γ,γ,p add_match m rs, s  t  Γ,γ,p rs, s  t" by(simp add: add_match_split_fst)
        obtain m' a where r: "r = Rule m' a" by (cases r)
        with Cons.prems(2) obtain ti where "Γ,γ,p [Rule (MatchAnd m m') a], s  ti" and "Γ,γ,p add_match m rs, ti  t"
          by(auto elim:seqE_cons simp add: add_match_split_fst)
        with Cons.prems(1) IH have "Γ,γ,p [Rule m' a], s  ti" by(simp add: matches_rule_and_simp)
        with Γ,γ,p add_match m rs, ti  t IH r show ?case by(metis decision state.exhaust iptables_bigstep_deterministic seq_cons)
      qed
  next
    assume ?r with m show ?l
      proof (induction rs)
        case Nil
        thus ?case
          unfolding add_match_def by simp
      next
        case (Cons r rs)
        hence IH: " Γ,γ,p rs, s  t  Γ,γ,p add_match m rs, s  t" by(simp add: add_match_split_fst)
        obtain m' a where r: "r = Rule m' a" by (cases r)
        with Cons.prems(2) obtain ti where "Γ,γ,p [Rule m' a], s  ti" and "Γ,γ,p rs, ti  t"
          by(auto elim:seqE_cons simp add: add_match_split_fst)
        with Cons.prems(1) IH have "Γ,γ,p [Rule (MatchAnd m m') a], s  ti" by(simp add: matches_rule_and_simp)
        with Γ,γ,p rs, ti  t IH r show ?case 
          apply(simp add: add_match_split_fst)
          by(metis decision state.exhaust iptables_bigstep_deterministic seq_cons)
      qed
  qed

lemma matches_add_match_MatchNot_simp:
  assumes m: "matches γ m p"
  shows "Γ,γ,p add_match (MatchNot m) rs, s  t  Γ,γ,p [], s  t" (is "?l s  ?r s")
  proof (cases s)
    case Undecided
    have "?l Undecided  ?r Undecided"
      proof
        assume "?l Undecided" with m show "?r Undecided"
          proof (induction rs)
            case Nil
            thus ?case
              unfolding add_match_def by simp
          next
            case (Cons r rs)
            thus ?case
              by (cases r) (metis matches_MatchNotAnd_simp skipD seqE_cons add_match_split_fst)
          qed
      next
        assume "?r Undecided" with m show "?l Undecided"
          proof (induction rs)
            case Nil
            thus ?case
              unfolding add_match_def by simp
          next
            case (Cons r rs)
            thus ?case
              by (cases r) (metis matches_MatchNotAnd_simp skipD seq'_cons add_match_split_fst)
          qed
      qed
    with Undecided show ?thesis by fast
  next
    case (Decision d)
    thus ?thesis
      by(metis decision decisionD)
  qed

lemma not_matches_add_match_simp:
  assumes "¬ matches γ m p"
  shows "Γ,γ,p add_match m rs, Undecided  t  Γ,γ,p [], Undecided  t"
  proof(induction rs)
    case Nil
    thus ?case
      unfolding add_match_def by simp
  next
    case (Cons r rs)
    thus ?case
      by (cases r) (metis assms add_match_split_fst matches.simps(1) nomatch seq'_cons nomatchD seqE_cons)
  qed

lemma iptables_bigstep_add_match_notnot_simp: 
  "Γ,γ,p add_match (MatchNot (MatchNot m)) rs, s  t  Γ,γ,p add_match m rs, s  t"
  proof(induction rs)
    case Nil
    thus ?case
      unfolding add_match_def by simp
  next
    case (Cons r rs)
    thus ?case
      by (cases r)
         (metis decision decisionD state.exhaust matches.simps(2) matches_add_match_simp not_matches_add_match_simp)
  qed


lemma add_match_match_not_cases:
  "Γ,γ,p add_match (MatchNot m) rs, Undecided  Undecided  matches γ m p  Γ,γ,p rs, Undecided  Undecided"
  by (metis matches.simps(2) matches_add_match_simp)


lemma not_matches_add_matchNot_simp:
  "¬ matches γ m p  Γ,γ,p add_match (MatchNot m) rs, s  t  Γ,γ,p rs, s  t"
  by (simp add: matches_add_match_simp)

lemma iptables_bigstep_add_match_and:
  "Γ,γ,p add_match m1 (add_match m2 rs), s  t  Γ,γ,p add_match (MatchAnd m1 m2) rs, s  t"
  proof(induction rs arbitrary: s t)
    case Nil
    thus ?case
      unfolding add_match_def by simp
  next
    case(Cons r rs)
    show ?case
    proof (cases r, simp only: add_match_split_fst)
      fix m a
      show "Γ,γ,p Rule (MatchAnd m1 (MatchAnd m2 m)) a # add_match m1 (add_match m2 rs), s  t  Γ,γ,p Rule (MatchAnd (MatchAnd m1 m2) m) a # add_match (MatchAnd m1 m2) rs, s  t" (is "?l  ?r")
      proof
        assume ?l with Cons.IH show ?r
          apply -
          apply(erule seqE_cons)
          apply(case_tac s)
          apply(case_tac ti)
          apply (metis matches.simps(1) matches_rule_and_simp matches_rule_and_simp_help nomatch seq'_cons)
          apply (metis add_match_split_fst matches.simps(1) matches_add_match_simp not_matches_add_match_simp seq_cons)
          apply (metis decision decisionD)
          done
      next
        assume ?r with Cons.IH show ?l
          apply -
          apply(erule seqE_cons)
          apply(case_tac s)
          apply(case_tac ti)
          apply (metis matches.simps(1) matches_rule_and_simp matches_rule_and_simp_help nomatch seq'_cons)
          apply (metis add_match_split_fst matches.simps(1) matches_add_match_simp not_matches_add_match_simp seq_cons)
          apply (metis decision decisionD)
          done
        qed
    qed
  qed


lemma optimize_matches_option_generic:
  assumes " r  set rs. P (get_match r)"
      and "(m m'. P m  f m = Some m'  matches γ m' p = matches γ m p)"
      and "(m. P m  f m = None  ¬ matches γ m p)"
  shows "Γ,γ,p optimize_matches_option f rs, s  t  Γ,γ,p rs, s  t"
      (is "?lhs  ?rhs")
  proof
    assume ?rhs
    from this assms show ?lhs
    apply(induction rs s t rule: iptables_bigstep_induct)
    apply(auto simp: optimize_matches_option_append intro: iptables_bigstep.intros split: option.split)
    done
  next
    assume ?lhs
    from this assms show ?rhs
    apply(induction f rs arbitrary: s rule: optimize_matches_option.induct)
     apply(simp; fail)
    apply(simp split: option.split_asm)
     apply(subgoal_tac "¬ matches γ m p")
     prefer 2 apply blast
    apply (metis decision nomatch seq'_cons state.exhaust)
    apply(erule seqE_cons)
    apply(rule_tac t=ti in seq'_cons)
     apply (meson matches_rule_iptables_bigstep)
    by blast
  qed

lemma optimize_matches_generic: " r  set rs. P (get_match r)  
      (m. P m  matches γ (f m) p = matches γ m p) 
      Γ,γ,p optimize_matches f rs, s  t  Γ,γ,p rs, s  t"
  unfolding optimize_matches_def
  apply(rule optimize_matches_option_generic)
    apply(simp; fail)
   apply(simp split: if_split_asm)
   apply blast
  apply(simp split: if_split_asm)
  using matcheq_matchNone_not_matches by fast
end