Theory Prediction_Utils_Matrix

(***********************************************************************************
 * Copyright (c) University of Exeter, UK
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * * Redistributions of source code must retain the above copyright notice, this
 *
 * * Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * SPDX-License-Identifier: BSD-2-Clause
 ***********************************************************************************)

subsection‹Useful Definitions for Analysing Matrix Predictions (\thy)›

theory
  Prediction_Utils_Matrix 
  imports 
    Complex_Main
    Jordan_Normal_Form.Matrix
begin


definition maxmat :: ‹'a::linorder Matrix.mat ⇒ 'a› where 
  ‹maxmat =  Max o elements_mat›

definition minmat :: ‹'a::linorder Matrix.mat ⇒ 'a› where 
  ‹minmat  =  Min o elements_mat›


lemma finite_elements_mat: "finite (elements_mat A)"
  unfolding elements_mat_def by blast

lemma maxmat_is_element:
  shows ‹elements_mat m ≠ {} ⟹ maxmat m ∈ elements_mat m›
  by (simp add: finite_elements_mat maxmat_def)

lemma minmat_is_element:
  ‹elements_mat m ≠ {} ⟹ minmat m ∈ elements_mat m›
  by (simp add: finite_elements_mat minmat_def)

definition max_list :: "'a::linorder list ⇒ 'a" where
  "max_list xs = fold max xs (hd xs)"

definition min_list :: "'a::linorder list ⇒ 'a" where
  "min_list xs = fold min xs (hd xs)"

definition maxvec :: ‹'a::linorder Matrix.vec ⇒ 'a› where 
  ‹maxvec =  max_list  o list_of_vec›

definition minvec :: ‹'a::linorder Matrix.vec ⇒ 'a› where 
  ‹minvec  =  min_list o list_of_vec›

lemma maxvec_is_element:
  shows ‹list_of_vec m ≠ [] ⟹ maxvec m ∈ set(list_of_vec m)›
  apply (simp add: maxvec_def max_list_def) 
  by (metis List.finite_set Max.set_eq_fold Max_eq_iff hd_in_set list.discI set_ConsD set_empty2)

lemma minvec_is_element:
  shows ‹list_of_vec m ≠ [] ⟹ minvec m ∈ set(list_of_vec m)›
  apply (simp add: minvec_def min_list_def) 
  by (metis List.finite_set Min.set_eq_fold Min_in empty_iff insert_absorb list.set_sel(1) list.simps(15))


lemma maxvec_vCons_append_eq: ‹maxvec (vCons x xs) = maxvec xs ∨ maxvec (vCons x xs) = x›
proof(cases "maxvec (vCons x xs) = x")
  case True
  then show ?thesis by blast
next
  case False
  then show ?thesis apply(simp add: maxvec_def max_list_def Max_eq_iff insertCI insertE ) 
    by (smt (verit) List.finite_set Max.in_idem Max.set_eq_fold Max_insert comp_apply 
        fold_simps(1) list.simps(15) list.simps(3) list_of_vec_vCons max.right_idem maxvec_def
        maxvec_is_element max_list_def set_ConsD set_empty2) (*takes long*)

qed

lemma maxvec_append_eq: ‹maxvec (vec_of_list (xs @ [x])) = maxvec (vec_of_list xs) ∨ maxvec (vec_of_list (xs @ [x])) = x›
proof(cases "maxvec (vec_of_list (xs @ [x])) = x")
  case True
  then show ?thesis by blast
next
  case False
  then show ?thesis 
    apply(simp add: maxvec_def maxvec_is_element max_list_def) 
    by (metis (no_types, lifting) append_self_conv2 comp_apply fold.simps(1) 
        fold_append fold_simps(2) hd_append2 id_apply list.sel(1) list_vec max_def)
qed

lemma minvec_vCons_append_eq: ‹minvec (vCons x xs) = minvec xs ∨ minvec (vCons x xs) = x›
proof(cases "minvec (vCons x xs) = x")
  case True
  then show ?thesis by blast
next
  case False
  then show ?thesis 
    apply(simp add: minvec_def min_list_def Min_eq_iff insertCI insertE ) 
    by (metis (no_types, lifting) List.finite_set Min.in_idem Min.insert 
        Min.semilattice_set_axioms Min_def fold_simps(1) list.set_sel(1) list.simps(15) 
        min_def semilattice_set.set_eq_fold set_empty)
qed

lemma minvec_append_eq: ‹minvec (vec_of_list (xs @ [x])) = minvec (vec_of_list xs) ∨ minvec (vec_of_list (xs @ [x])) = x›
proof(cases "minvec (vec_of_list (xs @ [x])) = x")
  case True
  then show ?thesis by blast
next
  case False
  then show ?thesis
    apply(simp add: minvec_def minvec_is_element min_list_def)
    by (metis (no_types, lifting) append_self_conv2 comp_apply fold.simps(1) 
        fold_append fold_simps(2) hd_append2 id_apply list.sel(1) list_vec min_def)
qed

lemma maxvec_vec_cons_eq: ‹maxvec ((vec_of_list [x]) @v xs) = maxvec xs ∨ maxvec ((vec_of_list [x]) @v xs) = x›
proof(cases "maxvec ((vec_of_list [x]) @v xs) = x")
  case True
  then show ?thesis by blast
next
  case False
  then show ?thesis
    apply(simp add: maxvec_def max_list_def)
    using  max_def 
    by (metis (no_types, lifting) comp_apply fold_simps(2) list.sel(1) 
        list_of_vec_vCons maxvec_def maxvec_vCons_append_eq max_list_def)
qed

lemma maxvec_cons_eq: ‹maxvec (vec_of_list (x#xs)) = maxvec (vec_of_list xs) ∨ maxvec (vec_of_list (x#xs)) = x›
proof(cases "maxvec (vec_of_list (x#xs)) = x")
  case True
  then show ?thesis by blast
next
  case False
  then show ?thesis
    apply(simp add: maxvec_def maxvec_is_element max_list_def) 
    by (metis (no_types, lifting) comp_apply fold_simps(2) list.sel(1) 
        list_of_vec_vCons max.idem maxvec_def maxvec_vCons_append_eq max_list_def)
qed

lemma minvec_vec_cons_eq: ‹minvec ((vec_of_list [x]) @v xs) = minvec xs ∨ minvec ((vec_of_list [x]) @v xs) = x›
proof(cases "minvec ((vec_of_list [x]) @v xs) = x")
  case True
  then show ?thesis by blast
next
  case False
  then show ?thesis
    apply(simp add: maxvec_def) 
    using minvec_vCons_append_eq by blast
qed

lemma minlist_cons_eq: ‹minvec (vec_of_list (x#xs)) = minvec (vec_of_list xs) ∨ minvec (vec_of_list (x#xs)) = x›
proof(cases "minvec (vec_of_list (x#xs)) = x")
  case True
  then show ?thesis by blast
next
  case False
  then show ?thesis
    apply (simp add: minvec_def minvec_is_element min_list_def)
    by (metis (no_types, lifting) comp_apply fold_simps(2) list.sel(1) 
        list_of_vec_vCons min.idem minvec_def minvec_vCons_append_eq min_list_def)
qed

lemma maxvec_vec_append_limit: assumes ‹xs ≠ vNil› shows ‹maxvec xs ≤ maxvec (vCons x xs)›
proof(cases "maxvec (vCons x xs) = x")
  case True 
  then show ?thesis using assms 
    apply (simp add: maxvec_def max_list_def) 
    by (metis List.finite_set Max.set_eq_fold Max_insert hd_in_set insert_absorb 
        list.simps(15) max.orderI set_empty2 vec_list vec_of_list_Nil)
next
  case False
  then show ?thesis
    using dual_order.order_iff_strict maxvec_vCons_append_eq by auto
qed 

lemma maxvec_append_limit: assumes ‹xs ≠ []› shows ‹maxvec (vec_of_list xs) ≤ maxvec (vec_of_list (xs @ [x]))›
proof(cases "maxvec (vec_of_list (xs @ [x])) = x")
  case True 
  then show ?thesis using assms
    apply (simp add: maxvec_def  maxvec_is_element max_list_def )
    by (metis List.finite_set Max.set_eq_fold Max_ge comp_apply list.set_intros(2) 
        list_vec maxvec_def maxvec_is_element max_list_def rotate1.simps(2) set_rotate1)
next
  case False
  then show ?thesis 
    by (metis dual_order.refl maxvec_append_eq)
qed 

lemma minvec_vec_append_limit: assumes ‹xs ≠ vNil› shows ‹minvec xs ≥ minvec (vCons x xs)›
proof(cases " minvec (vCons x xs) = x")
  case True 
  then show ?thesis using assms 
    apply (simp add: minvec_def min_list_def)
    by (metis List.finite_set Min.insert Min.set_eq_fold 
        Orderings.order_eq_iff hd_in_set insert_absorb list.simps(15) 
        min_def set_empty2 vec_list vec_of_list_Nil)
next
  case False
  then show ?thesis 
    by (metis dual_order.refl minvec_vCons_append_eq)
qed 

lemma minvec_append_limit: assumes ‹xs ≠ []› shows ‹minvec (vec_of_list xs) ≥  minvec (vec_of_list (xs @ [x]))›
proof(cases "minvec (vec_of_list (xs @ [x])) = x")
  case True 
  then show ?thesis using assms
    apply (simp add: minvec_def  minvec_is_element min_list_def )
    by (metis (no_types, lifting) append.right_neutral comp_apply 
        fold_append fold_simps(2) hd_append2 linorder_linear list_vec min_def)
next
  case False
  then show ?thesis
    by (metis dual_order.refl minvec_append_eq)
qed 

lemma maxvec_vec_cons_limit: assumes ‹xs ≠ vNil› shows ‹maxvec xs ≤ maxvec ((vec_of_list [x]) @v xs)›
proof(cases "maxvec ((vec_of_list [x]) @v xs) = x")
  case True 
  then show ?thesis using assms
    by (metis append_vec_vCons append_vec_vNil maxvec_vec_append_limit vec_of_list_Cons 
        vec_of_list_Nil)
next
  case False
  then show ?thesis
    by (simp add: assms maxvec_vec_append_limit)
qed 

lemma maxvec_cons_limit: assumes ‹xs ≠ []› shows ‹maxvec (vec_of_list xs) ≤ maxvec (vec_of_list (x#xs))›
proof(cases "maxvec (vec_of_list (x#xs)) = x")
  case True 
  then show ?thesis using assms
    by (metis list_vec maxvec_vec_append_limit vec_of_list_Cons vec_of_list_Nil)
next
  case False
  then show ?thesis
    by (metis dual_order.refl maxvec_cons_eq) 
qed 

lemma minvec_vec_cons_limit: assumes ‹xs ≠ vNil› shows ‹minvec xs ≥ minvec ((vec_of_list [x]) @v xs)›
proof(cases "minvec ((vec_of_list [x]) @v xs) = x")
  case True 
  then show ?thesis using assms
    by (metis append_vec_vCons append_vec_vNil minvec_vec_append_limit vec_of_list_Cons 
        vec_of_list_Nil)
next
  case False
  then show ?thesis
    by (simp add: assms minvec_vec_append_limit)
qed 

lemma minvec_cons_limit: assumes ‹xs ≠ []› shows ‹minvec (vec_of_list xs) ≥  minvec (vec_of_list (x#xs))›
proof(cases "minvec (vec_of_list (x#xs)) = x")
  case True 
  then show ?thesis using assms
    by (metis list_vec minvec_vec_append_limit vec_of_list_Cons vec_of_list_Nil)
next
  case False
  then show ?thesis 
    by (metis minlist_cons_eq order_refl) 
qed

paragraph‹Converting Predictions to Percentages›

definition prediction2percentage :: ‹real Matrix.vec ⇒ real Matrix.vec› where
  ‹prediction2percentage m = (let m' = maxvec m in map_vec (λ e. e / m' *  100.0) m)›


lemma prediction2percentage_id: 
  assumes ‹maxvec p = 100› 
  shows ‹prediction2percentage p = p›
  using assms unfolding prediction2percentage_def
  by auto


paragraph‹Maximum Prediction›

definition posmax_of :: ‹'a::linorder Matrix.vec ⇒ (nat × 'a) option› where
  ‹posmax_of l = (let m = maxvec l in find (λ e. snd e = m) (indexed_from 0 (list_of_vec l)))›
definition pos_of_max :: ‹'a::linorder Matrix.vec ⇒ nat option› where
  ‹pos_of_max l = map_option fst (posmax_of l)›

definition posmax_of' :: ‹'a::linorder Matrix.vec ⇒ (nat × 'a) option› where
  ‹posmax_of' l = (let l' = list_of_vec l in 
                          (if l' = [] then None
                                      else Some ((hd o rev o (sort_key snd) o (indexed_from 0)) l')))›
definition pos_of_max' :: ‹'a::linorder Matrix.vec ⇒ nat option› where
  ‹pos_of_max' l = map_option fst (posmax_of' l)›

lemma find_append_eq: ‹find P (xs@[x]) = (if find P xs = None then find P [x] else find P xs)›
proof (induction xs)
  case Nil
  then show ?case by simp 
next
  case (Cons a xs)
  then show ?case by simp 
qed

paragraph‹Distance of Maximum Prediction to Next Highest Prediction›

definition δmin :: "real mat ⇒ real" where 
  ‹δmin m = (let m'  = maxmat m; m'' = Max (elements_mat m - {m'})
                    in ¦m' - m''¦ )›

end