from big_ol_pile_of_manim_imports import * from old_projects.eola.chapter1 import plane_wave_homotopy from old_projects.eola.chapter3 import ColumnsToBasisVectors from old_projects.eola.chapter5 import get_det_text from old_projects.eola.chapter9 import get_small_bubble class OpeningQuote(Scene): def construct(self): words = TextMobject( "``Last time, I asked: `What does", "mathematics", """ mean to you?', and some people answered: `The manipulation of numbers, the manipulation of structures.' And if I had asked what""", "music", """means to you, would you have answered: `The manipulation of notes?' '' """, enforce_new_line_structure = False, alignment = "", ) words.set_color_by_tex("mathematics", BLUE) words.set_color_by_tex("music", BLUE) words.set_width(FRAME_WIDTH - 2) words.to_edge(UP) author = TextMobject("-Serge Lang") author.set_color(YELLOW) author.next_to(words, DOWN, buff = 0.5) self.play(Write(words, run_time = 10)) self.wait() self.play(FadeIn(author)) self.wait(3) class StudentsFindThisConfusing(TeacherStudentsScene): def construct(self): title = TextMobject("Eigenvectors and Eigenvalues") title.to_edge(UP) students = self.get_students() self.play( Write(title), *[ ApplyMethod(pi.look_at, title) for pi in self.get_pi_creatures() ] ) self.play( self.get_teacher().look_at, students[-1].eyes, students[0].change_mode, "confused", students[1].change_mode, "tired", students[2].change_mode, "sassy", ) self.random_blink() self.student_says( "Why are we doing this?", student_index = 0, run_time = 2, ) question1 = students[0].bubble.content.copy() self.student_says( "What does this actually mean?", student_index = 2, added_anims = [ question1.scale_in_place, 0.8, question1.to_edge, LEFT, question1.shift, DOWN, ] ) question2 = students[2].bubble.content.copy() question2.target = question2.copy() question2.target.next_to( question1, DOWN, aligned_edge = LEFT, buff = MED_SMALL_BUFF ) equation = TexMobject( "\\det\\left( %s \\right)=0"%matrix_to_tex_string([ ["a-\\lambda", "b"], ["c", "d-\\lambda"], ]) ) equation.set_color(YELLOW) self.teacher_says( equation, added_anims = [MoveToTarget(question2)] ) self.change_student_modes(*["confused"]*3) self.random_blink(3) class ShowComments(Scene): pass #TODO class EigenThingsArentAllThatBad(TeacherStudentsScene): def construct(self): self.teacher_says( "Eigen-things aren't \\\\ actually so bad", target_mode = "hooray" ) self.change_student_modes( "pondering", "pondering", "erm" ) self.random_blink(4) class ManyPrerequisites(Scene): def construct(self): title = TextMobject("Many prerequisites") title.to_edge(UP) h_line = Line(LEFT, RIGHT).scale(FRAME_X_RADIUS) h_line.next_to(title, DOWN) self.add(title) self.play(ShowCreation(h_line)) rect = Rectangle(height = 9, width = 16, color = BLUE) rect.set_width(FRAME_X_RADIUS-2) rects = [rect]+[rect.copy() for i in range(3)] words = [ "Linear transformations", "Determinants", "Linear systems", "Change of basis", ] for rect, word in zip(rects, words): word_mob = TextMobject(word) word_mob.next_to(rect, UP, buff = MED_SMALL_BUFF) rect.add(word_mob) Matrix(np.array(rects).reshape((2, 2))) rects = VGroup(*rects) rects.set_height(FRAME_HEIGHT - 1.5) rects.next_to(h_line, DOWN, buff = MED_SMALL_BUFF) self.play(Write(rects[0])) self.wait() self.play(*list(map(FadeIn, rects[1:]))) self.wait() class ExampleTranformationScene(LinearTransformationScene): CONFIG = { "t_matrix" : [[3, 0], [1, 2]] } def setup(self): LinearTransformationScene.setup(self) self.add_matrix() def add_matrix(self): matrix = Matrix(self.t_matrix.T) matrix.set_color_columns(X_COLOR, Y_COLOR) matrix.next_to(ORIGIN, LEFT, buff = MED_SMALL_BUFF) matrix.to_edge(UP) matrix.rect = BackgroundRectangle(matrix) matrix.add_to_back(matrix.rect) self.add_foreground_mobject(matrix) self.matrix = matrix def remove_matrix(self): self.remove(self.matrix) self.foreground_mobjects.remove(self.matrix) class IntroduceExampleTransformation(ExampleTranformationScene): def construct(self): self.remove_matrix() i_coords = Matrix(self.t_matrix[0]) j_coords = Matrix(self.t_matrix[1]) self.apply_transposed_matrix(self.t_matrix) for coords, vect in (i_coords, self.i_hat), (j_coords, self.j_hat): coords.set_color(vect.get_color()) coords.scale(0.8) coords.rect = BackgroundRectangle(coords) coords.add_to_back(coords.rect) coords.next_to(vect.get_end(), RIGHT) self.play(Write(coords)) self.wait() i_coords_copy = i_coords.copy() self.play(*[ Transform(*pair) for pair in [ (i_coords_copy.rect, self.matrix.rect), (i_coords_copy.get_brackets(), self.matrix.get_brackets()), ( i_coords_copy.get_entries(), VGroup(*self.matrix.get_mob_matrix()[:,0]) ) ] ]) to_remove = self.get_mobjects_from_last_animation() self.play(Transform( j_coords.copy().get_entries(), VGroup(*self.matrix.get_mob_matrix()[:,1]) )) to_remove += self.get_mobjects_from_last_animation() self.wait() self.remove(*to_remove) self.add(self.matrix) class VectorKnockedOffSpan(ExampleTranformationScene): def construct(self): vector = Vector([2, 1]) line = Line(vector.get_end()*-4, vector.get_end()*4, color = MAROON_B) vector.scale(0.7) top_words, off, span_label = all_words = TextMobject( "\\centering Vector gets knocked", "\\\\ off", "Span" ) all_words.shift( line.point_from_proportion(0.75) - \ span_label.get_corner(DOWN+RIGHT) + \ MED_SMALL_BUFF*LEFT ) for text in all_words: text.add_to_back(BackgroundRectangle(text)) self.add_vector(vector) self.wait() self.play( ShowCreation(line), Write(span_label), Animation(vector), ) self.add_foreground_mobject(span_label) self.wait() self.apply_transposed_matrix(self.t_matrix) self.play(Animation(span_label.copy()), Write(all_words)) self.wait() class VectorRemainsOnSpan(ExampleTranformationScene): def construct(self): vector = Vector([1, -1]) v_end = vector.get_end() line = Line(-4*v_end, 4*v_end, color = MAROON_B) words = TextMobject("Vector remains on", "\\\\its own span") words.next_to(ORIGIN, DOWN+LEFT) for part in words: part.add_to_back(BackgroundRectangle(part)) self.add_vector(vector) self.play(ShowCreation(line), Animation(vector)) self.wait() self.apply_transposed_matrix(self.t_matrix) self.play(Write(words)) self.wait() target_vectors = [ vector.copy().scale(scalar) for scalar in (2, -2, 1) ] for target, time in zip(target_vectors, [1, 2, 2]): self.play(Transform(vector, target, run_time = time)) self.wait() class IHatAsEigenVector(ExampleTranformationScene): def construct(self): self.set_color_first_column() self.set_color_x_axis() self.apply_transposed_matrix(self.t_matrix, path_arc = 0) self.label_i_hat_landing_spot() def set_color_first_column(self): faders = VGroup(self.plane, self.i_hat, self.j_hat) faders.save_state() column1 = VGroup(*self.matrix.get_mob_matrix()[:,0]) self.play(faders.fade, 0.7, Animation(self.matrix)) self.play(column1.scale_in_place, 1.3, rate_func = there_and_back) self.wait() self.play(faders.restore, Animation(self.matrix)) self.wait() def set_color_x_axis(self): x_axis = self.plane.axes[0] targets = [ self.i_hat.copy().scale(val) for val in (-FRAME_X_RADIUS, FRAME_X_RADIUS, 1) ] lines = [ Line(v1.get_end(), v2.get_end(), color = YELLOW) for v1, v2 in adjacent_pairs([self.i_hat]+targets) ] for target, line in zip(targets, lines): self.play( ShowCreation(line), Transform(self.i_hat, target), ) self.wait() self.remove(*lines) x_axis.set_color(YELLOW) def label_i_hat_landing_spot(self): array = Matrix(self.t_matrix[0]) array.set_color(X_COLOR) array.rect = BackgroundRectangle(array) array.add_to_back(array.rect) brace = Brace(self.i_hat, buff = 0) brace.put_at_tip(array) self.play(GrowFromCenter(brace)) matrix = self.matrix.copy() self.play( Transform(matrix.rect, array.rect), Transform(matrix.get_brackets(), array.get_brackets()), Transform( VGroup(*matrix.get_mob_matrix()[:,0]), array.get_entries() ), ) self.wait() class AllXAxisVectorsAreEigenvectors(ExampleTranformationScene): def construct(self): vectors = VGroup(*[ self.add_vector(u*x*RIGHT, animate = False) for x in reversed(list(range(1, int(FRAME_X_RADIUS)+1))) for u in [-1, 1] ]) vectors.set_color_by_gradient(YELLOW, X_COLOR) self.play(ShowCreation(vectors)) self.wait() self.apply_transposed_matrix(self.t_matrix, path_arc = 0) self.wait() class SneakierEigenVector(ExampleTranformationScene): def construct(self): coords = [-1, 1] vector = Vector(coords) array = Matrix(coords) array.scale(0.7) array.set_color(vector.get_color()) array.add_to_back(BackgroundRectangle(array)) array.target = array.copy() array.next_to(vector.get_end(), LEFT) array.target.next_to(2*vector.get_end(), LEFT) two_times = TexMobject("2 \\cdot") two_times.add_background_rectangle() two_times.next_to(array.target, LEFT) span_line = Line(-4*vector.get_end(), 4*vector.get_end()) span_line.set_color(MAROON_B) self.matrix.shift(-2*self.matrix.get_center()[0]*RIGHT) self.add_vector(vector) self.play(Write(array)) self.play( ShowCreation(span_line), Animation(vector), Animation(array), ) self.wait() self.apply_transposed_matrix( self.t_matrix, added_anims = [ MoveToTarget(array), Transform(VectorizedPoint(array.get_left()), two_times) ], path_arc = 0, ) self.wait() class FullSneakyEigenspace(ExampleTranformationScene): def construct(self): self.matrix.shift(-2*self.matrix.get_center()[0]*RIGHT) vectors = VGroup(*[ self.add_vector(u*x*(LEFT+UP), animate = False) for x in reversed(np.arange(0.5, 5, 0.5)) for u in [-1, 1] ]) vectors.set_color_by_gradient(MAROON_B, YELLOW) words = TextMobject("Stretch by 2") words.add_background_rectangle() words.next_to(ORIGIN, DOWN+LEFT, buff = MED_SMALL_BUFF) words.shift(MED_SMALL_BUFF*LEFT) words.rotate(vectors[0].get_angle()) words.start = words.copy() words.start.scale(0.5) words.start.set_fill(opacity = 0) self.play(ShowCreation(vectors)) self.wait() self.apply_transposed_matrix( self.t_matrix, added_anims = [Transform(words.start, words)], path_arc = 0 ) self.wait() class NameEigenvectorsAndEigenvalues(ExampleTranformationScene): CONFIG = { "show_basis_vectors" : False } def construct(self): self.remove(self.matrix) self.foreground_mobjects.remove(self.matrix) x_vectors = VGroup(*[ self.add_vector(u*x*RIGHT, animate = False) for x in range(int(FRAME_X_RADIUS)+1, 0, -1) for u in [-1, 1] ]) x_vectors.set_color_by_gradient(YELLOW, X_COLOR) self.remove(x_vectors) sneak_vectors = VGroup(*[ self.add_vector(u*x*(LEFT+UP), animate = False) for x in np.arange(int(FRAME_Y_RADIUS), 0, -0.5) for u in [-1, 1] ]) sneak_vectors.set_color_by_gradient(MAROON_B, YELLOW) self.remove(sneak_vectors) x_words = TextMobject("Stretched by 3") sneak_words = TextMobject("Stretched by 2") for words in x_words, sneak_words: words.add_background_rectangle() words.next_to(x_vectors, DOWN) words.next_to(words.get_center(), LEFT, buff = 1.5) eigen_word = TextMobject("Eigenvectors") eigen_word.add_background_rectangle() eigen_word.replace(words) words.target = eigen_word eigen_val_words = TextMobject( "with eigenvalue ", "%s"%words.get_tex_string()[-1] ) eigen_val_words.add_background_rectangle() eigen_val_words.next_to(words, DOWN, aligned_edge = RIGHT) words.eigen_val_words = eigen_val_words x_words.eigen_val_words.set_color(X_COLOR) sneak_words.eigen_val_words.set_color(YELLOW) VGroup( sneak_words, sneak_words.target, sneak_words.eigen_val_words, ).rotate(sneak_vectors[0].get_angle()) non_eigen = Vector([1, 1], color = PINK) non_eigen_span = Line( -FRAME_Y_RADIUS*non_eigen.get_end(), FRAME_Y_RADIUS*non_eigen.get_end(), color = RED ) non_eigen_words = TextMobject(""" Knocked off its own span """) non_eigen_words.add_background_rectangle() non_eigen_words.scale(0.7) non_eigen_words.next_to(non_eigen.get_end(), RIGHT) non_eigen_span.fade() for vectors in x_vectors, sneak_vectors: self.play(ShowCreation(vectors, run_time = 1)) self.wait() for words in x_words, sneak_words: self.play(Write(words, run_time = 1.5)) self.add_foreground_mobject(words) self.wait() self.play(ShowCreation(non_eigen)) self.play( ShowCreation(non_eigen_span), Write(non_eigen_words), Animation(non_eigen) ) self.add_vector(non_eigen, animate = False) self.wait() self.apply_transposed_matrix( self.t_matrix, added_anims = [FadeOut(non_eigen_words)], path_arc = 0, ) self.wait(2) self.play(*list(map(FadeOut, [non_eigen, non_eigen_span]))) self.play(*list(map(MoveToTarget, [x_words, sneak_words]))) self.wait() for words in x_words, sneak_words: self.play(Write(words.eigen_val_words), run_time = 2) self.wait() class CanEigenvaluesBeNegative(TeacherStudentsScene): def construct(self): self.student_says("Can eigenvalues be negative?") self.random_blink() self.teacher_says("But of course!", target_mode = "hooray") self.random_blink() class EigenvalueNegativeOneHalf(LinearTransformationScene): CONFIG = { "t_matrix" : [[0.5, -1], [-1, 0.5]], "foreground_plane_kwargs" : { "x_radius" : FRAME_WIDTH, "y_radius" : FRAME_WIDTH, "secondary_line_ratio" : 0 }, "include_background_plane" : False } def construct(self): matrix = Matrix(self.t_matrix.T) matrix.add_to_back(BackgroundRectangle(matrix)) matrix.set_color_columns(X_COLOR, Y_COLOR) matrix.next_to(ORIGIN, LEFT) matrix.to_edge(UP) self.add_foreground_mobject(matrix) vector = self.add_vector([1, 1]) words = TextMobject("Eigenvector with \\\\ eigenvalue $-\\frac{1}{2}$") words.add_background_rectangle() words.next_to(vector.get_end(), RIGHT) span = Line( -FRAME_Y_RADIUS*vector.get_end(), FRAME_Y_RADIUS*vector.get_end(), color = MAROON_B ) self.play(Write(words)) self.play( ShowCreation(span), Animation(vector), Animation(words), ) self.wait() self.apply_transposed_matrix( self.t_matrix, added_anims = [FadeOut(words)] ) self.wait() self.play( Rotate(span, np.pi/12, rate_func = wiggle), Animation(vector), ) self.wait() class ThreeDRotationTitle(Scene): def construct(self): title = TextMobject("3D Rotation") title.scale(2) self.play(Write(title)) self.wait() class ThreeDShowRotation(Scene): pass class ThreeDShowRotationWithEigenvector(Scene): pass class EigenvectorToAxisOfRotation(Scene): def construct(self): words = [ TextMobject("Eigenvector"), TextMobject("Axis of rotation"), ] for word in words: word.scale(2) self.play(Write(words[0])) self.wait() self.play(Transform(*words)) self.wait() class EigenvalueOne(Scene): def construct(self): text = TextMobject("Eigenvalue = $1$") text.set_color(MAROON_B) self.play(Write(text)) self.wait() class ContrastMatrixUnderstandingWithEigenvalue(TeacherStudentsScene): def construct(self): axis_and_rotation = TextMobject( "Rotate", "$30^\\circ$", "around", "$%s$"%matrix_to_tex_string([2, 3, 1]) ) axis_and_rotation[1].set_color(BLUE) axis_and_rotation[-1].set_color(MAROON_B) matrix = Matrix([ [ "\\cos(\\theta)\\cos(\\phi)", "-\\sin(\\phi)", "\\cos(\\theta)\\sin(\\phi)", ], [ "\\sin(\\theta)\\cos(\\phi)", "\\cos(\\theta)", "\\sin(\\theta)\\sin(\\phi)", ], [ "-\\sin(\\phi)", "0", "\\cos(\\phi)" ] ]) matrix.scale(0.7) for mob in axis_and_rotation, matrix: mob.to_corner(UP+RIGHT) everyone = self.get_pi_creatures() self.play( Write(axis_and_rotation), *it.chain(*list(zip( [pi.change_mode for pi in everyone], ["hooray"]*4, [pi.look_at for pi in everyone], [axis_and_rotation]*4, ))), run_time = 2 ) self.random_blink(2) self.play( Transform(axis_and_rotation, matrix), *it.chain(*list(zip( [pi.change_mode for pi in everyone], ["confused"]*4, [pi.look_at for pi in everyone], [matrix]*4, ))) ) self.random_blink(3) class CommonPattern(TeacherStudentsScene): def construct(self): self.teacher_says(""" This is a common pattern in linear algebra. """) self.random_blink(2) class DeduceTransformationFromMatrix(ColumnsToBasisVectors): def construct(self): self.setup() self.move_matrix_columns([[3, 0], [1, 2]]) words = TextMobject(""" This gives too much weight to our coordinate system """) words.add_background_rectangle() words.next_to(ORIGIN, DOWN+LEFT, buff = MED_SMALL_BUFF) words.shift_onto_screen() self.play(Write(words)) self.wait() class WordsOnComputation(TeacherStudentsScene): def construct(self): self.teacher_says( "I won't cover the full\\\\", "details of computation...", target_mode = "guilty" ) self.change_student_modes("angry", "sassy", "angry") self.random_blink() self.teacher_says( "...but I'll hit the \\\\", "important parts" ) self.change_student_modes(*["happy"]*3) self.random_blink(3) class SymbolicEigenvectors(Scene): def construct(self): self.introduce_terms() self.contrast_multiplication_types() self.rewrite_righthand_side() self.reveal_as_linear_system() self.bring_in_determinant() def introduce_terms(self): self.expression = TexMobject( "A", "\\vec{\\textbf{v}}", "=", "\\lambda", "\\vec{\\textbf{v}}" ) self.expression.scale(1.5) self.expression.shift(UP+2*LEFT) A, v1, equals, lamb, v2 = self.expression vs = VGroup(v1, v2) vs.set_color(YELLOW) lamb.set_color(MAROON_B) A_brace = Brace(A, UP, buff = 0) A_text = TextMobject("Transformation \\\\ matrix") A_text.next_to(A_brace, UP) lamb_brace = Brace(lamb, UP, buff = 0) lamb_text = TextMobject("Eigenvalue") lamb_text.set_color(lamb.get_color()) lamb_text.next_to(lamb_brace, UP, aligned_edge = LEFT) v_text = TextMobject("Eigenvector") v_text.set_color(vs.get_color()) v_text.next_to(vs, DOWN, buff = 1.5*LARGE_BUFF) v_arrows = VGroup(*[ Arrow(v_text.get_top(), v.get_bottom()) for v in vs ]) self.play(Write(self.expression)) self.wait() self.play( GrowFromCenter(A_brace), Write(A_text) ) self.wait() self.play( Write(v_text), ShowCreation(v_arrows) ) self.wait() self.play( GrowFromCenter(lamb_brace), Write(lamb_text) ) self.wait(2) self.play(*list(map(FadeOut, [ A_brace, A_text, lamb_brace, lamb_text, v_text, v_arrows ]))) def contrast_multiplication_types(self): A, v1, equals, lamb, v2 = self.expression left_group = VGroup(A, v1) left_group.brace = Brace(left_group, UP) left_group.text = left_group.brace.get_text("Matrix-vector multiplication") right_group = VGroup(lamb, v2) right_group.brace = Brace(right_group, DOWN) right_group.text = right_group.brace.get_text("Scalar multiplication") right_group.text.set_color(lamb.get_color()) for group in left_group, right_group: self.play( GrowFromCenter(group.brace), Write(group.text, run_time = 2) ) self.play(group.scale_in_place, 1.2, rate_func = there_and_back) self.wait() morty = Mortimer().to_edge(DOWN) morty.change_mode("speaking") bubble = morty.get_bubble(SpeechBubble, width = 5, direction = LEFT) VGroup(morty, bubble).to_edge(RIGHT) solve_text = TextMobject( "Solve for \\\\", "$\\lambda$", "and", "$\\vec{\\textbf{v}}$" ) solve_text.set_color_by_tex("$\\lambda$", lamb.get_color()) solve_text.set_color_by_tex("$\\vec{\\textbf{v}}$", v1.get_color()) bubble.add_content(solve_text) self.play( FadeIn(morty), FadeIn(bubble), Write(solve_text) ) self.play(Blink(morty)) self.wait(2) bubble.write("Fix different", "\\\\ multiplication", "types") self.play( Transform(solve_text, bubble.content), morty.change_mode, "sassy" ) self.play(Blink(morty)) self.wait() self.play(*list(map(FadeOut, [ left_group.brace, left_group.text, right_group.brace, right_group.text, morty, bubble, solve_text ]))) def rewrite_righthand_side(self): A, v1, equals, lamb, v2 = self.expression lamb_copy = lamb.copy() scaling_by = VGroup( TextMobject("Scaling by "), lamb_copy ) scaling_by.arrange_submobjects() arrow = TexMobject("\\Updownarrow") matrix_multiplication = TextMobject( "Matrix multiplication by" ) matrix = Matrix(np.identity(3, dtype = int)) corner_group = VGroup( scaling_by, arrow, matrix_multiplication, matrix ) corner_group.arrange_submobjects(DOWN) corner_group.to_corner(UP+RIGHT) q_marks = VGroup(*[ TexMobject("?").replace(entry) for entry in matrix.get_entries() ]) q_marks.set_color_by_gradient(X_COLOR, Y_COLOR, Z_COLOR) diag_entries = VGroup(*[ matrix.get_mob_matrix()[i,i] for i in range(3) ]) diag_entries.save_state() for entry in diag_entries: new_lamb = TexMobject("\\lambda") new_lamb.move_to(entry) new_lamb.set_color(lamb.get_color()) Transform(entry, new_lamb).update(1) new_lamb = lamb.copy() new_lamb.next_to(matrix, LEFT) id_brace = Brace(matrix) id_text = TexMobject("I").scale(1.5) id_text.next_to(id_brace, DOWN) self.play( Transform(lamb.copy(), lamb_copy), Write(scaling_by) ) self.remove(*self.get_mobjects_from_last_animation()) self.add(scaling_by) self.play(Write(VGroup( matrix_multiplication, arrow, matrix.get_brackets(), q_marks, ), run_time = 2 )) self.wait() self.play(Transform( q_marks, matrix.get_entries(), submobject_mode = "lagged_start", run_time = 2 )) self.remove(q_marks) self.add(*matrix.get_entries()) self.wait() self.play( Transform(diag_entries.copy(), new_lamb), diag_entries.restore ) self.remove(*self.get_mobjects_from_last_animation()) self.add(new_lamb, diag_entries) self.play( GrowFromCenter(id_brace), Write(id_text) ) self.wait() id_text_copy = id_text.copy() self.add(id_text_copy) l_paren, r_paren = parens = TexMobject("()").scale(1.5) for mob in lamb, id_text, v2: mob.target = mob.copy() VGroup( l_paren, lamb.target, id_text.target, r_paren, v2.target ).arrange_submobjects().next_to(equals).shift(SMALL_BUFF*UP) self.play( Write(parens), *list(map(MoveToTarget, [lamb, id_text, v2])) ) self.wait() self.play(*list(map(FadeOut, [ corner_group, id_brace, id_text_copy, new_lamb ]))) self.expression = VGroup( A, v1, equals, VGroup(l_paren, lamb, id_text, r_paren), v2 ) def reveal_as_linear_system(self): A, v1, equals, lamb_group, v2 = self.expression l_paren, lamb, I, r_paren = lamb_group zero = TexMobject("\\vec{\\textbf{0}}") zero.scale(1.3) zero.next_to(equals, RIGHT) zero.shift(SMALL_BUFF*UP/2) minus = TexMobject("-").scale(1.5) movers = A, v1, lamb_group, v2 for mob in movers: mob.target = mob.copy() VGroup( A.target, v1.target, minus, lamb_group.target, v2.target ).arrange_submobjects().next_to(equals, LEFT) self.play( Write(zero), Write(minus), *list(map(MoveToTarget, movers)), path_arc = np.pi/3 ) self.wait() A.target.next_to(minus, LEFT) l_paren.target = l_paren.copy() l_paren.target.next_to(A.target, LEFT) self.play( MoveToTarget(A), MoveToTarget(l_paren), Transform(v1, v2, path_arc = np.pi/3) ) self.remove(v1) self.wait() brace = Brace(VGroup(l_paren, r_paren)) brace.text = TextMobject("This matrix looks \\\\ something like") brace.text.next_to(brace, DOWN) brace.text.to_edge(LEFT) matrix = Matrix([ ["3-\\lambda", "1", "4"], ["1", "5-\\lambda", "9"], ["2", "6", "5-\\lambda"], ]) matrix.scale(0.7) VGroup( matrix.get_brackets()[1], *matrix.get_mob_matrix()[:,2] ).shift(0.5*RIGHT) matrix.next_to(brace.text, DOWN) for entry in matrix.get_entries(): if len(entry.get_tex_string()) > 1: entry[-1].set_color(lamb.get_color()) self.play( GrowFromCenter(brace), Write(brace.text), Write(matrix) ) self.wait() vect_words = TextMobject( "We want a nonzero solution for" ) v_copy = v2.copy().next_to(vect_words) vect_words.add(v_copy) vect_words.to_corner(UP+LEFT) arrow = Arrow(vect_words.get_bottom(), v2.get_top()) self.play( Write(vect_words), ShowCreation(arrow) ) self.wait() def bring_in_determinant(self): randy = Randolph(mode = "speaking").to_edge(DOWN) randy.flip() randy.look_at(self.expression) bubble = randy.get_bubble(SpeechBubble, direction = LEFT, width = 5) words = TextMobject("We need") equation = TexMobject( "\\det(A-", "\\lambda", "I)", "=0" ) equation.set_color_by_tex("\\lambda", MAROON_B) equation.next_to(words, DOWN) words.add(equation) bubble.add_content(words) self.play( FadeIn(randy), ShowCreation(bubble), Write(words) ) self.play(Blink(randy)) self.wait() everything = self.get_mobjects() equation_copy = equation.copy() self.play( FadeOut(VGroup(*everything)), Animation(equation_copy) ) self.play( equation_copy.center, equation_copy.scale, 1.5 ) self.wait() class NonZeroSolutionsVisually(LinearTransformationScene): CONFIG = { "t_matrix" : [[1, 1], [2, 2]], "v_coords" : [2, -1] } def construct(self): equation = TexMobject( "(A-", "\\lambda", "I)", "\\vec{\\textbf{v}}", "= \\vec{\\textbf{0}}" ) equation_matrix = VGroup(*equation[:3]) equation.set_color_by_tex("\\lambda", MAROON_B) equation.set_color_by_tex("\\vec{\\textbf{v}}", YELLOW) equation.add_background_rectangle() equation.next_to(ORIGIN, DOWN, buff = MED_SMALL_BUFF) equation.to_edge(LEFT) det_equation = TexMobject( "\\text{Squishification} \\Rightarrow", "\\det", "(A-", "\\lambda", "I", ")", "=0" ) det_equation_matrix = VGroup(*det_equation[2:2+4]) det_equation.set_color_by_tex("\\lambda", MAROON_B) det_equation.next_to(equation, DOWN, buff = MED_SMALL_BUFF) det_equation.to_edge(LEFT) det_equation.add_background_rectangle() self.add_foreground_mobject(equation) v = self.add_vector(self.v_coords) self.wait() self.apply_transposed_matrix(self.t_matrix) self.wait() transform = Transform( equation_matrix.copy(), det_equation_matrix ) self.play(Write(det_equation), transform) self.wait() class TweakLambda(LinearTransformationScene): CONFIG = { "t_matrix" : [[2, 1], [2, 3]], "include_background_plane" : False, "foreground_plane_kwargs" : { "x_radius" : FRAME_WIDTH, "y_radius" : FRAME_WIDTH, "secondary_line_ratio" : 1 }, } def construct(self): matrix = Matrix([ ["2-0.00", "2"], ["1", "3-0.00"], ]) matrix.add_to_back(BackgroundRectangle(matrix)) matrix.next_to(ORIGIN, LEFT, buff = LARGE_BUFF) matrix.to_edge(UP) self.lambda_vals = [] for i in range(2): entry = matrix.get_mob_matrix()[i,i] place_holders = VGroup(*entry[2:]) entry.remove(*place_holders) place_holders.set_color(MAROON_B) self.lambda_vals.append(place_holders) brace = Brace(matrix) brace_text = TexMobject("(A-", "\\lambda", "I)") brace_text.set_color_by_tex("\\lambda", MAROON_B) brace_text.next_to(brace, DOWN) brace_text.add_background_rectangle() det_text = get_det_text(matrix) equals = TexMobject("=").next_to(det_text) det = DecimalNumber(np.linalg.det(self.t_matrix)) det.set_color(YELLOW) det.next_to(equals) det.rect = BackgroundRectangle(det) self.det = det self.matrix = VGroup(matrix, brace, brace_text) self.add_foreground_mobject( self.matrix, *self.lambda_vals ) self.add_unit_square() self.plane_mobjects = [ self.plane, self.square, ] for mob in self.plane_mobjects: mob.save_state() self.apply_transposed_matrix(self.t_matrix) self.play( Write(det_text), Write(equals), ShowCreation(det.rect), Write(det) ) self.matrix.add(det_text, equals, det.rect) self.wait() self.range_lambda(0, 3, run_time = 5) self.wait() self.range_lambda(3, 0.5, run_time = 5) self.wait() self.range_lambda(0.5, 1.5, run_time = 3) self.wait() self.range_lambda(1.5, 1, run_time = 2) self.wait() def get_t_matrix(self, lambda_val): return self.t_matrix - lambda_val*np.identity(2) def range_lambda(self, start_val, end_val, run_time = 3): alphas = np.linspace(0, 1, run_time/self.frame_duration) matrix_transform = self.get_matrix_transformation( self.get_t_matrix(end_val) ) transformations = [] for mob in self.plane_mobjects: mob.target = mob.copy().restore().apply_function(matrix_transform) transformations.append(MoveToTarget(mob)) transformations += [ Transform( self.i_hat, Vector(matrix_transform(RIGHT), color = X_COLOR) ), Transform( self.j_hat, Vector(matrix_transform(UP), color = Y_COLOR) ), ] for alpha in alphas: self.clear() val = interpolate(start_val, end_val, alpha) new_t_matrix = self.get_t_matrix(val) for transformation in transformations: transformation.update(alpha) self.add(transformation.mobject) self.add(self.matrix) new_lambda_vals = [] for lambda_val in self.lambda_vals: new_lambda = DecimalNumber(val) new_lambda.move_to(lambda_val, aligned_edge = LEFT) new_lambda.set_color(lambda_val.get_color()) new_lambda_vals.append(new_lambda) self.lambda_vals = new_lambda_vals self.add(*self.lambda_vals) new_det = DecimalNumber( np.linalg.det([ self.i_hat.get_end()[:2], self.j_hat.get_end()[:2], ]) ) new_det.move_to(self.det, aligned_edge = LEFT) new_det.set_color(self.det.get_color()) self.det = new_det self.add(self.det) self.wait(self.frame_duration) class ShowEigenVectorAfterComputing(LinearTransformationScene): CONFIG = { "t_matrix" : [[2, 1], [2, 3]], "v_coords" : [2, -1], "include_background_plane" : False, "foreground_plane_kwargs" : { "x_radius" : FRAME_WIDTH, "y_radius" : FRAME_WIDTH, "secondary_line_ratio" : 1 }, } def construct(self): matrix = Matrix(self.t_matrix.T) matrix.add_to_back(BackgroundRectangle(matrix)) matrix.next_to(ORIGIN, RIGHT) matrix.shift(self.v_coords[0]*RIGHT) self.add_foreground_mobject(matrix) v_label = TexMobject( "\\vec{\\textbf{v}}", "=", "1", "\\vec{\\textbf{v}}", ) v_label.next_to(matrix, RIGHT) v_label.set_color_by_tex("\\vec{\\textbf{v}}", YELLOW) v_label.set_color_by_tex("1", MAROON_B) v_label.add_background_rectangle() v = self.add_vector(self.v_coords) eigenvector = TextMobject("Eigenvector") eigenvector.add_background_rectangle() eigenvector.next_to(ORIGIN, DOWN+RIGHT) eigenvector.rotate(v.get_angle()) self.play(Write(eigenvector)) self.add_foreground_mobject(eigenvector) line = Line(v.get_end()*(-4), v.get_end()*4, color = MAROON_B) self.play(Write(v_label)) self.add_foreground_mobject(v_label) self.play(ShowCreation(line), Animation(v)) self.wait() self.apply_transposed_matrix(self.t_matrix) self.wait() class LineOfReasoning(Scene): def construct(self): v_tex = "\\vec{\\textbf{v}}" expressions = VGroup(*it.starmap(TexMobject, [ ("A", v_tex, "=", "\\lambda", v_tex), ("A", v_tex, "-", "\\lambda", "I", v_tex, "=", "0"), ("(", "A", "-", "\\lambda", "I)", v_tex, "=", "0"), ("\\det(A-", "\\lambda", "I)", "=", "0") ])) expressions.arrange_submobjects(DOWN, buff = LARGE_BUFF/2.) for expression in expressions: for i, expression_part in enumerate(expression.expression_parts): if expression_part == "=": equals = expression[i] expression.shift(equals.get_center()[0]*LEFT) break expression.set_color_by_tex(v_tex, YELLOW) expression.set_color_by_tex("\\lambda", MAROON_B) self.play(FadeIn(expression)) self.wait() class IfYouDidntKnowDeterminants(TeacherStudentsScene): def construct(self): expression = TexMobject("\\det(A-", "\\lambda", "I" ")=0") expression.set_color_by_tex("\\lambda", MAROON_B) expression.scale(1.3) self.teacher_says(expression) self.random_blink() student = self.get_students()[0] bubble = get_small_bubble(student) bubble.write("Wait...why?") self.play( ShowCreation(bubble), Write(bubble.content), student.change_mode, "confused" ) self.random_blink(4) class RevisitExampleTransformation(ExampleTranformationScene): def construct(self): self.introduce_matrix() seeking_eigenvalue = TextMobject("Seeking eigenvalue") seeking_eigenvalue.add_background_rectangle() lamb = TexMobject("\\lambda") lamb.set_color(MAROON_B) words = VGroup(seeking_eigenvalue, lamb) words.arrange_submobjects() words.next_to(self.matrix, DOWN, buff = LARGE_BUFF) self.play(Write(words)) self.wait() self.play(*self.get_lambda_to_diag_movements(lamb.copy())) self.add_foreground_mobject(*self.get_mobjects_from_last_animation()) self.wait() self.show_determinant(to_fade = words) self.show_diagonally_altered_transform() self.show_unaltered_transform() def introduce_matrix(self): self.matrix.shift(2*LEFT) for mob in self.plane, self.i_hat, self.j_hat: mob.save_state() self.remove_matrix() i_coords = Matrix(self.t_matrix[0]) j_coords = Matrix(self.t_matrix[1]) self.apply_transposed_matrix(self.t_matrix) for coords, vect in (i_coords, self.i_hat), (j_coords, self.j_hat): coords.set_color(vect.get_color()) coords.scale(0.8) coords.rect = BackgroundRectangle(coords) coords.add_to_back(coords.rect) coords.next_to( vect.get_end(), RIGHT+DOWN if coords is i_coords else RIGHT ) self.play( Write(i_coords), Write(j_coords), ) self.wait() self.play(*[ Transform(*pair) for pair in [ (i_coords.rect, self.matrix.rect), (i_coords.get_brackets(), self.matrix.get_brackets()), ( i_coords.get_entries(), VGroup(*self.matrix.get_mob_matrix()[:,0]) ) ] ]) to_remove = self.get_mobjects_from_last_animation() self.play( FadeOut(j_coords.get_brackets()), FadeOut(j_coords.rect), Transform( j_coords.get_entries(), VGroup(*self.matrix.get_mob_matrix()[:,1]) ), ) to_remove += self.get_mobjects_from_last_animation() self.wait() self.remove(*to_remove) self.add_foreground_mobject(self.matrix) def get_lambda_to_diag_movements(self, lamb): three, two = [self.matrix.get_mob_matrix()[i, i] for i in range(2)] l_bracket, r_bracket = self.matrix.get_brackets() rect = self.matrix.rect lamb_copy = lamb.copy() movers = [rect, three, two, l_bracket, r_bracket, lamb, lamb_copy] for mover in movers: mover.target = mover.copy() minus1, minus2 = [TexMobject("-") for x in range(2)] new_three = VGroup(three.target, minus1, lamb.target) new_three.arrange_submobjects() new_three.move_to(three) new_two = VGroup(two.target, minus2, lamb_copy.target) new_two.arrange_submobjects() new_two.move_to(two) l_bracket.target.next_to(VGroup(new_three, new_two), LEFT) r_bracket.target.next_to(VGroup(new_three, new_two), RIGHT) rect.target = BackgroundRectangle( VGroup(l_bracket.target, r_bracket.target) ) result = list(map(MoveToTarget, movers)) result += list(map(Write, [minus1, minus2])) result += list(map(Animation, [ self.matrix.get_mob_matrix()[i, 1-i] for i in range(2) ])) self.diag_entries = [ VGroup(three, minus1, lamb), VGroup(two, minus2, lamb_copy), ] return result def show_determinant(self, to_fade = None): det_text = get_det_text(self.matrix) equals = TexMobject("=").next_to(det_text) three_minus_lamb, two_minus_lamb = diag_entries = [ entry.copy() for entry in self.diag_entries ] one = self.matrix.get_mob_matrix()[0, 1].copy() zero = self.matrix.get_mob_matrix()[1, 0].copy() for entry in diag_entries + [one, zero]: entry.target = entry.copy() lp1, rp1, lp2, rp2 = parens = TexMobject("()()") minus = TexMobject("-") cdot = TexMobject("\\cdot") VGroup( lp1, three_minus_lamb.target, rp1, lp2, two_minus_lamb.target, rp2, minus, one.target, cdot, zero.target ).arrange_submobjects().next_to(equals) parens.add_background_rectangle() new_rect = BackgroundRectangle(VGroup(minus, zero.target)) brace = Brace(new_rect, buff = 0) brace_text = brace.get_text("Equals 0, so ", "ignore") brace_text.add_background_rectangle() brace.target = Brace(parens) brace_text.target = brace.target.get_text( "Quadratic polynomial in ", "$\\lambda$" ) brace_text.target.set_color_by_tex("$\\lambda$", MAROON_B) brace_text.target.add_background_rectangle() equals_0 = TexMobject("=0") equals_0.next_to(parens, RIGHT) equals_0.add_background_rectangle() final_brace = Brace(VGroup(parens, equals_0)) final_text = TexMobject( "\\lambda", "=2", "\\text{ or }", "\\lambda", "=3" ) final_text.set_color_by_tex("\\lambda", MAROON_B) final_text.next_to(final_brace, DOWN) lambda_equals_two = VGroup(*final_text[:2]).copy() lambda_equals_two.add_to_back(BackgroundRectangle(lambda_equals_two)) final_text.add_background_rectangle() self.play( Write(det_text), Write(equals) ) self.wait() self.play( Write(parens), MoveToTarget(three_minus_lamb), MoveToTarget(two_minus_lamb), run_time = 2 ) self.wait() self.play( FadeIn(new_rect), MoveToTarget(one), MoveToTarget(zero), Write(minus), Write(cdot), run_time = 2 ) self.play( GrowFromCenter(brace), Write(brace_text) ) self.wait() self.play(*it.chain( list(map(MoveToTarget, [brace, brace_text])), list(map(FadeOut, [one, zero, minus, cdot, new_rect])) )) self.wait() self.play(Write(equals_0)) self.wait() self.play( Transform(brace, final_brace), Transform(brace_text, final_text) ) self.wait() faders = [ det_text, equals, parens, three_minus_lamb, two_minus_lamb, brace, brace_text, equals_0, ] if to_fade is not None: faders.append(to_fade) self.play(*it.chain( list(map(FadeOut, faders)), [ lambda_equals_two.scale_in_place, 1.3, lambda_equals_two.next_to, self.matrix, DOWN ] )) self.add_foreground_mobject(lambda_equals_two) self.lambda_equals_two = lambda_equals_two self.wait() def show_diagonally_altered_transform(self): for entry in self.diag_entries: lamb = entry[-1] two = TexMobject("2") two.set_color(lamb.get_color()) two.move_to(lamb) self.play(Transform(lamb, two)) self.play(*it.chain( [mob.restore for mob in (self.plane, self.i_hat, self.j_hat)], list(map(Animation, self.foreground_mobjects)), )) xy_array = Matrix(["x", "y"]) xy_array.set_color(YELLOW) zero_array = Matrix([0, 0]) for array in xy_array, zero_array: array.set_height(self.matrix.get_height()) array.add_to_back(BackgroundRectangle(array)) xy_array.next_to(self.matrix) equals = TexMobject("=").next_to(xy_array) equals.add_background_rectangle() zero_array.next_to(equals) self.play(*list(map(Write, [xy_array, equals, zero_array]))) self.wait() vectors = VGroup(*[ self.add_vector(u*x*(LEFT+UP), animate = False) for x in range(4, 0, -1) for u in [-1, 1] ]) vectors.set_color_by_gradient(MAROON_B, YELLOW) vectors.save_state() self.play( ShowCreation( vectors, submobject_mode = "lagged_start", run_time = 2 ), *list(map(Animation, self.foreground_mobjects)) ) self.wait() self.apply_transposed_matrix( self.t_matrix - 2*np.identity(2) ) self.wait() self.play(*it.chain( [mob.restore for mob in (self.plane, self.i_hat, self.j_hat, vectors)], list(map(FadeOut, [xy_array, equals, zero_array])), list(map(Animation, self.foreground_mobjects)) )) def show_unaltered_transform(self): movers = [] faders = [] for entry in self.diag_entries: mover = entry[0] faders += list(entry[1:]) mover.target = mover.copy() mover.target.move_to(entry) movers.append(mover) brace = Brace(self.matrix) brace_text = brace.get_text("Unaltered matrix") brace_text.add_background_rectangle() self.lambda_equals_two.target = brace_text movers.append(self.lambda_equals_two) self.play(*it.chain( list(map(MoveToTarget, movers)), list(map(FadeOut, faders)), [GrowFromCenter(brace)] )) VGroup(*faders).set_fill(opacity = 0) self.add_foreground_mobject(brace) self.wait() self.apply_transposed_matrix(self.t_matrix) self.wait() class ThereMightNotBeEigenvectors(TeacherStudentsScene): def construct(self): self.teacher_says(""" There could be \\emph{no} eigenvectors """) self.random_blink(3) class Rotate90Degrees(LinearTransformationScene): CONFIG = { "t_matrix" : [[0, 1], [-1, 0]], "example_vector_coords" : None, } def setup(self): LinearTransformationScene.setup(self) matrix = Matrix(self.t_matrix.T) matrix.set_color_columns(X_COLOR, Y_COLOR) matrix.next_to(ORIGIN, LEFT) matrix.to_edge(UP) matrix.rect = BackgroundRectangle(matrix) matrix.add_to_back(matrix.rect) self.add_foreground_mobject(matrix) self.matrix = matrix if self.example_vector_coords is not None: v = self.add_vector(self.example_vector_coords, animate = False) line = Line(v.get_end()*(-4), v.get_end()*4, color = MAROON_B) self.play(ShowCreation(line), Animation(v)) self.add_foreground_mobject(line) def construct(self): self.wait() self.apply_transposed_matrix(self.t_matrix) self.wait() class Rotate90DegreesWithVector(Rotate90Degrees): CONFIG = { "example_vector_coords" : [1, 2] } class SolveRotationEigenvalues(Rotate90Degrees): def construct(self): self.apply_transposed_matrix(self.t_matrix, run_time = 0) self.wait() diag_entries = [ self.matrix.get_mob_matrix()[i, i] for i in range(2) ] off_diag_entries = [ self.matrix.get_mob_matrix()[i, 1-i] for i in range(2) ] for entry in diag_entries: minus_lambda = TexMobject("-\\lambda") minus_lambda.set_color(MAROON_B) minus_lambda.move_to(entry) self.play(Transform(entry, minus_lambda)) self.wait() det_text = get_det_text(self.matrix) equals = TexMobject("=").next_to(det_text) self.play(*list(map(Write, [det_text, equals]))) self.wait() minus = TexMobject("-") for entries, sym in (diag_entries, equals), (off_diag_entries, minus): lp1, rp1, lp2, rp2 = parens = TexMobject("()()") for entry in entries: entry.target = entry.copy() group = VGroup( lp1, entries[0].target, rp1, lp2, entries[1].target, rp2, ) group.arrange_submobjects() group.next_to(sym) parens.add_background_rectangle() self.play( Write(parens), *[MoveToTarget(entry.copy()) for entry in entries], run_time = 2 ) self.wait() if entries == diag_entries: minus.next_to(parens) self.play(Write(minus)) polynomial = TexMobject( "=", "\\lambda^2", "+1=0" ) polynomial.set_color_by_tex("\\lambda^2", MAROON_B) polynomial.add_background_rectangle() polynomial.next_to(equals, DOWN, buff = MED_LARGE_BUFF, aligned_edge = LEFT) self.play(Write(polynomial)) self.wait() result = TexMobject( "\\lambda", "= i", "\\text{ or }", "\\lambda", "= -i" ) result.set_color_by_tex("\\lambda", MAROON_B) result.add_background_rectangle() result.next_to(polynomial, DOWN, buff = MED_LARGE_BUFF, aligned_edge = LEFT) self.play(Write(result)) self.wait() interesting_tidbit = TextMobject(""" Interestingly, though, the fact that multiplication by i in the complex plane looks like a 90 degree rotation is related to the fact that i is an eigenvalue of this transformation of 2d real vectors. The specifics of this are a little beyond what I want to talk about today, but note that that eigenvalues which are complex numbers generally correspond to some kind of rotation in the transformation. """, alignment = "") interesting_tidbit.add_background_rectangle() interesting_tidbit.set_height(FRAME_Y_RADIUS-0.5) interesting_tidbit.to_corner(DOWN+RIGHT) self.play(FadeIn(interesting_tidbit)) self.wait() class ShearExample(RevisitExampleTransformation): CONFIG = { "t_matrix" : [[1, 0], [1, 1]], "include_background_plane" : False, "foreground_plane_kwargs" : { "x_radius" : FRAME_WIDTH, "y_radius" : FRAME_HEIGHT, "secondary_line_ratio" : 1 }, } def construct(self): self.plane.fade() self.introduce_matrix() self.point_out_eigenvectors() lamb = TexMobject("\\lambda") lamb.set_color(MAROON_B) lamb.next_to(self.matrix, DOWN) self.play(FadeIn(lamb)) self.play(*self.get_lambda_to_diag_movements(lamb)) self.add_foreground_mobject(*self.get_mobjects_from_last_animation()) self.wait() self.show_determinant() def point_out_eigenvectors(self): vectors = VGroup(*[ self.add_vector(u*x*RIGHT, animate = False) for x in range(int(FRAME_X_RADIUS)+1, 0, -1) for u in [-1, 1] ]) vectors.set_color_by_gradient(YELLOW, X_COLOR) words = VGroup( TextMobject("Eigenvectors"), TextMobject("with eigenvalue", "1") ) for word in words: word.set_color_by_tex("1", MAROON_B) word.add_to_back(BackgroundRectangle(word)) words.arrange_submobjects(DOWN, buff = MED_SMALL_BUFF) words.next_to(ORIGIN, DOWN+RIGHT, buff = MED_SMALL_BUFF) self.play(ShowCreation(vectors), run_time = 2) self.play(Write(words)) self.wait() def show_determinant(self): det_text = get_det_text(self.matrix) equals = TexMobject("=").next_to(det_text) three_minus_lamb, two_minus_lamb = diag_entries = [ entry.copy() for entry in self.diag_entries ] one = self.matrix.get_mob_matrix()[0, 1].copy() zero = self.matrix.get_mob_matrix()[1, 0].copy() for entry in diag_entries + [one, zero]: entry.target = entry.copy() lp1, rp1, lp2, rp2 = parens = TexMobject("()()") minus = TexMobject("-") cdot = TexMobject("\\cdot") VGroup( lp1, three_minus_lamb.target, rp1, lp2, two_minus_lamb.target, rp2, minus, one.target, cdot, zero.target ).arrange_submobjects().next_to(equals) parens.add_background_rectangle() new_rect = BackgroundRectangle(VGroup(minus, zero.target)) brace = Brace(new_rect, buff = 0) brace_text = brace.get_text("Equals 0, so ", "ignore") brace_text.add_background_rectangle() brace.target = Brace(parens) brace_text.target = brace.target.get_text( "Quadratic polynomial in ", "$\\lambda$" ) brace_text.target.set_color_by_tex("$\\lambda$", MAROON_B) brace_text.target.add_background_rectangle() equals_0 = TexMobject("=0") equals_0.next_to(parens, RIGHT) equals_0.add_background_rectangle() final_brace = Brace(VGroup(parens, equals_0)) final_text = TexMobject("\\lambda", "=1") final_text.set_color_by_tex("\\lambda", MAROON_B) final_text.next_to(final_brace, DOWN) lambda_equals_two = VGroup(*final_text[:2]).copy() lambda_equals_two.add_to_back(BackgroundRectangle(lambda_equals_two)) final_text.add_background_rectangle() self.play( Write(det_text), Write(equals) ) self.wait() self.play( Write(parens), MoveToTarget(three_minus_lamb), MoveToTarget(two_minus_lamb), run_time = 2 ) self.wait() self.play( FadeIn(new_rect), MoveToTarget(one), MoveToTarget(zero), Write(minus), Write(cdot), run_time = 2 ) self.play( GrowFromCenter(brace), Write(brace_text) ) self.wait() self.play(* list(map(FadeOut, [ one, zero, minus, cdot, new_rect, brace, brace_text ]))) self.wait() self.play(Write(equals_0)) self.wait() self.play( FadeIn(final_brace), FadeIn(final_text) ) self.wait() # faders = [ # det_text, equals, parens, # three_minus_lamb, two_minus_lamb, # brace, brace_text, equals_0, # ] # if to_fade is not None: # faders.append(to_fade) # self.play(*it.chain( # map(FadeOut, faders), # [ # lambda_equals_two.scale_in_place, 1.3, # lambda_equals_two.next_to, self.matrix, DOWN # ] # )) # self.add_foreground_mobject(lambda_equals_two) # self.lambda_equals_two = lambda_equals_two # self.wait() class EigenvalueCanHaveMultipleEigenVectors(TeacherStudentsScene): def construct(self): self.teacher_says(""" A single eigenvalue can have more that a line full of eigenvectors """) self.change_student_modes(*["pondering"]*3) self.random_blink(2) class ScalingExample(LinearTransformationScene): CONFIG = { "t_matrix" : [[2, 0], [0, 2]] } def construct(self): matrix = Matrix(self.t_matrix.T) matrix.set_color_columns(X_COLOR, Y_COLOR) matrix.add_to_back(BackgroundRectangle(matrix)) matrix.next_to(ORIGIN, LEFT) matrix.to_edge(UP) words = TextMobject("Scale everything by 2") words.add_background_rectangle() words.next_to(matrix, RIGHT) self.add_foreground_mobject(matrix, words) for coords in [2, 1], [-2.5, -1], [1, -1]: self.add_vector(coords, color = random_color()) self.wait() self.apply_transposed_matrix(self.t_matrix) self.wait() class IntroduceEigenbasis(TeacherStudentsScene): def construct(self): words1, words2 = list(map(TextMobject, [ "Finish with ``eigenbasis.''", """Make sure you've watched the last video""" ])) words1.set_color(YELLOW) self.teacher_says(words1) self.change_student_modes( "pondering", "raise_right_hand", "erm" ) self.random_blink() new_words = VGroup(words1.copy(), words2) new_words.arrange_submobjects(DOWN, buff = MED_SMALL_BUFF) new_words.scale(0.8) self.teacher.bubble.add_content(new_words) self.play( self.get_teacher().change_mode, "sassy", Write(words2), Transform(words1, new_words[0]) ) student = self.get_students()[0] self.play( student.change_mode, "guilty", student.look, LEFT ) self.random_blink(2) class BasisVectorsAreEigenvectors(LinearTransformationScene): CONFIG = { "t_matrix" : [[-1, 0], [0, 2]] } def construct(self): matrix = Matrix(self.t_matrix.T) matrix.set_color_columns(X_COLOR, Y_COLOR) matrix.next_to(ORIGIN, LEFT) matrix.to_edge(UP) words = TextMobject( "What if both basis vectors \\\\", "are eigenvectors?" ) for word in words: word.add_to_back(BackgroundRectangle(word)) words.to_corner(UP+RIGHT) self.play(Write(words)) self.add_foreground_mobject(words) self.wait() self.apply_transposed_matrix([self.t_matrix[0], [0, 1]]) self.wait() self.apply_transposed_matrix([[1, 0], self.t_matrix[1]]) self.wait() i_coords = Matrix(self.t_matrix[0]) i_coords.next_to(self.i_hat.get_end(), DOWN+LEFT) i_coords.set_color(X_COLOR) j_coords = Matrix(self.t_matrix[1]) j_coords.next_to(self.j_hat.get_end(), RIGHT) j_coords.set_color(Y_COLOR) for array in matrix, i_coords, j_coords: array.rect = BackgroundRectangle(array) array.add_to_back(array.rect) self.play(*list(map(Write, [i_coords, j_coords]))) self.wait() self.play( Transform(i_coords.rect, matrix.rect), Transform(i_coords.get_brackets(), matrix.get_brackets()), i_coords.get_entries().move_to, VGroup( *matrix.get_mob_matrix()[:,0] ) ) self.play( FadeOut(j_coords.rect), FadeOut(j_coords.get_brackets()), j_coords.get_entries().move_to, VGroup( *matrix.get_mob_matrix()[:,1] ) ) self.remove(i_coords, j_coords) self.add(matrix) self.wait() diag_entries = VGroup(*[ matrix.get_mob_matrix()[i, i] for i in range(2) ]) off_diag_entries = VGroup(*[ matrix.get_mob_matrix()[1-i, i] for i in range(2) ]) for entries in diag_entries, off_diag_entries: self.play( entries.scale_in_place, 1.3, entries.set_color, YELLOW, run_time = 2, rate_func = there_and_back ) self.wait() class DefineDiagonalMatrix(Scene): def construct(self): n_dims = 4 numerical_matrix = np.identity(n_dims, dtype = 'int') for x in range(n_dims): numerical_matrix[x, x] = random.randint(-9, 9) matrix = Matrix(numerical_matrix) diag_entries = VGroup(*[ matrix.get_mob_matrix()[i,i] for i in range(n_dims) ]) off_diag_entries = VGroup(*[ matrix.get_mob_matrix()[i, j] for i in range(n_dims) for j in range(n_dims) if i != j ]) title = TextMobject("``Diagonal matrix''") title.to_edge(UP) self.add(matrix) self.wait() for entries in off_diag_entries, diag_entries: self.play( entries.scale_in_place, 1.1, entries.set_color, YELLOW, rate_func = there_and_back, ) self.wait() self.play(Write(title)) self.wait() self.play( matrix.set_color_columns, X_COLOR, Y_COLOR, Z_COLOR, YELLOW ) self.wait() self.play(diag_entries.set_color, MAROON_B) self.play( diag_entries.scale_in_place, 1.1, rate_func = there_and_back, ) self.wait() class RepeatedMultiplicationInAction(Scene): def construct(self): vector = Matrix(["x", "y"]) vector.set_color(YELLOW) vector.scale(1.2) vector.shift(RIGHT) matrix, scalars = self.get_matrix(vector) #First multiplication for v_entry, scalar in zip(vector.get_entries(), scalars): scalar.target = scalar.copy() scalar.target.next_to(v_entry, LEFT) l_bracket = vector.get_brackets()[0] l_bracket.target = l_bracket.copy() l_bracket.target.next_to(VGroup(*[ scalar.target for scalar in scalars ]), LEFT) self.add(vector) self.play(*list(map(FadeIn, [matrix]+scalars))) self.wait() self.play( FadeOut(matrix), *list(map(MoveToTarget, scalars + [l_bracket])) ) self.wait() #nth multiplications for scalar in scalars: scalar.exp = VectorizedPoint(scalar.get_corner(UP+RIGHT)) scalar.exp.shift(SMALL_BUFF*RIGHT/2.) for new_exp in range(2, 6): matrix, new_scalars = self.get_matrix(vector) new_exp_mob = TexMobject(str(new_exp)).scale(0.7) movers = [] to_remove = [] for v_entry, scalar, new_scalar in zip(vector.get_entries(), scalars, new_scalars): scalar.exp.target = new_exp_mob.copy() scalar.exp.target.set_color(scalar.get_color()) scalar.exp.target.move_to(scalar.exp, aligned_edge = LEFT) new_scalar.target = scalar.exp.target scalar.target = scalar.copy() VGroup(scalar.target, scalar.exp.target).next_to( v_entry, LEFT, aligned_edge = DOWN ) movers += [scalar, scalar.exp, new_scalar] to_remove.append(new_scalar) l_bracket.target.next_to(VGroup(*[ scalar.target for scalar in scalars ]), LEFT) movers.append(l_bracket) self.play(*list(map(FadeIn, [matrix]+new_scalars))) self.wait() self.play( FadeOut(matrix), *list(map(MoveToTarget, movers)) ) self.remove(*to_remove) self.wait() def get_matrix(self, vector): matrix = Matrix([[3, 0], [0, 2]]) matrix.set_color_columns(X_COLOR, Y_COLOR) matrix.next_to(vector, LEFT) scalars = [matrix.get_mob_matrix()[i, i] for i in range(2)] matrix.remove(*scalars) return matrix, scalars class RepeatedMultilpicationOfMatrices(Scene): CONFIG = { "matrix" : [[3, 0], [0, 2]], "diagonal" : True, } def construct(self): vector = Matrix(["x", "y"]) vector.set_color(YELLOW) matrix = Matrix(self.matrix) matrix.set_color_columns(X_COLOR, Y_COLOR) matrices = VGroup(*[ matrix.copy(), TexMobject("\\dots\\dots"), matrix.copy(), matrix.copy(), matrix.copy(), ]) last_matrix = matrices[-1] group = VGroup(*list(matrices) + [vector]) group.arrange_submobjects() brace = Brace(matrices) brace_text = brace.get_text("100", "times") hundred = brace_text[0] hundred_copy = hundred.copy() self.add(vector) for matrix in reversed(list(matrices)): self.play(FadeIn(matrix)) self.wait() self.play( GrowFromCenter(brace), Write(brace_text) ) self.wait() if self.diagonal: last_matrix.target = last_matrix.copy() for i, hund in enumerate([hundred, hundred_copy]): entry = last_matrix.target.get_mob_matrix()[i, i] hund.target = hund.copy() hund.target.scale(0.5) hund.target.next_to(entry, UP+RIGHT, buff = 0) hund.target.set_color(entry.get_color()) VGroup(hund.target, entry).move_to(entry, aligned_edge = DOWN) lb, rb = last_matrix.target.get_brackets() lb.shift(SMALL_BUFF*LEFT) rb.shift(SMALL_BUFF*RIGHT) VGroup( last_matrix.target, hundred.target, hundred_copy.target ).next_to(vector, LEFT) self.play(*it.chain( list(map(FadeOut, [brace, brace_text[1]] + list(matrices[:-1]))), list(map(MoveToTarget, [hundred, hundred_copy, last_matrix])) ), run_time = 2) self.wait() else: randy = Randolph().to_corner() self.play(FadeIn(randy)) self.play(randy.change_mode, "angry") self.play(Blink(randy)) self.wait() self.play(Blink(randy)) self.wait() class RepeatedMultilpicationOfNonDiagonalMatrices(RepeatedMultilpicationOfMatrices): CONFIG = { "matrix" : [[3, 4], [1, 1]], "diagonal" : False, } class WhatAreTheOddsOfThat(TeacherStudentsScene): def construct(self): self.student_says(""" Sure, but what are the odds of that happening? """) self.random_blink() self.change_student_modes("pondering") self.random_blink(3) class LastVideo(Scene): def construct(self): title = TextMobject("Last chapter: Change of basis") title.to_edge(UP) rect = Rectangle(width = 16, height = 9, color = BLUE) rect.set_height(6) rect.next_to(title, DOWN, buff = MED_SMALL_BUFF) self.add(title) self.play(ShowCreation(rect)) self.wait() class ChangeToEigenBasis(ExampleTranformationScene): CONFIG = { "show_basis_vectors" : False, "include_background_plane" : False, "foreground_plane_kwargs" : { "x_radius" : FRAME_WIDTH, "y_radius" : FRAME_HEIGHT, "secondary_line_ratio" : 0 }, } def construct(self): self.plane.fade() self.introduce_eigenvectors() self.write_change_of_basis_matrix() self.ask_about_power() def introduce_eigenvectors(self): x_vectors, v_vectors = [ VGroup(*[ self.add_vector(u*x*vect, animate = False) for x in range(num, 0, -1) for u in [-1, 1] ]) for vect, num in [(RIGHT, 7), (UP+LEFT, 4)] ] x_vectors.set_color_by_gradient(YELLOW, X_COLOR) v_vectors.set_color_by_gradient(MAROON_B, YELLOW) self.remove(x_vectors, v_vectors) self.play(ShowCreation(x_vectors, run_time = 2)) self.play(ShowCreation(v_vectors, run_time = 2)) self.wait() self.plane.save_state() self.apply_transposed_matrix( self.t_matrix, rate_func = there_and_back, path_arc = 0 ) x_vector = x_vectors[-1] v_vector = v_vectors[-1] x_vectors.remove(x_vector) v_vectors.remove(v_vector) words = TextMobject("Eigenvectors span space") new_words = TextMobject("Use eigenvectors as basis") for text in words, new_words: text.add_background_rectangle() text.next_to(ORIGIN, DOWN+LEFT, buff = MED_SMALL_BUFF) # text.to_edge(RIGHT) self.play(Write(words)) self.play( FadeOut(x_vectors), FadeOut(v_vectors), Animation(x_vector), Animation(v_vector), ) self.wait() self.play(Transform(words, new_words)) self.wait() self.b1, self.b2 = x_vector, v_vector self.moving_vectors = [self.b1, self.b2] self.to_fade = [words] def write_change_of_basis_matrix(self): b1, b2 = self.b1, self.b2 for vect in b1, b2: vect.coords = vector_coordinate_label(vect) vect.coords.set_color(vect.get_color()) vect.entries = vect.coords.get_entries() vect.entries.target = vect.entries.copy() b1.coords.next_to(b1.get_end(), DOWN+RIGHT) b2.coords.next_to(b2.get_end(), LEFT) for vect in b1, b2: self.play(Write(vect.coords)) self.wait() cob_matrix = Matrix(np.array([ list(vect.entries.target) for vect in (b1, b2) ]).T) cob_matrix.rect = BackgroundRectangle(cob_matrix) cob_matrix.add_to_back(cob_matrix.rect) cob_matrix.set_height(self.matrix.get_height()) cob_matrix.next_to(self.matrix) brace = Brace(cob_matrix) brace_text = brace.get_text("Change of basis matrix") brace_text.next_to(brace, DOWN, aligned_edge = LEFT) brace_text.add_background_rectangle() copies = [vect.coords.copy() for vect in (b1, b2)] self.to_fade += copies self.add(*copies) self.play( Transform(b1.coords.rect, cob_matrix.rect), Transform(b1.coords.get_brackets(), cob_matrix.get_brackets()), MoveToTarget(b1.entries) ) to_remove = self.get_mobjects_from_last_animation() self.play(MoveToTarget(b2.entries)) to_remove += self.get_mobjects_from_last_animation() self.remove(*to_remove) self.add(cob_matrix) self.to_fade += [b2.coords] self.play( GrowFromCenter(brace), Write(brace_text) ) self.to_fade += [brace, brace_text] self.wait() inv_cob = cob_matrix.copy() inv_cob.target = inv_cob.copy() neg_1 = TexMobject("-1") neg_1.add_background_rectangle() inv_cob.target.next_to( self.matrix, LEFT, buff = neg_1.get_width()+2*SMALL_BUFF ) neg_1.next_to( inv_cob.target.get_corner(UP+RIGHT), RIGHT, ) self.play( MoveToTarget(inv_cob, path_arc = -np.pi/2), Write(neg_1) ) self.wait() self.add_foreground_mobject(cob_matrix, inv_cob, neg_1) self.play(*list(map(FadeOut, self.to_fade))) self.wait() self.play(FadeOut(self.plane)) cob_transform = self.get_matrix_transformation([[1, 0], [-1, 1]]) ApplyMethod(self.plane.apply_function, cob_transform).update(1) self.plane.main_lines.set_color(BLUE_D) self.plane.axes.set_color(WHITE) self.play( FadeIn(self.plane), *list(map(Animation, self.foreground_mobjects+self.moving_vectors)) ) self.add(self.plane.copy().set_color(GREY).set_stroke(width = 2)) self.apply_transposed_matrix(self.t_matrix) equals = TexMobject("=").next_to(cob_matrix) final_matrix = Matrix([[3, 0], [0, 2]]) final_matrix.add_to_back(BackgroundRectangle(final_matrix)) for i in range(2): final_matrix.get_mob_matrix()[i, i].set_color(MAROON_B) final_matrix.next_to(equals, RIGHT) self.play( Write(equals), Write(final_matrix) ) self.wait() eigenbasis = TextMobject("``Eigenbasis''") eigenbasis.add_background_rectangle() eigenbasis.next_to(ORIGIN, DOWN) self.play(Write(eigenbasis)) self.wait() def ask_about_power(self): morty = Mortimer() morty.to_edge(DOWN).shift(LEFT) bubble = morty.get_bubble( "speech", height = 3, width = 5, direction = RIGHT ) bubble.set_fill(BLACK, opacity = 1) matrix_copy = self.matrix.copy().scale(0.7) hundred = TexMobject("100").scale(0.7) hundred.next_to(matrix_copy.get_corner(UP+RIGHT), RIGHT) compute = TextMobject("Compute") compute.next_to(matrix_copy, LEFT, buff = MED_SMALL_BUFF) words = VGroup(compute, matrix_copy, hundred) bubble.add_content(words) self.play(FadeIn(morty)) self.play( morty.change_mode, "speaking", ShowCreation(bubble), Write(words) ) for x in range(2): self.play(Blink(morty)) self.wait(2) class CannotDoWithWithAllTransformations(TeacherStudentsScene): def construct(self): self.teacher_says(""" Not all matrices can become diagonal """) self.change_student_modes(*["tired"]*3) self.random_blink(2)