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) (enumerate 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 (enumerate 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