theory Chapter3
  imports Chapter2
begin

(*
In this Section, we first review the relaxation from a topological closure operator
(in a Topological System) to a generalized closure operator (in a Closure System), also
denoted Cl here. We use the terminology Closure System to refer to the set system associated
with this generalized closure operator (and related operators) to be discussed below, and
reserve the terminology Topological System to refer exclusively to the topology (in the usual
sense) character
*)

(*
To study a Closure System, we start with the generalized closure operator. It turns
out that in analogous to the situation of a Topological System, the three axioms for a
generalized closure operator Cl can turn equivalently to an axiom system for a generalized
interior operator Int and an axiom system for a generalized exterior operator Ext. Note
that all operators treated from now on refer to the “generalized” version, despite using the
same bold-face symbols (and sometimes omitting the word “generalized”).
*)

section "1  Generalized Closure, Interior, and Exterior Operators"

(*
We first recall the standard definition of a generalized closure operator.

Definition 7: (Closure Operator).

An operator Cl: P(X) \<rightarrow> P(X) is called a generalized closure operator
(or simply, closure operator)
if for any sets A, B \<subseteq> X, Cl satisfies the following three axioms:
[C1] A \<subseteq> Cl(A);
[C2] A \<subseteq> B \<Rightarrow> Cl(A) \<subseteq> Cl(B);
[C3] Cl(Cl(A)) = Cl(A)
*)

definition C1 :: "'w cl \<Rightarrow> bool" where "C1 Cl \<equiv> \<forall>A. A \<^bold>\<preceq> Cl A"
definition C2 :: "'w cl \<Rightarrow> bool" where "C2 Cl \<equiv> \<forall>A B. A \<^bold>\<preceq> B \<longrightarrow> Cl A \<^bold>\<preceq> Cl B"
definition C3 :: "'w cl \<Rightarrow> bool" where "C3 Cl \<equiv> \<forall>A. Cl(Cl A) \<^bold>\<approx> (Cl A)"

definition general_Cl :: "'w cl \<Rightarrow> bool"
  where "general_Cl \<equiv> C1 \<^bold>\<and> C2 \<^bold>\<and> C3"

(*
Dually, we also have the axiomatic definition of a generalized interior operator,
which is also well known.

Definition 8: (Interior Operator).

An operator Int: P(X) \<rightarrow> P(X) is called the generalized interior operator
(or simply, interior operator)
if for any sets A, B \<subseteq> X, Int satisfies the following three axioms:
[I1] Int(A) \<subseteq> A;
[I2] A \<subseteq> B \<Rightarrow> Int(A) \<subseteq> Int(B);
[I3] Int(Int(A)) = Int(A).
*)

definition I1 :: "'w cl \<Rightarrow> bool" where "I1 Int' \<equiv> \<forall>A. Int' A \<^bold>\<preceq> A"
definition I2 :: "'w cl \<Rightarrow> bool" where "I2 Int' \<equiv> \<forall>A B. A \<^bold>\<preceq> B \<longrightarrow> Int' A \<^bold>\<preceq> Int' B"
definition I3 :: "'w cl \<Rightarrow> bool" where "I3 Int' \<equiv> \<forall>A. Int'(Int' A) \<^bold>\<approx> (Int' A)"

definition general_Int' :: "'w cl \<Rightarrow> bool"
  where "general_Int' \<equiv> I1 \<^bold>\<and> I2 \<^bold>\<and> I3"

(*
The interior operator Int is dual to the closure operator Cl,
in the sense that for any A \<subset> X, Int(A) = (Cl(A\<^sup>c))\<^sup>c and Cl(A) = (Int(A\<^sup>c))\<^sup>c.
*)

lemma fixes Cl
  assumes "general_Cl Cl" shows "general_Int' (\<lambda> A. \<^bold>\<midarrow> Cl (\<^bold>\<midarrow> A))" sorry

lemma fixes Int'
  assumes "general_Int' Int'" shows "general_Cl (\<lambda> A . \<^bold>\<midarrow> Int' (\<^bold>\<midarrow> A))" sorry

(*
In light of the identity between an exterior operator
and an interior operator operating on any subset A of X: Int(A) \<equiv> Ext(A\<^sup>c),
the axiomatic definition of a generalized exterior operator is obtained
(in analogous to how the topological exterior operator is defined
in relation to the definitions of topological closure
and topological interior operators) as follows.
*)

(*
Definition 9: (Exterior Operator).

An operator Ext: P(X) \<rightarrow> P(X) is called a generalized exterior operator
(or simply, exterior operator)
if for any sets A, B \<subseteq> X, Ext satisfies the following three axioms:
[E1] A \<inter> Ext(A) = \<emptyset>;
[E2] A \<subseteq> B \<Rightarrow> Ext(A) \<supseteq> Ext(B);
[E3] Ext(X \ Ext(A)) = Ext(A).
*)

definition E1 :: "'w cl \<Rightarrow> bool" where "E1 Ext \<equiv> \<forall>A. A \<^bold>\<and> Ext A \<^bold>\<approx> \<^bold>\<bottom>"
definition E2 :: "'w cl \<Rightarrow> bool" where "E2 Ext \<equiv> \<forall>A B. A \<^bold>\<preceq> B \<longrightarrow> Ext A \<^bold>\<succeq> Ext B"
definition E3 :: "'w cl \<Rightarrow> bool" where "E3 Ext \<equiv> \<forall>A. Ext(\<^bold>\<midarrow> (Ext A)) \<^bold>\<approx> (Ext A)"

definition general_Ext :: "'w cl \<Rightarrow> bool"
  where "general_Ext \<equiv> E1 \<^bold>\<and> E2 \<^bold>\<and> E3"

section "2 Generalized Boundary Operator"

(*
We now turn to generalized boundary (or frontier) operator.
A careful comparison of how a topological closure operator can be relaxed
to become a generalized closure operator,
we see that [FO1] and [FO5] in the definition of topological boundary operator
can be dropped to obtain a generalized boundary operator.
[FO2] expresses the essence of “boundary” (or “frontier”) of a closed set.
[FO3] shows Fr is “monotone” in some sense.
[FO4]\<^sup>* corresponds to the “idempotency” of the closure operator.
Therefore, we only retain [FO2], [FO3] and [FO4]\<^sup>* to obtain the definition
of generalized boundary operator.
*)

(*
Definition 10: (Boundary Operator).

An operator Fr: P(X) \<rightarrow> P(X) is called a generalized boundary operator
(or simply, boundary operator)
if for any sets A, B \<subseteq> X, Fr satisfies the following three axioms:
[F1] Fr(A) = Fr(X \ A);
[F2] A \<subseteq> B \<Rightarrow> Fr(A) \<subseteq> B \<union> Fr(B);
[F3] Fr(A \<union> Fr(A)) \<subseteq> Fr(A).
*)

definition F1 :: "'w cl \<Rightarrow> bool" where "F1 Fr \<equiv> \<forall>A. Fr A \<^bold>\<approx> Fr (\<^bold>\<midarrow> A)"
definition F2 :: "'w cl \<Rightarrow> bool" where "F2 Fr \<equiv> \<forall>A B. A \<^bold>\<preceq> B \<longrightarrow> Fr A \<^bold>\<preceq> B \<^bold>\<or> Fr B"
definition F3 :: "'w cl \<Rightarrow> bool" where "F3 Fr \<equiv> \<forall>A. Fr(A \<^bold>\<or> (Fr A)) \<^bold>\<preceq> (Fr A)"

definition general_Fr :: "'w cl \<Rightarrow> bool"
  where "general_Fr \<equiv> F1 \<^bold>\<and> F2 \<^bold>\<and> F3"

(*
Proposition 4.
The boundary operator Fr has the following property:
[F3]\<^sup>* Fr(Fr(A)) \<subseteq> Fr(A) for any A \<subseteq> X.
*)
definition F3' :: "'w cl \<Rightarrow> bool" where "F3' Fr \<equiv> \<forall>A. Fr(Fr A) \<^bold>\<preceq> (Fr A)"

lemma fixes Fr assumes "general_Fr Fr" shows "F3' Fr" sorry

(*Proof. See the proof of Proposition 2*)

(*
As we recall, [F3]\<^sup>* as stated above is axiom [FO4]
in the topological boundary operator.
However, [F3]\<^sup>* cannot be an alternative axiom
in the definition of generalized boundary operator.
In fact, [F3]\<^sup>* is strictly weaker than [F3] under [F1] and [F2].
It can be seen from the following example.
Example 1. Let X = {1, 2, 3}. ...
*)

(*
Boundary operators and closure operators have a one-to-one correspondence in Topological Systems. Likewise, for their generalizations in Closure Systems, we expect such
correspondence to still hold.
*)

(*
Theorem 1: (From Fr to Cl).
Let Fr: P(X) \<rightarrow> P(X) be a boundary operator.
Define the operator Cl as Cl(A) =: A \<union> Fr(A) for any subset A of X.
Then Cl as defined is a (generalized) closure operator.
*)

definition cl_from_fr :: "'w cl \<Rightarrow> 'w cl"
  where "cl_from_fr Fr \<equiv> \<lambda>A. A \<^bold>\<or> Fr A"

lemma
  fixes Fr :: "'w cl"
  assumes "general_Fr Fr"
  shows "general_Cl (cl_from_fr Fr)"
  sorry

(*
Proof:

To prove [C1], for any subset A of X, we have A \<subseteq> A \<union> Fr(A) = Cl(A),
where the last step is by our definition of the operator Cl.
Therefore, A \<subseteq> Cl(A).

To prove [C2], given A \<subseteq> B \<subseteq> X, axiom [F2] gives Fr(A) \<subseteq> B \<union> Fr(B).
Therefore, we have A \<union> Fr(A) \<subseteq> B \<union> Fr(B).
This, by the definition of Cl, is nothing but Cl(A) \<subseteq> Cl(B).

To prove [C3], applying the definition of Cl twice,
we have Cl(Cl(A))=Cl(A \<union> Fr(A))= A \<union> Fr(A) \<union> Fr(A \<union> Fr(A)).
By axiom [F3], then Cl(A \<union> Fr(A)) = A \<union> Fr(A) = Cl(A),
that is, Cl(Cl(A)) = Cl(A) holds.
*)

(*Conversely, we also can obtain a boundary operator from a closure operator.*)

(*
Theorem 2. (From Cl to Fr).
Let Cl: P(X) \<rightarrow> P(X) be a closure operator.
Define Fr(A) := Cl(A) \<inter> Cl(A\<^sup>c) for any subset A of X.
Then Fr as defined is a (generalized) boundary operator.
*)

definition fr_from_cl :: "'w cl \<Rightarrow> 'w cl"
  where "fr_from_cl Cl \<equiv> \<lambda>A. Cl A \<^bold>\<and> Cl (\<^bold>\<midarrow> A)"

lemma
  fixes Cl :: "'w cl"
  assumes "general_Cl Cl"
  shows "general_Fr (fr_from_cl Cl)"
  sorry

(*
Proof.

To prove [F1], from the definition of Fr,
Fr(A\<^sup>c) = Cl(A\<^sup>c) \<inter> Cl((A\<^sup>c)\<^sup>c) = Cl(A\<^sup>c) \<inter> Cl(A) = Fr(A).

To prove [F2], first by axiom [C1], A \<subseteq> Cl(A).
Again, by axiom [C1], A \<union> Cl(A\<^sup>c) \<supseteq> A \<union> A\<^sup>c = X, so A \<union> Cl(A\<^sup>c) = X.
Therefore, apply the definition of Fr,
A \<union> Fr(A) = A \<union> (Cl(A) \<inter> Cl(A\<^sup>c)) = (A \<union> Cl(A)) \<inter> (A \<union> Cl(A\<^sup>c))
= Cl(A) \<inter> X = Cl(A).
By axiom [C2], for any subsets A, B \<subseteq> X with A \<subseteq> B, Cl(A) \<subseteq> Cl(B),
i.e., Fr as defined satisfies [F2].

To prove [F3], from the above proof of [F2],
it follows that A \<union> Fr(A) = Cl(A) for any A \<subseteq> X.
We only need to check Fr(Cl(A)) \<subseteq> Fr(A).
Again, by the definition of Fr, Fr(Cl(A)) = Cl(Cl(A)) \<inter> Cl((Cl(A))\<^sup>c).
The first term on the right-hand side, by axiom [C3],
becomes Cl(Cl(A)) = Cl(A).
To deal with the second term, Cl((Cl(A))\<^sup>c),
by axiom [C1] we have A \<subseteq> Cl(A), which implies (Cl(A))\<^sup>c \<subseteq> A\<^sup>c;
then apply axiom [C2], Cl((Cl(A))\<^sup>c) \<subseteq> Cl(A\<^sup>c).
Therefore, Fr(Cl(A)) = Cl(Cl(A)) \<inter> Cl((Cl(A))\<^sup>c) \<subseteq> Cl(A) \<inter> Cl(A\<^sup>c) = Fr(A).
*)

(*
In the proof of Theorem 1, we have not used [F1] in the definition of generalized
boundary operator. So, we can further weaken the notion of generalized boundary set
operator as follows.
*)

(*
Definition 11: (Pre-Boundary Operator Pb).

An operator on P(X) is called a Pre-Boundary Operator, denoted Pb,
if Pb satisfies the following two conditions:

[Pb1] A \<subseteq> B \<Rightarrow> Pb(A) \<subseteq> B \<union> Pb(B);
[Pb2] Pb(A \<union> Pb(A)) \<subseteq> Pb(A).
*)

definition Pb1 :: "'w cl \<Rightarrow> bool" where "Pb1 Pb \<equiv> \<forall>A B. A \<^bold>\<preceq> B \<longrightarrow> Pb A \<^bold>\<preceq> B \<^bold>\<or> Pb B"
definition Pb2 :: "'w cl \<Rightarrow> bool" where "Pb2 Pb \<equiv> \<forall>A. Pb(A \<^bold>\<or> (Pb A)) \<^bold>\<preceq> (Pb A)"

definition general_Pb :: "'w cl \<Rightarrow> bool"
  where "general_Pb \<equiv> Pb1 \<^bold>\<and> Pb2"

(*
Theorem 3:

Let Pb be a pre-boundary operator.

1. Define Cl as Cl(A) =: A \<union> Pb(A) for any subset A of X.
Then Cl is a (generalized) closure operator.

2. Define Fr(A) =: Cl(A) \<inter> Cl(A\<^sup>c) as the (generalized) boundary operator
associated with Cl. Then the following two statements are equivalent:
  (i) For any subset A \<subseteq> X, Pb(A) = Pb(A\<^sup>c);
  (ii) For any subset A \<subseteq> X, Pb(A) = Fr(A).
*)

definition cl_from_pb :: "'w cl \<Rightarrow> 'w cl"
  where "cl_from_pb Pb \<equiv> \<lambda>A. A \<^bold>\<or> Pb A"

lemma
  fixes Pb :: "'w cl"
  assumes "general_Pb Pb"
  shows "general_Cl (cl_from_pb Pb)"
  sorry

lemma
  fixes Pb :: "'w cl"
  assumes "general_Pb Pb"
  shows "\<forall> A. Pb A \<^bold>\<approx> Pb (\<^bold>\<midarrow> A) \<longleftrightarrow>
              Pb A \<^bold>\<approx> (fr_from_cl (cl_from_pb Pb)) (\<^bold>\<midarrow> A)"
  sorry

(*
Proof.

For Statement 1:
Follow the proof of Theorem 1.

We now prove Statement 2:
From (i) to (ii).

By the construction of Fr,
for any subset A \<subseteq> X,
Fr(A) = Cl(A) \<inter> Cl(A\<^sup>c) = (A \<union> Pb(A)) \<inter> (A\<^sup>c \<union> Pb(A\<^sup>c))
= (A \<inter> A\<^sup>c) \<union> (A \<inter> Pb (A\<^sup>c)) \<union> (A\<^sup>c \<inter> Pb(A)) \<union> (Pb(A) \<inter> Pb(A\<^sup>c))
= (A \<inter> Pb (A\<^sup>c)) \<union> (A\<^sup>c \<inter> Pb(A)) \<union> (Pb(A) \<inter> Pb(A\<^sup>c)).

By (i),
for any subset A \<subseteq> X, Pb(A) = Pb(A\<^sup>c),
then Fr(A) = (A \<inter> Pb (A)) \<union> (A\<^sup>c \<inter> Pb(A)) \<union> (Pb(A) \<inter> Pb(A))
= (A \<inter> Pb (A)) \<union> (A\<^sup>c \<inter> Pb(A)) \<union> Pb(A)
= Pb(A), i.e.,
(i) implies (ii).

From (ii) to (i).
This is through the definition of Fr,
with axiom (F1) stating that Fr(A) = Fr(A\<^sup>c).
Given (ii) which states Pb = Fr,
then (i) is obvious by the definition of Fr(A).
*)

(*
From the above theorem, we can see
that in the axiomatic definition of a boundary operator,
axiom [F1], Fr(A) = Fr(A\<^sup>c), is indispensable,
which guarantees the one-to-one correspondence between boundary operators
and closure operators.
*)

section "3 Generalized Derived-Set Operator"

(*
In this section, we consider the generalized derived-set operator.
Compared with how one obtains the generalized closure operator
from the topological closure operator,
axiom [DO1] of the topological derived-set operator should be omitted
and [DO5] should be weakened to just being monotone.

From Proposition 2 and its proof, we expect to retain axiom [DO3].
Axiom [DO2] will also be retained, since it shows the essence
of the notion of a derived set.

Combining the above considerations, we have the following definition of
generalized derived-set operator.

Definition 12: (Derived-Set Operator Der).

An operator Der: P(X) \<rightarrow> P(X) is called a generalized derived-set operator
(or simply, derived-set operator)
if for any sets A, B \<subseteq> X, Der satisfies the following three axioms:

[D1] x \<in> Der(A) \<Leftarrow>\<Rightarrow> x \<in> Der(A \ {x});
[D2] A \<subseteq> B \<Rightarrow> Der(A) \<subseteq> Der(B);
[D3] Der(A \<union> Der(A)) \<subseteq> A \<union> Der(A).
*)

definition D1 :: "'w cl \<Rightarrow> bool" where "D1 Der \<equiv> \<forall>A x. Der A x \<longleftrightarrow> Der (A \<^bold>\<leftharpoonup> \<lbrace>x\<rbrace>) x"
definition D2 :: "'w cl \<Rightarrow> bool" where "D2 Der \<equiv> \<forall>A B. A \<^bold>\<preceq> B \<longrightarrow> Der A \<^bold>\<preceq> Der B"
definition D3 :: "'w cl \<Rightarrow> bool" where "D3 Der \<equiv> \<forall>A. Der(A \<^bold>\<or> (Der A)) \<^bold>\<preceq> (A \<^bold>\<or> Der A)"

definition general_Der :: "'w cl \<Rightarrow> bool"
  where "general_Der \<equiv> D1 \<^bold>\<and> D2 \<^bold>\<and> D3"

(*
Proposition 5:
A derived-set operator Der satisfies
[D3]\<^sup>* Der(Der(A)) \<subseteq> A \<union> Der(A), for any A \<subseteq> X.
*)

definition D3' :: "'w cl \<Rightarrow> bool" where "D3' Der \<equiv> \<forall>A. Der(Der A) \<^bold>\<preceq> (A \<^bold>\<or> Der A)"

lemma
  fixes Der
  assumes "general_Der Der"
  shows "D3' Der"
  sorry
(*  by (smt (z3) D2_def D3'_def D3_def assms general_Der_def join_def meet_def subset_def) *)

(*
Proof. See proof of Proposition 3.
*)

(*
In the case of topological derived-set operator,
property [DO3] and [DO3]\<^sup>* are substitutable.
However, their equivalence does not hold in the situation of a generalized
derived-set operator.

In fact, [D3]\<^sup>* is strictly weaker than [D3] in the case of generalized
derived-set operator. The following example can illustrate this ....
*)

(*
Derived-set operators and closure operators have a one-to-one correspondence in
Topological Systems. Likewise, for their generalizations in Closure Systems, we expect
such correspondence to still hold.
*)

(*
Theorem 4: (From Der to Cl).
Let Der: P(X) \<rightarrow> P(X) be a derived-set operator.
Define Cl as Cl(A) =: A \<union> Der(A) for any subset A of X.
Then Cl as defined is a closure operator.
*)

definition cl_from_der :: "'w cl \<Rightarrow> 'w cl"
  where "cl_from_der Der \<equiv> \<lambda> A . A \<^bold>\<or> Der A"

lemma
  fixes Der
  assumes "general_Der Der"
  shows "general_Cl (cl_from_der Der)"
  sorry

(*
Proof.

To prove [C1], since A \<subseteq> A \<union> Der(A) for any subset A of X,
we apply the definition of the operator Cl, Cl(A) = A \<union> Der(A),
and obtain A \<subseteq> Cl(A).

To prove [C2], suppose A \<subseteq> B \<subseteq> X.
By [D2], Der(A) \<subseteq> Der(B). Therefore A \<union> Der(A) \<subseteq> B \<union> Der(B).
According to our definition, this is Cl(A) \<subseteq> Cl(B).

To prove [C3], apply the definition of Cl twice,
we have Cl(Cl(A))=Cl(A \<union> Der(A))= A \<union> Der(A) \<union> Der(A \<union> Der(A)).
By [D3], then Cl(A \<union> Der(A)) = A \<union> Der(A) = Cl(A), that is,
the law of idempotency Cl(Cl(A)) = Cl(A) holds.
*)

(*
Conversely, we also can obtain a derived-set operator from a closure operator.
*)

(*
Theorem 5: (From Cl to Der).
Let Cl: P(X) \<rightarrow> P(X) be a closure operator.
Define Der(A) := {x \<in> X | x \<in> Cl(A \ {x})} for any subset A of X.
Then Der as defined is a derived-set operator
*)

definition der_from_cl :: "'w cl \<Rightarrow> 'w cl"
  where "der_from_cl Cl \<equiv> \<lambda> A . (\<lambda> x. Cl (A \<^bold>\<leftharpoonup> \<lbrace>x\<rbrace>) x)"

lemma
  fixes Cl
  assumes "general_Cl Cl"
  shows "general_Der (der_from_cl Cl)"
  sorry

(*
Proof.

To prove [D1],
assume that x \<in> Der(A),
then by the definition of Der,
it follows x \<in> Cl(A \ {x}).
Since A \ {x} = (A \ {x}) \ {x},
we have x \<in> Cl(A \ {x}) = Cl((A \ {x}) \ {x}).
Again, by the definition of Der, x \<in> Der(A \ {x}) holds.
Every step in the above can be reversed.
Therefore, x \<in> Der(A) \<Leftarrow>\<Rightarrow> x \<in> Der(A \ {x}) holds.

To prove [D2],
given that any subsets A, B \<subseteq> X, A \<subseteq> B, we have A \ {x} \<subseteq> B \ {x}.
For any x \<in> Der(A), apply the definition of Der, we have x \<in> Cl(A \ {x}).
By [C2], we have x \<in> Cl(A \ {x}) \<subseteq> Cl(B \ {x}).
Again, by the definition of Der, x \<in> Der(B).
Therefore, Der(A) \<subseteq> Der(B) holds.

To prove [D3],
let us first show A \<union> Der(A) = Cl(A) for any A \<subseteq> X.
For any x \<in> Der(A), we have x \<in> Cl(A \ {x}) by the definition of Der.
Since Cl(A \ {x}) \<subseteq> Cl(A) by [C2], then x \<in> Cl(A).
So Der(A) \<subseteq> Cl(A).
Together with [C1], A \<union> Der(A) \<subseteq> Cl(A) holds.
On the other hand,
for every x \<in> Cl(A), assume that x 6\<in> A,
then A = A \ {x}.
So x \<in> Cl(A) = Cl(A \ {x}),
namely again by the definition of Der, x \<in> Der(A),
so Cl(A) \<subseteq> A \<union> Der(A).
Therefore, A \<union> Der(A) = Cl(A).
Because of this Der(A) \<subseteq> Cl(A).
So Der(A \<union> Der(A)) =Der(Cl(A)) \<subseteq> Cl(Cl(A)) = Cl(A), by [C3].
Therefore, Der(A \<union> Der(A)) \<subseteq> Cl(A) = A \<union> Der(A), which is [D3].
*)

(*
In the proof of Theorem 4, we have not used [D1]
in the definition of generalized derived-set operator Der.
A further weakening of the generalized derived-set operator can be obtained.
*)

(*
Definition 13: (Pre-Derived-Set Operator Pd).

An operator on P(X) is called a pre-derived-set operator, denoted Pd,
if Pd satisfies the following conditions:

[Pd1] A \<subseteq> B \<Rightarrow> Pd(A) \<subseteq> Pd(B);
[Pd2] Pd(A \<union> Pd(A)) \<subseteq> A \<union> Pd(A).
*)

definition Pd1 :: "'w cl \<Rightarrow> bool" where "Pd1 Pd \<equiv> \<forall>A B. A \<^bold>\<preceq> B \<longrightarrow> Pd A \<^bold>\<preceq> Pd B"
definition Pd2 :: "'w cl \<Rightarrow> bool" where "Pd2 Pd \<equiv> \<forall>A. Pd(A \<^bold>\<or> (Pd A)) \<^bold>\<preceq> (A \<^bold>\<or> Pd A)"

definition general_Pd :: "'w cl \<Rightarrow> bool"
  where "general_Pd \<equiv> Pd1 \<^bold>\<and> Pd2"

(*
Theorem 6:

Let Pd be a pre-derived-set operator.

1. Define the operator Cl by Cl(A) =: A \<union> Pd(A) for any subset A of X.
Then Cl is a (generalized) closure operator.

2. Define the operartor Der by Der(A) = {x \<in> X | x \<in> Cl(A \ {x})}.
Then the following two statements are equivalent:
  (i) For any subset A \<subseteq> X, x \<in> Pd(A) \<Leftarrow>\<Rightarrow> x \<in> Pd(A \ {x});
  (ii) For any subset A \<subseteq> X, Pd(A) = Der(A).
*)

definition cl_from_pd :: "'w cl \<Rightarrow> 'w cl"
  where "cl_from_pd Pd \<equiv> \<lambda>A. A \<^bold>\<or> Pd A"

lemma
  fixes Pd :: "'w cl"
  assumes "general_Pd Pd"
  shows "general_Cl (cl_from_pd Pd)"
  sorry

lemma
  fixes Pd :: "'w cl"
  assumes "general_Pd Pd"
  shows "\<forall> A x. (Pd A x \<longleftrightarrow> Pd (A \<^bold>\<leftharpoonup> \<lbrace>x\<rbrace>) x) \<longleftrightarrow>
                (Pd A \<^bold>\<approx> (der_from_cl (cl_from_pd Pb)) A)"
  sorry

(*
Proof.

For Statement 1:
see the proof of Theorem 4.

So, we now prove Statement 2:

From (i) to (ii).
Assume that (i) holds,
namely for any subset A \<subseteq> X, x \<in> Pd(A) \<Leftarrow>\<Rightarrow> x \<in> Pd(A \ {x}).
By the definitions of Cl and Der,
for any x \<in> Der(A), then x \<in> Cl(A \ {x}) = (A \ {x}) \<union> Pd(A \ {x}),
which implies x \<in> Pd(A \ {x}).
By the given condition (i),
we have x \<in> Pd(A), then Der(A) \<subseteq> Pd(A).
Similarly, for the other direction,
for any x \<in> Pd(A), by the given condition (i),
x \<in> Pd(A \ {x}), so x \<in> Cl(A \ {x}) by the definition of Cl.
Again, by the definition of Der, x \<in> Der(A).
Therefore, Pd(A) \<subseteq> Der(A).
That is to say, (ii) holds.

From (ii) to (i).
If (ii) holds, Pd is a generalized derived-set operator.
Then Pd satisfies (i).
So, the proof is completed.
*)

section "4 Generalized Co-Derived-Set Operator"

(*
Dual to a generalized derived-set operator,
we can define a generalized co-derivedset operator.
*)

(*
Definition 14. (Co-Derived-Set Operator Cod).

A generalized co-derived-set operator
(or simply, co-derived-set operator), denoted Cod,
is defined as an operator on P(X) which satisfies:

[A1] x \<in> Cod(A) \<Leftarrow>\<Rightarrow> x \<in> Cod(A \<union> {x});
[A2] A \<subseteq> B \<Rightarrow> Cod(A) \<subseteq> Cod(B);
[A3] Cod(A \<inter> Cod(A)) \<supseteq> A \<inter> Cod(A).
*)

definition A1 :: "'w cl \<Rightarrow> bool" where "A1 Cod \<equiv> \<forall>A x. Cod A x \<longleftrightarrow> Cod (A \<^bold>\<or> \<lbrace>x\<rbrace>) x"
definition A2 :: "'w cl \<Rightarrow> bool" where "A2 Cod \<equiv> \<forall>A B. A \<^bold>\<preceq> B \<longrightarrow> Cod A \<^bold>\<preceq> Cod B"
definition A3 :: "'w cl \<Rightarrow> bool" where "A3 Cod \<equiv> \<forall>A. Cod(A \<^bold>\<and> (Cod A)) \<^bold>\<succeq> (A \<^bold>\<and> Cod A)"

definition general_Cod :: "'w cl \<Rightarrow> bool"
  where "general_Cod \<equiv> A1 \<^bold>\<and> A2 \<^bold>\<and> A3"

(*
That the derived-set operator Der is dual to the co-derived-set operator Cod
is reflected in Cod(A) = (Der(A\<^sup>c))\<^sup>c and Der(A) = (Cod(A\<^sup>c))\<^sup>c.*)

lemma assumes "general_Der Der" shows "general_Cod (\<lambda> A. \<^bold>\<midarrow> Der (\<^bold>\<midarrow> A))" sorry
lemma assumes "general_Cod Cod" shows "general_Der (\<lambda> A. \<^bold>\<midarrow> Cod (\<^bold>\<midarrow> A))" sorry

(*
Combining the duality of derived-set operator and the co-derived-set operator with
the duality of the closure operator and the interior operator, we have the following results
(proof omitted) complementary to previous theorems for derived-set operators.
*)

(*
Theorem 7. (From Cod to Int).
Let Cod: P(X) \<rightarrow> P(X) be a co-derived-set operator.
Define Int(A) =: A \<inter> Cod(A) for any subset A of X.
Then Int as defined is an interior operator.
*)

definition int_from_cod :: "'w cl \<Rightarrow> 'w cl"
  where "int_from_cod Cod \<equiv> \<lambda>A. A \<^bold>\<and> Cod A"

lemma
  fixes Cod :: "'w cl"
  assumes "general_Cod Cod"
  shows "general_Int' (int_from_cod Cod)"
  sorry

(*
Theorem 8. (From Int to Cod).
Let Int: P(X) \<rightarrow> P(X) be an interior operator.
Define Cod(A) := {x \<in> X | x \<in> Int(A \<union> {x})} for any subset A of X.
Then Cod as defined is a co-derived-set operator
*)

definition cod_from_int :: "'w cl \<Rightarrow> 'w cl"
  where "cod_from_int Int' \<equiv> \<lambda> A . (\<lambda> x. Int' (A \<^bold>\<or> \<lbrace>x\<rbrace>) x)"

lemma
  fixes Int' :: "'w cl"
  assumes "general_Int' Cod"
  shows "general_Cod (cod_from_int Int')"
  sorry

(*
Definition 15. (Pre-Co-Derived-Set Operator Pcd).
An operator on P(X) is called a pre-co-derived-set operator, denoted Pcd,
if it satisfies the following conditions:

[Pcd1] A \<subseteq> B \<Rightarrow> Pcd(A) \<subseteq> Pcd(B);
[Pcd2] Pcd(A \<union> Pcd(A)) \<supseteq> A \<union> Pcd(A).
*)

definition Pcd1 :: "'w cl \<Rightarrow> bool" where "Pcd1 Pcd \<equiv> \<forall>A B. A \<^bold>\<preceq> B \<longrightarrow> Pcd A \<^bold>\<preceq> Pcd B"
definition Pcd2 :: "'w cl \<Rightarrow> bool" where "Pcd2 Pcd \<equiv> \<forall>A. Pcd(A \<^bold>\<or> (Pcd A)) \<^bold>\<succeq> (A \<^bold>\<or> Pcd A)"

definition general_Pcd :: "'w cl \<Rightarrow> bool"
  where "general_Pcd \<equiv> Pcd1 \<^bold>\<and> Pcd2"

(*
Theorem 9.

Let Pcd be a pre-co-derived-set operator.
For any subset A \<subseteq> X, denote Int as the interior operator generated by Pcd:
Int(A) =: A \<inter> Pcd(A),
and Cod as the resulting co-derived-set operator:
Cod(A) = {x \<in> X | x \<in> Int(A \<union> {x})}.

Then the following two statements are equivalent:
(i) For any subset A \<subseteq> X, x \<in> Pcd(A) \<Leftarrow>\<Rightarrow> x \<in> Pcd(A \<union> {x});
(ii) For any subset A \<subseteq> X, Pcd(A) = Cod(A).
*)

definition int_from_pcd :: "'w cl \<Rightarrow> 'w cl"
  where "int_from_pcd Pcd \<equiv> \<lambda> A . A \<^bold>\<and> Pcd A"

lemma
  fixes Pcd :: "'w cl"
  assumes "general_Pcd Pcd"
  shows "\<forall> A x. (Pcd A x \<longleftrightarrow> Pcd (A \<^bold>\<or> \<lbrace>x\<rbrace>) x) \<longleftrightarrow>
                (Pcd A \<^bold>\<approx> (cod_from_int (int_from_pcd Pcb)) A)"
  sorry

section "5 Relations between Various Characterizations"

(*
Following the formulation of generalized closure operator Cl and generalized interior
operator Int, we have, in the previous subsections, proposed axiomatic systems for four
related generalized set operators: generalized exterior operator Ext, generalized boundary
operator Fr, generalized derived-set operator Der, and generalized co-derived-set operator
Cod. The prefix “generalized” can be omitted if the context clearly refers to the “generalized” Closure System. These six operators provide a complete generalization (for the case
of Closure System) of the suite of six corresponding operators encountered in topology
(in the Topological System). The generalized operators we obtained, Fr, Der, Cod, are
in one-to-one correspondence to the operator Cl and the immediately related operators
Int, Ext. Given any operator, the remaining five operators can be specified. The results are
summarized in the following figure (Figure 1).

...

1. Int(A) = Ext(A\<^sup>c),
1\<^sup>*. Ext(A) = Int(A\<^sup>c).
2. Cod(A) = {x \<in> X | x \<in> Int(A \<union> {x})},
2\<^sup>*. Int(A) = A \<inter> Cod(A).
3. Cl(A) = (Ext(A))\<^sup>c,
3\<^sup>*. Ext(A) = (Cl(A))\<^sup>c.
4. Cl(A) = (Int(A\<^sup>c))\<^sup>c,
4\<^sup>*. Int(A) = (Cl(A\<^sup>c))\<^sup>c.
5. Der(A) = (Cod(A\<^sup>c))\<^sup>c,
5\<^sup>*. Cod(A) = (Der(A\<^sup>c))\<^sup>c.
6. Cl(A) = A \<union> Fr(A),
6\<^sup>*. Fr(A) = Cl(A) \<inter> Cl(A\<^sup>c).
7. Der(A) := {x \<in> X | x \<in> Cl(A \ {x})},
7\<^sup>*. Cl(A) = A \<union> Der(A).
8. Cl(A) = A \<union> Pb(A).
9. Cl(A) = A \<union> Pd(A).
*)

section "6 Closure/Interior Operators from Galois Connection"

(*
In this subsection,
we make the observation that closure/interior operators may arise naturally
from Galois connection, namely a pair of monotone maps between two sets.
This construction of closure/interior operators provides a completely
dualistic view of a closure system as composition of two half-systems.
*)

(*
Let X,Y be sets,
Pow(X),Pow(Y) be their corresponding power sets,
and  s : P(X) \<rightarrow> P(Y) and t : P(Y) \<rightarrow> P(X) be a pair of functions

In addition, we recall
• s is said to be monotone if
whenever U1 \<subseteq> U2 \<subseteq> X, we have s(U1) \<subseteq> s(U2) \<subseteq> Y ;
• t is said to be monotone if
whenever V1 \<subseteq> V2 \<subseteq> Y, we have t(V1) \<subseteq> t(V2) \<subseteq> X
*)

(**Monotonicity (MONO).*)
definition MONO::"(('x \<Rightarrow> bool) \<Rightarrow> ('y \<Rightarrow> bool)) \<Rightarrow> bool" ("MONO")
  where "MONO \<phi> \<equiv> \<forall>A B. A \<^bold>\<preceq> B \<longrightarrow> \<phi> A \<^bold>\<preceq> \<phi> B"

(*
Definition 16. The pair of functions (s, t) is called
(i) an antitone Galois connection if: V \<subseteq> s(U) if and only if U \<subseteq> t(V);
(ii) a monotone Galois connection if: s(U) \<subseteq> V if and only if U \<subseteq> t(V);
(iii) a Lagois connection [20] if: s(U) \<subseteq> V if and only if t(V) \<subseteq> U.
for each U \<in> P(X) and V \<in> P(Y).
*)

type_synonym ('x,'y) op = "('x \<Rightarrow> bool) \<Rightarrow> ('y \<Rightarrow> bool)"

definition antitone_gal :: "('x,'y) op \<Rightarrow> ('y,'x) op \<Rightarrow> bool"
  where "antitone_gal s t \<equiv> \<forall> V U. V \<^bold>\<preceq> s U \<longleftrightarrow> U \<^bold>\<preceq> t V"
definition monotone_gal :: "('x,'y) op \<Rightarrow> ('y,'x) op \<Rightarrow> bool"
  where "monotone_gal s t \<equiv> \<forall> V U. s U \<^bold>\<preceq> V \<longleftrightarrow> U \<^bold>\<preceq> t V"
definition lagois_conn :: "('x,'y) op \<Rightarrow> ('y,'x) op \<Rightarrow> bool"
  where "lagois_conn s t \<equiv> \<forall> V U. s U \<^bold>\<preceq> V \<longleftrightarrow> t V \<^bold>\<preceq> U"

(*
The monotone Galois connection is
order-preserving (monotone) between P(X) and P(Y),
while the antitone Galois and the Lagois connection are
order-reversing (antimonotone) between the two powersets
*)

(*
It is well known that closure operators can be derived
from Galois connections in a natural way.
More generally, it is easy to show that

(i) In the antitone Galois connection case:
    t \<circ> s is a closure operator on P(X), and
    s \<circ> t is a closure operator on P(Y);
(ii) In the monotone Galois connection case:
     t \<circ> s is a closure operator on P(X), and
     s \<circ> t is an interior operator on P(Y);
(iii) In the anti-Galois connection case:
     t \<circ> s is an interior operator on P(X), and
     s \<circ> t is an interior operator on P(Y).
*)

lemma
  assumes "antitone_gal s t"
  shows "general_Cl (t \<circ> s)" and "general_Cl (s \<circ> t)"
  sorry

lemma
  assumes "monotone_gal s t"
  shows "general_Cl (t \<circ> s)" and "general_Int' (s \<circ> t)"
  sorry

lemma
  assumes "lagois_conn s t"
  shows "general_Int' (t \<circ> s)" and "general_Int' (s \<circ> t)"
  sorry

(*
Case (i)
is the well-known case for generating a pair of closure operators
from the (antitone) Galois connections,
used in the Formal Concept Analysis [8].

Case (ii)
generates one closure operator and one interior operator
from the (monotone) Galois connections, as used in rough set theory
and concept lattice [21–23].

Both Case (i) and (ii) are popular in theoretical computer science.

Case (iii) produces a pair of interior operators,
a variant of the other two kinds, see Ref. [20].
*)

end


(*
  File:    Data_Structures/Selection.thy
  Author:  Manuel Eberl, TU München
*)
section \<open>The Median-of-Medians Selection Algorithm\<close>
theory Selection
  imports Complex_Main Time_Funs Sorting
begin

text \<open>
  Note that there is significant overlap between this theory (which is intended mostly for the
  Functional Data Structures book) and the Median-of-Medians AFP entry.
\<close>

subsection \<open>Auxiliary material\<close>

lemma replicate_numeral: "replicate (numeral n) x = x # replicate (pred_numeral n) x"
  by (simp add: numeral_eq_Suc)

lemma insort_correct: "insort xs = sort xs"
  using sorted_insort mset_insort by (metis properties_for_sort)

lemma sum_list_replicate [simp]: "sum_list (replicate n x) = n * x"
  by (induction n) auto

lemma mset_concat: "mset (concat xss) = sum_list (map mset xss)"
  by (induction xss) simp_all

lemma set_mset_sum_list [simp]: "set_mset (sum_list xs) = (\<Union>x\<in>set xs. set_mset x)"
  by (induction xs) auto

lemma filter_mset_image_mset:
  "filter_mset P (image_mset f A) = image_mset f (filter_mset (\<lambda>x. P (f x)) A)"
  by (induction A) auto

lemma filter_mset_sum_list: "filter_mset P (sum_list xs) = sum_list (map (filter_mset P) xs)"
  by (induction xs) simp_all

lemma sum_mset_mset_mono:
  assumes "(\<And>x. x \<in># A \<Longrightarrow> f x \<subseteq># g x)"
  shows   "(\<Sum>x\<in>#A. f x) \<subseteq># (\<Sum>x\<in>#A. g x)"
  using assms by (induction A) (auto intro!: subset_mset.add_mono)

lemma mset_filter_mono:
  assumes "A \<subseteq># B" "\<And>x. x \<in># A \<Longrightarrow> P x \<Longrightarrow> Q x"
  shows   "filter_mset P A \<subseteq># filter_mset Q B"
  by (rule mset_subset_eqI) (insert assms, auto simp: mset_subset_eq_count count_eq_zero_iff)

lemma size_mset_sum_mset_distrib: "size (sum_mset A :: 'a multiset) = sum_mset (image_mset size A)"
  by (induction A) auto

lemma sum_mset_mono:
  assumes "\<And>x. x \<in># A \<Longrightarrow> f x \<le> (g x :: 'a :: {ordered_ab_semigroup_add,comm_monoid_add})"
  shows   "(\<Sum>x\<in>#A. f x) \<le> (\<Sum>x\<in>#A. g x)"
  using assms by (induction A) (auto intro!: add_mono)

lemma filter_mset_is_empty_iff: "filter_mset P A = {#} \<longleftrightarrow> (\<forall>x. x \<in># A \<longrightarrow> \<not>P x)"
  by (auto simp: multiset_eq_iff count_eq_zero_iff)

lemma sort_eq_Nil_iff [simp]: "sort xs = [] \<longleftrightarrow> xs = []"
  by (metis set_empty set_sort)

lemma sort_mset_cong: "mset xs = mset ys \<Longrightarrow> sort xs = sort ys"
  by (metis sorted_list_of_multiset_mset)

lemma Min_set_sorted: "sorted xs \<Longrightarrow> xs \<noteq> [] \<Longrightarrow> Min (set xs) = hd xs"
  by (cases xs; force intro: Min_insert2)

lemma hd_sort:
  fixes xs :: "'a :: linorder list"
  shows "xs \<noteq> [] \<Longrightarrow> hd (sort xs) = Min (set xs)"
  by (subst Min_set_sorted [symmetric]) auto

lemma length_filter_conv_size_filter_mset: "length (filter P xs) = size (filter_mset P (mset xs))"
  by (induction xs) auto

lemma sorted_filter_less_subset_take:
  assumes "sorted xs" and "i < length xs"
  shows   "{#x \<in># mset xs. x < xs ! i#} \<subseteq># mset (take i xs)"
  using assms
proof (induction xs arbitrary: i rule: list.induct)
  case (Cons x xs i)
  show ?case
  proof (cases i)
    case 0
    thus ?thesis using Cons.prems by (auto simp: filter_mset_is_empty_iff)
  next
    case (Suc i')
    have "{#y \<in># mset (x # xs). y < (x # xs) ! i#} \<subseteq># add_mset x {#y \<in># mset xs. y < xs ! i'#}"
      using Suc Cons.prems by (auto)
    also have "\<dots> \<subseteq># add_mset x (mset (take i' xs))"
      unfolding mset_subset_eq_add_mset_cancel using Cons.prems Suc
      by (intro Cons.IH) (auto)
    also have "\<dots> = mset (take i (x # xs))" by (simp add: Suc)
    finally show ?thesis .
  qed
qed auto

lemma sorted_filter_greater_subset_drop:
  assumes "sorted xs" and "i < length xs"
  shows   "{#x \<in># mset xs. x > xs ! i#} \<subseteq># mset (drop (Suc i) xs)"
  using assms
proof (induction xs arbitrary: i rule: list.induct)
  case (Cons x xs i)
  show ?case
  proof (cases i)
    case 0
    thus ?thesis by (auto simp: sorted_append filter_mset_is_empty_iff)
  next
    case (Suc i')
    have "{#y \<in># mset (x # xs). y > (x # xs) ! i#} \<subseteq># {#y \<in># mset xs. y > xs ! i'#}"
      using Suc Cons.prems by (auto simp: set_conv_nth)
    also have "\<dots> \<subseteq># mset (drop (Suc i') xs)"
      using Cons.prems Suc by (intro Cons.IH) (auto)
    also have "\<dots> = mset (drop (Suc i) (x # xs))" by (simp add: Suc)
    finally show ?thesis .
  qed
qed auto

subsection \<open>Chopping a list into equally-sized bits\<close>

fun chop :: "nat \<Rightarrow> 'a list \<Rightarrow> 'a list list" where
  "chop 0 _  = []"
| "chop _ [] = []"
| "chop n xs = take n xs # chop n (drop n xs)"

lemmas [simp del] = chop.simps

text \<open>
  This is an alternative induction rule for \<^const>\<open>chop\<close>, which is often nicer to use.
\<close>
lemma chop_induct' [case_names trivial reduce]:
  assumes "\<And>n xs. n = 0 \<or> xs = [] \<Longrightarrow> P n xs"
  assumes "\<And>n xs. n > 0 \<Longrightarrow> xs \<noteq> [] \<Longrightarrow> P n (drop n xs) \<Longrightarrow> P n xs"
  shows   "P n xs"
  using assms
proof induction_schema
  show "wf (measure (length \<circ> snd))"
    by auto
qed (blast | simp)+

lemma chop_0 [simp]: "chop 0 xs = []"
  by (simp add: chop.simps)

lemma chop_Nil [simp]: "chop n [] = []"
  by (cases n) (auto simp: chop.simps)

lemma chop_reduce: "n > 0 \<Longrightarrow> xs \<noteq> [] \<Longrightarrow> chop n xs = take n xs # chop n (drop n xs)"
  by (cases n; cases xs) (auto simp: chop.simps)

lemma concat_chop [simp]: "n > 0 \<Longrightarrow> concat (chop n xs) = xs"
  by (induction n xs rule: chop.induct; subst chop.simps) auto

lemma chop_elem_not_Nil [dest]: "ys \<in> set (chop n xs) \<Longrightarrow> ys \<noteq> []"
  by (induction n xs rule: chop.induct; subst (asm) chop.simps)
     (auto simp: eq_commute[of "[]"] split: if_splits)

lemma length_chop_part_le: "ys \<in> set (chop n xs) \<Longrightarrow> length ys \<le> n"
  by (induction n xs rule: chop.induct; subst (asm) chop.simps) (auto split: if_splits)

lemma length_chop:
  assumes "n > 0"
  shows   "length (chop n xs) = nat \<lceil>length xs / n\<rceil>"
proof -
  from \<open>n > 0\<close> have "real n * length (chop n xs) \<ge> length xs"
    by (induction n xs rule: chop.induct; subst chop.simps) (auto simp: field_simps)
  moreover from \<open>n > 0\<close> have "real n * length (chop n xs) < length xs + n"
    by (induction n xs rule: chop.induct; subst chop.simps)
       (auto simp: field_simps split: nat_diff_split_asm)+
  ultimately have "length (chop n xs) \<ge> length xs / n" and "length (chop n xs) < length xs / n + 1"
    using assms by (auto simp: field_simps)
  thus ?thesis by linarith
qed

lemma sum_msets_chop: "n > 0 \<Longrightarrow> (\<Sum>ys\<leftarrow>chop n xs. mset ys) = mset xs"
  by (subst mset_concat [symmetric]) simp_all

lemma UN_sets_chop: "n > 0 \<Longrightarrow> (\<Union>ys\<in>set (chop n xs). set ys) = set xs"
  by (simp only: set_concat [symmetric] concat_chop)

lemma chop_append: "d dvd length xs \<Longrightarrow> chop d (xs @ ys) = chop d xs @ chop d ys"
  by (induction d xs rule: chop_induct') (auto simp: chop_reduce dvd_imp_le)

lemma chop_replicate [simp]: "d > 0 \<Longrightarrow> chop d (replicate d xs) = [replicate d xs]"
  by (subst chop_reduce) auto

lemma chop_replicate_dvd [simp]:
  assumes "d dvd n"
  shows   "chop d (replicate n x) = replicate (n div d) (replicate d x)"
proof (cases "d = 0")
  case False
  from assms obtain k where k: "n = d * k"
    by blast
  have "chop d (replicate (d * k) x) = replicate k (replicate d x)"
    using False by (induction k) (auto simp: replicate_add chop_append)
  thus ?thesis using False by (simp add: k)
qed auto

lemma chop_concat:
  assumes "\<forall>xs\<in>set xss. length xs = d" and "d > 0"
  shows   "chop d (concat xss) = xss"
  using assms
proof (induction xss)
  case (Cons xs xss)
  have "chop d (concat (xs # xss)) = chop d (xs @ concat xss)"
    by simp
  also have "\<dots> = chop d xs @ chop d (concat xss)"
    using Cons.prems by (intro chop_append) auto
  also have "chop d xs = [xs]"
    using Cons.prems by (subst chop_reduce) auto
  also have "chop d (concat xss) = xss"
    using Cons.prems by (intro Cons.IH) auto
  finally show ?case by simp
qed auto

subsection \<open>Selection\<close>

definition select :: "nat \<Rightarrow> ('a :: linorder) list \<Rightarrow> 'a" where
  "select k xs = sort xs ! k"

lemma select_0: "xs \<noteq> [] \<Longrightarrow> select 0 xs = Min (set xs)"
  by (simp add: hd_sort select_def flip: hd_conv_nth)

lemma select_mset_cong: "mset xs = mset ys \<Longrightarrow> select k xs = select k ys"
  using sort_mset_cong[of xs ys] unfolding select_def by auto

lemma
  assumes "n < length xs"
  shows   size_less_than_select: "size {#y \<in># mset xs. y < select n xs#} \<le> n"
    and   size_greater_than_select: "size {#y \<in># mset xs. y > select n xs#} < length xs - n"
proof -
  have "size {#y \<in># mset (sort xs). y < select n xs#} \<le> size (mset (take n (sort xs)))"
    unfolding select_def using assms
    by (intro size_mset_mono sorted_filter_less_subset_take) auto
  thus "size {#y \<in># mset xs. y < select n xs#} \<le> n"
    by simp
  have "size {#y \<in># mset (sort xs). y > select n xs#} \<le> size (mset (drop (Suc n) (sort xs)))"
    unfolding select_def using assms
    by (intro size_mset_mono sorted_filter_greater_subset_drop) auto
  thus "size {#y \<in># mset xs. y > select n xs#} < length xs - n"
    using assms by simp
qed

subsection \<open>The designated median of a list\<close>

definition median where "median xs = select ((length xs - 1) div 2) xs"

lemma median_in_set [intro, simp]:
  assumes "xs \<noteq> []"
  shows   "median xs \<in> set xs"
proof -
  from assms have "length xs > 0" by auto
  hence "(length xs - 1) div 2 < length xs" by linarith
  thus ?thesis by (simp add: median_def)
qed

lemma size_less_than_median: "size {#y \<in># mset xs. y < median xs#} \<le> (length xs - 1) div 2"
proof (cases "xs = []")
  case False
  hence "length xs > 0"
    by auto
  hence less: "(length xs - 1) div 2 < length xs"
    by linarith
  show "size {#y \<in># mset xs. y < median xs#} \<le> (length xs - 1) div 2"
    using size_less_than_select[OF less] by (simp add: median_def)
qed auto

lemma size_greater_than_median: "size {#y \<in># mset xs. y > median xs#} \<le> length xs div 2"
proof (cases "xs = []")
  case False
  hence "length xs > 0"
    by auto
  hence less: "(length xs - 1) div 2 < length xs"
    by linarith
  have "size {#y \<in># mset xs. y > median xs#} < length xs - (length xs - 1) div 2"
    using size_greater_than_select[OF less] by (simp add: median_def)
  also have "\<dots> = length xs div 2 + 1"
    using \<open>length xs > 0\<close> by linarith
  finally show "size {#y \<in># mset xs. y > median xs#} \<le> length xs div 2"
    by simp
qed auto

lemmas median_props = size_less_than_median size_greater_than_median

subsection \<open>A recurrence for selection\<close>

definition partition3 :: "'a \<Rightarrow> 'a :: linorder list \<Rightarrow> 'a list \<times> 'a list \<times> 'a list" where
  "partition3 x xs = (filter (\<lambda>y. y < x) xs, filter (\<lambda>y. y = x) xs, filter (\<lambda>y. y > x) xs)"

lemma partition3_code [code]:
  "partition3 x [] = ([], [], [])"
  "partition3 x (y # ys) =
     (case partition3 x ys of (ls, es, gs) \<Rightarrow>
        if y < x then (y # ls, es, gs) else if x = y then (ls, y # es, gs) else (ls, es, y # gs))"
  by (auto simp: partition3_def)

lemma sort_append:
  assumes "\<forall>x\<in>set xs. \<forall>y\<in>set ys. x \<le> y"
  shows   "sort (xs @ ys) = sort xs @ sort ys"
  using assms by (intro properties_for_sort) (auto simp: sorted_append)

lemma select_append:
  assumes "\<forall>y\<in>set ys. \<forall>z\<in>set zs. y \<le> z"
  shows   "k < length ys \<Longrightarrow> select k (ys @ zs) = select k ys"
    and   "k \<in> {length ys..<length ys + length zs} \<Longrightarrow>
             select k (ys @ zs) = select (k - length ys) zs"
  using assms by (simp_all add: select_def sort_append nth_append)

lemma select_append':
  assumes "\<forall>y\<in>set ys. \<forall>z\<in>set zs. y \<le> z" and "k < length ys + length zs"
  shows   "select k (ys @ zs) = (if k < length ys then select k ys else select (k - length ys) zs)"
  using assms by (auto intro!: select_append)

theorem select_rec_partition:
  assumes "k < length xs"
  shows "select k xs = (
           let (ls, es, gs) = partition3 x xs
           in
             if k < length ls then select k ls
             else if k < length ls + length es then x
             else select (k - length ls - length es) gs
          )" (is "_ = ?rhs")
proof -
  define ls es gs where "ls = filter (\<lambda>y. y < x) xs" and "es = filter (\<lambda>y. y = x) xs"
                    and "gs = filter (\<lambda>y. y > x) xs"
  define nl ne where [simp]: "nl = length ls" "ne = length es"
  have mset_eq: "mset xs = mset ls + mset es + mset gs"
    unfolding ls_def es_def gs_def by (induction xs) auto
  have length_eq: "length xs = length ls + length es + length gs"
    unfolding ls_def es_def gs_def
    using [[simp_depth_limit = 1]] by (induction xs) auto
  have [simp]: "select i es = x" if "i < length es" for i
  proof -
    have "select i es \<in> set (sort es)" unfolding select_def
      using that by (intro nth_mem) auto
    thus ?thesis
      by (auto simp: es_def)
  qed

  have "select k xs = select k (ls @ (es @ gs))"
    by (intro select_mset_cong) (simp_all add: mset_eq)
  also have "\<dots> = (if k < nl then select k ls else select (k - nl) (es @ gs))"
    unfolding nl_ne_def using assms
    by (intro select_append') (auto simp: ls_def es_def gs_def length_eq)
  also have "\<dots> = (if k < nl then select k ls else if k < nl + ne then x
                    else select (k - nl - ne) gs)"
  proof (rule if_cong)
    assume "\<not>k < nl"
    have "select (k - nl) (es @ gs) =
                 (if k - nl < ne then select (k - nl) es else select (k - nl - ne) gs)"
      unfolding nl_ne_def using assms \<open>\<not>k < nl\<close>
      by (intro select_append') (auto simp: ls_def es_def gs_def length_eq)
    also have "\<dots> = (if k < nl + ne then x else select (k - nl - ne) gs)"
      using \<open>\<not>k < nl\<close> by auto
    finally show "select (k - nl) (es @ gs) = \<dots>" .
  qed simp_all
  also have "\<dots> = ?rhs"
    by (simp add: partition3_def ls_def es_def gs_def)
  finally show ?thesis .
qed

subsection \<open>The size of the lists in the recursive calls\<close>

text \<open>
  We now derive an upper bound for the number of elements of a list that are smaller
  (resp. bigger) than the median of medians with chopping size 5. To avoid having to do the
  same proof twice, we do it generically for an operation \<open>\<prec>\<close> that we will later instantiate
  with either \<open><\<close> or \<open>>\<close>.
\<close>

context
  fixes xs :: "'a :: linorder list"
  fixes M defines "M \<equiv> median (map median (chop 5 xs))"
begin

lemma size_median_of_medians_aux:
  fixes R :: "'a :: linorder \<Rightarrow> 'a \<Rightarrow> bool" (infix "\<prec>" 50)
  assumes R: "R \<in> {(<), (>)}"
  shows "size {#y \<in># mset xs. y \<prec> M#} \<le> nat \<lceil>0.7 * length xs + 3\<rceil>"
proof -
  define n and m where [simp]: "n = length xs" and "m = length (chop 5 xs)"
  text \<open>We define an abbreviation for the multiset of all the chopped-up groups:\<close>

  text \<open>We then split that multiset into those groups whose medians is less than @{term M}
        and the rest.\<close>
  define Y_small ("Y\<^sub>\<prec>") where "Y\<^sub>\<prec> = filter_mset (\<lambda>ys. median ys \<prec> M) (mset (chop 5 xs))"
  define Y_big ("Y\<^sub>\<succeq>") where "Y\<^sub>\<succeq> = filter_mset (\<lambda>ys. \<not>(median ys \<prec> M)) (mset (chop 5 xs))"
  have "m = size (mset (chop 5 xs))" by (simp add: m_def)
  also have "mset (chop 5 xs) = Y\<^sub>\<prec> + Y\<^sub>\<succeq>" unfolding Y_small_def Y_big_def
    by (rule multiset_partition)
  finally have m_eq: "m = size Y\<^sub>\<prec> + size Y\<^sub>\<succeq>" by simp

  text \<open>At most half of the lists have a median that is smaller than the median of medians:\<close>
  have "size Y\<^sub>\<prec> = size (image_mset median Y\<^sub>\<prec>)" by simp
  also have "image_mset median Y\<^sub>\<prec> = {#y \<in># mset (map median (chop 5 xs)). y \<prec> M#}"
    unfolding Y_small_def by (subst filter_mset_image_mset [symmetric]) simp_all
  also have "size \<dots> \<le> (length (map median (chop 5 xs))) div 2"
    unfolding M_def using median_props[of "map median (chop 5 xs)"] R by auto
  also have "\<dots> = m div 2" by (simp add: m_def)
  finally have size_Y\<^sub>_small: "size Y\<^sub>\<prec> \<le> m div 2" .

  text \<open>We estimate the number of elements less than @{term M} by grouping them into elements
      coming from @{term "Y\<^sub>\<prec>"} and elements coming from @{term "Y\<^sub>\<succeq>"}:\<close>
  have "{#y \<in># mset xs. y \<prec> M#} = {#y \<in># (\<Sum>ys\<leftarrow>chop 5 xs. mset ys). y \<prec> M#}"
    by (subst sum_msets_chop) simp_all
  also have "\<dots> = (\<Sum>ys\<leftarrow>chop 5 xs. {#y \<in># mset ys. y \<prec> M#})"
    by (subst filter_mset_sum_list) (simp add: o_def)
  also have "\<dots> = (\<Sum>ys\<in>#mset (chop 5 xs). {#y \<in># mset ys. y \<prec> M#})"
    by (subst sum_mset_sum_list [symmetric]) simp_all
  also have "mset (chop 5 xs) = Y\<^sub>\<prec> + Y\<^sub>\<succeq>"
    by (simp add: Y_small_def Y_big_def not_le)
  also have "(\<Sum>ys\<in>#\<dots>. {#y \<in># mset ys. y \<prec> M#}) =
               (\<Sum>ys\<in>#Y\<^sub>\<prec>. {#y \<in># mset ys. y \<prec> M#}) + (\<Sum>ys\<in>#Y\<^sub>\<succeq>. {#y \<in># mset ys. y \<prec> M#})"
    by simp

  text \<open>Next, we overapproximate the elements contributed by @{term "Y\<^sub>\<prec>"}: instead of those elements
        that are smaller than the median, we take \<^emph>\<open>all\<close> the elements of each group.
        For the elements contributed by @{term "Y\<^sub>\<succeq>"}, we overapproximate by taking all those that
        are less than their median instead of only those that are less than @{term M}.\<close>
  also have "\<dots> \<subseteq># (\<Sum>ys\<in>#Y\<^sub>\<prec>. mset ys) + (\<Sum>ys\<in>#Y\<^sub>\<succeq>. {#y \<in># mset ys. y \<prec> median ys#})"
    using R
    by (intro subset_mset.add_mono sum_mset_mset_mono mset_filter_mono) (auto simp: Y_big_def)
  finally have "size {# y \<in># mset xs. y \<prec> M#} \<le> size \<dots>"
    by (rule size_mset_mono)
  hence "size {# y \<in># mset xs. y \<prec> M#} \<le>
           (\<Sum>ys\<in>#Y\<^sub>\<prec>. length ys) + (\<Sum>ys\<in>#Y\<^sub>\<succeq>. size {#y \<in># mset ys. y \<prec> median ys#})"
    by (simp add: size_mset_sum_mset_distrib multiset.map_comp o_def)

  text \<open>Next, we further overapproximate the first sum by noting that each group has
        at most size 5.\<close>
  also have "(\<Sum>ys\<in>#Y\<^sub>\<prec>. length ys) \<le> (\<Sum>ys\<in>#Y\<^sub>\<prec>. 5)"
    by (intro sum_mset_mono) (auto simp: Y_small_def length_chop_part_le)
  also have "\<dots> = 5 * size Y\<^sub>\<prec>" by simp

  text \<open>Next, we note that each group in @{term "Y\<^sub>\<succeq>"} can have at most 2 elements that are
        smaller than its median.\<close>
  also have "(\<Sum>ys\<in>#Y\<^sub>\<succeq>. size {#y \<in># mset ys. y \<prec> median ys#}) \<le>
               (\<Sum>ys\<in>#Y\<^sub>\<succeq>. length ys div 2)"
  proof (intro sum_mset_mono, goal_cases)
    fix ys assume "ys \<in># Y\<^sub>\<succeq>"
    hence "ys \<noteq> []"
      by (auto simp: Y_big_def)
    thus "size {#y \<in># mset ys. y \<prec> median ys#} \<le> length ys div 2"
      using R median_props[of ys] by auto
  qed
  also have "\<dots> \<le> (\<Sum>ys\<in>#Y\<^sub>\<succeq>. 2)"
    by (intro sum_mset_mono div_le_mono diff_le_mono)
       (auto simp: Y_big_def dest: length_chop_part_le)
  also have "\<dots> = 2 * size Y\<^sub>\<succeq>" by simp

  text \<open>Simplifying gives us the main result.\<close>
  also have "5 * size Y\<^sub>\<prec> + 2 * size Y\<^sub>\<succeq> = 2 * m + 3 * size Y\<^sub>\<prec>"
    by (simp add: m_eq)
  also have "\<dots> \<le> 3.5 * m"
    using \<open>size Y\<^sub>\<prec> \<le> m div 2\<close> by linarith
  also have "\<dots> = 3.5 * \<lceil>n / 5\<rceil>"
    by (simp add: m_def length_chop)
  also have "\<dots> \<le> 0.7 * n + 3.5"
    by linarith
  finally have "size {#y \<in># mset xs. y \<prec> M#} \<le> 0.7 * n + 3.5"
    by simp
  thus "size {#y \<in># mset xs. y \<prec> M#} \<le> nat \<lceil>0.7 * n + 3\<rceil>"
    by linarith
qed

lemma size_less_than_median_of_medians:
  "size {#y \<in># mset xs. y < M#} \<le> nat \<lceil>0.7 * length xs + 3\<rceil>"
  using size_median_of_medians_aux[of "(<)"] by simp

lemma size_greater_than_median_of_medians:
  "size {#y \<in># mset xs. y > M#} \<le> nat \<lceil>0.7 * length xs + 3\<rceil>"
  using size_median_of_medians_aux[of "(>)"] by simp

end

subsection \<open>Efficient algorithm\<close>

text \<open>
  We handle the base cases and computing the median for the chopped-up sublists of size 5
  using the naive selection algorithm where we sort the list using insertion sort.
\<close>
definition slow_select where
  "slow_select k xs = insort xs ! k"

definition slow_median where
  "slow_median xs = slow_select ((length xs - 1) div 2) xs"

lemma slow_select_correct: "slow_select k xs = select k xs"
  by (simp add: slow_select_def select_def insort_correct)

lemma slow_median_correct: "slow_median xs = median xs"
  by (simp add: median_def slow_median_def slow_select_correct)

text \<open>
  The definition of the selection algorithm is complicated somewhat by the fact that its
  termination is contingent on its correctness: if the first recursive call were to return an
  element for \<open>x\<close> that is e.g. smaller than all list elements, the algorithm would not terminate.

  Therefore, we first prove partial correctness, then termination, and then combine the two
  to obtain total correctness.
\<close>
function mom_select where
  "mom_select k xs = (
     if length xs \<le> 20 then
       slow_select k xs
     else
       let M = mom_select (((length xs + 4) div 5 - 1) div 2) (map slow_median (chop 5 xs));
           (ls, es, gs) = partition3 M xs
       in
         if k < length ls then mom_select k ls
         else if k < length ls + length es then M
         else mom_select (k - length ls - length es) gs
      )"
  by auto

text \<open>
  If @{const "mom_select"} terminates, it agrees with @{const select}:
\<close>
lemma mom_select_correct_aux:
  assumes "mom_select_dom (k, xs)" and "k < length xs"
  shows   "mom_select k xs = select k xs"
  using assms
proof (induction rule: mom_select.pinduct)
  case (1 k xs)
  show "mom_select k xs = select k xs"
  proof (cases "length xs \<le> 20")
    case True
    thus "mom_select k xs = select k xs" using "1.prems" "1.hyps"
      by (subst mom_select.psimps) (auto simp: select_def slow_select_correct)
  next
    case False
    define x where
      "x = mom_select (((length xs + 4) div 5 - 1) div 2) (map slow_median (chop 5 xs))"
    define ls es gs where "ls = filter (\<lambda>y. y < x) xs" and "es = filter (\<lambda>y. y = x) xs"
                      and "gs = filter (\<lambda>y. y > x) xs"
    define nl ne where "nl = length ls" and "ne = length es"
    note defs = nl_def ne_def x_def ls_def es_def gs_def
    have tw: "(ls, es, gs) = partition3 x xs"
      unfolding partition3_def defs One_nat_def ..
    have length_eq: "length xs = nl + ne + length gs"
      unfolding nl_def ne_def ls_def es_def gs_def
      using [[simp_depth_limit = 1]] by (induction xs) auto
    note IH = "1.IH"(2,3)[OF False x_def tw refl refl]

    have "mom_select k xs = (if k < nl then mom_select k ls else if k < nl + ne then x
                                else mom_select (k - nl - ne) gs)" using "1.hyps" False
      by (subst mom_select.psimps) (simp_all add: partition3_def flip: defs One_nat_def)
    also have "\<dots> = (if k < nl then select k ls else if k < nl + ne then x
                       else select (k - nl - ne) gs)"
      using IH length_eq "1.prems" by (simp add: ls_def es_def gs_def nl_def ne_def)
    also have "\<dots> = select k xs" using \<open>k < length xs\<close>
      by (subst (3) select_rec_partition[of _ _ x]) (simp_all add: nl_def ne_def flip: tw)
    finally show "mom_select k xs = select k xs" .
  qed
qed

text \<open>
  @{const mom_select} indeed terminates for all inputs:
\<close>
lemma mom_select_termination: "All mom_select_dom"
proof (relation "measure (length \<circ> snd)"; (safe)?)
  fix k :: nat and xs :: "'a list"
  assume "\<not> length xs \<le> 20"
  thus "((((length xs + 4) div 5 - 1) div 2, map slow_median (chop 5 xs)), k, xs)
           \<in> measure (length \<circ> snd)"
    by (auto simp: length_chop nat_less_iff ceiling_less_iff)
next
  fix k :: nat and xs ls es gs :: "'a list"
  define x where "x = mom_select (((length xs + 4) div 5 - 1) div 2) (map slow_median (chop 5 xs))"
  assume A: "\<not> length xs \<le> 20"
            "(ls, es, gs) = partition3 x xs"
            "mom_select_dom (((length xs + 4) div 5 - 1) div 2,
                             map slow_median (chop 5 xs))"
  have less: "((length xs + 4) div 5 - 1) div 2 < nat \<lceil>length xs / 5\<rceil>"
    using A(1) by linarith

  text \<open>For termination, it suffices to prove that @{term x} is in the list.\<close>
  have "x = select (((length xs + 4) div 5 - 1) div 2) (map slow_median (chop 5 xs))"
    using less unfolding x_def by (intro mom_select_correct_aux A) (auto simp: length_chop)
  also have "\<dots> \<in> set (map slow_median (chop 5 xs))"
    using less by (intro select_in_set) (simp_all add: length_chop)
  also have "\<dots> \<subseteq> set xs"
    unfolding set_map
  proof safe
    fix ys assume ys: "ys \<in> set (chop 5 xs)"
    hence "median ys \<in> set ys"
      by auto
    also have "set ys \<subseteq> \<Union>(set ` set (chop 5 xs))"
      using ys by blast
    also have "\<dots> = set xs"
      by (rule UN_sets_chop) simp_all
    finally show "slow_median ys \<in> set xs"
      by (simp add: slow_median_correct)
  qed
  finally have "x \<in> set xs" .
  thus "((k, ls), k, xs) \<in> measure (length \<circ> snd)"
   and "((k - length ls - length es, gs), k, xs) \<in> measure (length \<circ> snd)"
    using A(1,2) by (auto simp: partition3_def intro!: length_filter_less[of x])
qed

termination mom_select by (rule mom_select_termination)

lemmas [simp del] = mom_select.simps

lemma mom_select_correct: "k < length xs \<Longrightarrow> mom_select k xs = select k xs"
  using mom_select_correct_aux and mom_select_termination by blast

subsection \<open>Running time analysis\<close>

fun T_partition3 :: "'a \<Rightarrow> 'a list \<Rightarrow> nat" where
  "T_partition3 x [] = 1"
| "T_partition3 x (y # ys) = T_partition3 x ys + 1"

lemma T_partition3_eq: "T_partition3 x xs = length xs + 1"
  by (induction x xs rule: T_partition3.induct) auto

definition T_slow_select :: "nat \<Rightarrow> 'a :: linorder list \<Rightarrow> nat" where
  "T_slow_select k xs = T_insort xs + T_nth (insort xs) k + 1"

definition T_slow_median :: "'a :: linorder list \<Rightarrow> nat" where
  "T_slow_median xs = T_slow_select ((length xs - 1) div 2) xs + 1"

lemma T_slow_select_le: "T_slow_select k xs \<le> length xs ^ 2 + 3 * length xs + 3"
proof -
  have "T_slow_select k xs \<le> (length xs + 1)\<^sup>2 + (length (insort xs) + 1) + 1"
    unfolding T_slow_select_def
    by (intro add_mono T_insort_length) (auto simp: T_nth_eq)
  also have "\<dots> = length xs ^ 2 + 3 * length xs + 3"
    by (simp add: insort_correct algebra_simps power2_eq_square)
  finally show ?thesis .
qed

lemma T_slow_median_le: "T_slow_median xs \<le> length xs ^ 2 + 3 * length xs + 4"
  unfolding T_slow_median_def using T_slow_select_le[of "(length xs - 1) div 2" xs] by simp

fun T_chop :: "nat \<Rightarrow> 'a list \<Rightarrow> nat" where
  "T_chop 0 _  = 1"
| "T_chop _ [] = 1"
| "T_chop n xs = T_take n xs + T_drop n xs + T_chop n (drop n xs)"

lemmas [simp del] = T_chop.simps

lemma T_chop_Nil [simp]: "T_chop d [] = 1"
  by (cases d) (auto simp: T_chop.simps)

lemma T_chop_0 [simp]: "T_chop 0 xs = 1"
  by (auto simp: T_chop.simps)

lemma T_chop_reduce:
  "n > 0 \<Longrightarrow> xs \<noteq> [] \<Longrightarrow> T_chop n xs = T_take n xs + T_drop n xs + T_chop n (drop n xs)"
  by (cases n; cases xs) (auto simp: T_chop.simps)

lemma T_chop_le: "T_chop d xs \<le> 5 * length xs + 1"
  by (induction d xs rule: T_chop.induct) (auto simp: T_chop_reduce T_take_eq T_drop_eq)

text \<open>
  The option \<open>domintros\<close> here allows us to explicitly reason about where the function does and
  does not terminate. With this, we can skip the termination proof this time because we can
  reuse the one for \<^const>\<open>mom_select\<close>.
\<close>
function (domintros) T_mom_select :: "nat \<Rightarrow> 'a :: linorder list \<Rightarrow> nat" where
  "T_mom_select k xs = (
     if length xs \<le> 20 then
       T_slow_select k xs
     else
       let xss = chop 5 xs;
           ms = map slow_median xss;
           idx = (((length xs + 4) div 5 - 1) div 2);
           x = mom_select idx ms;
           (ls, es, gs) = partition3 x xs;
           nl = length ls;
           ne = length es
       in
         (if k < nl then T_mom_select k ls
          else if k < nl + ne then 0
          else T_mom_select (k - nl - ne) gs) +
         T_mom_select idx ms + T_chop 5 xs + T_map T_slow_median xss +
         T_partition3 x xs + T_length ls + T_length es + 1
      )"
  by auto

termination T_mom_select
proof (rule allI, safe)
  fix k :: nat and xs :: "'a :: linorder list"
  have "mom_select_dom (k, xs)"
    using mom_select_termination by blast
  thus "T_mom_select_dom (k, xs)"
    by (induction k xs rule: mom_select.pinduct)
       (rule T_mom_select.domintros, simp_all)
qed

lemmas [simp del] = T_mom_select.simps

function T'_mom_select :: "nat \<Rightarrow> nat" where
  "T'_mom_select n =
     (if n \<le> 20 then
        463
      else
        T'_mom_select (nat \<lceil>0.2*n\<rceil>) + T'_mom_select (nat \<lceil>0.7*n+3\<rceil>) + 17 * n + 50)"
  by force+
termination by (relation "measure id"; simp; linarith)

lemmas [simp del] = T'_mom_select.simps

lemma T'_mom_select_ge: "T'_mom_select n \<ge> 463"
  by (induction n rule: T'_mom_select.induct; subst T'_mom_select.simps) auto

lemma T'_mom_select_mono:
  "m \<le> n \<Longrightarrow> T'_mom_select m \<le> T'_mom_select n"
proof (induction n arbitrary: m rule: less_induct)
  case (less n m)
  show ?case
  proof (cases "m \<le> 20")
    case True
    hence "T'_mom_select m = 463"
      by (subst T'_mom_select.simps) auto
    also have "\<dots> \<le> T'_mom_select n"
      by (rule T'_mom_select_ge)
    finally show ?thesis .
  next
    case False
    hence "T'_mom_select m =
             T'_mom_select (nat \<lceil>0.2*m\<rceil>) + T'_mom_select (nat \<lceil>0.7*m + 3\<rceil>) + 17 * m + 50"
      by (subst T'_mom_select.simps) auto
    also have "\<dots> \<le> T'_mom_select (nat \<lceil>0.2*n\<rceil>) + T'_mom_select (nat \<lceil>0.7*n + 3\<rceil>) + 17 * n + 50"
      using \<open>m \<le> n\<close> and False by (intro add_mono less.IH; linarith)
    also have "\<dots> = T'_mom_select n"
      using \<open>m \<le> n\<close> and False by (subst T'_mom_select.simps) auto
    finally show ?thesis .
  qed
qed

lemma T_mom_select_le_aux: "T_mom_select k xs \<le> T'_mom_select (length xs)"
proof (induction k xs rule: T_mom_select.induct)
  case (1 k xs)
  define n where [simp]: "n = length xs"
  define x where
    "x = mom_select (((length xs + 4) div 5 - 1) div 2) (map slow_median (chop 5 xs))"
  define ls es gs where "ls = filter (\<lambda>y. y < x) xs" and "es = filter (\<lambda>y. y = x) xs"
                    and "gs = filter (\<lambda>y. y > x) xs"
  define nl ne where "nl = length ls" and "ne = length es"
  note defs = nl_def ne_def x_def ls_def es_def gs_def
  have tw: "(ls, es, gs) = partition3 x xs"
    unfolding partition3_def defs One_nat_def ..
  note IH = "1.IH"(1,2,3)[OF _ refl refl refl x_def tw refl refl refl refl]

  show ?case
  proof (cases "length xs \<le> 20")
    case True \<comment> \<open>base case\<close>
    hence "T_mom_select k xs \<le> (length xs)\<^sup>2 + 3 * length xs + 3"
      using T_slow_select_le[of k xs] by (subst T_mom_select.simps) auto
    also have "\<dots> \<le> 20\<^sup>2 + 3 * 20 + 3"
      using True by (intro add_mono power_mono) auto
    also have "\<dots> \<le> 463"
      by simp
    also have "\<dots> = T'_mom_select (length xs)"
      using True by (simp add: T'_mom_select.simps)
    finally show ?thesis by simp
  next
    case False \<comment> \<open>recursive case\<close>
    have "((n + 4) div 5 - 1) div 2 < nat \<lceil>n / 5\<rceil>"
      using False unfolding n_def by linarith
    hence "x = select (((n + 4) div 5 - 1) div 2) (map slow_median (chop 5 xs))"
      unfolding x_def n_def by (intro mom_select_correct) (auto simp: length_chop)
    also have "((n + 4) div 5 - 1) div 2 = (nat \<lceil>n / 5\<rceil> - 1) div 2"
      by linarith
    also have "select \<dots> (map slow_median (chop 5 xs)) = median (map slow_median (chop 5 xs))"
      by (auto simp: median_def length_chop)
    finally have x_eq: "x = median (map slow_median (chop 5 xs))" .

    text \<open>The cost of computing the medians of all the subgroups:\<close>
    define T_ms where "T_ms = T_map T_slow_median (chop 5 xs)"
    have "T_ms \<le> 9 * n + 45"
    proof -
      have "T_ms = (\<Sum>ys\<leftarrow>chop 5 xs. T_slow_median ys) + length (chop 5 xs) + 1"
        by (simp add: T_ms_def T_map_eq)
      also have "(\<Sum>ys\<leftarrow>chop 5 xs. T_slow_median ys) \<le> (\<Sum>ys\<leftarrow>chop 5 xs. 44)"
      proof (intro sum_list_mono)
        fix ys assume "ys \<in> set (chop 5 xs)"
        hence "length ys \<le> 5"
          using length_chop_part_le by blast
        have "T_slow_median ys \<le> (length ys) ^ 2 + 3 * length ys + 4"
          by (rule T_slow_median_le)
        also have "\<dots> \<le> 5 ^ 2 + 3 * 5 + 4"
          using \<open>length ys \<le> 5\<close> by (intro add_mono power_mono) auto
        finally show "T_slow_median ys \<le> 44" by simp
      qed
      also have "(\<Sum>ys\<leftarrow>chop 5 xs. 44) + length (chop 5 xs) + 1 =
                   45 * nat \<lceil>real n / 5\<rceil> + 1"
        by (simp add: map_replicate_const length_chop)
      also have "\<dots> \<le> 9 * n + 45"
        by linarith
      finally show "T_ms \<le> 9 * n + 45" by simp
    qed

    text \<open>The cost of the first recursive call (to compute the median of medians):\<close>
    define T_rec1 where
      "T_rec1 = T_mom_select (((length xs + 4) div 5 - 1) div 2) (map slow_median (chop 5 xs))"
    have "T_rec1 \<le> T'_mom_select (length (map slow_median (chop 5 xs)))"
      using False unfolding T_rec1_def by (intro IH(3)) auto
    hence "T_rec1 \<le> T'_mom_select (nat \<lceil>0.2 * n\<rceil>)"
      by (simp add: length_chop)

    text \<open>The cost of the second recursive call (to compute the final result):\<close>
    define T_rec2 where "T_rec2 = (if k < nl then T_mom_select k ls
                                 else if k < nl + ne then 0
                                 else T_mom_select (k - nl - ne) gs)"
    consider "k < nl" | "k \<in> {nl..<nl+ne}" | "k \<ge> nl+ne"
      by force
    hence "T_rec2 \<le> T'_mom_select (nat \<lceil>0.7 * n + 3\<rceil>)"
    proof cases
      assume "k < nl"
      hence "T_rec2 = T_mom_select k ls"
        by (simp add: T_rec2_def)
      also have "\<dots> \<le> T'_mom_select (length ls)"
        by (rule IH(1)) (use \<open>k < nl\<close> False in \<open>auto simp: defs\<close>)
      also have "length ls \<le> nat \<lceil>0.7 * n + 3\<rceil>"
        unfolding ls_def using size_less_than_median_of_medians[of xs]
        by (auto simp: length_filter_conv_size_filter_mset slow_median_correct[abs_def] x_eq)
      hence "T'_mom_select (length ls) \<le> T'_mom_select (nat \<lceil>0.7 * n + 3\<rceil>)"
        by (rule T'_mom_select_mono)
      finally show ?thesis .
    next
      assume "k \<in> {nl..<nl + ne}"
      hence "T_rec2 = 0"
        by (simp add: T_rec2_def)
      thus ?thesis
        using T'_mom_select_ge[of "nat \<lceil>0.7 * n + 3\<rceil>"] by simp
    next
      assume "k \<ge> nl + ne"
      hence "T_rec2 = T_mom_select (k - nl - ne) gs"
        by (simp add: T_rec2_def)
      also have "\<dots> \<le> T'_mom_select (length gs)"
        unfolding nl_def ne_def by (rule IH(2)) (use \<open>k \<ge> nl + ne\<close> False in \<open>auto simp: defs\<close>)
      also have "length gs \<le> nat \<lceil>0.7 * n + 3\<rceil>"
        unfolding gs_def using size_greater_than_median_of_medians[of xs]
        by (auto simp: length_filter_conv_size_filter_mset slow_median_correct[abs_def] x_eq)
      hence "T'_mom_select (length gs) \<le> T'_mom_select (nat \<lceil>0.7 * n + 3\<rceil>)"
        by (rule T'_mom_select_mono)
      finally show ?thesis .
    qed

    text \<open>Now for the final inequality chain:\<close>
    have "T_mom_select k xs = T_rec2 + T_rec1 + T_ms + n + nl + ne + T_chop 5 xs + 4" using False
      by (subst T_mom_select.simps, unfold Let_def tw [symmetric] defs [symmetric])
         (simp_all add: nl_def ne_def T_rec1_def T_rec2_def T_partition3_eq
                        T_length_eq T_ms_def)
    also have "nl \<le> n" by (simp add: nl_def ls_def)
    also have "ne \<le> n" by (simp add: ne_def es_def)
    also note \<open>T_ms \<le> 9 * n + 45\<close>
    also have "T_chop 5 xs \<le> 5 * n + 1"
      using T_chop_le[of 5 xs] by simp
    also note \<open>T_rec1 \<le> T'_mom_select (nat \<lceil>0.2*n\<rceil>)\<close>
    also note \<open>T_rec2 \<le> T'_mom_select (nat \<lceil>0.7*n + 3\<rceil>)\<close>
    finally have "T_mom_select k xs \<le>
                    T'_mom_select (nat \<lceil>0.7*n + 3\<rceil>) + T'_mom_select (nat \<lceil>0.2*n\<rceil>) + 17 * n + 50"
      by simp
    also have "\<dots> = T'_mom_select n"
      using False by (subst T'_mom_select.simps) auto
    finally show ?thesis by simp
  qed
qed

subsection \<open>Akra--Bazzi Light\<close>

lemma akra_bazzi_light_aux1:
  fixes a b :: real and n n0 :: nat
  assumes ab: "a > 0" "a < 1" "n > n0"
  assumes "n0 \<ge> (max 0 b + 1) / (1 - a)"
  shows "nat \<lceil>a*n+b\<rceil> < n"
proof -
  have "a * real n + max 0 b \<ge> 0"
    using ab by simp
  hence "real (nat \<lceil>a*n+b\<rceil>) \<le> a * n + max 0 b + 1"
    by linarith
  also {
    have "n0 \<ge> (max 0 b + 1) / (1 - a)"
      by fact
    also have "\<dots> < real n"
      using assms by simp
    finally have "a * real n + max 0 b + 1 < real n"
      using ab by (simp add: field_simps)
  }
  finally show "nat \<lceil>a*n+b\<rceil> < n"
    using \<open>n > n0\<close> by linarith
qed

lemma akra_bazzi_light_aux2:
  fixes f :: "nat \<Rightarrow> real"
  fixes n\<^sub>0 :: nat and a b c d :: real and C1 C2 C\<^sub>1 C\<^sub>2 :: real
  assumes bounds: "a > 0" "c > 0" "a + c < 1" "C\<^sub>1 \<ge> 0"
  assumes rec: "\<forall>n>n\<^sub>0. f n = f (nat \<lceil>a*n+b\<rceil>) + f (nat \<lceil>c*n+d\<rceil>) + C\<^sub>1 * n + C\<^sub>2"
  assumes ineqs: "n\<^sub>0 > (max 0 b + max 0 d + 2) / (1 - a - c)"
                 "C\<^sub>3 \<ge> C\<^sub>1 / (1 - a - c)"
                 "C\<^sub>3 \<ge> (C\<^sub>1 * n\<^sub>0 + C\<^sub>2 + C\<^sub>4) / ((1 - a - c) * n\<^sub>0 - max 0 b - max 0 d - 2)"
                 "\<forall>n\<le>n\<^sub>0. f n \<le> C\<^sub>4"
  shows   "f n \<le> C\<^sub>3 * n + C\<^sub>4"
proof (induction n rule: less_induct)
  case (less n)
  have "0 \<le> C\<^sub>1 / (1 - a - c)"
    using bounds by auto
  also have "\<dots> \<le> C\<^sub>3"
    by fact
  finally have "C\<^sub>3 \<ge> 0" .

  show ?case
  proof (cases "n > n\<^sub>0")
    case False
    hence "f n \<le> C\<^sub>4"
      using ineqs(4) by auto
    also have "\<dots> \<le> C\<^sub>3 * real n + C\<^sub>4"
      using bounds \<open>C\<^sub>3 \<ge> 0\<close> by auto
    finally show ?thesis .
  next
    case True
    have nonneg: "a * n \<ge> 0" "c * n \<ge> 0"
      using bounds by simp_all

    have "(max 0 b + 1) / (1 - a) \<le> (max 0 b + max 0 d + 2) / (1 - a - c)"
      using bounds by (intro frac_le) auto
    hence "n\<^sub>0 \<ge> (max 0 b + 1) / (1 - a)"
      using ineqs(1) by linarith
    hence rec_less1: "nat \<lceil>a*n+b\<rceil> < n"
      using bounds \<open>n > n\<^sub>0\<close> by (intro akra_bazzi_light_aux1[of _ n\<^sub>0]) auto

    have "(max 0 d + 1) / (1 - c) \<le> (max 0 b + max 0 d + 2) / (1 - a - c)"
      using bounds by (intro frac_le) auto
    hence "n\<^sub>0 \<ge> (max 0 d + 1) / (1 - c)"
      using ineqs(1) by linarith
    hence rec_less2: "nat \<lceil>c*n+d\<rceil> < n"
      using bounds \<open>n > n\<^sub>0\<close> by (intro akra_bazzi_light_aux1[of _ n\<^sub>0]) auto

    have "f n = f (nat \<lceil>a*n+b\<rceil>) + f (nat \<lceil>c*n+d\<rceil>) + C\<^sub>1 * n + C\<^sub>2"
      using \<open>n > n\<^sub>0\<close> by (subst rec) auto
    also have "\<dots> \<le> (C\<^sub>3 * nat \<lceil>a*n+b\<rceil> + C\<^sub>4) + (C\<^sub>3 * nat \<lceil>c*n+d\<rceil> + C\<^sub>4) + C\<^sub>1 * n + C\<^sub>2"
      using rec_less1 rec_less2 by (intro add_mono less.IH) auto
    also have "\<dots> \<le> (C\<^sub>3 * (a*n+max 0 b+1) + C\<^sub>4) + (C\<^sub>3 * (c*n+max 0 d+1) + C\<^sub>4) + C\<^sub>1 * n + C\<^sub>2"
      using bounds \<open>C\<^sub>3 \<ge> 0\<close> nonneg by (intro add_mono mult_left_mono order.refl; linarith)
    also have "\<dots> = C\<^sub>3 * n  +  ((C\<^sub>3 * (max 0 b + max 0 d + 2) + 2 * C\<^sub>4 + C\<^sub>2) -
                                 (C\<^sub>3 * (1 - a - c) - C\<^sub>1) * n)"
      by (simp add: algebra_simps)
    also have "\<dots> \<le> C\<^sub>3 * n  +  ((C\<^sub>3 * (max 0 b + max 0 d + 2) + 2 * C\<^sub>4 + C\<^sub>2) -
                                 (C\<^sub>3 * (1 - a - c) - C\<^sub>1) * n\<^sub>0)"
      using \<open>n > n\<^sub>0\<close> ineqs(2) bounds
      by (intro add_mono diff_mono order.refl mult_left_mono) (auto simp: field_simps)
    also have "(C\<^sub>3 * (max 0 b + max 0 d + 2) + 2 * C\<^sub>4 + C\<^sub>2) - (C\<^sub>3 * (1 - a - c) - C\<^sub>1) * n\<^sub>0 \<le> C\<^sub>4"
      using ineqs bounds by (simp add: field_simps)
    finally show "f n \<le> C\<^sub>3 * real n + C\<^sub>4"
      by (simp add: mult_right_mono)
  qed
qed

lemma akra_bazzi_light:
  fixes f :: "nat \<Rightarrow> real"
  fixes n\<^sub>0 :: nat and a b c d C\<^sub>1 C\<^sub>2 :: real
  assumes bounds: "a > 0" "c > 0" "a + c < 1" "C\<^sub>1 \<ge> 0"
  assumes rec: "\<forall>n>n\<^sub>0. f n = f (nat \<lceil>a*n+b\<rceil>) + f (nat \<lceil>c*n+d\<rceil>) + C\<^sub>1 * n + C\<^sub>2"
  shows "\<exists>C\<^sub>3 C\<^sub>4. \<forall>n. f n \<le> C\<^sub>3 * real n + C\<^sub>4"
proof -
  define n\<^sub>0' where "n\<^sub>0' = max n\<^sub>0 (nat \<lceil>(max 0 b + max 0 d + 2) / (1 - a - c) + 1\<rceil>)"
  define C\<^sub>4 where "C\<^sub>4 = Max (f ` {..n\<^sub>0'})"
  define C\<^sub>3 where "C\<^sub>3 = max (C\<^sub>1 / (1 - a - c))
                         ((C\<^sub>1 * n\<^sub>0' + C\<^sub>2 + C\<^sub>4) / ((1 - a - c) * n\<^sub>0' - max 0 b - max 0 d - 2))"

  have "f n \<le> C\<^sub>3 * n + C\<^sub>4" for n
  proof (rule akra_bazzi_light_aux2[OF bounds _])
    show "\<forall>n>n\<^sub>0'. f n = f (nat \<lceil>a*n+b\<rceil>) + f (nat \<lceil>c*n+d\<rceil>) + C\<^sub>1 * n + C\<^sub>2"
      using rec by (auto simp: n\<^sub>0'_def)
  next
    show "C\<^sub>3 \<ge> C\<^sub>1 / (1 - a - c)"
     and "C\<^sub>3 \<ge> (C\<^sub>1 * n\<^sub>0' + C\<^sub>2 + C\<^sub>4) / ((1 - a - c) * n\<^sub>0' - max 0 b - max 0 d - 2)"
      by (simp_all add: C\<^sub>3_def)
  next
    have "(max 0 b + max 0 d + 2) / (1 - a - c) < nat \<lceil>(max 0 b + max 0 d + 2) / (1 - a - c) + 1\<rceil>"
      by linarith
    also have "\<dots> \<le> n\<^sub>0'"
      by (simp add: n\<^sub>0'_def)
    finally show "(max 0 b + max 0 d + 2) / (1 - a - c) < real n\<^sub>0'" .
  next
    show "\<forall>n\<le>n\<^sub>0'. f n \<le> C\<^sub>4"
      by (auto simp: C\<^sub>4_def)
  qed
  thus ?thesis by blast
qed

lemma akra_bazzi_light_nat:
  fixes f :: "nat \<Rightarrow> nat"
  fixes n\<^sub>0 :: nat and a b c d :: real and C\<^sub>1 C\<^sub>2 :: nat
  assumes bounds: "a > 0" "c > 0" "a + c < 1" "C\<^sub>1 \<ge> 0"
  assumes rec: "\<forall>n>n\<^sub>0. f n = f (nat \<lceil>a*n+b\<rceil>) + f (nat \<lceil>c*n+d\<rceil>) + C\<^sub>1 * n + C\<^sub>2"
  shows "\<exists>C\<^sub>3 C\<^sub>4. \<forall>n. f n \<le> C\<^sub>3 * n + C\<^sub>4"
proof -
  have "\<exists>C\<^sub>3 C\<^sub>4. \<forall>n. real (f n) \<le> C\<^sub>3 * real n + C\<^sub>4"
    using assms by (intro akra_bazzi_light[of a c C\<^sub>1 n\<^sub>0 f b d C\<^sub>2]) auto
  then obtain C\<^sub>3 C\<^sub>4 where le: "\<forall>n. real (f n) \<le> C\<^sub>3 * real n + C\<^sub>4"
    by blast
  have "f n \<le> nat \<lceil>C\<^sub>3\<rceil> * n + nat \<lceil>C\<^sub>4\<rceil>" for n
  proof -
    have "real (f n) \<le> C\<^sub>3 * real n + C\<^sub>4"
      using le by blast
    also have "\<dots> \<le> real (nat \<lceil>C\<^sub>3\<rceil>) * real n + real (nat \<lceil>C\<^sub>4\<rceil>)"
      by (intro add_mono mult_right_mono; linarith)
    also have "\<dots> = real (nat \<lceil>C\<^sub>3\<rceil> * n + nat \<lceil>C\<^sub>4\<rceil>)"
      by simp
    finally show ?thesis by linarith
  qed
  thus ?thesis by blast
qed

lemma T'_mom_select_le': "\<exists>C\<^sub>1 C\<^sub>2. \<forall>n. T'_mom_select n \<le> C\<^sub>1 * n + C\<^sub>2"
proof (rule akra_bazzi_light_nat)
  show "\<forall>n>20. T'_mom_select n = T'_mom_select (nat \<lceil>0.2 * n + 0\<rceil>) +
                 T'_mom_select (nat \<lceil>0.7 * n + 3\<rceil>) + 17 * n + 50"
    using T'_mom_select.simps by auto
qed auto

end


theory Definitions
  imports Main
begin

primrec repeat :: "'a \<Rightarrow> nat \<Rightarrow> 'a list" where
  "repeat a 0 = []"
| "repeat a (Suc n) = a # repeat a n"

lemma repeat_nth: "i < n \<Longrightarrow> repeat a n ! i = a"
  apply (induct n arbitrary: i)
  apply simp
  apply simp
  using less_Suc_eq_0_disj by fastforce

lemma repeat_length: "length (repeat a n) = n"
  apply (induct n)
  apply simp
  apply simp
  done

fun update :: "nat \<Rightarrow> 'a \<Rightarrow> 'a list \<Rightarrow> 'a list" where
  "update 0 x (y # ys) = x # ys"
| "update (Suc n) x (y # ys) = y # update n x ys"
| "update _ _ _ = undefined"

lemma update_nth_updated: "length xs > i \<Longrightarrow> update i a xs ! i = a"
  apply (induct xs arbitrary: i)
  apply simp
  apply simp
  using less_Suc_eq_0_disj by fastforce

lemma update_nth_nonupdated: "\<lbrakk> length xs > i; length xs > j; i \<noteq> j \<rbrakk> \<Longrightarrow> update i a xs ! j = xs ! j"
  apply (induct xs arbitrary: i j)
  apply simp
proof-
  fix aa xs i j
  assume "(\<And>i j. i < length xs \<Longrightarrow> j < length xs \<Longrightarrow> i \<noteq> j \<Longrightarrow> update i a xs ! j = xs ! j)" "i < length (aa # xs)" "j < length (aa # xs)" "i \<noteq> j"

  show "update i a (aa # xs) ! j = (aa # xs) ! j"
    apply (cases i)
    apply simp
    using \<open>i \<noteq> j\<close> apply force
    apply simp
    apply (cases j)
    apply simp
    using \<open>\<And>j i. \<lbrakk>i < length xs; j < length xs; i \<noteq> j\<rbrakk> \<Longrightarrow> update i a xs ! j = xs ! j\<close> \<open>i < length (aa # xs)\<close> \<open>i \<noteq> j\<close> \<open>j < length (aa # xs)\<close> by auto
qed

lemma update_length [simp]: "i < length xs \<Longrightarrow> length (update i a xs) = length xs"
  apply (induct xs arbitrary: i)
  apply simp_all
proof-
  fix aa xs i
  assume "(\<And>i. i < length xs \<Longrightarrow> length (update i a xs) = length xs)" "i < Suc (length xs)"

  show "length (update i a (aa # xs)) = Suc (length xs)"
    apply (cases i)
    apply simp_all
    using \<open>\<And>i. i < length xs \<Longrightarrow> length (update i a xs) = length xs\<close> \<open>i < Suc (length xs)\<close> by auto
qed

datatype election_term = election_term (election_term_of: nat)

instantiation election_term :: ord
begin

definition
  "i < j \<longleftrightarrow> election_term_of i < election_term_of j"

definition
  "i \<le> j \<longleftrightarrow> election_term_of i \<le> election_term_of j"

instance ..

end

fun increment_election_term where
  "increment_election_term t = election_term (election_term_of t + 1)"

lemma increment_election_term_greater_or_eq: "t < election_term (Suc (election_term_of t))"
  apply (cases t)
  apply simp
  by (simp add: less_election_term_def)

lemma increment_election_term_greater: "t \<le> election_term (Suc (election_term_of t))"
  using less_eq_election_term_def by force

datatype node = node (node_of: nat)

lemma hd_0th: "length xs > 0 \<Longrightarrow> hd xs = xs ! 0"
  by (simp add: hd_conv_nth)

end