Theory SWF_Impossibility_Library

section ‹Auxiliary Material›
subsection ‹Miscellaneous›
theory SWF_Impossibility_Library
imports
  "Randomised_Social_Choice.Preference_Profiles"
  "HOL-Combinatorics.Multiset_Permutations"
begin

lemma wfp_on_iff_wfp: "wfp_on A R  wfp (λx y. R x y  x  A  y  A)"
proof -
  have "wfp_on A R  wf_on A {(x,y). R x y}"
    by (simp add: wfp_on_def wf_on_def)
  also have " = wf {(x,y). R x y  x  A  y  A}"
    by (subst wf_on_iff_wf) simp_all
  also have "  wfp (λx y. R x y  x  A  y  A)"
    by (simp add: wfp_def)
  finally show ?thesis .
qed

lemma permutations_of_set_conv_mset:
  "finite A  permutations_of_set A = {xs. mset xs = mset_set A}"
  by (metis permutations_of_multiset_def permutations_of_set_altdef)

lemma Set_filter_insert_if:
  "Set.filter P (insert x A) = (if P x then insert x (Set.filter P A) else Set.filter P A)"
  by auto

lemma Set_filter_insert:
  "P x  Set.filter P (insert x A) = insert x (Set.filter P A)"
  "¬P x  Set.filter P (insert x A) = Set.filter P A"
  by auto

lemma Set_filter_empty [simp]: "Set.filter P {} = {}"
  by auto

(* facts about multisets *)
lemma filter_mset_empty_conv: "filter_mset P A = {#}  (x∈#A. ¬P x)"
  by (induction A) auto

lemma image_mset_repeat_mset: "image_mset f (repeat_mset n A) = repeat_mset n (image_mset f A)"
  by (induction A) auto

lemma filter_mset_repeat_mset: "filter_mset P (repeat_mset n A) = repeat_mset n (filter_mset P A)"
  by (induction n) auto

lemma mset_eq_mset_set_iff:
  assumes "finite A"
  shows   "mset xs = mset_set A  xs  permutations_of_set A"
  using assms unfolding permutations_of_set_def mem_Collect_eq
  by (metis mset_set_set permutations_of_multisetI permutations_of_setD(1,2) permutations_of_set_altdef)

lemma size_Diff_mset_same_size:
  fixes A B :: "'a multiset"
  assumes "size (A - B) = n" "size A = size B"
  shows   "size (B - A) = n"
proof -
  define E where "E = A - B"
  define C where "C = B ∩# A"
  define D where "D = B - A"
  have "B = C + D"
    unfolding C_def D_def by (simp add: inter_mset_def)
  have "A - B + B = E + B"
    by (simp add: E_def)
  also have "A - B + B = A + D" unfolding D_def
    by (metis add.commute subset_mset.inf.commute union_diff_inter_eq_sup union_mset_def)
  finally have "size (A + D) = size (E + B)"
    by (rule arg_cong)
  hence "size A + size D = size B + size E"
    by simp
  also have "size A = size B"
    by fact
  finally have "size D = size E"
    by simp
  thus ?thesis using assms
    by (simp add: D_def E_def)
qed

lemma image_mset_diff_if_inj_on:
  fixes f :: "'a  'b"
  assumes "inj_on f (set_mset (A+B))"
  shows "image_mset f (A - B) = image_mset f A - image_mset f B"
  using assms
proof (induction B arbitrary: A)
  case (add x B A)
  show ?case
  proof (cases "x ∈# A")
    case False
    hence "f x ∉# image_mset f A"
      using add.prems by auto
    have "image_mset f (A - add_mset x B) = image_mset f (A - B)"
      using False by simp
    also have " = image_mset f A - image_mset f B"
      by (rule add.IH) (use add.prems in auto)
    also have " = image_mset f A - image_mset f (add_mset x B)"
      using f x ∉# image_mset f A by simp
    finally show ?thesis .
  next
    case True
    define A' where "A' = A - {#x#}"
    have A_eq: "A = A' + {#x#}"
      using True by (simp add: A'_def)
    have "image_mset f (A - add_mset x B) = image_mset f (A' - B)"
      by (simp add: A_eq)
    also have " = image_mset f A' - image_mset f B"
      by (rule add.IH) (use add.prems in auto simp: A_eq)
    also have " = image_mset f A - image_mset f (add_mset x B)"
      by (simp add: A_eq)
    finally show ?thesis .
  qed
qed auto


(* material about orders *)

context preorder_on
begin

sublocale dual: preorder_on carrier "λx y. le y x"
  by standard (use not_outside refl in auto intro: trans)

end


context order_on
begin

sublocale dual: order_on carrier "λx y. le y x"
  by standard (use antisymmetric in auto)

end


context total_preorder_on
begin

sublocale dual: total_preorder_on carrier "λx y. le y x"
  by standard (use total in auto)

end


context linorder_on
begin

sublocale dual: linorder_on carrier "λx y. le y x"
  by standard (use total in auto)

end


context finite_linorder_on
begin

sublocale dual: finite_linorder_on carrier "λx y. le y x"
  by standard auto

end


locale linorder_family = preorder_family dom carrier R for dom carrier R +
  assumes linorder_in_dom [simp]: "i  dom  linorder_on carrier (R i)"

lemma preorder_familyI [intro?]:
  fixes dom
  assumes "dom  {}"
  assumes "i. i  dom  preorder_on carrier (R i)"
  assumes "i x y. i  dom  ¬ R i x y"
  shows  "preorder_family dom carrier R"
  using assms unfolding preorder_family_def by auto

lemma linorder_familyI [intro?]:
  fixes dom
  assumes "dom  {}"
  assumes "i. i  dom  linorder_on carrier (R i)"
  assumes "i x y. i  dom  ¬ R i x y"
  shows   "linorder_family dom carrier R"
proof -
  have "preorder_family dom carrier R"
    by rule (use assms in auto simp: linorder_on_def total_preorder_on_def)
  thus ?thesis
    unfolding linorder_family_def linorder_family_axioms_def
    using assms by auto
qed


context order_on
begin

lemma order_on_restrict:
  "order_on (carrier  A) (restrict_relation A le)"
proof -
  interpret restrict: preorder_on "carrier  A" "restrict_relation A le"
    by (rule preorder_on_restrict)
  show ?thesis
    by standard (use antisymmetric in auto simp: restrict_relation_def)
qed

lemma order_on_restrict_subset:
  "A  carrier  order_on A (restrict_relation A le)"
  using order_on_restrict[of A] by (simp add: Int_absorb1)

end


context linorder_on
begin

lemma linorder_on_restrict:
  "linorder_on (carrier  A) (restrict_relation A le)"
proof -
  interpret restrict: order_on "carrier  A" "restrict_relation A le"
    by (rule order_on_restrict)
  show ?thesis
    by standard (use total in auto simp: restrict_relation_def)
qed

lemma linorder_on_restrict_subset:
  "A  carrier  linorder_on A (restrict_relation A le)"
  using linorder_on_restrict[of A] by (simp add: Int_absorb1)

end

lemma linorder_on_concat:
  assumes "linorder_on A R" "linorder_on B S" "A  B = {}"
  shows   "linorder_on (A  B) (λx y. if x  A then R x y  y  B else S x y)"
proof -
  interpret R: linorder_on A R
    by fact
  interpret S: linorder_on B S
    by fact
  show ?thesis
  proof (unfold_locales, goal_cases)
    case (1 x y)
    thus ?case
      using R.not_outside S.not_outside by (auto split: if_splits)
  next
    case (2 x y)
    thus ?case
      using R.not_outside S.not_outside by (auto split: if_splits)
  next
    case (3 x)
    thus ?case
      by (auto simp: R.refl S.refl)
  next
    case (4 x y z)
    thus ?case using assms(3) R.not_outside S.not_outside
      by (auto split: if_splits intro: R.trans S.trans)
  next
    case (5 x y)
    thus ?case using assms(3) R.not_outside S.not_outside
      by (auto split: if_splits intro: R.antisymmetric S.antisymmetric)
  next
    case (6 x y)
    thus ?case using R.total S.total
      by auto
  qed
qed

lemma linorder_on_prepend:
  assumes "linorder_on A R" "z  A"
  shows   "linorder_on (insert z A) (λx y. if x = z then y  insert z A else R x y)"
proof -
  have *: "linorder_on {z} (λx y. x = z  y = z)"
    by standard auto
  have "linorder_on ({z}  A) (λx y. if x  {z} then x = z  y = z  y  A else R x y)"
    by (rule linorder_on_concat) (use assms * in auto)
  also have " = (λx y. if x = z then y  insert z A else R x y)"
    by auto
  finally show ?thesis
    by simp
qed

lemma finite_linorder_on_exists:
  assumes "finite A"
  shows   "R. linorder_on A R"
  using assms
proof (induction rule: finite_induct)
  case empty
  have "linorder_on ({} :: 'a set) (λ_ _. False)"
    by standard auto
  thus ?case by blast
next
  case (insert x A)
  from insert.IH obtain R where R: "linorder_on A R"
    by blast
  have "linorder_on (insert x A) (λy z. if y = x then z  insert x A else R y z)"
    by (rule linorder_on_prepend) fact+
  thus ?case
    by blast
qed



context order_on
begin

lemma order_on_map:
  assumes "bij_betw f A carrier"
  shows   "order_on A (restrict_relation A (map_relation f le))"
proof -
  have "preorder_on (f -` carrier) (map_relation f le)"
    by (rule preorder_on_map)
  hence "preorder_on (f -` carrier  A) (restrict_relation A (map_relation f le))"
    by (rule preorder_on.preorder_on_restrict)
  also have "f -` carrier  A = A"
    using assms by (auto simp: bij_betw_def)
  finally interpret f: preorder_on A "restrict_relation A (map_relation f le)" .

  show ?thesis
  proof
    fix x y
    assume "restrict_relation A (map_relation f le) x y" "restrict_relation A (map_relation f le) y x"
    hence "f x = f y" "x  A" "y  A" using antisymmetric
      by (auto simp: restrict_relation_def map_relation_def)
    thus "x = y"
      using assms by (auto simp: bij_betw_def inj_on_def)
  qed
qed

end



context linorder_on
begin

lemma linorder_on_map:
  assumes "bij_betw f A carrier"
  shows   "linorder_on A (restrict_relation A (map_relation f le))"
proof -
  interpret order_on A "restrict_relation A (map_relation f le)"
    by (rule order_on_map) fact

  have "total_preorder_on (f -` carrier) (map_relation f le)"
    by (rule total_preorder_on_map)
  hence "total_preorder_on (f -` carrier  A) (restrict_relation A (map_relation f le))"
    by (rule total_preorder_on.total_preorder_on_restrict)
  also have "f -` carrier  A = A"
    using assms by (auto simp: bij_betw_def)
  finally interpret f: total_preorder_on A "restrict_relation A (map_relation f le)" .
  show ?thesis ..
qed

end


context finite_linorder_on
begin

lemma finite_linorder_on_map:
  assumes "bij_betw f A carrier"
  shows   "finite_linorder_on A (restrict_relation A (map_relation f le))"
proof -
  interpret linorder_on A "restrict_relation A (map_relation f le)"
    by (rule linorder_on_map) fact
  have [simp]: "finite A"
    using finite_carrier bij_betw_finite[OF assms] by simp
  show ?thesis
    by standard auto
qed

end



subsection ‹The Majority Relation›

text ‹
  Given a family of preorders, the majority relation induced by it is the one where $x$ and $y$
  are related iff $x \preceq y$ holds in at least half of the relations in the family.

  Note that the majority relation is in general neither antisymmetric
  (due to the possibility of ties) nor transitive (due to Condorcet cycles).
›

definition majority :: "('a  'b relation)  'b relation" where
  "majority R x y  (i. R i x x)  (i. R i y y)  card {i. R i x y}  card {i. R i y x}"

text ‹
  The same notion can easily be defined for multisets of relations as well.
›
definition majority_mset :: "'a relation multiset  'a relation" where
  "majority_mset Rs x y 
     (R∈#Rs. R x x)  (R∈#Rs. R y y)  
     size (filter_mset (λR. R x y) Rs)  size (filter_mset (λR. R y x) Rs)"

lemma majority_mset_not_outside:
  assumes "majority_mset Rs x y" "R. R ∈# Rs  preorder_on A R"
  shows   "x  A" "y  A"
proof -
  from assms(1) obtain R1 R2 where "R1 ∈# Rs" "R2 ∈# Rs" "R1 x x" "R2 y y"
    unfolding majority_mset_def by blast
  thus "x  A" "y  A"
    using assms(2) by (meson preorder_on.not_outside(1))+
qed

lemma majority_mset_refl_iff': "majority_mset Rs x x  (R∈#Rs. R x x)"
  unfolding majority_mset_def by simp

lemma majority_mset_refl_iff:
  assumes "R. R ∈# Rs  preorder_on A R" "Rs  {#}"
  shows   "majority_mset Rs x x  x  A"
  unfolding majority_mset_refl_iff' using assms
  by (metis multiset_nonemptyE preorder_on.not_outside(1) preorder_on.refl)

lemma majority_mset_refl: 
  assumes "R. R ∈# Rs  preorder_on A R" "Rs  {#}" "x  A"
  shows   "majority_mset Rs x x"
  using majority_mset_refl_iff[OF assms(1,2)] assms(3) by simp

lemma majority_mset_iff':
  assumes "R. R ∈# Rs  preorder_on A R" "Rs  {#}"
  shows   "majority_mset Rs x y 
             x  A  y  A  
             size (filter_mset (λR. R x y) Rs)  size (filter_mset (λR. R y x) Rs)"
proof -
  obtain R where R: "R ∈# Rs"
    using Rs  {#} by auto
  interpret R: preorder_on A R
    using assms(1) R by auto
  have *: "R x x  x  A" if "R ∈# Rs" for R x
    using assms(1)[OF that] preorder_on.refl preorder_on.not_outside(1) by metis
  show ?thesis using R
    unfolding majority_mset_def by (auto simp: *)
qed

lemma majority_mset_iff:
  assumes "R. R ∈# Rs  preorder_on A R" "Rs  {#}" "x  A" "y  A"
  shows   "majority_mset Rs x y 
             size (filter_mset (λR. R x y) Rs)  size (filter_mset (λR. R y x) Rs)"
  by (subst majority_mset_iff'[of Rs A]) (use assms in auto)

lemma majority_mset_iff_ge:
  assumes "R. R ∈# Rs  linorder_on A R" "Rs  {#}" "x  A" "y  A"
  shows   "majority_mset Rs x y 
             2 * size (filter_mset (λR. R x y) Rs)  size Rs"
proof (cases "x = y")
  case True
  have [simp]: "R y y" if "R ∈# Rs" for R
    using assms(1) y  A by (metis linorder_on_def that total_preorder_on.total)
  have "majority_mset Rs y y"
    using assms by (metis linorder_on_def majority_mset_refl order_on_def)
  moreover have "{#R ∈# Rs. R y y#} = filter_mset (λ_. True) Rs"
    by (intro filter_mset_cong) auto
  ultimately show ?thesis using True
    by simp
next
  case False
  have "Rs = filter_mset (λR. R x y) Rs + filter_mset (λR. ¬R x y) Rs"
    by (rule multiset_partition)
  also have "size  = size (filter_mset (λR. R x y) Rs) + size (filter_mset (λR. ¬R x y) Rs)"
    by (rule size_union)
  also have "filter_mset (λR. ¬R x y) Rs = filter_mset (λR. R y x) Rs"
  proof (rule filter_mset_cong)
    fix R assume "R ∈# Rs"
    then interpret R: linorder_on A R using assms(1) by auto
    show "¬R x y  R y x"
      using x  y R.antisymmetric R.total assms(3-4) by blast
  qed auto
  finally have eq: "size Rs = size {#R ∈# Rs. R x y#} + size {#R ∈# Rs. R y x#}" .
  show ?thesis
  proof (subst majority_mset_iff[of Rs A])
    fix R assume "R ∈# Rs"
    then interpret linorder_on A R using assms(1) by blast
    show "preorder_on A R" ..
  qed (use assms eq in auto)
qed

lemma majority_mset_iff_le:
  assumes "R. R ∈# Rs  linorder_on A R" "Rs  {#}" "x  A" "y  A" "x  y"
  shows   "majority_mset Rs x y 
             2 * size (filter_mset (λR. R y x) Rs)  size Rs"
proof -
  have "Rs = filter_mset (λR. R x y) Rs + filter_mset (λR. ¬R x y) Rs"
    by (rule multiset_partition)
  also have "size  = size (filter_mset (λR. R x y) Rs) + size (filter_mset (λR. ¬R x y) Rs)"
    by (rule size_union)
  also have "filter_mset (λR. ¬R x y) Rs = filter_mset (λR. R y x) Rs"
  proof (rule filter_mset_cong)
    fix R assume "R ∈# Rs"
    then interpret R: linorder_on A R using assms(1) by auto
    show "¬R x y  R y x"
      using x  y R.antisymmetric R.total assms(3-4) by blast
  qed auto
  finally have eq: "size Rs = size {#R ∈# Rs. R x y#} + size {#R ∈# Rs. R y x#}" .
  show ?thesis
  proof (subst majority_mset_iff[of Rs A])
    fix R assume "R ∈# Rs"
    then interpret linorder_on A R using assms(1) by blast
    show "preorder_on A R" ..
  qed (use assms eq in auto)
qed

lemma strongly_preferred_majority_mset_iff_gt:
  assumes "R. R ∈# Rs  linorder_on A R" "Rs  {#}" "x  A" "y  A"
  shows   "x ≺[majority_mset Rs] y  x  y 
             2 * size (filter_mset (λR. R x y) Rs) > size Rs"
proof (cases "x = y")
  case True
  show ?thesis using True
    by (auto simp: strongly_preferred_def)
next
  case False
  have "Rs = filter_mset (λR. R x y) Rs + filter_mset (λR. ¬R x y) Rs"
    by (rule multiset_partition)
  also have "size  = size (filter_mset (λR. R x y) Rs) + size (filter_mset (λR. ¬R x y) Rs)"
    by (rule size_union)
  also have "filter_mset (λR. ¬R x y) Rs = filter_mset (λR. R y x) Rs"
  proof (rule filter_mset_cong)
    fix R assume "R ∈# Rs"
    then interpret R: linorder_on A R using assms(1) by auto
    show "¬R x y  R y x"
      using x  y R.antisymmetric R.total assms(3-4) by blast
  qed auto
  finally have eq: "size Rs = size {#R ∈# Rs. R x y#} + size {#R ∈# Rs. R y x#}" .
  show ?thesis unfolding strongly_preferred_def
  proof (subst (1 2) majority_mset_iff[of Rs A])
    fix R assume "R ∈# Rs"
    then interpret linorder_on A R using assms(1) by blast
    show "preorder_on A R" ..
  qed (use assms eq in auto)
qed

lemma strongly_preferred_majority_mset_iff_lt:
  assumes "R. R ∈# Rs  linorder_on A R" "Rs  {#}" "x  A" "y  A"
  shows   "x ≺[majority_mset Rs] y 
             2 * size (filter_mset (λR. R y x) Rs) < size Rs"
proof (cases "x = y")
  case True
  have [simp]: "R y y" if "R ∈# Rs" for R
    using assms(1) y  A by (metis linorder_on_def that total_preorder_on.total)
  have "{#R ∈# Rs. R y y#} = filter_mset (λ_. True) Rs"
    by (intro filter_mset_cong) auto
  thus ?thesis using True
    by (auto simp: strongly_preferred_def)
next
  case False
  have *: "R. R ∈# Rs  preorder_on A R"
    using assms(1) by (simp add: linorder_on_def order_on_def)
  have "x ≺[majority_mset Rs] y  ¬(y ≼[majority_mset Rs] x)"
    using False majority_mset_iff[OF * assms(2)] assms(3,4)
    by (auto simp: strongly_preferred_def)
  also have "  size Rs > 2 * size {#R ∈# Rs. R y x#}"
    by (subst majority_mset_iff_ge[of Rs A]) (use assms in auto)
  finally show ?thesis .
qed

context preorder_family
begin

lemma majority_iff':
  "majority R x y  x  carrier  y  carrier  card {idom. R i x y}  card {idom. R i y x}"
proof -
  have *: "{i. R i x y} = {idom. R i x y}" for x y
    using not_in_dom by blast
  from nonempty_dom obtain i where "i  dom"
    by blast
  then interpret Ri: preorder_on carrier "R i"
    by simp
  show ?thesis
    using Ri.refl unfolding majority_def *
    by (meson in_dom not_in_dom preorder_on.not_outside(1))
qed

lemma majority_iff:
  assumes "x  carrier" "y  carrier"
  shows   "majority R x y  card {idom. R i x y}  card {idom. R i y x}"
  using assms by (simp add: majority_iff')

lemma majority_refl [simp]: "x  carrier  majority R x x"
  by (auto simp: majority_iff)

lemma majority_refl_iff: "majority R x x  x  carrier"
  by (auto simp: majority_iff')

lemma majority_total: "x  carrier  y  carrier  majority R x y  majority R y x"
  by (auto simp: majority_iff)

lemma strongly_preferred_majority_iff:
  assumes "x  carrier" "y  carrier"
  shows   "x ≺[majority R] y  card {idom. R i x y} > card {idom. R i y x}"
  unfolding strongly_preferred_def by (auto simp: majority_iff assms)

lemma majority_not_outside:
  assumes "majority R x y"
  shows   "x  carrier" "y  carrier"
  using assms in_dom not_in_dom preorder_on.not_outside unfolding majority_def by meson+

text ‹
  The majority relation chains with the unanimity relation.
›
lemma majority_Pareto1:
  assumes "Pareto R x y" "majority R y z" "finite dom"
  shows   "majority R x z"
proof -
  have xyz: "x  carrier" "y  carrier" "z  carrier"
    using Pareto.not_outside assms majority_not_outside by auto
   have "card {i  dom. R i z x}  card {i  dom. R i z y}"
    by (rule card_mono)
       (use assms(1,3) in_dom in auto simp: Pareto_iff intro: preorder_on.trans[OF in_dom])
  also have "card {i  dom. R i z y}  card {i  dom. R i y z}"
    using assms(2) xyz by (simp add: majority_iff)
  also have "  card {i  dom. R i x z}"
    by (rule card_mono)
       (use assms(1,3) in_dom in auto simp: Pareto_iff intro: preorder_on.trans[OF in_dom])
  finally show ?thesis
    using assms(2) xyz by (simp add: majority_iff)
qed

lemma majority_Pareto2:
  assumes "majority R x y" "Pareto R y z" "finite dom"
  shows   "majority R x z"
proof -
  have xyz: "x  carrier" "y  carrier" "z  carrier"
    using Pareto.not_outside assms majority_not_outside by auto
   have "card {i  dom. R i z x}  card {i  dom. R i y x}"
    by (rule card_mono)
       (use assms in_dom in auto simp: Pareto_iff intro: preorder_on.trans[OF in_dom])
  also have "card {i  dom. R i y x}  card {i  dom. R i x y}"
    using assms(1) xyz by (simp add: majority_iff)
  also have "  card {i  dom. R i x z}"
    by (rule card_mono)
       (use assms in_dom in auto simp: Pareto_iff intro: preorder_on.trans[OF in_dom])
  finally show ?thesis
    using assms(2) xyz by (simp add: majority_iff)
qed

lemma majority_conv_majority_mset:
  assumes "finite dom"
  shows   "majority R = majority_mset (image_mset R (mset_set dom))" (is "?lhs = ?rhs")
proof (intro ext)
  fix x y
  show "?lhs x y  ?rhs x y"
    unfolding majority_iff'
    by (subst majority_mset_iff'[where A = carrier])
       (use in_dom nonempty_dom
        in  auto simp del: in_dom simp: assms mset_set_empty_iff filter_mset_image_mset)
qed

end


context linorder_family
begin

lemma majority_iff_ge_half: 
  assumes "x  carrier" "y  carrier" "finite dom"
  shows   "majority R x y  2 * card {idom. R i x y}  card dom"
proof (cases "x = y")
  case [simp]: True
  have "{idom. R i x y} = dom"
    using assms preorder_on.refl[OF in_dom] by auto
  with assms show ?thesis
    by (simp add: majority_iff)
next
  case False
  have "dom = {i  dom. R i x y}  {i  dom. ¬R i x y}"
    by auto
  also have "card  = card {i  dom. R i x y} + card {i  dom. ¬R i x y}"
    by (rule card_Un_disjoint) (use finite dom in auto)
  also have "{i  dom. ¬R i x y} = {i  dom. R i y x}"
  proof (rule set_eqI, unfold mem_Collect_eq, intro conj_cong refl)
    fix i assume i: "i  dom"
    interpret Ri: linorder_on carrier "R i"
      using i by simp
    show "¬R i x y  R i y x"
      using Ri.total[of x y] Ri.antisymmetric[of x y] assms x  y by blast
  qed
  finally show ?thesis
    using assms by (auto simp: majority_iff)
qed

lemma majority_iff_le_half: 
  assumes "x  carrier" "y  carrier" "x  y" "finite dom"
  shows   "majority R x y  2 * card {idom. R i y x}  card dom"
proof -
  have "dom = {i  dom. R i x y}  {i  dom. ¬R i x y}"
    by auto
  also have "card  = card {i  dom. R i x y} + card {i  dom. ¬R i x y}"
    by (rule card_Un_disjoint) (use finite dom in auto)
  also have "{i  dom. ¬R i x y} = {i  dom. R i y x}"
  proof (rule set_eqI, unfold mem_Collect_eq, intro conj_cong refl)
    fix i assume i: "i  dom"
    interpret Ri: linorder_on carrier "R i"
      using i by simp
    show "¬R i x y  R i y x"
      using Ri.total[of x y] Ri.antisymmetric[of x y] assms x  y by blast
  qed
  finally show ?thesis
    using assms by (auto simp: majority_iff)
qed

text ‹
  For families of odd cardinality, the majority rule is always antisymmetric.
›
lemma odd_imp_majority_antisymmetric:
  assumes "odd (card dom)" "majority R x y" "majority R y x"
  shows   "x = y"
proof (rule ccontr)
  assume "x  y"
  have [simp]: "finite dom"
    using assms(1) card_ge_0_finite odd_pos by blast
  have xy: "x  carrier" "y  carrier" "card {i  dom. R i y x} = card {i  dom. R i x y}"
    using assms unfolding majority_iff' by auto
  have "dom = {i  dom. R i x y}  {i  dom. ¬R i x y}"
    by auto
  also have "card  = card {i  dom. R i x y} + card {i  dom. ¬R i x y}"
    by (rule card_Un_disjoint) auto
  also have "{i  dom. ¬R i x y} = {i  dom. R i y x}"
  proof (rule set_eqI, unfold mem_Collect_eq, intro conj_cong refl)
    fix i assume i: "i  dom"
    interpret Ri: linorder_on carrier "R i"
      using i by simp
    show "¬R i x y  R i y x"
      using Ri.total[of x y] Ri.antisymmetric[of x y] xy(1,2) x  y by blast
  qed
  also have "card  = card {i  dom. R i x y}"
    using xy(3) by simp
  finally have "even (card dom)"
    by simp
  with odd (card dom) show False
    by simp
qed

end



subsection ‹The lexicographic order on lists›

fun lexprod_list_aux :: "'a relation  'a list relation" where
  "lexprod_list_aux R [] ys  True"
| "lexprod_list_aux R (x # xs) []  False"
| "lexprod_list_aux R (x # xs) (y # ys)  x ≼[R] y  (x ≺[R] y  lexprod_list_aux R xs ys)"

lemma lexprod_list_aux_Nil_right_iff [simp]: "lexprod_list_aux R xs []  xs = []"
  by (cases xs) auto

lemma lexprod_list_aux_refl: "(xset xs. R x x)  lexprod_list_aux R xs xs"
  by (induction xs) auto

definition lexprod_list :: "'a relation  'a list relation" where
  "lexprod_list R = restrict_relation {xs. xset xs. R x x} (lexprod_list_aux R)"

definition lexprod_length_list :: "nat  'a relation  'a list relation" where
  "lexprod_length_list n R = restrict_relation {xs. length xs = n} (lexprod_list R)"


context preorder_on
begin

lemma lexprod_list_aux_trans:
  assumes "lexprod_list_aux le xs ys" "lexprod_list_aux le ys zs"
  shows "lexprod_list_aux le xs zs"
  using assms
proof (induction xs arbitrary: ys zs)
  case (Cons x xs ys zs)
  obtain y ys' where [simp]: "ys = y # ys'"
    using Cons.prems by (cases ys) auto
  obtain z zs' where [simp]: "zs = z # zs'"
    using Cons.prems by (cases zs) auto
  show ?case
    using Cons.prems Cons.IH[of ys' zs'] trans by (auto simp: strongly_preferred_def)
qed auto

lemma preorder_lexprod_list: "preorder_on (lists carrier) (lexprod_list le)"
proof
  show "lexprod_list le xs xs" if "xs  lists carrier" for xs
  proof -
    have "lexprod_list_aux le xs xs"
      using that by (induction xs) (auto intro: refl)
    thus ?thesis
      using that by (auto simp: lexprod_list_def restrict_relation_def refl)
  qed
next
  show "lexprod_list le xs zs" if "lexprod_list le xs ys" "lexprod_list le ys zs" for xs ys zs
    using lexprod_list_aux_trans[of xs ys zs] that
    by (auto simp: lexprod_list_def restrict_relation_def)
next
  show "xs  lists carrier" "ys  lists carrier"
    if "lexprod_list le xs ys" for xs ys
  proof -
    have "{xs, ys}  {xs. xset xs. le x x}"
      using that by (auto simp: lexprod_list_def restrict_relation_def)
    also have "  lists carrier"
      using not_outside by blast
    finally show "xs  lists carrier" "ys  lists carrier"
      by blast+
  qed
qed


lemma preorder_lexprod_length_list:
  "preorder_on {xs. set xs  carrier  length xs = n} (lexprod_length_list n le)"
proof -
  interpret lex: preorder_on "lists carrier" "lexprod_list le"
    by (rule preorder_lexprod_list)
  have "preorder_on (lists carrier  {xs. length xs = n}) (lexprod_length_list n le)"
    unfolding lexprod_length_list_def by (rule lex.preorder_on_restrict)
  also have "lists carrier  {xs. length xs = n} = {xs. set xs  carrier  length xs = n}"
    by auto
  finally show ?thesis .
qed

end



context total_preorder_on
begin

lemma total_preorder_lexprod_list: "total_preorder_on (lists carrier) (lexprod_list le)"
proof -
  interpret lex: preorder_on "lists carrier" "lexprod_list le"
    by (rule preorder_lexprod_list)
  show ?thesis
  proof
    show "lexprod_list le xs ys  lexprod_list le ys xs" 
      if "xs  lists carrier" "ys  lists carrier" for xs ys
    proof -
      have "lexprod_list_aux le xs ys  lexprod_list_aux le ys xs" using that total
        by (induction le xs ys rule: lexprod_list_aux.induct)
           (auto simp: strongly_preferred_def)
      thus ?thesis
        using that not_outside refl unfolding lexprod_list_def restrict_relation_def
        by blast
    qed
  qed
qed

lemma total_preorder_lexprod_length_list:
  "total_preorder_on {xs. set xs  carrier  length xs = n} (lexprod_length_list n le)"
proof -
  interpret lex: total_preorder_on "lists carrier" "lexprod_list le"
    by (rule total_preorder_lexprod_list)
  have "total_preorder_on (lists carrier  {xs. length xs = n}) (lexprod_length_list n le)"
    unfolding lexprod_length_list_def by (rule lex.total_preorder_on_restrict)
  also have "lists carrier  {xs. length xs = n} = {xs. set xs  carrier  length xs = n}"
    by auto
  finally show ?thesis .
qed

end


context order_on
begin

lemma order_lexprod_list: "order_on (lists carrier) (lexprod_list le)"
proof -
  interpret lex: preorder_on "lists carrier" "lexprod_list le"
    by (rule preorder_lexprod_list)
  show ?thesis
  proof
    show "xs = ys" if "lexprod_list le xs ys" "lexprod_list le ys xs"  for xs ys
    proof -
      have "lexprod_list_aux le xs ys" "lexprod_list_aux le ys xs"
           "set xs  carrier" "set ys  carrier"
        using that not_outside by (auto simp: lexprod_list_def restrict_relation_def)
      thus "xs = ys" using antisymmetric
        by (induction le xs ys rule: lexprod_list_aux.induct)
           (auto simp: strongly_preferred_def)
    qed
  qed
qed

lemma order_lexprod_length_list:
  "order_on {xs. set xs  carrier  length xs = n} (lexprod_length_list n le)"
proof -
  interpret lex: order_on "lists carrier" "lexprod_list le"
    by (rule order_lexprod_list)
  have "order_on (lists carrier  {xs. length xs = n}) (lexprod_length_list n le)"
    unfolding lexprod_length_list_def by (rule lex.order_on_restrict)
  also have "lists carrier  {xs. length xs = n} = {xs. set xs  carrier  length xs = n}"
    by auto
  finally show ?thesis .
qed

end



context linorder_on
begin

lemma order_lexprod_list: "linorder_on (lists carrier) (lexprod_list le)"
proof -
  interpret lex: order_on "lists carrier" "lexprod_list le"
    by (rule order_lexprod_list)
  interpret lex: total_preorder_on "lists carrier" "lexprod_list le"
    by (rule total_preorder_lexprod_list)
  show ?thesis ..
qed

lemma linorder_lexprod_length_list:
  "linorder_on {xs. set xs  carrier  length xs = n} (lexprod_length_list n le)"
proof -
  interpret lex: linorder_on "lists carrier" "lexprod_list le"
    by (rule order_lexprod_list)
  have "linorder_on (lists carrier  {xs. length xs = n}) (lexprod_length_list n le)"
    unfolding lexprod_length_list_def by (rule lex.linorder_on_restrict)
  also have "lists carrier  {xs. length xs = n} = {xs. set xs  carrier  length xs = n}"
    by auto
  finally show ?thesis .
qed

end



subsection ‹Maximal and minimal elements›

definition Min_wrt_among :: "'a relation  'a set  'a set" where
  "Min_wrt_among R A = {xA. R x x  (yA. R y x  R x y)}"

lemma Min_wrt_among_cong:
  assumes "restrict_relation A R = restrict_relation A R'"
  shows   "Min_wrt_among R A = Min_wrt_among R' A"
proof -
  from assms have "R x y  R' x y" if "x  A" "y  A" for x y
    using that by (auto simp: restrict_relation_def fun_eq_iff)
  thus ?thesis unfolding Min_wrt_among_def by blast
qed

definition Min_wrt :: "'a relation  'a set" where
  "Min_wrt R = Min_wrt_among R UNIV"
  
lemma Min_wrt_altdef: "Min_wrt R = {x. R x x  (y. R y x  R x y)}"
  unfolding Min_wrt_def Min_wrt_among_def by simp

lemma Min_wrt_among_conv_Max_wrt_among: "Min_wrt_among R A = Max_wrt_among (λx y. R y x) A"
  by (simp add: Min_wrt_among_def Max_wrt_among_def)


context preorder_on
begin

lemma Min_wrt_among_preorder:
  "Min_wrt_among le A = {xcarrier  A. ycarrier  A. le y x  le x y}"
  unfolding Min_wrt_among_def using not_outside refl by blast

lemma Min_wrt_preorder:
  "Min_wrt le = {xcarrier. ycarrier. le y x  le x y}"
  unfolding Min_wrt_altdef using not_outside refl by blast

lemma Min_wrt_among_subset:
  "Min_wrt_among le A  carrier" "Min_wrt_among le A  A"
  unfolding Min_wrt_among_preorder by auto
  
lemma Min_wrt_subset:
  "Min_wrt le  carrier"
  unfolding Min_wrt_preorder by auto

lemma Min_wrt_among_nonempty:
  assumes "B  carrier  {}" "finite (B  carrier)"
  shows   "Min_wrt_among le B  {}"
  by (simp add: Min_wrt_among_conv_Max_wrt_among assms(1,2) dual.Max_wrt_among_nonempty)
  
lemma Min_wrt_nonempty:
  "carrier  {}  finite carrier  Min_wrt le  {}"
  using Min_wrt_among_nonempty[of UNIV] by (simp add: Min_wrt_def)

lemma Min_wrt_among_map_relation_vimage:
  "f -` Min_wrt_among le A  Min_wrt_among (map_relation f le) (f -` A)"
  by (auto simp: Min_wrt_among_def map_relation_def)

lemma Min_wrt_map_relation_vimage:
  "f -` Min_wrt le  Min_wrt (map_relation f le)"
  by (auto simp: Min_wrt_altdef map_relation_def)

lemma Min_wrt_among_map_relation_bij_subset:
  assumes "bij (f :: 'a  'b)"
  shows   "f ` Min_wrt_among le A  
             Min_wrt_among (map_relation (inv f) le) (f ` A)"
  using assms Min_wrt_among_map_relation_vimage[of "inv f" A]
  by (simp add: bij_imp_bij_inv inv_inv_eq bij_vimage_eq_inv_image)
  
lemma Min_wrt_among_map_relation_bij:
  assumes "bij f"
  shows   "f ` Min_wrt_among le A = Min_wrt_among (map_relation (inv f) le) (f ` A)"
proof (intro equalityI Min_wrt_among_map_relation_bij_subset assms)
  interpret R: preorder_on "f ` carrier" "map_relation (inv f) le"
    using preorder_on_map[of "inv f"] assms 
      by (simp add: bij_imp_bij_inv bij_vimage_eq_inv_image inv_inv_eq)
  show "Min_wrt_among (map_relation (inv f) le) (f ` A)  f ` Min_wrt_among le A"
    unfolding Min_wrt_among_preorder R.Min_wrt_among_preorder 
    using assms bij_is_inj[OF assms]
    by (auto simp: map_relation_def inv_f_f image_Int [symmetric])
qed

lemma Min_wrt_map_relation_bij:
  "bij f  f ` Min_wrt le = Min_wrt (map_relation (inv f) le)"
proof -
  assume bij: "bij f"
  interpret R: preorder_on "f ` carrier" "map_relation (inv f) le"
    using preorder_on_map[of "inv f"] bij
      by (simp add: bij_imp_bij_inv bij_vimage_eq_inv_image inv_inv_eq)
  from bij show ?thesis
    unfolding R.Min_wrt_preorder Min_wrt_preorder
    by (auto simp: map_relation_def inv_f_f bij_is_inj)
qed

lemma Min_wrt_among_mono:
  "le y x  x  Min_wrt_among le A  y  A  y  Min_wrt_among le A"
  using not_outside by (auto simp: Min_wrt_among_preorder intro: trans)

lemma Min_wrt_mono:
  "le y x  x  Min_wrt le  y  Min_wrt le"
  unfolding Min_wrt_def using Min_wrt_among_mono[of y x UNIV] by blast

end


context total_preorder_on
begin

lemma Min_wrt_among_total_preorder:
  "Min_wrt_among le A = {xcarrier  A. ycarrier  A. le x y}"
  unfolding Min_wrt_among_preorder using total by blast

lemma Min_wrt_total_preorder:
  "Min_wrt le = {xcarrier. ycarrier. le x y}"
  unfolding Min_wrt_preorder using total by blast

lemma decompose_Min:
  assumes A: "A  carrier"
  defines "M  Min_wrt_among le A"
  shows   "restrict_relation A le = (λx y. x  M  y  A  (y  M  restrict_relation (A - M) le x y))"
  using A by (intro ext) (auto simp: M_def Min_wrt_among_total_preorder 
                            restrict_relation_def Int_absorb1 intro: trans)
  
end



definition min_wrt_among :: "'a relation  'a set  'a" where
  "min_wrt_among R A = the_elem (Min_wrt_among R A)"

definition min_wrt :: "'a relation  'a" where
  "min_wrt R = min_wrt_among R UNIV"

definition max_wrt_among :: "'a relation  'a set  'a" where
  "max_wrt_among R A = the_elem (Max_wrt_among R A)"

definition max_wrt :: "'a relation  'a" where
  "max_wrt R = max_wrt_among R UNIV"


context finite_linorder_on
begin

lemma Max_wrt_among_singleton:
  assumes "A  {}" "A  carrier"
  shows   "is_singleton (Max_wrt_among le A)"
proof -
  have "x = y" if "x  Max_wrt_among le A" "y  Max_wrt_among le A" for x y
    using antisymmetric[of x y] total[of x y] that assms
    unfolding Max_wrt_among_def by blast
  moreover have "Max_wrt_among le A  {}"
    by (rule Max_wrt_among_nonempty) (use assms in auto)
  ultimately show ?thesis
    unfolding is_singleton_def by blast
qed

lemma max_wrt_among_inside:
  assumes "A  {}" "A  carrier"
  shows   "max_wrt_among le A  A"
proof -
  have "max_wrt_among le A  Max_wrt_among le A"
    using Max_wrt_among_singleton[OF assms]
    unfolding is_singleton_def max_wrt_among_def by force
  also have "  A"
    by (auto simp: Max_wrt_among_def)
  finally show ?thesis .
qed

lemma le_max_wrt_among:
  assumes "y  A" "A  carrier"
  shows   "le y (max_wrt_among le A)"
proof -
  have "A  {}"
    using assms by auto
  have "max_wrt_among le A  Max_wrt_among le A"
    using Max_wrt_among_singleton[OF A  {} assms(2)]
    unfolding is_singleton_def max_wrt_among_def by force
  thus ?thesis using y  A
    by (metis assms(2) decompose_Max restrict_relation_def)
qed

end


context finite_linorder_on
begin

lemma Min_wrt_among_singleton:
  assumes "A  {}" "A  carrier"
  shows   "is_singleton (Min_wrt_among le A)"
  using assms by (metis Min_wrt_among_conv_Max_wrt_among dual.Max_wrt_among_singleton)

lemma min_wrt_among_inside:
  assumes "A  {}" "A  carrier"
  shows   "min_wrt_among le A  A"
  using dual.max_wrt_among_inside[OF assms]
  by (simp add: max_wrt_among_def min_wrt_among_def Min_wrt_among_conv_Max_wrt_among)

lemma le_min_wrt_among:
  assumes "y  A" "A  carrier"
  shows   "le (min_wrt_among le A) y"
  using dual.le_max_wrt_among[OF assms]
  by (simp add: max_wrt_among_def min_wrt_among_def Min_wrt_among_conv_Max_wrt_among)

end

end