Theory Multiset_Extension2

```section ‹Multiset extension of order pairs in the other direction›

text ‹Many term orders are formulated in the other direction, i.e., they use
strong normalization of \$>\$ instead of well-foundedness of \$<\$. Here, we
flip the direction of the multiset extension of two orders, connect it to existing interfaces,
and prove some further properties of the multiset extension.›

theory Multiset_Extension2
imports
List_Order
Multiset_Extension_Pair
begin

subsection ‹List based characterization of @{const multpw}›

lemma multpw_listI:
assumes "length xs = length ys" "X = mset xs" "Y = mset ys"
"∀i. i < length ys ⟶ (xs ! i, ys ! i) ∈ ns"
shows "(X, Y) ∈ multpw ns"
using assms
proof (induct xs arbitrary: ys X Y)
case (Nil ys) then show ?case by (cases ys) (auto intro: multpw.intros)
next
case Cons1: (Cons x xs ys' X Y) then show ?case
proof (cases ys')
case (Cons y ys)
then have "∀i. i < length ys ⟶ (xs ! i, ys ! i) ∈ ns" using Cons1(5) by fastforce
then show ?thesis using Cons1(2,5) by (auto intro!: multpw.intros simp: Cons(1) Cons1)
qed auto
qed

lemma multpw_listE:
assumes "(X, Y) ∈ multpw ns"
obtains xs ys where "length xs = length ys" "X = mset xs" "Y = mset ys"
"∀i. i < length ys ⟶ (xs ! i, ys ! i) ∈ ns"
using assms
proof (induct X Y arbitrary: thesis rule: multpw.induct)
case (add x y X Y)
then obtain xs ys where "length xs = length ys" "X = mset xs"
"Y = mset ys" "(∀i. i < length ys ⟶ (xs ! i, ys ! i) ∈ ns)" by blast
then show ?case using add(1) by (intro add(4)[of "x # xs" "y # ys"]) (auto, case_tac i, auto)
qed auto

subsection‹Definition of the multiset extension of \$>\$-orders›

text‹We define here the non-strict extension of the order pair \$(\geqslant, >)\$ --
usually written as (ns, s) in the sources --
by just flipping the directions twice.›

definition ns_mul_ext :: "'a rel ⇒ 'a rel ⇒ 'a multiset rel"
where "ns_mul_ext ns s ≡ (mult2_alt_ns (ns¯) (s¯))¯"

lemma ns_mul_extI:
assumes "A = A1 + A2" and "B = B1 + B2"
and "(A1, B1) ∈ multpw ns"
and "⋀b. b ∈# B2 ⟹ ∃a. a ∈# A2 ∧ (a, b) ∈ s"
shows "(A, B) ∈ ns_mul_ext ns s"
using assms by (auto simp: ns_mul_ext_def multpw_converse intro!: mult2_alt_nsI)

lemma ns_mul_extE:
assumes "(A, B) ∈ ns_mul_ext ns s"
obtains A1 A2 B1 B2 where "A = A1 + A2" and "B = B1 + B2"
and "(A1, B1) ∈ multpw ns"
and "⋀b. b ∈# B2 ⟹ ∃a. a ∈# A2 ∧ (a, b) ∈ s"
using assms by (auto simp: ns_mul_ext_def multpw_converse elim!: mult2_alt_nsE)

lemmas ns_mul_extI_old = ns_mul_extI[OF _ _ multpw_listI[OF _ refl refl], rule_format]

text‹Same for the "greater than" order on multisets.›

definition s_mul_ext :: "'a rel ⇒ 'a rel ⇒ 'a multiset rel"
where "s_mul_ext ns s ≡ (mult2_alt_s (ns¯) (s¯))¯"

lemma s_mul_extI:
assumes "A = A1 + A2" and "B = B1 + B2"
and "(A1, B1) ∈ multpw ns"
and "A2 ≠ {#}" and "⋀b. b ∈# B2 ⟹ ∃a. a ∈# A2 ∧ (a, b) ∈ s"
shows "(A, B) ∈ s_mul_ext ns s"
using assms by (auto simp: s_mul_ext_def multpw_converse intro!: mult2_alt_sI)

lemma s_mul_extE:
assumes "(A, B) ∈ s_mul_ext ns s"
obtains A1 A2 B1 B2 where "A = A1 + A2" and "B = B1 + B2"
and "(A1, B1) ∈ multpw ns"
and "A2 ≠ {#}" and "⋀b. b ∈# B2 ⟹ ∃a. a ∈# A2 ∧ (a, b) ∈ s"
using assms by (auto simp: s_mul_ext_def multpw_converse elim!: mult2_alt_sE)

lemmas s_mul_extI_old = s_mul_extI[OF _ _ multpw_listI[OF _ refl refl], rule_format]

subsection‹Basic properties›

lemma s_mul_ext_mono:
assumes "ns ⊆ ns'" "s ⊆ s'" shows "s_mul_ext ns s ⊆ s_mul_ext ns' s'"
unfolding s_mul_ext_def using assms mono_mult2_alt[of "ns¯" "ns'¯" "s¯" "s'¯"] by simp

lemma ns_mul_ext_mono:
assumes "ns ⊆ ns'" "s ⊆ s'" shows "ns_mul_ext ns s ⊆ ns_mul_ext ns' s'"
unfolding ns_mul_ext_def using assms mono_mult2_alt[of "ns¯" "ns'¯" "s¯" "s'¯"] by simp

lemma s_mul_ext_local_mono:
assumes sub: "(set_mset xs × set_mset ys) ∩ ns ⊆ ns'" "(set_mset xs × set_mset ys) ∩ s ⊆ s'"
and rel: "(xs,ys) ∈ s_mul_ext ns s"
shows "(xs,ys) ∈ s_mul_ext ns' s'"
using rel s_mul_ext_mono[OF sub] mult2_alt_local[of ys xs False "ns¯" "s¯"]
by (auto simp: s_mul_ext_def converse_Int ac_simps converse_Times)

lemma ns_mul_ext_local_mono:
assumes sub: "(set_mset xs × set_mset ys) ∩ ns ⊆ ns'" "(set_mset xs × set_mset ys) ∩ s ⊆ s'"
and rel: "(xs,ys) ∈ ns_mul_ext ns s"
shows "(xs,ys) ∈ ns_mul_ext ns' s'"
using rel ns_mul_ext_mono[OF sub] mult2_alt_local[of ys xs True "ns¯" "s¯"]
by (auto simp: ns_mul_ext_def converse_Int ac_simps converse_Times)

lemma s_mul_ext_ord_s [mono]:
assumes "⋀s t. ord s t ⟶ ord' s t"
shows "(s, t) ∈ s_mul_ext ns {(s,t). ord s t} ⟶ (s, t) ∈ s_mul_ext ns {(s,t). ord' s t}"
using assms s_mul_ext_mono by (metis (mono_tags) case_prod_conv mem_Collect_eq old.prod.exhaust subset_eq)

lemma ns_mul_ext_ord_s [mono]:
assumes "⋀s t. ord s t ⟶ ord' s t"
shows "(s, t) ∈ ns_mul_ext ns {(s,t). ord s t} ⟶ (s, t) ∈ ns_mul_ext ns {(s,t). ord' s t}"
using assms ns_mul_ext_mono by (metis (mono_tags) case_prod_conv mem_Collect_eq old.prod.exhaust subset_eq)

text‹The empty multiset is the minimal element for these orders›

lemma ns_mul_ext_bottom: "(A,{#}) ∈ ns_mul_ext ns s"
by (auto intro!: ns_mul_extI)

lemma ns_mul_ext_bottom_uniqueness:
assumes "({#},A) ∈ ns_mul_ext ns s"
shows "A = {#}"
using assms by (auto simp: ns_mul_ext_def mult2_alt_ns_def)

lemma ns_mul_ext_bottom2:
assumes "(A,B) ∈ ns_mul_ext ns s"
and "B ≠ {#}"
shows "A ≠ {#}"
using assms by (auto simp: ns_mul_ext_def mult2_alt_ns_def)

lemma s_mul_ext_bottom:
assumes "A ≠ {#}"
shows "(A,{#}) ∈ s_mul_ext ns s"
using assms by (auto simp: s_mul_ext_def mult2_alt_s_def)

lemma s_mul_ext_bottom_strict:
"({#},A) ∉ s_mul_ext ns s"
by (auto simp: s_mul_ext_def mult2_alt_s_def)

text‹Obvious introduction rules.›

lemma all_ns_ns_mul_ext:
assumes "length as = length bs"
and "∀i. i < length bs ⟶ (as ! i, bs ! i) ∈ ns"
shows "(mset as, mset bs) ∈ ns_mul_ext ns s"
using assms by (auto intro!: ns_mul_extI[of _ _ "{#}" _ _ "{#}"] multpw_listI)

lemma all_s_s_mul_ext:
assumes "A ≠ {#}"
and "∀b. b ∈# B ⟶ (∃a. a ∈# A ∧ (a,b) ∈ s)"
shows "(A, B) ∈ s_mul_ext ns s"
using assms by (auto intro!: s_mul_extI[of _ "{#}" _ _ "{#}"] multpw_listI)

text‹Being stricly lesser than implies being lesser than›

lemma s_ns_mul_ext:
assumes "(A, B) ∈ s_mul_ext ns s"
shows "(A, B) ∈ ns_mul_ext ns s"
using assms by (simp add: s_mul_ext_def ns_mul_ext_def mult2_alt_s_implies_mult2_alt_ns)

text‹The non-strict order is reflexive.›

lemma multpw_refl':
assumes "locally_refl ns A"
shows "(A, A) ∈ multpw ns"
proof -
have "Restr Id (set_mset A) ⊆ ns" using assms by (auto simp: locally_refl_def)
from refl_multpw[of Id] multpw_local[of A A Id] mono_multpw[OF this]
show ?thesis by (auto simp: refl_on_def)
qed

lemma ns_mul_ext_refl_local:
assumes "locally_refl ns A"
shows "(A, A) ∈ ns_mul_ext ns s"
using assms by (auto intro!:  ns_mul_extI[of A A "{#}" A A "{#}" ns s] multpw_refl')

lemma ns_mul_ext_refl:
assumes "refl ns"
shows "(A, A) ∈ ns_mul_ext ns s"
using assms ns_mul_ext_refl_local[of ns A s] unfolding refl_on_def locally_refl_def by auto

text‹The orders are union-compatible›

lemma ns_s_mul_ext_union_multiset_l:
assumes "(A, B) ∈ ns_mul_ext ns s"
and "C ≠ {#}"
and "∀d. d ∈# D ⟶ (∃c. c ∈# C ∧ (c,d) ∈ s)"
shows "(A + C, B + D) ∈ s_mul_ext ns s"
using assms unfolding ns_mul_ext_def s_mul_ext_def
by (auto intro!: converseI mult2_alt_ns_s_add mult2_alt_sI[of _ "{#}" _ _ "{#}"])

lemma s_mul_ext_union_compat:
assumes "(A, B) ∈ s_mul_ext ns s"
and "locally_refl ns C"
shows "(A + C, B + C) ∈ s_mul_ext ns s"
using assms ns_mul_ext_refl_local[OF assms(2)] unfolding ns_mul_ext_def s_mul_ext_def

lemma ns_mul_ext_union_compat:
assumes "(A, B) ∈ ns_mul_ext ns s"
and "locally_refl ns C"
shows "(A + C, B + C) ∈ ns_mul_ext ns s"
using assms ns_mul_ext_refl_local[OF assms(2)] unfolding ns_mul_ext_def s_mul_ext_def

context
fixes NS :: "'a rel"
assumes NS: "refl NS"
begin

lemma refl_imp_locally_refl: "locally_refl NS A" using NS unfolding refl_on_def locally_refl_def by auto

lemma supseteq_imp_ns_mul_ext:
assumes "A ⊇# B"
shows "(A, B) ∈ ns_mul_ext NS S"
using assms
by (auto intro!: ns_mul_extI[of A B "A - B" B B "{#}"] multpw_refl' refl_imp_locally_refl

lemma supset_imp_s_mul_ext:
assumes "A ⊃# B"
shows "(A, B) ∈ s_mul_ext NS S"
by (auto intro!: s_mul_extI[of A B "A - B" B B "{#}"] multpw_refl' refl_imp_locally_refl
simp: Diff_eq_empty_iff_mset)

end

definition mul_ext :: "('a ⇒ 'a ⇒ bool × bool) ⇒ 'a list ⇒ 'a list ⇒ bool × bool"
where "mul_ext f xs ys ≡ let s = {(x,y). fst (f x y)}; ns = {(x,y). snd (f x y)}
in ((mset xs,mset ys) ∈ s_mul_ext ns s, (mset xs, mset ys) ∈ ns_mul_ext ns s)"

definition "smulextp f m n ⟷ (m, n) ∈ s_mul_ext {(x, y). snd (f x y)} {(x, y). fst (f x y)}"
definition "nsmulextp f m n ⟷ (m, n) ∈ ns_mul_ext {(x, y). snd (f x y)} {(x, y). fst (f x y)}"

lemma smulextp_cong[fundef_cong]:
assumes "xs1 = ys1"
and "xs2 = ys2"
and "⋀ x x'. x ∈# ys1 ⟹ x' ∈# ys2 ⟹ f x x' = g x x'"
shows "smulextp f xs1 xs2 = smulextp g ys1 ys2"
unfolding smulextp_def
proof
assume "(xs1, xs2) ∈ s_mul_ext {(x, y). snd (f x y)} {(x, y). fst (f x y)}"
from s_mul_ext_local_mono[OF _ _ this, of "{(x, y). snd (g x y)}" "{(x, y). fst (g x y)}"]
show "(ys1, ys2) ∈ s_mul_ext {(x, y). snd (g x y)} {(x, y). fst (g x y)}"
using assms by force
next
assume "(ys1, ys2) ∈ s_mul_ext {(x, y). snd (g x y)} {(x, y). fst (g x y)}"
from s_mul_ext_local_mono[OF _ _ this, of "{(x, y). snd (f x y)}" "{(x, y). fst (f x y)}"]
show "(xs1, xs2) ∈ s_mul_ext {(x, y). snd (f x y)} {(x, y). fst (f x y)}"
using assms by force
qed

lemma nsmulextp_cong[fundef_cong]:
assumes "xs1 = ys1"
and "xs2 = ys2"
and "⋀ x x'. x ∈# ys1 ⟹ x' ∈# ys2 ⟹ f x x' = g x x'"
shows "nsmulextp f xs1 xs2 = nsmulextp g ys1 ys2"
unfolding nsmulextp_def
proof
assume "(xs1, xs2) ∈ ns_mul_ext {(x, y). snd (f x y)} {(x, y). fst (f x y)}"
from ns_mul_ext_local_mono[OF _ _ this, of "{(x, y). snd (g x y)}" "{(x, y). fst (g x y)}"]
show "(ys1, ys2) ∈ ns_mul_ext {(x, y). snd (g x y)} {(x, y). fst (g x y)}"
using assms by force
next
assume "(ys1, ys2) ∈ ns_mul_ext {(x, y). snd (g x y)} {(x, y). fst (g x y)}"
from ns_mul_ext_local_mono[OF _ _ this, of "{(x, y). snd (f x y)}" "{(x, y). fst (f x y)}"]
show "(xs1, xs2) ∈ ns_mul_ext {(x, y). snd (f x y)} {(x, y). fst (f x y)}"
using assms by force
qed

definition "mulextp f m n = (smulextp f m n, nsmulextp f m n)"

lemma mulextp_cong[fundef_cong]:
assumes "xs1 = ys1"
and "xs2 = ys2"
and "⋀ x x'. x ∈# ys1 ⟹ x' ∈# ys2 ⟹ f x x' = g x x'"
shows "mulextp f xs1 xs2 = mulextp g ys1 ys2"
unfolding mulextp_def using assms by (auto cong: nsmulextp_cong smulextp_cong)

lemma mset_s_mul_ext:
"(mset xs, mset ys) ∈ s_mul_ext {(x, y). snd (f x y)} {(x, y).fst (f x y)} ⟷
fst (mul_ext f xs ys)"
by (auto simp: mul_ext_def Let_def)

lemma mset_ns_mul_ext:
"(mset xs, mset ys) ∈ ns_mul_ext {(x, y). snd (f x y)} {(x, y).fst (f x y)} ⟷
snd (mul_ext f xs ys)"
by (auto simp: mul_ext_def Let_def)

lemma smulextp_mset_code:
"smulextp f (mset xs) (mset ys) ⟷ fst (mul_ext f xs ys)"
unfolding smulextp_def mset_s_mul_ext ..

lemma nsmulextp_mset_code:
"nsmulextp f (mset xs) (mset ys) ⟷ snd (mul_ext f xs ys)"
unfolding nsmulextp_def mset_ns_mul_ext ..

lemma nstri_mul_ext_map:
assumes "⋀s t. s ∈ set ss ⟹ t ∈ set ts ⟹ fst (order s t) ⟹ fst (order' (f s) (f t))"
and "⋀s t. s ∈ set ss ⟹ t ∈ set ts ⟹ snd (order s t) ⟹ snd (order' (f s) (f t))"
and "snd (mul_ext order ss ts)"
shows "snd (mul_ext order' (map f ss) (map f ts))"
using assms mult2_alt_map[of "mset ts" "mset ss" "{(t, s). snd (order s t)}" f f
"{(t, s). snd (order' s t)}" "{(t, s). fst (order s t)}" "{(t, s). fst (order' s t)}" True]
by (auto simp: mul_ext_def ns_mul_ext_def converse_unfold)

lemma stri_mul_ext_map:
assumes "⋀s t. s ∈ set ss ⟹ t ∈ set ts ⟹ fst (order s t) ⟹ fst (order' (f s) (f t))"
and "⋀s t. s ∈ set ss ⟹ t ∈ set ts ⟹ snd (order s t) ⟹ snd (order' (f s) (f t))"
and "fst (mul_ext order ss ts)"
shows "fst (mul_ext order' (map f ss) (map f ts))"
using assms mult2_alt_map[of "mset ts" "mset ss" "{(t,s). snd (order s t)}" f f
"{(t, s). snd (order' s t)}" "{(t, s). fst (order s t)}" "{(t, s). fst (order' s t)}" False]
by (auto simp: mul_ext_def s_mul_ext_def converse_unfold)

lemma mul_ext_arg_empty: "snd (mul_ext f [] xs) ⟹ xs = []"
unfolding mul_ext_def Let_def by (auto simp: ns_mul_ext_def mult2_alt_def)

text ‹The non-strict order is irreflexive›
lemma s_mul_ext_irrefl: assumes irr: "irrefl_on (set_mset A) S"
and S_NS: "S ⊆ NS"
and compat: "S O NS ⊆ S"
shows "(A,A) ∉ s_mul_ext NS S" using irr
proof (induct A rule: wf_induct[OF wf_measure[of size]])
case (1 A)
show ?case
proof
assume "(A,A) ∈ s_mul_ext NS S"
from s_mul_extE[OF this]
obtain A1 A2 B1 B2 where
A: "A = A1 + A2"
and B: "A = B1 + B2"
and AB1: "(A1, B1) ∈ multpw NS"
and ne: "A2 ≠ {#}"
and S: "⋀b. b ∈# B2 ⟹ ∃a. a ∈# A2 ∧ (a, b) ∈ S"
by blast
from multpw_listE[OF AB1] obtain as1 bs1 where
l1: "length as1 = length bs1"
and A1: "A1 = mset as1"
and B1: "B1 = mset bs1"
and NS: "⋀ i. i<length bs1 ⟹ (as1 ! i, bs1 ! i) ∈ NS" by blast
(* store for later usage *)
note NSS = NS
note SS = S

obtain as2 where A2: "A2 = mset as2" by (metis ex_mset)
obtain bs2 where B2: "B2 = mset bs2" by (metis ex_mset)
define as where "as = as1 @ as2"
define bs where "bs = bs1 @ bs2"
have as: "A = mset as" unfolding A A1 A2 as_def by simp
have bs: "A = mset bs" unfolding B B1 B2 bs_def by simp
from as bs have abs: "mset as = mset bs" by simp
hence set_ab: "set as = set bs" by (rule mset_eq_setD)
let ?n = "length bs"
have las: "length as = ?n"
using mset_eq_length abs by fastforce
let ?m = "length bs1"
define decr where "decr j i ≡
(as ! j, bs ! i) ∈ NS ∧ (i < ?m ⟶ j = i) ∧ (?m ≤ i ⟶ ?m ≤ j ∧ (as ! j, bs ! i) ∈ S)" for i j
define step where "step i j k =
(i < ?n ∧ j < ?n ∧ k < ?n ∧ bs ! k = as ! j ∧ decr j i)"
for i j k
{
fix i
assume i: "i < ?n"
let ?b = "bs ! i"
have "∃ j. j < ?n ∧ decr j i"
proof (cases "i < ?m")
case False
with i have "?b ∈ set bs2" unfolding bs_def
by (auto simp: nth_append)
hence "?b ∈# B2" unfolding B2 by auto
from S[OF this, unfolded A2] obtain a where a: "a ∈ set as2" and S: "(a, ?b) ∈ S"
by auto
from a obtain k where a: "a = as2 ! k" and k: "k < length as2" unfolding set_conv_nth by auto
have "a = as ! (?m + k)" unfolding a as_def l1[symmetric] by simp
from S[unfolded this] S_NS False k
show ?thesis unfolding decr_def
by (intro exI[of _ "?m + k"], auto simp: las[symmetric] l1[symmetric] as_def)
next
case True
from NS[OF this] i True show ?thesis unfolding decr_def
by (auto simp: as_def bs_def l1 nth_append)
qed (insert i NS)
from this[unfolded set_conv_nth] las
obtain j where j: "j < ?n" and decr: "decr j i" by auto
let ?a = "as ! j"
from j las have "?a ∈ set as" by auto
from this[unfolded set_ab, unfolded set_conv_nth] obtain k where
k: "k < ?n" and id: "?a = bs ! k" by auto
have "∃ j k. step i j k"
using j k decr id i unfolding step_def by metis
}
hence "∀ i. ∃ j k. i < ?n ⟶ step i j k" by blast
from choice[OF this] obtain J' where "∀ i. ∃ k. i < ?n ⟶ step i (J' i) k" by blast
from choice[OF this] obtain K' where
step: "⋀ i. i < ?n ⟹ step i (J' i) (K' i)" by blast
define I where "I i = (K'^^i) 0" for i
define J where "J i = J' (I i)" for i
define K where "K i = K' (I i)" for i
from ne have "A ≠ {#}" unfolding A by auto
hence "set as ≠ {}" unfolding as by auto
hence "length as ≠ 0" by simp
hence n0: "0 < ?n" using las by auto
{
fix n
have "step (I n) (J n) (K n)"
proof (induct n)
case 0
from step[OF n0] show ?case unfolding I_def J_def K_def by auto
next
case (Suc n)
from Suc have "K n < ?n" unfolding step_def by auto
from step[OF this] show ?case unfolding J_def K_def I_def by auto
qed
}
note step = this
have "I n ∈ {..<?n}" for n using step[of n] unfolding step_def by auto
hence "I ` UNIV ⊆ {..<?n}" by auto
from finite_subset[OF this] have "finite (I ` UNIV)" by simp
from pigeonhole_infinite[OF _ this] obtain m where
"infinite {i. I i = I m}" by auto
hence "∃ m'. m' > m ∧ I m' = I m"
then obtain m' where *: "m < m'" "I m' = I m" by auto
let ?P = "λ n. ∃ m. n ≠ 0 ∧ I (n + m) = I m"
define n where "n = (LEAST n. ?P n)"
have "∃ n. ?P n"
by (rule exI[of _ "m' - m"], rule exI[of _ m], insert *, auto)
from LeastI_ex[of ?P, OF this, folded n_def]
obtain m where n: "n ≠ 0" and Im: "I (n + m) = I m" by auto
let ?M = "{m..<m+n}"
{
fix i j
assume *: "m ≤ i" "i < j" "j < n + m"
define k where "k = j - i"
have k0: "k ≠ 0" and j: "j = k + i" and kn: "k < n" using * unfolding k_def by auto
from not_less_Least[of _ ?P, folded n_def, OF kn] k0
have "I i ≠ I j" unfolding j by metis
}
hence inj: "inj_on I ?M" unfolding inj_on_def
define b where "b i = bs ! I i" for i
have bnm: "b (n + m) = b m" unfolding b_def Im ..
{
fix i
from step[of i, unfolded step_def]
have id: "bs ! K i = as ! J i" and decr: "decr (J i) (I i)" by auto
from id decr[unfolded decr_def] have "(bs ! K i, bs ! I i) ∈ NS" by auto
also have "K i = I (Suc i)" unfolding I_def K_def by auto
finally have "(b (Suc i), b i) ∈ NS" unfolding b_def by auto
} note NS = this
{
fix i j :: nat
assume "i ≤ j"
then obtain k where j: "j = i + k" by (rule less_eqE)
have "(b j, b i) ∈ NS^*" unfolding j
proof (induct k)
case (Suc k)
thus ?case using NS[of "i + k"] by auto
qed auto
} note NSstar = this
{
assume "∃ i ∈ ?M. I i ≥ ?m"
then obtain k where k: "k ∈ ?M" and I: "I k ≥ ?m" by auto
from step[of k, unfolded step_def]
have id: "bs ! K k = as ! J k" and decr: "decr (J k) (I k)" by auto
from id decr[unfolded decr_def] I have "(bs ! K k, bs ! I k) ∈ S" by auto
also have "K k = I (Suc k)" unfolding I_def K_def by auto
finally have S: "(b (Suc k), b k) ∈ S" unfolding b_def by auto
from k have "m ≤ k" by auto
from NSstar[OF this] have NS1: "(b k, b m) ∈ NS^*" .
from k have "Suc k ≤ n + m" by auto
from NSstar[OF this, unfolded bnm] have NS2: "(b m, b (Suc k)) ∈ NS^*" .
from NS1 NS2 have "(b k, b (Suc k)) ∈ NS^*" by simp
with S have "(b (Suc k), b (Suc k)) ∈ S O NS^*" by auto
also have "… ⊆ S" using compat
by (metis compat_tr_compat converse_inward(1) converse_mono converse_relcomp)
finally have contradiction: "b (Suc k) ∉ set_mset A" using 1 unfolding irrefl_on_def by auto
have "b (Suc k) ∈ set bs" unfolding b_def using step[of "Suc k"] unfolding step_def
by auto
also have "set bs = set_mset A" unfolding bs by auto
finally have False using contradiction by auto
}
hence only_NS: "i ∈ ?M ⟹ I i < ?m" for i by force
{
fix i
assume i: "i ∈ ?M"
from step[of i, unfolded step_def] have *: "I i < ?n" "K i < ?n"
and id: "bs ! K i = as ! J i" and decr: "decr (J i) (I i)" by auto
from decr[unfolded decr_def] only_NS[OF i] have "J i = I i" by auto
with id have id: "bs ! K i = as ! I i" by auto
note only_NS[OF i] id
} note pre_result = this
{
fix i
assume i: "i ∈ ?M"
have *: "I i < ?m" "K i < ?m"
proof (rule pre_result[OF i])
have "∃ j ∈ ?M. K i = I j"
proof (cases "Suc i ∈ ?M")
case True
show ?thesis by (rule bexI[OF _ True], auto simp: K_def I_def)
next
case False
with i have id: "n + m = Suc i" by auto
hence id: "K i = I m" by (subst Im[symmetric], unfold id, auto simp: K_def I_def)
with i show ?thesis by (intro bexI[of _ m], auto simp: K_def I_def)
qed
with pre_result show "K i < ?m" by auto
qed
from pre_result(2)[OF i] * l1 have "bs1 ! K i = as1 ! I i" "K i = I (Suc i)"
unfolding as_def bs_def by (auto simp: nth_append K_def I_def)
with * have "bs1 ! I (Suc i) = as1 ! I i" "I i < ?m" "I (Suc i) < ?m"
by auto
} note pre_identities = this
define M where "M = ?M"
note inj = inj[folded M_def]
define nxt where "nxt i = (if Suc i = n + m then m else Suc i)" for i
define prv where "prv i = (if i = m then n + m - 1 else i - 1)" for i
{
fix i
assume "i ∈ M"
hence i: "i ∈ ?M" unfolding M_def by auto
from i n have inM: "nxt i ∈ M" "prv i ∈ M" "nxt (prv i) = i" "prv (nxt i) = i"
unfolding nxt_def prv_def by (auto simp: M_def)
from i pre_identities[OF i] pre_identities[of m] Im n
have nxt: "bs1 ! I (nxt i) = as1 ! I i"
unfolding nxt_def prv_def by (auto simp: M_def)
note nxt inM
} note identities = this

(* next up: remove elements indexed by I ` ?m from both as1 and bs1
and apply induction hypothesis *)
note identities = identities[folded M_def]
define Drop where "Drop = I ` M"

define rem_idx where "rem_idx = filter (λ i. i ∉ Drop) [0..<?m]"
define drop_idx where "drop_idx = filter (λ i. i ∈ Drop) [0..<?m]"
define as1' where "as1' = map ((!) as1) rem_idx"
define bs1' where "bs1' = map ((!) bs1) rem_idx"
define as1'' where "as1'' = map ((!) as1) drop_idx"
define bs1'' where "bs1'' = map ((!) bs1) drop_idx"
{
fix as1 :: "'a list" and D :: "nat set"
define I where "I = [0..< length as1]"
have "mset as1 = mset (map ((!) as1) I)" unfolding I_def
by (rule arg_cong[of _ _ mset], intro nth_equalityI, auto)
also have "… = mset (map ((!) as1) (filter (λ i. i ∈ D) I))
+ mset (map ((!) as1) (filter (λ i. i ∉ D) I))"
by (induct I, auto)
also have "I = [0..< length as1]" by fact
finally have "mset as1 = mset (map ((!) as1) (filter (λi. i ∈ D) [0..<length as1])) + mset (map ((!) as1) (filter (λi. i ∉ D) [0..<length as1]))" .
} note split = this
from split[of bs1 Drop, folded rem_idx_def drop_idx_def, folded bs1'_def bs1''_def]
have bs1: "mset bs1 = mset bs1'' + mset bs1'" .
from split[of as1 Drop, unfolded l1, folded rem_idx_def drop_idx_def, folded as1'_def as1''_def]
have as1: "mset as1 = mset as1'' + mset as1'" .

(* showing that as1'' = bs1'' *)
define I' where "I' = the_inv_into M I"
have bij: "bij_betw I M Drop" using inj unfolding Drop_def by (rule inj_on_imp_bij_betw)
from the_inv_into_f_f[OF inj, folded I'_def] have I'I: "i ∈ M ⟹ I' (I i) = i" for i by auto
from bij I'I have II': "i ∈ Drop ⟹ I (I' i) = i" for i
from II' I'I identities bij have Drop_M: "i ∈ Drop ⟹ I' i ∈ M" for i
using Drop_def by force
have M_Drop: "i ∈ M ⟹ I i ∈ Drop" for i unfolding Drop_def by auto
{
fix x
assume "x ∈ Drop"
then obtain i where i: "i ∈ M" and x: "x = I i" unfolding Drop_def by auto
have "x < ?m" unfolding x using i pre_identities[of i] unfolding M_def by auto
} note Drop_m = this
hence drop_idx: "set drop_idx = Drop" unfolding M_def drop_idx_def set_filter set_upt by auto
have "mset as1'' = mset (map ((!) as1) drop_idx)" unfolding as1''_def mset_map by auto
also have "drop_idx = map (I o I') drop_idx" using drop_idx by (intro nth_equalityI, auto intro!: II'[symmetric])
also have "map ((!) as1) … = map (λ i. as1 ! I i) (map I' drop_idx)" by auto
also have "… = map (λ i. bs1 ! I (nxt i)) (map I' drop_idx)"
by (rule map_cong[OF refl], rule identities(1)[symmetric], insert drop_idx Drop_M, auto)
also have "… = map ((!) bs1) (map (I o nxt o I') drop_idx)"
by auto
also have "mset … = image_mset ((!) bs1) (image_mset (I o nxt o I') (mset drop_idx))" unfolding mset_map ..
also have "image_mset (I o nxt o I') (mset drop_idx) = image_mset I (image_mset nxt (image_mset I' (mset drop_idx)))"
by (metis multiset.map_comp)
also have "image_mset nxt (image_mset I' (mset drop_idx)) = image_mset I' (mset drop_idx)"
proof -
have dist: "distinct drop_idx" unfolding drop_idx_def by auto
have injI': "inj_on I' Drop" using II' by (rule inj_on_inverseI)
have "mset drop_idx = mset_set Drop" unfolding drop_idx[symmetric]
by (rule mset_set_set[symmetric, OF dist])
from image_mset_mset_set[OF injI', folded this]
have "image_mset I' (mset drop_idx) = mset_set (I' ` Drop)" by auto
also have "I' ` Drop = M" using II' I'I M_Drop Drop_M by force
finally have id: "image_mset I' (mset drop_idx) = mset_set M" .
have inj_nxt: "inj_on nxt M" using identities by (intro inj_on_inverseI)
have nxt: "nxt ` M = M" using identities by force
show ?thesis unfolding id image_mset_mset_set[OF inj_nxt] nxt ..
qed
also have "image_mset I … = mset drop_idx" unfolding multiset.map_comp using II'
by (intro multiset.map_ident_strong, auto simp: drop_idx)
also have "image_mset ((!) bs1) … = mset bs1''" unfolding bs1''_def mset_map ..
finally have bs1'': "mset bs1'' = mset as1''" ..

(* showing the remaining identities *)
let ?A = "mset as1' + mset as2"
let ?B = "mset bs1' + mset bs2"
from as1 bs1'' have as1: "mset as1 = mset bs1'' + mset as1'" by auto
have A: "A = mset bs1'' + ?A" unfolding A A1 A2 as1 by auto
have B: "A = mset bs1'' + ?B" unfolding B B1 B2 bs1 by auto
from A[unfolded B] have AB: "?A = ?B" by simp

have l1': "length as1' = length bs1'" unfolding as1'_def bs1'_def by auto
have NS: "(mset as1', mset bs1') ∈ multpw NS"
proof (rule multpw_listI[OF l1' refl refl], intro allI impI)
fix i
assume i: "i < length bs1'"
hence "rem_idx ! i ∈ set rem_idx" unfolding bs1'_def by (auto simp: nth_append)
hence ri: "rem_idx ! i < ?m" unfolding rem_idx_def by auto
from NSS[OF this] i
show "(as1' ! i, bs1' ! i) ∈ NS" unfolding as1'_def bs1'_def by (auto simp: nth_append)
qed
have S: "(mset as1' + mset as2, ?B) ∈ s_mul_ext NS S"
by (intro s_mul_extI[OF refl refl NS], unfold A2[symmetric] B2[symmetric], rule ne, rule S)
have irr: "irrefl_on (set_mset ?B) S" using 1(2) B unfolding irrefl_on_def by simp
have "M ≠ {}" unfolding M_def using n by auto
hence "Drop ≠ {}" unfolding Drop_def by auto
with drop_idx have "drop_idx ≠ []" by auto
hence "bs1'' ≠ []" unfolding bs1''_def by auto
hence "?B ⊂# A" unfolding B by (simp add: subset_mset.less_le)
hence "size ?B < size A" by (rule mset_subset_size)
thus False using 1(1) AB S irr by auto
qed
qed

lemma mul_ext_irrefl: assumes "⋀ x. x ∈ set xs ⟹ ¬ fst (rel x x)"
and "⋀ x y z. fst (rel x y) ⟹ snd (rel y z) ⟹ fst (rel x z)"
and "⋀ x y. fst (rel x y) ⟹ snd (rel x y)"
shows "¬ fst (mul_ext rel xs xs)"
unfolding mul_ext_def Let_def fst_conv
by (rule s_mul_ext_irrefl, insert assms, auto simp: irrefl_on_def)

text ‹The non-strict order is transitive.›

lemma ns_mul_ext_trans:
assumes "trans s" "trans ns" "compatible_l ns s" "compatible_r ns s" "refl ns"
and "(A, B) ∈ ns_mul_ext ns s"
and "(B, C) ∈ ns_mul_ext ns s"
shows "(A, C) ∈ ns_mul_ext ns s"
using assms unfolding compatible_l_def compatible_r_def ns_mul_ext_def
using trans_mult2_ns[of "s¯" "ns¯"]
by (auto simp: mult2_ns_eq_mult2_ns_alt converse_relcomp[symmetric]) (metis trans_def)

text‹The strict order is trans.›

lemma s_mul_ext_trans:
assumes "trans s" "trans ns" "compatible_l ns s" "compatible_r ns s" "refl ns"
and "(A, B) ∈ s_mul_ext ns s"
and "(B, C) ∈ s_mul_ext ns s"
shows "(A, C) ∈ s_mul_ext ns s"
using assms unfolding compatible_l_def compatible_r_def s_mul_ext_def
using trans_mult2_s[of "s¯" "ns¯"]
by (auto simp: mult2_s_eq_mult2_s_alt converse_relcomp[symmetric]) (metis trans_def)

text‹The strict order is compatible on the left with the non strict one›

lemma s_ns_mul_ext_trans:
assumes "trans s" "trans ns" "compatible_l ns s" "compatible_r ns s" "refl ns"
and "(A, B) ∈ s_mul_ext ns s"
and "(B, C) ∈ ns_mul_ext ns s"
shows "(A, C) ∈ s_mul_ext ns s"
using assms unfolding compatible_l_def compatible_r_def s_mul_ext_def ns_mul_ext_def
using compat_mult2(1)[of "s¯" "ns¯"]
by (auto simp: mult2_s_eq_mult2_s_alt mult2_ns_eq_mult2_ns_alt converse_relcomp[symmetric])

text‹The strict order is compatible on the right with the non-strict one.›

lemma ns_s_mul_ext_trans:
assumes "trans s" "trans ns" "compatible_l ns s" "compatible_r ns s" "refl ns"
and "(A, B) ∈ ns_mul_ext ns s"
and "(B, C) ∈ s_mul_ext ns s"
shows "(A, C) ∈ s_mul_ext ns s"
using assms unfolding compatible_l_def compatible_r_def s_mul_ext_def ns_mul_ext_def
using compat_mult2(2)[of "s¯" "ns¯"]
by (auto simp: mult2_s_eq_mult2_s_alt mult2_ns_eq_mult2_ns_alt converse_relcomp[symmetric])

text‹@{const s_mul_ext} is strongly normalizing›

lemma SN_s_mul_ext_strong:
assumes "order_pair s ns"
and "∀y. y ∈# M ⟶ SN_on s {y}"
shows "SN_on (s_mul_ext ns s) {M}"
using mult2_s_eq_mult2_s_alt[of "ns¯" "s¯"] assms wf_below_pointwise[of "s¯" "set_mset M"]
unfolding SN_on_iff_wf_below s_mul_ext_def order_pair_def compat_pair_def pre_order_pair_def
by (auto intro!: wf_below_mult2_s_local simp: converse_relcomp[symmetric])

lemma SN_s_mul_ext:
assumes "order_pair s ns" "SN s"
shows "SN (s_mul_ext ns s)"
using SN_s_mul_ext_strong[OF assms(1)] assms(2)
by (auto simp: SN_on_def)

lemma (in order_pair) mul_ext_order_pair:
"order_pair (s_mul_ext NS S) (ns_mul_ext NS S)" (is "order_pair ?S ?NS")
proof
from s_mul_ext_trans trans_S trans_NS compat_NS_S compat_S_NS refl_NS
show "trans ?S" unfolding trans_def compatible_l_def compatible_r_def by blast
next
from ns_mul_ext_trans trans_S trans_NS compat_NS_S compat_S_NS refl_NS
show "trans ?NS" unfolding trans_def compatible_l_def compatible_r_def by blast
next
from ns_s_mul_ext_trans trans_S trans_NS compat_NS_S compat_S_NS refl_NS
show "?NS O ?S ⊆ ?S" unfolding trans_def compatible_l_def compatible_r_def by blast
next
from s_ns_mul_ext_trans trans_S trans_NS compat_NS_S compat_S_NS refl_NS
show "?S O ?NS ⊆ ?S" unfolding trans_def compatible_l_def compatible_r_def by blast
next
from ns_mul_ext_refl[OF refl_NS, of _ S]
show "refl ?NS" unfolding refl_on_def by fast
qed

lemma (in SN_order_pair) mul_ext_SN_order_pair: "SN_order_pair (s_mul_ext NS S) (ns_mul_ext NS S)"
(is "SN_order_pair ?S ?NS")
proof -
from mul_ext_order_pair
interpret order_pair ?S ?NS .
have "order_pair S NS" by unfold_locales
then interpret SN_ars ?S using SN_s_mul_ext[of S NS] SN by unfold_locales
show ?thesis by unfold_locales
qed

lemma mul_ext_compat:
assumes compat: "⋀ s t u. ⟦s ∈ set ss; t ∈ set ts; u ∈ set us⟧ ⟹
(snd (f s t) ∧ fst (f t u) ⟶ fst (f s u)) ∧
(fst (f s t) ∧ snd (f t u) ⟶ fst (f s u)) ∧
(snd (f s t) ∧ snd (f t u) ⟶ snd (f s u)) ∧
(fst (f s t) ∧ fst (f t u) ⟶ fst (f s u))"
shows "
(snd (mul_ext f ss ts) ∧ fst (mul_ext f ts us) ⟶ fst (mul_ext f ss us)) ∧
(fst (mul_ext f ss ts) ∧ snd (mul_ext f ts us) ⟶ fst (mul_ext f ss us)) ∧
(snd (mul_ext f ss ts) ∧ snd (mul_ext f ts us) ⟶ snd (mul_ext f ss us)) ∧
(fst (mul_ext f ss ts) ∧ fst (mul_ext f ts us) ⟶ fst (mul_ext f ss us)) "
proof -
let ?s = "{(x, y). fst (f x y)}¯" and ?ns = "{(x, y). snd (f x y)}¯"
have [dest]: "(mset ts, mset ss) ∈ mult2_alt b2 ?ns ?s ⟹ (mset us, mset ts) ∈ mult2_alt b1 ?ns ?s ⟹
(mset us, mset ss) ∈ mult2_alt (b1 ∧ b2) ?ns ?s" for b1 b2
using assms by (auto intro!: trans_mult2_alt_local[of _ "mset ts"] simp: in_multiset_in_set)
show ?thesis by (auto simp: mul_ext_def s_mul_ext_def ns_mul_ext_def Let_def)
qed

lemma mul_ext_cong[fundef_cong]:
assumes "mset xs1 = mset ys1"
and "mset xs2 = mset ys2"
and "⋀ x x'. x ∈ set ys1 ⟹ x' ∈ set ys2 ⟹ f x x' = g x x'"
shows "mul_ext f xs1 xs2 = mul_ext g ys1 ys2"
using assms
mult2_alt_map[of "mset xs2" "mset xs1" "{(x, y). snd (f x y)}¯" id id "{(x, y). snd (g x y)}¯"
"{(x, y). fst (f x y)}¯" "{(x, y). fst (g x y)}¯"]
mult2_alt_map[of "mset ys2" "mset ys1" "{(x, y). snd (g x y)}¯" id id "{(x, y). snd (f x y)}¯"
"{(x, y). fst (g x y)}¯" "{(x, y). fst (f x y)}¯"]
by (auto simp: mul_ext_def s_mul_ext_def ns_mul_ext_def Let_def in_multiset_in_set)

lemma all_nstri_imp_mul_nstri:
assumes "∀i<length ys. snd (f (xs ! i) (ys ! i))"
and "length xs = length ys"
shows "snd (mul_ext f xs ys)"
proof-
from assms(1) have "∀i. i < length ys ⟶ (xs ! i, ys ! i) ∈ {(x,y). snd (f x y)}" by simp
from all_ns_ns_mul_ext[OF assms(2) this] show ?thesis by (simp add: mul_ext_def)
qed

lemma relation_inter:
shows "{(x,y). P x y} ∩ {(x,y). Q x y} = {(x,y). P x y ∧ Q x y}"
by blast

lemma mul_ext_unfold:
"(x,y) ∈ {(a,b). fst (mul_ext g a b)} ⟷ (mset x, mset y) ∈ (s_mul_ext {(a,b). snd (g a b)} {(a,b). fst (g a b)})"
unfolding mul_ext_def by (simp add: Let_def)

text ‹The next lemma is a local version of strong-normalization of
the multiset extension, where the base-order only has to be strongly normalizing
on elements of the multisets. This will be crucial for orders that are defined recursively
on terms, such as RPO or WPO.›
lemma mul_ext_SN:
assumes "∀x. snd (g x x)"
and "∀x y z. fst (g x y) ⟶ snd (g y z) ⟶ fst (g x z)"
and "∀x y z. snd (g x y) ⟶ fst (g y z) ⟶ fst (g x z)"
and "∀x y z. snd (g x y) ⟶ snd (g y z) ⟶ snd (g x z)"
and "∀x y z. fst (g x y) ⟶ fst (g y z) ⟶ fst (g x z)"
shows "SN {(ys, xs).
(∀y∈set ys. SN_on {(s ,t). fst (g s t)} {y}) ∧
fst (mul_ext g ys xs)}"
proof -
let ?R1 = "λxs ys. ∀y∈ set ys. SN_on {(s ,t). fst (g s t)} {y}"
let ?R2 = "λxs ys. fst (mul_ext g ys xs)"
let ?s = "{(x,y). fst (g x y)}" and ?ns = "{(x,y). snd (g x y)}"
have OP: "order_pair ?s ?ns" using assms(1-5)
by unfold_locales ((unfold refl_on_def trans_def)?, blast)+
let ?R = "{(ys, xs). ?R1 xs ys ∧ ?R2 xs ys}"
let ?Sn = "SN_on ?R"
{
fix ys xs
assume R_ys_xs: "(ys, xs) ∈ ?R"
let ?mys = "mset ys"
let ?mxs = "mset xs"
from R_ys_xs have  HSN_ys: "∀y. y ∈ set ys ⟶ SN_on ?s {y}" by simp
with in_multiset_in_set[of ys] have "∀y. y ∈# ?mys ⟶ SN_on ?s {y}" by simp
from SN_s_mul_ext_strong[OF OP this] and mul_ext_unfold
have "SN_on {(ys,xs). fst (mul_ext g ys xs)} {ys}" by fast
from relation_inter[of ?R2 ?R1] and SN_on_weakening[OF this]
have "SN_on ?R {ys}" by blast
}
then have Hyp: "∀ys xs. (ys,xs) ∈ ?R ⟶ SN_on ?R {ys}" by auto
{
fix ys
have "SN_on ?R {ys}"
proof (cases "∃ xs. (ys, xs) ∈ ?R")
case True with Hyp show ?thesis by simp
next
case False then show ?thesis by auto
qed
}
then show ?thesis unfolding SN_on_def by simp
qed

lemma mul_ext_stri_imp_nstri:
assumes "fst (mul_ext f as bs)"
shows "snd (mul_ext f as bs)"
using assms and s_ns_mul_ext unfolding mul_ext_def by (auto simp: Let_def)

lemma ns_ns_mul_ext_union_compat:
assumes "(A,B) ∈ ns_mul_ext ns s"
and "(C,D) ∈ ns_mul_ext ns s"
shows "(A + C, B + D) ∈ ns_mul_ext ns s"
using assms by (auto simp: ns_mul_ext_def intro: mult2_alt_ns_ns_add)

lemma s_ns_mul_ext_union_compat:
assumes "(A,B) ∈ s_mul_ext ns s"
and "(C,D) ∈ ns_mul_ext ns s"
shows "(A + C, B + D) ∈ s_mul_ext ns s"
using assms by (auto simp: s_mul_ext_def ns_mul_ext_def intro: mult2_alt_s_ns_add)

lemma ns_ns_mul_ext_union_compat_rtrancl: assumes refl: "refl ns"
and AB: "(A, B) ∈ (ns_mul_ext ns s)⇧*"
and CD: "(C, D) ∈ (ns_mul_ext ns s)⇧*"
shows "(A + C, B + D) ∈ (ns_mul_ext ns s)⇧*"
proof -
{
fix A B C
assume "(A, B) ∈ (ns_mul_ext ns s)⇧*"
then have "(A + C, B + C) ∈ (ns_mul_ext ns s)⇧*"
proof (induct rule: rtrancl_induct)
case (step B D)
have "(C, C) ∈ ns_mul_ext ns s"
by (rule ns_mul_ext_refl, insert refl, auto simp: locally_refl_def refl_on_def)
from ns_ns_mul_ext_union_compat[OF step(2) this] step(3)
show ?case by auto
qed auto
}
from this[OF AB, of C] this[OF CD, of B]
show ?thesis by (auto simp: ac_simps)
qed

subsection ‹Multisets as order on lists›

interpretation mul_ext_list: list_order_extension
"λs ns. {(as, bs). (mset as, mset bs) ∈ s_mul_ext ns s}"
"λs ns. {(as, bs). (mset as, mset bs) ∈ ns_mul_ext ns s}"
proof -
let ?m = "mset :: ('a list ⇒ 'a multiset)"
let ?S = "λs ns. {(as, bs). (?m as, ?m bs) ∈ s_mul_ext ns s}"
let ?NS = "λs ns. {(as, bs). (?m as, ?m bs) ∈ ns_mul_ext ns s}"
show "list_order_extension ?S ?NS"
proof (rule list_order_extension.intro)
fix s ns
let ?s = "?S s ns"
let ?ns = "?NS s ns"
assume "SN_order_pair s ns"
then interpret SN_order_pair s ns .
interpret SN_order_pair "(s_mul_ext ns s)" "(ns_mul_ext ns s)"
by (rule mul_ext_SN_order_pair)
show "SN_order_pair ?s ?ns"
proof
show "refl ?ns" using refl_NS unfolding refl_on_def by blast
show "?ns O ?s ⊆ ?s" using compat_NS_S by blast
show "?s O ?ns ⊆ ?s" using compat_S_NS by blast
show "trans ?ns" using trans_NS unfolding trans_def by blast
show "trans ?s" using trans_S unfolding trans_def by blast
show "SN ?s" using SN_inv_image[OF SN, of ?m, unfolded inv_image_def] .
qed
next
fix S f NS as bs
assume "⋀a b. (a, b) ∈ S ⟹ (f a, f b) ∈ S"
"⋀a b. (a, b) ∈ NS ⟹ (f a, f b) ∈ NS"
"(as, bs) ∈ ?S S NS"
then show "(map f as, map f bs) ∈ ?S S NS"
using mult2_alt_map[of _ _ "NS¯" f f "NS¯" "S¯" "S¯"] by (auto simp: mset_map s_mul_ext_def)
next
fix S f NS as bs
assume "⋀a b. (a, b) ∈ S ⟹ (f a, f b) ∈ S"
"⋀a b. (a, b) ∈ NS ⟹ (f a, f b) ∈ NS"
"(as, bs) ∈ ?NS S NS"
then show "(map f as, map f bs) ∈ ?NS S NS"
using mult2_alt_map[of _ _ "NS¯" f f "NS¯" "S¯" "S¯"] by (auto simp: mset_map ns_mul_ext_def)
next
fix as bs :: "'a list" and NS S :: "'a rel"
assume ass: "length as = length bs"
"⋀i. i < length bs ⟹ (as ! i, bs ! i) ∈ NS"
show "(as, bs) ∈ ?NS S NS"
by (rule, unfold split, rule all_ns_ns_mul_ext, insert ass, auto)
qed
qed

lemma s_mul_ext_singleton [simp, intro]:
assumes "(a, b) ∈ s"
shows "({#a#}, {#b#}) ∈ s_mul_ext ns s"
using assms by (auto simp: s_mul_ext_def mult2_alt_s_single)

lemma ns_mul_ext_singleton [simp, intro]:
"(a, b) ∈ ns ⟹ ({#a#}, {#b#}) ∈ ns_mul_ext ns s"
by (auto simp: ns_mul_ext_def multpw_converse intro: multpw_implies_mult2_alt_ns multpw_single)

lemma ns_mul_ext_singleton2:
"(a, b) ∈ s ⟹ ({#a#}, {#b#}) ∈ ns_mul_ext ns s"
by (intro s_ns_mul_ext s_mul_ext_singleton)

lemma s_mul_ext_self_extend_left:
assumes "A ≠ {#}" and "locally_refl W B"
shows "(A + B, B) ∈ s_mul_ext W S"
proof -
have "(A + B, {#} + B) ∈ s_mul_ext W S"
using assms by (intro s_mul_ext_union_compat) (auto dest: s_mul_ext_bottom)
then show ?thesis by simp
qed

lemma s_mul_ext_ne_extend_left:
assumes "A ≠ {#}" and "(B, C) ∈ ns_mul_ext W S"
shows "(A + B, C) ∈ s_mul_ext W S"
using assms
proof -
have "(A + B, {#} + C) ∈ s_mul_ext W S"
using assms by (intro s_ns_mul_ext_union_compat)
(auto simp: s_mul_ext_bottom dest: s_ns_mul_ext)
then show ?thesis by (simp add: ac_simps)
qed

lemma s_mul_ext_extend_left:
assumes "(B, C) ∈ s_mul_ext W S"
shows "(A + B, C) ∈ s_mul_ext W S"
using assms
proof -
have "(B + A, C + {#}) ∈ s_mul_ext W S"
using assms by (intro s_ns_mul_ext_union_compat)
(auto simp: ns_mul_ext_bottom dest: s_ns_mul_ext)
then show ?thesis by (simp add: ac_simps)
qed

lemma mul_ext_mono:
assumes "⋀x y. ⟦x ∈ set xs; y ∈ set ys; fst (P x y)⟧ ⟹ fst (P' x y)"
and   "⋀x y. ⟦x ∈ set xs; y ∈ set ys; snd (P x y)⟧ ⟹ snd (P' x y)"
shows
"fst (mul_ext P xs ys) ⟹ fst (mul_ext P' xs ys)"
"snd (mul_ext P xs ys) ⟹ snd (mul_ext P' xs ys)"
unfolding mul_ext_def Let_def fst_conv snd_conv
proof -
assume mem: "(mset xs, mset ys) ∈ s_mul_ext {(x, y). snd (P x y)} {(x, y). fst (P x y)}"
show "(mset xs, mset ys) ∈ s_mul_ext {(x, y). snd (P' x y)} {(x, y). fst (P' x y)}"
by (rule s_mul_ext_local_mono[OF _ _ mem], insert assms, auto)
next
assume mem: "(mset xs, mset ys) ∈ ns_mul_ext {(x, y). snd (P x y)} {(x, y). fst (P x y)}"
show "(mset xs, mset ys) ∈ ns_mul_ext {(x, y). snd (P' x y)} {(x, y). fst (P' x y)}"
by (rule ns_mul_ext_local_mono[OF _ _ mem], insert assms, auto)
qed

subsection ‹Special case: non-strict order is equality›

lemma ns_mul_ext_IdE:
assumes "(M, N) ∈ ns_mul_ext Id R"
obtains X and Y and Z where "M = X + Z" and "N = Y + Z"
and "∀y ∈ set_mset Y. ∃x ∈ set_mset X. (x, y) ∈ R"
using assms
by (auto simp: ns_mul_ext_def elim!: mult2_alt_nsE) (insert union_commute, blast)

lemma ns_mul_ext_IdI:
assumes "M = X + Z" and "N = Y + Z" and "∀y ∈ set_mset Y. ∃x ∈ set_mset X. (x, y) ∈ R"
shows "(M, N) ∈ ns_mul_ext Id R"
using assms mult2_alt_nsI[of N Z Y M Z X Id "R¯"]
by (auto simp: ns_mul_ext_def)

lemma s_mul_ext_IdE:
assumes "(M, N) ∈ s_mul_ext Id R"
obtains X and Y and Z where "X ≠ {#}" and "M = X + Z" and "N = Y + Z"
and "∀y ∈ set_mset Y. ∃x ∈ set_mset X. (x, y) ∈ R"
using assms
by (auto simp: s_mul_ext_def elim!: mult2_alt_sE) (metis union_commute)

lemma s_mul_ext_IdI:
assumes "X ≠ {#}" and "M = X + Z" and "N = Y + Z"
and "∀y ∈ set_mset Y. ∃x ∈ set_mset X. (x, y) ∈ R"
shows "(M, N) ∈ s_mul_ext Id R"
using assms mult2_alt_sI[of N Z Y M Z X Id "R¯"]
by (auto simp: s_mul_ext_def ac_simps)

lemma mult_s_mul_ext_conv:
assumes "trans R"
shows "(mult (R¯))¯ = s_mul_ext Id R"
using mult2_s_eq_mult2_s_alt[of Id "R¯"] assms
by (auto simp: s_mul_ext_def refl_Id mult2_s_def)

lemma ns_mul_ext_Id_eq:
"ns_mul_ext Id R = (s_mul_ext Id R)⇧="
by (auto simp add: ns_mul_ext_def s_mul_ext_def mult2_alt_ns_conv)

lemma subseteq_mset_imp_ns_mul_ext_Id:
assumes "A ⊆# B"
shows "(B, A) ∈ ns_mul_ext Id R"
proof -
obtain C where [simp]: "B = C + A" using assms by (auto simp: mset_subset_eq_exists_conv ac_simps)
have "(C + A, {#} + A) ∈ ns_mul_ext Id R"
by (intro ns_mul_ext_IdI [of _ C A _ "{#}"]) auto
then show ?thesis by simp
qed

lemma subset_mset_imp_s_mul_ext_Id:
assumes "A ⊂# B"
shows "(B, A) ∈ s_mul_ext Id R"
using assms by (intro supset_imp_s_mul_ext) (auto simp: refl_Id)

end
```