Theory Argmax
section ‹Locus where a function or a list (of linord type) attains its maximum value›
theory Argmax
imports Main
begin
text ‹Structural induction is used in proofs on lists.›
lemma structInduct: assumes "P []" and "∀x xs. P (xs) ⟶ P (x#xs)"
shows "P l"
using assms list_nonempty_induct by (metis)
text ‹the subset of elements of a set where a function reaches its maximum›
fun argmax :: "('a ⇒ 'b::linorder) ⇒ 'a set ⇒ 'a set"
where "argmax f A = { x ∈ A . f x = Max (f ` A) }"
lemma argmaxLemma: "argmax f A = { x ∈ A . f x = Max (f ` A) }"
by simp
lemma maxLemma:
assumes "x ∈ X" "finite X"
shows "Max (f`X) >= f x"
(is "?L >= ?R") using assms
by (metis (opaque_lifting, no_types) Max.coboundedI finite_imageI image_eqI)
lemma lm01:
"argmax f A = A ∩ f -` {Max (f ` A)}"
by force
lemma lm02:
assumes "y ∈ f`A"
shows "A ∩ f -` {y} ≠ {}"
using assms by blast
lemma argmaxEquivalence:
assumes "∀x∈X. f x = g x"
shows "argmax f X = argmax g X"
using assms argmaxLemma Collect_cong image_cong
by (metis(no_types,lifting))
text ‹The arg max of a function over a non-empty set is non-empty.›
corollary argmax_non_empty_iff: assumes "finite X" "X ≠ {}"
shows "argmax f X ≠{}"
using assms Max_in finite_imageI image_is_empty lm01 lm02
by (metis(no_types))
text ‹The previous definition of argmax operates on sets. In the following we define a corresponding notion on lists. To this end, we start with defining a filter predicate and are looking for the elements of a list satisfying a given predicate;
but, rather than returning them directly, we return the (sorted) list of their indices.
This is done, in different ways, by @{term filterpositions} and @{term filterpositions2}.›
definition filterpositions :: "('a => bool) => 'a list => nat list"
where "filterpositions P l = map snd (filter (P o fst) (zip l (upt 0 (size l))))"
definition filterpositions2
where "filterpositions2 P l = [n. n ← [0..<size l], P (l!n)]"
definition maxpositions
where "maxpositions l = filterpositions2 (%x . x ≥ Max (set l)) l"
lemma lm03: "maxpositions l = [n. n←[0..<size l], l!n ≥ Max(set l)]"
unfolding maxpositions_def filterpositions2_def by fastforce
definition argmaxList
where "argmaxList f l = map (nth l) (maxpositions (map f l))"
lemma lm04: "[n . n <- l, P n] = [n . n <- l, n ∈ set l, P n]"
proof -
have "map (λuu. if P uu then [uu] else []) l =
map (λuu. if uu ∈ set l then if P uu then [uu] else [] else []) l" by simp
thus "concat (map (λn. if P n then [n] else []) l) =
concat (map (λn. if n ∈ set l then if P n then [n] else [] else []) l)" by presburger
qed
lemma lm05: "[n . n <- [0..<m], P n] = [n . n <- [0..<m], n ∈ set [0..<m], P n]"
using lm04 by fast
lemma lm06: fixes f m P
shows "(map f [n . n <- [0..<m], P n]) = [ f n . n <- [0..<m], P n]"
by (induct m) auto
lemma map_commutes_a: "[f n . n <- [], Q (f n)] = [x <- (map f []). Q x]"
by simp
lemma map_commutes_b: "∀ x xs. ([f n . n <- xs, Q (f n)] = [x <- (map f xs). Q x] ⟶
[f n . n <- (x#xs), Q (f n)] = [x <- (map f (x#xs)). Q x])"
by simp
lemma map_commutes: fixes f::"'a => 'b" fixes Q::"'b => bool" fixes xs::"'a list"
shows "[f n . n <- xs, Q (f n)] = [x <- (map f xs). Q x]"
using map_commutes_a map_commutes_b structInduct by fast
lemma lm07: fixes f l
shows "maxpositions (map f l) =
[n . n <- [0..<size l], f (l!n) ≥ Max (f`(set l))]"
(is "maxpositions (?fl) = _")
proof -
have "maxpositions ?fl =
[n. n <- [0..<size ?fl], n∈ set[0..<size ?fl], ?fl!n ≥ Max (set ?fl)]"
using lm04 unfolding filterpositions2_def maxpositions_def .
also have "... =
[n . n <- [0..<size l], (n<size l), (?fl!n ≥ Max (set ?fl))]" by simp
also have "... =
[n . n <- [0..<size l], (n<size l) ∧ (f (l!n) ≥ Max (set ?fl))]"
using nth_map by (metis (poly_guards_query, opaque_lifting)) also have "... =
[n . n <- [0..<size l], (n∈ set [0..<size l]),(f (l!n) ≥ Max (set ?fl))]"
using atLeastLessThan_iff le0 set_upt by (metis(no_types))
also have "... =
[n . n <- [0..<size l], f (l!n) ≥ Max (set ?fl)]" using lm05 by presburger
finally show ?thesis by auto
qed
lemma lm08: fixes f l
shows "argmaxList f l =
[ l!n . n <- [0..<size l], f (l!n) ≥ Max (f`(set l))]"
unfolding lm07 argmaxList_def by (metis lm06)
text‹The theorem expresses that argmaxList is the list of arguments greater equal the Max of the list.›
theorem argmaxadequacy: fixes f::"'a => ('b::linorder)" fixes l::"'a list"
shows "argmaxList f l = [ x <- l. f x ≥ Max (f`(set l))]"
(is "?lh=_")
proof -
let ?P="% y::('b::linorder) . y ≥ Max (f`(set l))"
let ?mh="[nth l n . n <- [0..<size l], ?P (f (nth l n))]"
let ?rh="[ x <- (map (nth l) [0..<size l]). ?P (f x)]"
have "?lh = ?mh" using lm08 by fast
also have "... = ?rh" using map_commutes by fast
also have "...= [x <- l. ?P (f x)]" using map_nth by metis
finally show ?thesis by force
qed
end