Theory System_Of_Equations_IArrays
section‹Solving systems of equations using the Gauss Jordan algorithm over nested IArrays›
theory System_Of_Equations_IArrays
imports
System_Of_Equations
Bases_Of_Fundamental_Subspaces_IArrays
begin
subsection‹Previous definitions and properties›
definition greatest_not_zero :: "'a::{zero} iarray => nat"
where "greatest_not_zero A = the (List.find (λn. A !! n ≠ 0) (rev [0..<IArray.length A]))"
lemma vec_to_iarray_exists:
shows "(∃b. A $ b ≠ 0) = IArray.exists (λb. (vec_to_iarray A) !! b ≠ 0) (IArray[0..<IArray.length (vec_to_iarray A)])"
proof (unfold IArray.exists_def length_vec_to_iarray, auto simp del: IArray.sub_def)
fix b assume Ab: "A $ b ≠ 0"
show "∃b∈{0..<CARD('a)}. vec_to_iarray A !! b ≠ 0"
by (rule bexI[of _ "to_nat b"], unfold vec_to_iarray_nth', auto simp add: Ab to_nat_less_card[of b])
next
fix b assume b: "b < CARD('a)" and Ab_vec: "vec_to_iarray A !! b ≠ 0"
show "∃b. A $ b ≠ 0" by (rule exI[of _ "from_nat b"], metis Ab_vec vec_to_iarray_nth[OF b])
qed
corollary vec_to_iarray_exists':
shows "(∃b. A $ b ≠ 0) = IArray.exists (λb. (vec_to_iarray A) !! b ≠ 0) (IArray (rev [0..<IArray.length (vec_to_iarray A)]))"
by (simp add: vec_to_iarray_exists Option.is_none_def find_None_iff)
lemma not_is_zero_iarray_eq_iff: "(∃b. A $ b ≠ 0) = (¬ is_zero_iarray (vec_to_iarray A))"
by (metis (full_types) is_zero_iarray_eq_iff vec_eq_iff zero_index)
lemma vec_to_iarray_greatest_not_zero:
assumes ex_b: "(∃b. A $ b ≠ 0)"
shows "greatest_not_zero (vec_to_iarray A) = to_nat (GREATEST b. A $ b ≠ 0)"
proof -
let ?P="(λn. (vec_to_iarray A) !! n ≠ 0)"
let ?xs="(rev [0..<IArray.length (vec_to_iarray A)])"
have "∃a. (List.find ?P ?xs) = Some a"
proof(rule ccontr, simp, unfold find_None_iff)
assume "¬ (∃x. x ∈ set (rev [0..<length (IArray.list_of (vec_to_iarray A))]) ∧ IArray.list_of (vec_to_iarray A) ! x ≠ 0)"
thus False using ex_b
unfolding set_rev by (auto, unfold IArray.length_def[symmetric] IArray.sub_def[symmetric] length_vec_to_iarray,metis to_nat_less_card vec_to_iarray_nth')
qed
from this obtain a where a: "(List.find ?P ?xs) = Some a" by blast
from this obtain ia where ia_less_length: "ia<length ?xs"
and P_xs_ia: "?P (?xs!ia)" and a_eq: "a = ?xs!ia" and all_zero: "(∀j<ia. ¬ ?P (?xs!j))"
unfolding find_Some_iff by auto
have ia_less_card: "ia < CARD('a)" using ia_less_length by (metis diff_zero length_rev length_upt length_vec_to_iarray)
have ia_less_length': "ia < length ([0..<IArray.length (vec_to_iarray A)])" using ia_less_length unfolding length_rev .
have a_less_card: "a < CARD('a)" unfolding a_eq unfolding rev_nth[OF ia_less_length']
using nth_upt[of 0 "(length [0..<IArray.length (vec_to_iarray A)] - Suc ia)" "(length [0..<IArray.length (vec_to_iarray A)])" ]
by (metis diff_less length_upt length_vec_to_iarray minus_nat.diff_0 plus_nat.add_0 zero_less_Suc zero_less_card_finite)
have "(GREATEST b. A $ b ≠ 0) = from_nat a"
proof (rule Greatest_equality)
have "A $ from_nat a = (vec_to_iarray A) !! a" by (rule vec_to_iarray_nth[symmetric,OF a_less_card])
also have "... ≠ 0" using P_xs_ia unfolding a_eq[symmetric] .
finally show "A $ from_nat a ≠ 0" .
next
fix y assume Ay: "A $ y ≠ 0"
show "y ≤ from_nat a"
proof (rule ccontr)
assume "¬ y ≤ from_nat a" hence y_greater_a: "y > from_nat a" by simp
have y_greater_a': "to_nat y > a" using y_greater_a using to_nat_mono[of "from_nat a" y] using to_nat_from_nat_id by (metis a_less_card)
have "a = ?xs ! ia" using a_eq .
also have "... = [0..<IArray.length (vec_to_iarray A)] ! (length [0..<IArray.length (vec_to_iarray A)] - Suc ia)" by (rule rev_nth[OF ia_less_length'])
also have "... = 0 + (length [0..<IArray.length (vec_to_iarray A)] - Suc ia)" apply (rule nth_upt) using ia_less_length' by fastforce
also have "... = (length [0..<IArray.length (vec_to_iarray A)] - Suc ia)" by simp
finally have "a = (length [0..<IArray.length (vec_to_iarray A)] - Suc ia)" .
hence ia_eq: "ia = length [0..<IArray.length (vec_to_iarray A)] - (Suc a)"
by (metis Suc_diff_Suc Suc_eq_plus1_left diff_diff_cancel less_imp_le ia_less_length length_rev)
define ja where "ja = length [0..<IArray.length (vec_to_iarray A)] - to_nat y - 1"
have ja_less_length: "ja < length [0..<IArray.length (vec_to_iarray A)]" unfolding ja_def
using ia_eq ia_less_length' by (simp add: algebra_simps )
have suc_i_le: "IArray.length (vec_to_iarray A)≥Suc (to_nat y)" unfolding vec_to_iarray_def using to_nat_less_card[of y] by auto
have "?xs ! ja = [0..<IArray.length (vec_to_iarray A)] ! (length [0..<IArray.length (vec_to_iarray A)] - Suc ja)" unfolding rev_nth[OF ja_less_length] ..
also have "... = 0 + (length [0..<IArray.length (vec_to_iarray A)] - Suc ja)" apply (rule nth_upt, auto simp del: IArray.length_def) unfolding ja_def
by (metis diff_Suc_less ia_less_length' length_upt less_nat_zero_code minus_nat.diff_0 neq0_conv)
also have "... = (length [0..<IArray.length (vec_to_iarray A)] - Suc ja)" by simp
also have "... = to_nat y" unfolding ja_def using suc_i_le by force
finally have xs_ja_eq_y: "?xs ! ja = to_nat y" .
have ja_less_ia: "ja < ia" unfolding ja_def ia_eq by (auto simp del: IArray.length_def, metis Suc_leI suc_i_le diff_less_mono2 le_imp_less_Suc less_le_trans y_greater_a')
hence eq_0: "vec_to_iarray A !! (?xs ! ja) = 0" using all_zero by simp
hence "A $ y = 0" using vec_to_iarray_nth'[of A y] unfolding xs_ja_eq_y by simp
thus False using Ay by contradiction
qed
qed
thus ?thesis unfolding greatest_not_zero_def a unfolding to_nat_eq[symmetric]
unfolding to_nat_from_nat_id[OF a_less_card] by simp
qed
subsection‹Consistency and inconsistency›
definition "consistent_iarrays A b = (let GJ=Gauss_Jordan_iarrays_PA A;
rank_A = length [x←IArray.list_of (snd GJ) . ¬ is_zero_iarray x];
P_mult_b = fst(GJ) *iv b
in (rank_A ≥ (if (¬ is_zero_iarray P_mult_b)
then (greatest_not_zero P_mult_b + 1) else 0)))"
definition "inconsistent_iarrays A b = (¬ consistent_iarrays A b)"
lemma matrix_to_iarray_consistent[code]: "consistent A b = consistent_iarrays (matrix_to_iarray A) (vec_to_iarray b)"
unfolding consistent_eq_rank_ge_code
unfolding consistent_iarrays_def Let_def
unfolding Gauss_Jordan_PA_eq
unfolding rank_Gauss_Jordan_code[symmetric, unfolded Let_def]
unfolding snd_Gauss_Jordan_iarrays_PA_eq
unfolding rank_iarrays_code[symmetric]
unfolding matrix_to_iarray_rank
unfolding matrix_to_iarray_fst_Gauss_Jordan_PA[symmetric]
unfolding vec_to_iarray_matrix_matrix_mult[symmetric]
unfolding not_is_zero_iarray_eq_iff
using vec_to_iarray_greatest_not_zero[unfolded not_is_zero_iarray_eq_iff]
by force
lemma matrix_to_iarray_inconsistent[code]: "inconsistent A b = inconsistent_iarrays (matrix_to_iarray A) (vec_to_iarray b)"
unfolding inconsistent_def inconsistent_iarrays_def
unfolding matrix_to_iarray_consistent ..
definition "solve_consistent_rref_iarrays A b
= IArray.of_fun (λj. if (IArray.exists (λi. A !! i !! j = 1 ∧ j=least_non_zero_position_of_vector (row_iarray i A)) (IArray[0..<nrows_iarray A]))
then b !! (least_non_zero_position_of_vector (column_iarray j A)) else 0) (ncols_iarray A)"
lemma exists_solve_consistent_rref:
fixes A::"'a::{field}^'cols::{mod_type}^'rows::{mod_type}"
assumes rref: "reduced_row_echelon_form A"
shows "(∃i. A $ i $ j = 1 ∧ j = (LEAST n. A $ i $ n ≠ 0))
= (IArray.exists (λi. (matrix_to_iarray A) !! i !! (to_nat j) = 1
∧ (to_nat j)=least_non_zero_position_of_vector (row_iarray i (matrix_to_iarray A))) (IArray[0..<nrows_iarray (matrix_to_iarray A)]))"
proof (rule)
assume "∃i. A $ i $ j = 1 ∧ j = (LEAST n. A $ i $ n ≠ 0)"
from this obtain i where Aij: "A $ i $ j = 1" and j_eq: "j = (LEAST n. A $ i $ n ≠ 0)" by blast
show "IArray.exists (λi. matrix_to_iarray A !! i !! to_nat j = 1 ∧ to_nat j = least_non_zero_position_of_vector (row_iarray i (matrix_to_iarray A)))
(IArray [0..<nrows_iarray (matrix_to_iarray A)])"
unfolding IArray.exists_def find_Some_iff
apply (rule bexI[of _ "to_nat i"])+
proof (auto, unfold IArray.sub_def[symmetric])
show "to_nat i < nrows_iarray (matrix_to_iarray A)" unfolding matrix_to_iarray_nrows[symmetric] nrows_def using to_nat_less_card by fast
have "to_nat j = to_nat (LEAST n. A $ i $ n ≠ 0)" unfolding j_eq by simp
also have "... = to_nat (LEAST n. A $ i $ n ≠ 0 ∧ 0≤n)" by (metis least_mod_type)
also have "...= least_non_zero_position_of_vector_from_index (vec_to_iarray (row i A)) (to_nat (0::'cols))"
proof (rule vec_to_iarray_least_non_zero_position_of_vector_from_index''[symmetric, of "0::'cols" i A])
show "¬ vector_all_zero_from_index (to_nat (0::'cols), vec_to_iarray (row i A))"
unfolding vector_all_zero_from_index_eq[symmetric, of "0::'cols" "row i A"] unfolding row_def vec_nth_inverse using Aij least_mod_type[of j] by fastforce
qed
also have "... = least_non_zero_position_of_vector (row_iarray (to_nat i) (matrix_to_iarray A))" unfolding vec_to_iarray_row least_non_zero_position_of_vector_def
unfolding to_nat_0 ..
finally show "to_nat j = least_non_zero_position_of_vector (row_iarray (to_nat i) (matrix_to_iarray A))" .
show "matrix_to_iarray A !! mod_type_class.to_nat i !! mod_type_class.to_nat j = 1" unfolding matrix_to_iarray_nth using Aij .
qed
next
assume ex_eq: "IArray.exists (λi. matrix_to_iarray A !! i !! to_nat j = 1 ∧ to_nat j = least_non_zero_position_of_vector (row_iarray i (matrix_to_iarray A)))
(IArray [0..<nrows_iarray (matrix_to_iarray A)])"
have "∃y. List.find (λi. matrix_to_iarray A !! i !! to_nat j = 1 ∧ to_nat j = least_non_zero_position_of_vector (row_iarray i (matrix_to_iarray A)))
[0..<nrows_iarray (matrix_to_iarray A)] = Some y"
proof (rule ccontr, simp del: IArray.length_def IArray.sub_def, unfold find_None_iff)
assume" ¬ (∃x. x ∈ set [0..<nrows_iarray (matrix_to_iarray A)] ∧
matrix_to_iarray A !! x !! mod_type_class.to_nat j = 1 ∧ mod_type_class.to_nat j = least_non_zero_position_of_vector (row_iarray x (matrix_to_iarray A)))"
thus False using ex_eq unfolding IArray.exists_def by auto
qed
from this obtain y where y: "List.find (λi. matrix_to_iarray A !! i !! to_nat j = 1 ∧ to_nat j = least_non_zero_position_of_vector (row_iarray i (matrix_to_iarray A)))
[0..<nrows_iarray (matrix_to_iarray A)] = Some y" by blast
from this obtain i where i_less_length: "i<length [0..<nrows_iarray (matrix_to_iarray A)]" and
Aij_1: "matrix_to_iarray A !! ([0..<nrows_iarray (matrix_to_iarray A)] ! i) !! to_nat j = 1"
and j_eq: "to_nat j = least_non_zero_position_of_vector (row_iarray ([0..<nrows_iarray (matrix_to_iarray A)] ! i) (matrix_to_iarray A))" and
y_eq: "y = [0..<nrows_iarray (matrix_to_iarray A)] ! i"
and least: "(∀ja<i. ¬ (matrix_to_iarray A !! ([0..<nrows_iarray (matrix_to_iarray A)] ! ja) !! to_nat j = 1 ∧
to_nat j = least_non_zero_position_of_vector (row_iarray ([0..<nrows_iarray (matrix_to_iarray A)] ! ja) (matrix_to_iarray A))))"
unfolding find_Some_iff by blast
show "∃i. A $ i $ j = 1 ∧ j = (LEAST n. A $ i $ n ≠ 0)"
proof (rule exI[of _ "from_nat i"], rule conjI)
have i_rw: "[0..<nrows_iarray (matrix_to_iarray A)] ! i = i" using nth_upt[of 0 i "nrows_iarray (matrix_to_iarray A)"] using i_less_length by auto
have i_less_card: "i < CARD ('rows)" using i_less_length unfolding nrows_iarray_def matrix_to_iarray_def by auto
show A_ij: "A $ from_nat i $ j = 1"
using Aij_1 unfolding i_rw using matrix_to_iarray_nth[of A "from_nat i" j] unfolding to_nat_from_nat_id[OF i_less_card] by simp
have "to_nat j = least_non_zero_position_of_vector (row_iarray ([0..<nrows_iarray (matrix_to_iarray A)] ! i) (matrix_to_iarray A))" using j_eq .
also have "... = least_non_zero_position_of_vector_from_index (row_iarray i (matrix_to_iarray A)) 0"
unfolding least_non_zero_position_of_vector_def i_rw ..
also have "... = least_non_zero_position_of_vector_from_index (vec_to_iarray (row (from_nat i) A)) (to_nat (0::'cols))" unfolding vec_to_iarray_row
unfolding to_nat_from_nat_id[OF i_less_card] unfolding to_nat_0 ..
also have "... = to_nat (LEAST n. A $ (from_nat i) $ n ≠ 0 ∧ 0 ≤ n)"
proof (rule vec_to_iarray_least_non_zero_position_of_vector_from_index'')
show "¬ vector_all_zero_from_index (to_nat (0::'cols), vec_to_iarray (row (from_nat i) A))"
unfolding vector_all_zero_from_index_eq[symmetric] using A_ij by (metis iarray_to_vec_vec_to_iarray least_mod_type vec_matrix vec_to_iarray_row' zero_neq_one)
qed
also have "... = to_nat (LEAST n. A $ (from_nat i) $ n ≠ 0)" using least_mod_type by metis
finally show "j = (LEAST n. A $ from_nat i $ n ≠ 0)" unfolding to_nat_eq .
qed
qed
lemma to_nat_the_solve_consistent_rref:
fixes A::"'a::{field}^'cols::{mod_type}^'rows::{mod_type}"
assumes rref: "reduced_row_echelon_form A"
and exists: "(∃i. A $ i $ j = 1 ∧ j = (LEAST n. A $ i $ n ≠ 0))"
shows "to_nat (THE i. A $ i $ j = 1) = least_non_zero_position_of_vector (column_iarray (to_nat j) (matrix_to_iarray A))"
proof -
obtain i where Aij: "A $ i $ j = 1" and j:"j = (LEAST n. A $ i $ n ≠ 0)" using exists by blast
have "least_non_zero_position_of_vector (column_iarray (to_nat j) (matrix_to_iarray A)) =
least_non_zero_position_of_vector (vec_to_iarray (column j A))" unfolding vec_to_iarray_column ..
also have "... = least_non_zero_position_of_vector_from_index (vec_to_iarray (column j A)) (to_nat (0::'rows))" unfolding least_non_zero_position_of_vector_def to_nat_0 ..
also have "... = to_nat (LEAST n. A $ n $ j ≠ 0 ∧ 0 ≤ n)"
proof (rule vec_to_iarray_least_non_zero_position_of_vector_from_index')
show "¬ vector_all_zero_from_index (to_nat (0::'rows), vec_to_iarray (column j A))"
unfolding vector_all_zero_from_index_eq[symmetric] column_def using Aij least_mod_type[of i] by fastforce
qed
also have "... = to_nat (LEAST n. A $ n $ j ≠ 0)" using least_mod_type by metis
finally have least_eq: "least_non_zero_position_of_vector (column_iarray (to_nat j) (matrix_to_iarray A)) = to_nat (LEAST n. A $ n $ j ≠ 0)" .
have i_eq_least: "i=(LEAST n. A $ n $ j ≠ 0)"
proof (rule Least_equality[symmetric])
show "A $ i $ j ≠ 0" by (metis Aij zero_neq_one)
show "⋀y. A $ y $ j ≠ 0 ⟹ i ≤ y" by (metis (mono_tags) Aij is_zero_row_def' j order_refl rref rref_condition4 zero_neq_one)
qed
have the_eq_least_pos: "(THE i. A $ i $ j = 1) = from_nat (least_non_zero_position_of_vector (column_iarray (to_nat j) (matrix_to_iarray A)))"
proof (rule the_equality)
show " A $ from_nat (least_non_zero_position_of_vector (column_iarray (to_nat j) (matrix_to_iarray A))) $ j = 1"
unfolding least_eq from_nat_to_nat_id i_eq_least[symmetric] using Aij .
fix a assume a: "A $ a $ j = 1"
show "a = from_nat (least_non_zero_position_of_vector (column_iarray (to_nat j) (matrix_to_iarray A)))"
unfolding least_eq from_nat_to_nat_id
by (metis Aij a i_eq_least is_zero_row_def' j rref rref_condition4_explicit zero_neq_one)
qed
have "to_nat (THE i. A $ i $ j = 1) = to_nat (from_nat (least_non_zero_position_of_vector (column_iarray (to_nat j) (matrix_to_iarray A)))::'rows)" using the_eq_least_pos by auto
also have "... = (least_non_zero_position_of_vector (column_iarray (to_nat j) (matrix_to_iarray A)))" by (rule to_nat_from_nat_id, unfold least_eq, simp add: to_nat_less_card)
also have "... = to_nat (LEAST n. A $ n $ j ≠ 0)" unfolding least_eq from_nat_to_nat_id ..
finally have "(THE i. A $ i $ j = 1) = (LEAST n. A $ n $ j ≠ 0)" unfolding to_nat_eq .
thus ?thesis unfolding least_eq from_nat_to_nat_id unfolding to_nat_eq .
qed
lemma iarray_exhaust2:
"(xs = ys) = (IArray.list_of xs = IArray.list_of ys)"
by (metis iarray.exhaust list_of.simps)
lemma vec_to_iarray_solve_consistent_rref:
fixes A::"'a::{field}^'cols::{mod_type}^'rows::{mod_type}"
assumes rref: "reduced_row_echelon_form A"
shows "vec_to_iarray (solve_consistent_rref A b) = solve_consistent_rref_iarrays (matrix_to_iarray A) (vec_to_iarray b)"
proof(unfold iarray_exhaust2 list_eq_iff_nth_eq IArray.length_def[symmetric] IArray.sub_def[symmetric], rule conjI)
show "IArray.length (vec_to_iarray (solve_consistent_rref A b)) = IArray.length (solve_consistent_rref_iarrays (matrix_to_iarray A) (vec_to_iarray b))"
unfolding solve_consistent_rref_def solve_consistent_rref_iarrays_def
unfolding ncols_iarray_def matrix_to_iarray_def by (simp add: vec_to_iarray_def)
show "∀i<IArray.length (vec_to_iarray (solve_consistent_rref A b)). vec_to_iarray (solve_consistent_rref A b) !! i = solve_consistent_rref_iarrays (matrix_to_iarray A) (vec_to_iarray b) !! i"
proof (clarify)
fix i assume i: "i < IArray.length (vec_to_iarray (solve_consistent_rref A b))"
hence i_less_card: "i<CARD('cols)" unfolding vec_to_iarray_def by auto
hence i_less_ncols: "i<(ncols_iarray (matrix_to_iarray A))" unfolding ncols_eq_card_columns .
show "vec_to_iarray (solve_consistent_rref A b) !! i = solve_consistent_rref_iarrays (matrix_to_iarray A) (vec_to_iarray b) !! i"
unfolding vec_to_iarray_nth[OF i_less_card]
unfolding solve_consistent_rref_def
unfolding vec_lambda_beta
unfolding solve_consistent_rref_iarrays_def
unfolding of_fun_nth[OF i_less_ncols]
unfolding exists_solve_consistent_rref[OF rref, of "from_nat i", symmetric, unfolded to_nat_from_nat_id[OF i_less_card]]
using to_nat_the_solve_consistent_rref[OF rref, of "from_nat i", symmetric, unfolded to_nat_from_nat_id[OF i_less_card]]
using vec_to_iarray_nth' by metis
qed
qed
subsection‹Independence and dependence›
definition "independent_and_consistent_iarrays A b =
(let GJ = Gauss_Jordan_iarrays_PA A;
rank_A = length [x←IArray.list_of (snd GJ) . ¬ is_zero_iarray x];
P_mult_b = fst GJ *iv b;
consistent_A = ((if ¬ is_zero_iarray P_mult_b then greatest_not_zero P_mult_b + 1 else 0) ≤ rank_A);
dim_solution_set = ncols_iarray A - rank_A
in consistent_A ∧ dim_solution_set = 0)"
definition "dependent_and_consistent_iarrays A b =
(let GJ = Gauss_Jordan_iarrays_PA A;
rank_A = length [x←IArray.list_of (snd GJ) . ¬ is_zero_iarray x];
P_mult_b = fst GJ *iv b;
consistent_A = ((if ¬ is_zero_iarray P_mult_b then greatest_not_zero P_mult_b + 1 else 0) ≤ rank_A);
dim_solution_set = ncols_iarray A - rank_A
in consistent_A ∧ dim_solution_set > 0)"
lemma matrix_to_iarray_independent_and_consistent[code]:
shows "independent_and_consistent A b = independent_and_consistent_iarrays (matrix_to_iarray A) (vec_to_iarray b)"
unfolding independent_and_consistent_def
unfolding independent_and_consistent_iarrays_def
unfolding dim_solution_set_homogeneous_eq_dim_null_space
unfolding matrix_to_iarray_consistent
unfolding consistent_iarrays_def
unfolding dim_null_space_iarray
unfolding rank_iarrays_code
unfolding snd_Gauss_Jordan_iarrays_PA_eq[symmetric]
unfolding Let_def ..
lemma matrix_to_iarray_dependent_and_consistent[code]:
shows "dependent_and_consistent A b = dependent_and_consistent_iarrays (matrix_to_iarray A) (vec_to_iarray b)"
unfolding dependent_and_consistent_def
unfolding dependent_and_consistent_iarrays_def
unfolding dim_solution_set_homogeneous_eq_dim_null_space
unfolding matrix_to_iarray_consistent
unfolding consistent_iarrays_def
unfolding dim_null_space_iarray
unfolding rank_iarrays_code
unfolding snd_Gauss_Jordan_iarrays_PA_eq[symmetric]
unfolding Let_def ..
subsection‹Solve a system of equations over nested IArrays›
definition "solve_system_iarrays A b = (let A' = Gauss_Jordan_iarrays_PA A in (snd A', fst A' *iv b))"
lemma matrix_to_iarray_fst_solve_system: "matrix_to_iarray (fst (solve_system A b)) = fst (solve_system_iarrays (matrix_to_iarray A) (vec_to_iarray b))"
unfolding solve_system_def solve_system_iarrays_def Let_def fst_conv
by (metis matrix_to_iarray_snd_Gauss_Jordan_PA)
lemma vec_to_iarray_snd_solve_system: "vec_to_iarray (snd (solve_system A b)) = snd (solve_system_iarrays (matrix_to_iarray A) (vec_to_iarray b))"
unfolding solve_system_def solve_system_iarrays_def Let_def snd_conv
by (metis matrix_to_iarray_fst_Gauss_Jordan_PA vec_to_iarray_matrix_matrix_mult)
definition "solve_iarrays A b = (let GJ_P=Gauss_Jordan_iarrays_PA A;
P_mult_b = fst GJ_P *iv b;
rank_A = length [x←IArray.list_of (snd GJ_P) . ¬ is_zero_iarray x];
consistent_Ab = (if ¬ is_zero_iarray P_mult_b then greatest_not_zero P_mult_b + 1 else 0) ≤ rank_A;
GJ_transpose = Gauss_Jordan_iarrays_PA (transpose_iarray A);
basis = set (map (λi. row_iarray i (fst GJ_transpose)) [rank_A..<ncols_iarray A])
in (if consistent_Ab then Some (solve_consistent_rref_iarrays (snd GJ_P) P_mult_b,basis) else None))"
definition "pair_vec_vecset A = (if Option.is_none A then None else Some (vec_to_iarray (fst (the A)), vec_to_iarray` (snd (the A))))"
lemma pair_vec_vecset_solve[code_unfold]:
shows "pair_vec_vecset (solve A b) = solve_iarrays (matrix_to_iarray A) (vec_to_iarray b)"
unfolding pair_vec_vecset_def
proof (auto)
assume none_solve_Ab: "Option.is_none (solve A b)"
show "None = solve_iarrays (matrix_to_iarray A) (vec_to_iarray b)"
proof -
define GJ_P where "GJ_P = Gauss_Jordan_iarrays_PA (matrix_to_iarray A)"
define P_mult_b where "P_mult_b = fst GJ_P *iv vec_to_iarray b"
define rank_A where "rank_A = length [x←IArray.list_of (snd GJ_P). ¬ is_zero_iarray x]"
have "¬ consistent A b" using none_solve_Ab unfolding solve_def unfolding Option.is_none_def by auto
hence "¬ consistent_iarrays (matrix_to_iarray A) (vec_to_iarray b)" using matrix_to_iarray_consistent by auto
hence "¬ (if ¬ is_zero_iarray P_mult_b then greatest_not_zero P_mult_b + 1 else 0) ≤ rank_A"
unfolding GJ_P_def P_mult_b_def rank_A_def
using consistent_iarrays_def unfolding Let_def by fast
thus ?thesis unfolding solve_iarrays_def Let_def unfolding GJ_P_def P_mult_b_def rank_A_def by presburger
qed
next
assume not_none: "¬ Option.is_none (solve A b)"
show "Some (vec_to_iarray (fst (the (solve A b))), vec_to_iarray ` snd (the (solve A b))) = solve_iarrays (matrix_to_iarray A) (vec_to_iarray b)"
proof -
define GJ_P where "GJ_P = Gauss_Jordan_iarrays_PA (matrix_to_iarray A)"
define P_mult_b where "P_mult_b = fst GJ_P *iv vec_to_iarray b"
define rank_A where "rank_A = length [x←IArray.list_of (snd GJ_P) . ¬ is_zero_iarray x]"
define GJ_transpose where "GJ_transpose = Gauss_Jordan_iarrays_PA (transpose_iarray (matrix_to_iarray A))"
define basis where "basis = set (map (λi. row_iarray i (fst GJ_transpose)) [rank_A..<ncols_iarray (matrix_to_iarray A)])"
define P_mult_b where "P_mult_b = fst GJ_P *iv vec_to_iarray b"
have consistent_Ab: "consistent A b" using not_none unfolding solve_def unfolding Option.is_none_def by metis
hence "consistent_iarrays (matrix_to_iarray A) (vec_to_iarray b)" using matrix_to_iarray_consistent by auto
hence "(if ¬ is_zero_iarray P_mult_b then greatest_not_zero P_mult_b + 1 else 0) ≤ rank_A"
unfolding GJ_P_def P_mult_b_def rank_A_def
using consistent_iarrays_def unfolding Let_def by fast
hence solve_iarrays_rw: "solve_iarrays (matrix_to_iarray A) (vec_to_iarray b) = Some (solve_consistent_rref_iarrays (snd GJ_P) P_mult_b, basis)"
unfolding solve_iarrays_def Let_def P_mult_b_def GJ_P_def rank_A_def basis_def GJ_transpose_def by auto
have snd_rw: "vec_to_iarray ` basis_null_space A = basis" unfolding basis_def GJ_transpose_def rank_A_def GJ_P_def
unfolding vec_to_iarray_basis_null_space unfolding basis_null_space_iarrays_def Let_def
unfolding snd_Gauss_Jordan_iarrays_PA_eq
unfolding rank_iarrays_code[symmetric]
unfolding matrix_to_iarray_transpose[symmetric]
unfolding matrix_to_iarray_rank[symmetric]
unfolding rank_transpose[symmetric, of A] ..
have fst_rw: "vec_to_iarray (solve_consistent_rref (fst (solve_system A b)) (snd (solve_system A b))) = solve_consistent_rref_iarrays (snd GJ_P) P_mult_b"
using vec_to_iarray_solve_consistent_rref[OF rref_Gauss_Jordan, of A "fst (Gauss_Jordan_PA A) *v b"]
unfolding solve_system_def Let_def fst_conv
unfolding Gauss_Jordan_PA_eq snd_conv
unfolding GJ_P_def P_mult_b_def
unfolding vec_to_iarray_matrix_matrix_mult
unfolding matrix_to_iarray_fst_Gauss_Jordan_PA[symmetric]
unfolding matrix_to_iarray_snd_Gauss_Jordan_PA[symmetric]
unfolding Gauss_Jordan_PA_eq .
show ?thesis unfolding solve_iarrays_rw
unfolding solve_def if_P[OF consistent_Ab] option.sel fst_conv snd_conv
unfolding fst_rw snd_rw ..
qed
qed
end