diff -r 0f4d4a13dc16 -r a8faf6f15da7 src/HOL/Analysis/Cartesian_Space.thy --- a/src/HOL/Analysis/Cartesian_Space.thy Thu Jan 17 15:50:28 2019 +0000 +++ b/src/HOL/Analysis/Cartesian_Space.thy Thu Jan 17 16:08:41 2019 +0000 @@ -930,4 +930,492 @@ lemma%unimportant const_vector_cart:"((\ i. d)::real^'n) = (\i\Basis. d *\<^sub>R i)" by (rule vector_cart) +subsection%unimportant \Explicit formulas for low dimensions\ + +lemma%unimportant prod_neutral_const: "prod f {(1::nat)..1} = f 1" + by simp + +lemma%unimportant prod_2: "prod f {(1::nat)..2} = f 1 * f 2" + by (simp add: eval_nat_numeral atLeastAtMostSuc_conv mult.commute) + +lemma%unimportant prod_3: "prod f {(1::nat)..3} = f 1 * f 2 * f 3" + by (simp add: eval_nat_numeral atLeastAtMostSuc_conv mult.commute) + + +subsection%important \Orthogonality of a matrix\ + +definition%important "orthogonal_matrix (Q::'a::semiring_1^'n^'n) \ + transpose Q ** Q = mat 1 \ Q ** transpose Q = mat 1" + +lemma%unimportant orthogonal_matrix: "orthogonal_matrix (Q:: real ^'n^'n) \ transpose Q ** Q = mat 1" + by (metis matrix_left_right_inverse orthogonal_matrix_def) + +lemma%unimportant orthogonal_matrix_id: "orthogonal_matrix (mat 1 :: _^'n^'n)" + by (simp add: orthogonal_matrix_def) + +lemma%unimportant orthogonal_matrix_mul: + fixes A :: "real ^'n^'n" + assumes "orthogonal_matrix A" "orthogonal_matrix B" + shows "orthogonal_matrix(A ** B)" + using assms + by (simp add: orthogonal_matrix matrix_transpose_mul matrix_left_right_inverse matrix_mul_assoc) + +lemma%important orthogonal_transformation_matrix: + fixes f:: "real^'n \ real^'n" + shows "orthogonal_transformation f \ linear f \ orthogonal_matrix(matrix f)" + (is "?lhs \ ?rhs") +proof%unimportant - + let ?mf = "matrix f" + let ?ot = "orthogonal_transformation f" + let ?U = "UNIV :: 'n set" + have fU: "finite ?U" by simp + let ?m1 = "mat 1 :: real ^'n^'n" + { + assume ot: ?ot + from ot have lf: "Vector_Spaces.linear (*s) (*s) f" and fd: "\v w. f v \ f w = v \ w" + unfolding orthogonal_transformation_def orthogonal_matrix linear_def scalar_mult_eq_scaleR + by blast+ + { + fix i j + let ?A = "transpose ?mf ** ?mf" + have th0: "\b (x::'a::comm_ring_1). (if b then 1 else 0)*x = (if b then x else 0)" + "\b (x::'a::comm_ring_1). x*(if b then 1 else 0) = (if b then x else 0)" + by simp_all + from fd[of "axis i 1" "axis j 1", + simplified matrix_works[OF lf, symmetric] dot_matrix_vector_mul] + have "?A$i$j = ?m1 $ i $ j" + by (simp add: inner_vec_def matrix_matrix_mult_def columnvector_def rowvector_def + th0 sum.delta[OF fU] mat_def axis_def) + } + then have "orthogonal_matrix ?mf" + unfolding orthogonal_matrix + by vector + with lf have ?rhs + unfolding linear_def scalar_mult_eq_scaleR + by blast + } + moreover + { + assume lf: "Vector_Spaces.linear (*s) (*s) f" and om: "orthogonal_matrix ?mf" + from lf om have ?lhs + unfolding orthogonal_matrix_def norm_eq orthogonal_transformation + apply (simp only: matrix_works[OF lf, symmetric] dot_matrix_vector_mul) + apply (simp add: dot_matrix_product linear_def scalar_mult_eq_scaleR) + done + } + ultimately show ?thesis + by (auto simp: linear_def scalar_mult_eq_scaleR) +qed + + +subsection%important \ We can find an orthogonal matrix taking any unit vector to any other\ + +lemma%unimportant orthogonal_matrix_transpose [simp]: + "orthogonal_matrix(transpose A) \ orthogonal_matrix A" + by (auto simp: orthogonal_matrix_def) + +lemma%unimportant orthogonal_matrix_orthonormal_columns: + fixes A :: "real^'n^'n" + shows "orthogonal_matrix A \ + (\i. norm(column i A) = 1) \ + (\i j. i \ j \ orthogonal (column i A) (column j A))" + by (auto simp: orthogonal_matrix matrix_mult_transpose_dot_column vec_eq_iff mat_def norm_eq_1 orthogonal_def) + +lemma%unimportant orthogonal_matrix_orthonormal_rows: + fixes A :: "real^'n^'n" + shows "orthogonal_matrix A \ + (\i. norm(row i A) = 1) \ + (\i j. i \ j \ orthogonal (row i A) (row j A))" + using orthogonal_matrix_orthonormal_columns [of "transpose A"] by simp + +lemma%important orthogonal_matrix_exists_basis: + fixes a :: "real^'n" + assumes "norm a = 1" + obtains A where "orthogonal_matrix A" "A *v (axis k 1) = a" +proof%unimportant - + obtain S where "a \ S" "pairwise orthogonal S" and noS: "\x. x \ S \ norm x = 1" + and "independent S" "card S = CARD('n)" "span S = UNIV" + using vector_in_orthonormal_basis assms by force + then obtain f0 where "bij_betw f0 (UNIV::'n set) S" + by (metis finite_class.finite_UNIV finite_same_card_bij finiteI_independent) + then obtain f where f: "bij_betw f (UNIV::'n set) S" and a: "a = f k" + using bij_swap_iff [of k "inv f0 a" f0] + by (metis UNIV_I \a \ S\ bij_betw_inv_into_right bij_betw_swap_iff swap_apply(1)) + show thesis + proof + have [simp]: "\i. norm (f i) = 1" + using bij_betwE [OF \bij_betw f UNIV S\] by (blast intro: noS) + have [simp]: "\i j. i \ j \ orthogonal (f i) (f j)" + using \pairwise orthogonal S\ \bij_betw f UNIV S\ + by (auto simp: pairwise_def bij_betw_def inj_on_def) + show "orthogonal_matrix (\ i j. f j $ i)" + by (simp add: orthogonal_matrix_orthonormal_columns column_def) + show "(\ i j. f j $ i) *v axis k 1 = a" + by (simp add: matrix_vector_mult_def axis_def a if_distrib cong: if_cong) + qed +qed + +lemma%unimportant orthogonal_transformation_exists_1: + fixes a b :: "real^'n" + assumes "norm a = 1" "norm b = 1" + obtains f where "orthogonal_transformation f" "f a = b" +proof%unimportant - + obtain k::'n where True + by simp + obtain A B where AB: "orthogonal_matrix A" "orthogonal_matrix B" and eq: "A *v (axis k 1) = a" "B *v (axis k 1) = b" + using orthogonal_matrix_exists_basis assms by metis + let ?f = "\x. (B ** transpose A) *v x" + show thesis + proof + show "orthogonal_transformation ?f" + by (subst orthogonal_transformation_matrix) + (auto simp: AB orthogonal_matrix_mul) + next + show "?f a = b" + using \orthogonal_matrix A\ unfolding orthogonal_matrix_def + by (metis eq matrix_mul_rid matrix_vector_mul_assoc) + qed +qed + +lemma%important orthogonal_transformation_exists: + fixes a b :: "real^'n" + assumes "norm a = norm b" + obtains f where "orthogonal_transformation f" "f a = b" +proof%unimportant (cases "a = 0 \ b = 0") + case True + with assms show ?thesis + using that by force +next + case False + then obtain f where f: "orthogonal_transformation f" and eq: "f (a /\<^sub>R norm a) = (b /\<^sub>R norm b)" + by (auto intro: orthogonal_transformation_exists_1 [of "a /\<^sub>R norm a" "b /\<^sub>R norm b"]) + show ?thesis + proof + interpret linear f + using f by (simp add: orthogonal_transformation_linear) + have "f a /\<^sub>R norm a = f (a /\<^sub>R norm a)" + by (simp add: scale) + also have "\ = b /\<^sub>R norm a" + by (simp add: eq assms [symmetric]) + finally show "f a = b" + using False by auto + qed (use f in auto) +qed + + +subsection%important \Linearity of scaling, and hence isometry, that preserves origin\ + +lemma%important scaling_linear: + fixes f :: "'a::real_inner \ 'a::real_inner" + assumes f0: "f 0 = 0" + and fd: "\x y. dist (f x) (f y) = c * dist x y" + shows "linear f" +proof%unimportant - + { + fix v w + have "norm (f x) = c * norm x" for x + by (metis dist_0_norm f0 fd) + then have "f v \ f w = c\<^sup>2 * (v \ w)" + unfolding dot_norm_neg dist_norm[symmetric] + by (simp add: fd power2_eq_square field_simps) + } + then show ?thesis + unfolding linear_iff vector_eq[where 'a="'a"] scalar_mult_eq_scaleR + by (simp add: inner_add field_simps) +qed + +lemma%unimportant isometry_linear: + "f (0::'a::real_inner) = (0::'a) \ \x y. dist(f x) (f y) = dist x y \ linear f" + by (rule scaling_linear[where c=1]) simp_all + +text \Hence another formulation of orthogonal transformation\ + +lemma%important orthogonal_transformation_isometry: + "orthogonal_transformation f \ f(0::'a::real_inner) = (0::'a) \ (\x y. dist(f x) (f y) = dist x y)" + unfolding orthogonal_transformation + apply (auto simp: linear_0 isometry_linear) + apply (metis (no_types, hide_lams) dist_norm linear_diff) + by (metis dist_0_norm) + + +subsection%important \Can extend an isometry from unit sphere\ + +lemma%important isometry_sphere_extend: + fixes f:: "'a::real_inner \ 'a" + assumes f1: "\x. norm x = 1 \ norm (f x) = 1" + and fd1: "\x y. \norm x = 1; norm y = 1\ \ dist (f x) (f y) = dist x y" + shows "\g. orthogonal_transformation g \ (\x. norm x = 1 \ g x = f x)" +proof%unimportant - + { + fix x y x' y' u v u' v' :: "'a" + assume H: "x = norm x *\<^sub>R u" "y = norm y *\<^sub>R v" + "x' = norm x *\<^sub>R u'" "y' = norm y *\<^sub>R v'" + and J: "norm u = 1" "norm u' = 1" "norm v = 1" "norm v' = 1" "norm(u' - v') = norm(u - v)" + then have *: "u \ v = u' \ v' + v' \ u' - v \ u " + by (simp add: norm_eq norm_eq_1 inner_add inner_diff) + have "norm (norm x *\<^sub>R u' - norm y *\<^sub>R v') = norm (norm x *\<^sub>R u - norm y *\<^sub>R v)" + using J by (simp add: norm_eq norm_eq_1 inner_diff * field_simps) + then have "norm(x' - y') = norm(x - y)" + using H by metis + } + note norm_eq = this + let ?g = "\x. if x = 0 then 0 else norm x *\<^sub>R f (x /\<^sub>R norm x)" + have thfg: "?g x = f x" if "norm x = 1" for x + using that by auto + have thd: "dist (?g x) (?g y) = dist x y" for x y + proof (cases "x=0 \ y=0") + case False + show "dist (?g x) (?g y) = dist x y" + unfolding dist_norm + proof (rule norm_eq) + show "x = norm x *\<^sub>R (x /\<^sub>R norm x)" "y = norm y *\<^sub>R (y /\<^sub>R norm y)" + "norm (f (x /\<^sub>R norm x)) = 1" "norm (f (y /\<^sub>R norm y)) = 1" + using False f1 by auto + qed (use False in \auto simp: field_simps intro: f1 fd1[unfolded dist_norm]\) + qed (auto simp: f1) + show ?thesis + unfolding orthogonal_transformation_isometry + by (rule exI[where x= ?g]) (metis thfg thd) +qed + +subsection%important\Induction on matrix row operations\ + +lemma%unimportant induct_matrix_row_operations: + fixes P :: "real^'n^'n \ bool" + assumes zero_row: "\A i. row i A = 0 \ P A" + and diagonal: "\A. (\i j. i \ j \ A$i$j = 0) \ P A" + and swap_cols: "\A m n. \P A; m \ n\ \ P(\ i j. A $ i $ Fun.swap m n id j)" + and row_op: "\A m n c. \P A; m \ n\ + \ P(\ i. if i = m then row m A + c *\<^sub>R row n A else row i A)" + shows "P A" +proof - + have "P A" if "(\i j. \j \ -K; i \ j\ \ A$i$j = 0)" for A K + proof - + have "finite K" + by simp + then show ?thesis using that + proof (induction arbitrary: A rule: finite_induct) + case empty + with diagonal show ?case + by simp + next + case (insert k K) + note insertK = insert + have "P A" if kk: "A$k$k \ 0" + and 0: "\i j. \j \ - insert k K; i \ j\ \ A$i$j = 0" + "\i. \i \ -L; i \ k\ \ A$i$k = 0" for A L + proof - + have "finite L" + by simp + then show ?thesis using 0 kk + proof (induction arbitrary: A rule: finite_induct) + case (empty B) + show ?case + proof (rule insertK) + fix i j + assume "i \ - K" "j \ i" + show "B $ j $ i = 0" + using \j \ i\ \i \ - K\ empty + by (metis ComplD ComplI Compl_eq_Diff_UNIV Diff_empty UNIV_I insert_iff) + qed + next + case (insert l L B) + show ?case + proof (cases "k = l") + case True + with insert show ?thesis + by auto + next + case False + let ?C = "\ i. if i = l then row l B - (B $ l $ k / B $ k $ k) *\<^sub>R row k B else row i B" + have 1: "\j \ - insert k K; i \ j\ \ ?C $ i $ j = 0" for j i + by (auto simp: insert.prems(1) row_def) + have 2: "?C $ i $ k = 0" + if "i \ - L" "i \ k" for i + proof (cases "i=l") + case True + with that insert.prems show ?thesis + by (simp add: row_def) + next + case False + with that show ?thesis + by (simp add: insert.prems(2) row_def) + qed + have 3: "?C $ k $ k \ 0" + by (auto simp: insert.prems row_def \k \ l\) + have PC: "P ?C" + using insert.IH [OF 1 2 3] by auto + have eqB: "(\ i. if i = l then row l ?C + (B $ l $ k / B $ k $ k) *\<^sub>R row k ?C else row i ?C) = B" + using \k \ l\ by (simp add: vec_eq_iff row_def) + show ?thesis + using row_op [OF PC, of l k, where c = "B$l$k / B$k$k"] eqB \k \ l\ + by (simp add: cong: if_cong) + qed + qed + qed + then have nonzero_hyp: "P A" + if kk: "A$k$k \ 0" and zeroes: "\i j. j \ - insert k K \ i\j \ A$i$j = 0" for A + by (auto simp: intro!: kk zeroes) + show ?case + proof (cases "row k A = 0") + case True + with zero_row show ?thesis by auto + next + case False + then obtain l where l: "A$k$l \ 0" + by (auto simp: row_def zero_vec_def vec_eq_iff) + show ?thesis + proof (cases "k = l") + case True + with l nonzero_hyp insert.prems show ?thesis + by blast + next + case False + have *: "A $ i $ Fun.swap k l id j = 0" if "j \ k" "j \ K" "i \ j" for i j + using False l insert.prems that + by (auto simp: swap_def insert split: if_split_asm) + have "P (\ i j. (\ i j. A $ i $ Fun.swap k l id j) $ i $ Fun.swap k l id j)" + by (rule swap_cols [OF nonzero_hyp False]) (auto simp: l *) + moreover + have "(\ i j. (\ i j. A $ i $ Fun.swap k l id j) $ i $ Fun.swap k l id j) = A" + by (vector Fun.swap_def) + ultimately show ?thesis + by simp + qed + qed + qed + qed + then show ?thesis + by blast +qed + +lemma%unimportant induct_matrix_elementary: + fixes P :: "real^'n^'n \ bool" + assumes mult: "\A B. \P A; P B\ \ P(A ** B)" + and zero_row: "\A i. row i A = 0 \ P A" + and diagonal: "\A. (\i j. i \ j \ A$i$j = 0) \ P A" + and swap1: "\m n. m \ n \ P(\ i j. mat 1 $ i $ Fun.swap m n id j)" + and idplus: "\m n c. m \ n \ P(\ i j. if i = m \ j = n then c else of_bool (i = j))" + shows "P A" +proof - + have swap: "P (\ i j. A $ i $ Fun.swap m n id j)" (is "P ?C") + if "P A" "m \ n" for A m n + proof - + have "A ** (\ i j. mat 1 $ i $ Fun.swap m n id j) = ?C" + by (simp add: matrix_matrix_mult_def mat_def vec_eq_iff if_distrib sum.delta_remove) + then show ?thesis + using mult swap1 that by metis + qed + have row: "P (\ i. if i = m then row m A + c *\<^sub>R row n A else row i A)" (is "P ?C") + if "P A" "m \ n" for A m n c + proof - + let ?B = "\ i j. if i = m \ j = n then c else of_bool (i = j)" + have "?B ** A = ?C" + using \m \ n\ unfolding matrix_matrix_mult_def row_def of_bool_def + by (auto simp: vec_eq_iff if_distrib [of "\x. x * y" for y] sum.remove cong: if_cong) + then show ?thesis + by (rule subst) (auto simp: that mult idplus) + qed + show ?thesis + by (rule induct_matrix_row_operations [OF zero_row diagonal swap row]) +qed + +lemma%unimportant induct_matrix_elementary_alt: + fixes P :: "real^'n^'n \ bool" + assumes mult: "\A B. \P A; P B\ \ P(A ** B)" + and zero_row: "\A i. row i A = 0 \ P A" + and diagonal: "\A. (\i j. i \ j \ A$i$j = 0) \ P A" + and swap1: "\m n. m \ n \ P(\ i j. mat 1 $ i $ Fun.swap m n id j)" + and idplus: "\m n. m \ n \ P(\ i j. of_bool (i = m \ j = n \ i = j))" + shows "P A" +proof - + have *: "P (\ i j. if i = m \ j = n then c else of_bool (i = j))" + if "m \ n" for m n c + proof (cases "c = 0") + case True + with diagonal show ?thesis by auto + next + case False + then have eq: "(\ i j. if i = m \ j = n then c else of_bool (i = j)) = + (\ i j. if i = j then (if j = n then inverse c else 1) else 0) ** + (\ i j. of_bool (i = m \ j = n \ i = j)) ** + (\ i j. if i = j then if j = n then c else 1 else 0)" + using \m \ n\ + apply (simp add: matrix_matrix_mult_def vec_eq_iff of_bool_def if_distrib [of "\x. y * x" for y] cong: if_cong) + apply (simp add: if_if_eq_conj sum.neutral conj_commute cong: conj_cong) + done + show ?thesis + apply (subst eq) + apply (intro mult idplus that) + apply (auto intro: diagonal) + done + qed + show ?thesis + by (rule induct_matrix_elementary) (auto intro: assms *) +qed + +lemma%unimportant matrix_vector_mult_matrix_matrix_mult_compose: + "(*v) (A ** B) = (*v) A \ (*v) B" + by (auto simp: matrix_vector_mul_assoc) + +lemma%unimportant induct_linear_elementary: + fixes f :: "real^'n \ real^'n" + assumes "linear f" + and comp: "\f g. \linear f; linear g; P f; P g\ \ P(f \ g)" + and zeroes: "\f i. \linear f; \x. (f x) $ i = 0\ \ P f" + and const: "\c. P(\x. \ i. c i * x$i)" + and swap: "\m n::'n. m \ n \ P(\x. \ i. x $ Fun.swap m n id i)" + and idplus: "\m n::'n. m \ n \ P(\x. \ i. if i = m then x$m + x$n else x$i)" + shows "P f" +proof - + have "P ((*v) A)" for A + proof (rule induct_matrix_elementary_alt) + fix A B + assume "P ((*v) A)" and "P ((*v) B)" + then show "P ((*v) (A ** B))" + by (auto simp add: matrix_vector_mult_matrix_matrix_mult_compose matrix_vector_mul_linear + intro!: comp) + next + fix A :: "real^'n^'n" and i + assume "row i A = 0" + show "P ((*v) A)" + using matrix_vector_mul_linear + by (rule zeroes[where i=i]) + (metis \row i A = 0\ inner_zero_left matrix_vector_mul_component row_def vec_lambda_eta) + next + fix A :: "real^'n^'n" + assume 0: "\i j. i \ j \ A $ i $ j = 0" + have "A $ i $ i * x $ i = (\j\UNIV. A $ i $ j * x $ j)" for x and i :: "'n" + by (simp add: 0 comm_monoid_add_class.sum.remove [where x=i]) + then have "(\x. \ i. A $ i $ i * x $ i) = ((*v) A)" + by (auto simp: 0 matrix_vector_mult_def) + then show "P ((*v) A)" + using const [of "\i. A $ i $ i"] by simp + next + fix m n :: "'n" + assume "m \ n" + have eq: "(\j\UNIV. if i = Fun.swap m n id j then x $ j else 0) = + (\j\UNIV. if j = Fun.swap m n id i then x $ j else 0)" + for i and x :: "real^'n" + unfolding swap_def by (rule sum.cong) auto + have "(\x::real^'n. \ i. x $ Fun.swap m n id i) = ((*v) (\ i j. if i = Fun.swap m n id j then 1 else 0))" + by (auto simp: mat_def matrix_vector_mult_def eq if_distrib [of "\x. x * y" for y] cong: if_cong) + with swap [OF \m \ n\] show "P ((*v) (\ i j. mat 1 $ i $ Fun.swap m n id j))" + by (simp add: mat_def matrix_vector_mult_def) + next + fix m n :: "'n" + assume "m \ n" + then have "x $ m + x $ n = (\j\UNIV. of_bool (j = n \ m = j) * x $ j)" for x :: "real^'n" + by (auto simp: of_bool_def if_distrib [of "\x. x * y" for y] sum.remove cong: if_cong) + then have "(\x::real^'n. \ i. if i = m then x $ m + x $ n else x $ i) = + ((*v) (\ i j. of_bool (i = m \ j = n \ i = j)))" + unfolding matrix_vector_mult_def of_bool_def + by (auto simp: vec_eq_iff if_distrib [of "\x. x * y" for y] cong: if_cong) + then show "P ((*v) (\ i j. of_bool (i = m \ j = n \ i = j)))" + using idplus [OF \m \ n\] by simp + qed + then show ?thesis + by (metis \linear f\ matrix_vector_mul) +qed + end \ No newline at end of file