3b1b-manim/old_projects/eola/chapter4.py
2018-08-21 19:15:16 -07:00

1082 lines
36 KiB
Python

from big_ol_pile_of_manim_imports import *
from eola.chapter3 import MatrixVectorMultiplicationAbstract
class OpeningQuote(Scene):
def construct(self):
words = TextMobject([
"It is my experience that proofs involving",
"matrices",
"can be shortened by 50\\% if one",
"throws the matrices out."
])
words.set_width(FRAME_WIDTH - 2)
words.to_edge(UP)
words.split()[1].set_color(GREEN)
words.split()[3].set_color(BLUE)
author = TextMobject("-Emil Artin")
author.set_color(YELLOW)
author.next_to(words, DOWN, buff = 0.5)
self.play(FadeIn(words))
self.wait(2)
self.play(Write(author, run_time = 3))
self.wait()
class MatrixToBlank(Scene):
def construct(self):
matrix = Matrix([[3, 1], [0, 2]])
arrow = Arrow(LEFT, RIGHT)
matrix.to_edge(LEFT)
arrow.next_to(matrix, RIGHT)
matrix.add(arrow)
self.play(Write(matrix))
self.wait()
class ExampleTransformation(LinearTransformationScene):
def construct(self):
self.setup()
self.apply_transposed_matrix([[3, 0], [1, 2]])
self.wait(2)
class RecapTime(TeacherStudentsScene):
def construct(self):
self.setup()
self.teacher_says("Quick recap time!")
self.random_blink()
self.wait()
student = self.get_students()[0]
everyone = self.get_mobjects()
everyone.remove(student)
everyone = VMobject(*everyone)
self.play(
ApplyMethod(everyone.fade, 0.7),
ApplyMethod(student.change_mode, "confused")
)
self.play(Blink(student))
self.wait()
self.play(ApplyFunction(
lambda m : m.change_mode("pondering").look(LEFT),
student
))
self.play(Blink(student))
self.wait()
class DeterminedByTwoBasisVectors(LinearTransformationScene):
CONFIG = {
"show_basis_vectors" : False
}
def construct(self):
self.setup()
i_hat = self.add_vector([1, 0], color = X_COLOR)
self.add_transformable_label(
i_hat, "\\hat{\\imath}", "\\hat{\\imath}",
color = X_COLOR
)
j_hat = self.add_vector([0, 1], color = Y_COLOR)
self.add_transformable_label(
j_hat, "\\hat{\\jmath}", "\\hat{\\jmath}",
color = Y_COLOR
)
t_matrix = np.array([[2, 2], [-2, 1]])
matrix = t_matrix.transpose()
matrix1 = np.array(matrix)
matrix1[:,1] = [0, 1]
matrix2 = np.dot(matrix, np.linalg.inv(matrix1))
self.wait()
self.apply_transposed_matrix(matrix1.transpose())
self.apply_transposed_matrix(matrix2.transpose())
self.wait()
class FollowLinearCombination(LinearTransformationScene):
def construct(self):
vect_coords = [-1, 2]
t_matrix = np.array([[2, 2], [-2, 1]])
#Draw vectors
self.setup()
i_label = self.add_transformable_label(
self.i_hat, "\\hat{\\imath}", animate = False,
direction = "right", color = X_COLOR
)
j_label = self.add_transformable_label(
self.j_hat, "\\hat{\\jmath}", animate = False,
direction = "right", color = Y_COLOR
)
vect = self.add_vector(vect_coords)
vect_array = Matrix(["x", "y"], add_background_rectangles_to_entries = True)
v_equals = TexMobject(["\\vec{\\textbf{v}}", "="])
v_equals.split()[0].set_color(YELLOW)
v_equals.next_to(vect_array, LEFT)
vect_array.add(v_equals)
vect_array.to_edge(UP, buff = 0.2)
background_rect = BackgroundRectangle(vect_array)
vect_array.get_entries().set_color(YELLOW)
self.play(ShowCreation(background_rect), Write(vect_array))
self.add_foreground_mobject(background_rect, vect_array)
#Show scaled vectors
x, y = vect_array.get_entries().split()
scaled_i_label = VMobject(x.copy(), i_label)
scaled_j_label = VMobject(y.copy(), j_label)
scaled_i = self.i_hat.copy().scale(vect_coords[0])
scaled_j = self.j_hat.copy().scale(vect_coords[1])
for mob in scaled_i, scaled_j:
mob.fade(0.3)
scaled_i_label_target = scaled_i_label.copy()
scaled_i_label_target.arrange_submobjects(buff = 0.1)
scaled_i_label_target.next_to(scaled_i, DOWN)
scaled_j_label_target = scaled_j_label.copy()
scaled_j_label_target.arrange_submobjects(buff = 0.1)
scaled_j_label_target.next_to(scaled_j, LEFT)
self.show_scaled_vectors(vect_array, vect_coords, i_label, j_label)
self.apply_transposed_matrix(t_matrix)
self.show_scaled_vectors(vect_array, vect_coords, i_label, j_label)
self.record_basis_coordinates(vect_array, vect)
def show_scaled_vectors(self, vect_array, vect_coords, i_label, j_label):
x, y = vect_array.get_entries().split()
scaled_i_label = VMobject(x.copy(), i_label.copy())
scaled_j_label = VMobject(y.copy(), j_label.copy())
scaled_i = self.i_hat.copy().scale(vect_coords[0])
scaled_j = self.j_hat.copy().scale(vect_coords[1])
for mob in scaled_i, scaled_j:
mob.fade(0.3)
scaled_i_label_target = scaled_i_label.copy()
scaled_i_label_target.arrange_submobjects(buff = 0.1)
scaled_i_label_target.next_to(scaled_i.get_center(), DOWN)
scaled_j_label_target = scaled_j_label.copy()
scaled_j_label_target.arrange_submobjects(buff = 0.1)
scaled_j_label_target.next_to(scaled_j.get_center(), LEFT)
self.play(
Transform(self.i_hat.copy(), scaled_i),
Transform(scaled_i_label, scaled_i_label_target)
)
scaled_i = self.get_mobjects_from_last_animation()[0]
self.play(
Transform(self.j_hat.copy(), scaled_j),
Transform(scaled_j_label, scaled_j_label_target)
)
scaled_j = self.get_mobjects_from_last_animation()[0]
self.play(*[
ApplyMethod(mob.shift, scaled_i.get_end())
for mob in (scaled_j, scaled_j_label)
])
self.wait()
self.play(*list(map(FadeOut, [
scaled_i, scaled_j, scaled_i_label, scaled_j_label,
])))
def record_basis_coordinates(self, vect_array, vect):
i_label = vector_coordinate_label(self.i_hat)
i_label.set_color(X_COLOR)
j_label = vector_coordinate_label(self.j_hat)
j_label.set_color(Y_COLOR)
for mob in i_label, j_label:
mob.scale_in_place(0.8)
background = BackgroundRectangle(mob)
self.play(ShowCreation(background), Write(mob))
self.wait()
x, y = vect_array.get_entries().split()
pre_formula = VMobject(
x, i_label, TexMobject("+"),
y, j_label
)
post_formula = pre_formula.copy()
pre_formula.split()[2].fade(1)
post_formula.arrange_submobjects(buff = 0.1)
post_formula.next_to(vect, DOWN)
background = BackgroundRectangle(post_formula)
everything = self.get_mobjects()
everything.remove(vect)
self.play(*[
ApplyMethod(m.fade) for m in everything
] + [
ShowCreation(background, run_time = 2, rate_func = squish_rate_func(smooth, 0.5, 1)),
Transform(pre_formula.copy(), post_formula, run_time = 2),
ApplyMethod(vect.set_stroke, width = 7)
])
self.wait()
class MatrixVectorMultiplicationCopy(MatrixVectorMultiplicationAbstract):
pass ## Here just for stage_animations.py purposes
class RecapOver(TeacherStudentsScene):
def construct(self):
self.setup()
self.teacher_says("Recap over!")
class TwoSuccessiveTransformations(LinearTransformationScene):
CONFIG = {
"foreground_plane_kwargs" : {
"x_radius" : FRAME_WIDTH,
"y_radius" : FRAME_WIDTH,
"secondary_line_ratio" : 0
},
}
def construct(self):
self.setup()
self.apply_transposed_matrix([[2, 1],[1, 2]])
self.apply_transposed_matrix([[-1, -0.5],[0, -0.5]])
self.wait()
class RotationThenShear(LinearTransformationScene):
CONFIG = {
"foreground_plane_kwargs" : {
"x_radius" : FRAME_X_RADIUS,
"y_radius" : FRAME_WIDTH,
"secondary_line_ratio" : 0
},
}
def construct(self):
self.setup()
rot_words = TextMobject("$90^\\circ$ rotation counterclockwise")
shear_words = TextMobject("followed by a shear")
rot_words.set_color(YELLOW)
shear_words.set_color(PINK)
VMobject(rot_words, shear_words).arrange_submobjects(DOWN).to_edge(UP)
for words in rot_words, shear_words:
words.add_background_rectangle()
self.play(Write(rot_words, run_time = 1))
self.add_foreground_mobject(rot_words)
self.apply_transposed_matrix([[0, 1], [-1, 0]])
self.play(Write(shear_words, run_time = 1))
self.add_foreground_mobject(shear_words)
self.apply_transposed_matrix([[1, 0], [1, 1]])
self.wait()
class IntroduceIdeaOfComposition(RotationThenShear):
def construct(self):
self.setup()
self.show_composition()
matrix = self.track_basis_vectors()
self.show_overall_effect(matrix)
def show_composition(self):
words = TextMobject([
"``Composition''",
"of a",
"rotation",
"and a",
"shear"
])
words.split()[0].set_submobject_colors_by_gradient(YELLOW, PINK, use_color_range_to = False)
words.split()[2].set_color(YELLOW)
words.split()[4].set_color(PINK)
words.add_background_rectangle()
words.to_edge(UP)
self.apply_transposed_matrix([[0, 1], [-1, 0]], run_time = 2)
self.apply_transposed_matrix([[1, 0], [1, 1]], run_time = 2)
self.play(
ApplyMethod(self.plane.fade),
Write(words),
Animation(self.i_hat),
Animation(self.j_hat),
)
self.wait()
def track_basis_vectors(self):
last_words = self.get_mobjects_from_last_animation()[1]
words = TextMobject([
"Record where",
"$\\hat{\\imath}$",
"and",
"$\\hat{\\jmath}$",
"land:"
])
rw, i_hat, a, j_hat, l = words.split()
i_hat.set_color(X_COLOR)
j_hat.set_color(Y_COLOR)
words.add_background_rectangle()
words.next_to(last_words, DOWN)
i_coords = vector_coordinate_label(self.i_hat)
j_coords = vector_coordinate_label(self.j_hat)
i_coords.set_color(X_COLOR)
j_coords.set_color(Y_COLOR)
i_background = BackgroundRectangle(i_coords)
j_background = BackgroundRectangle(j_coords)
matrix = Matrix(np.append(
i_coords.copy().get_mob_matrix(),
j_coords.copy().get_mob_matrix(),
axis = 1
))
matrix.next_to(words, RIGHT, aligned_edge = UP)
col1, col2 = [
VMobject(*matrix.get_mob_matrix()[:,i])
for i in (0, 1)
]
matrix_background = BackgroundRectangle(matrix)
self.play(Write(words))
self.wait()
self.play(ShowCreation(i_background), Write(i_coords), run_time = 2)
self.wait()
self.play(
Transform(i_background.copy(), matrix_background),
Transform(i_coords.copy().get_brackets(), matrix.get_brackets()),
ApplyMethod(i_coords.copy().get_entries().move_to, col1)
)
self.wait()
self.play(ShowCreation(j_background), Write(j_coords), run_time = 2)
self.wait()
self.play(
ApplyMethod(j_coords.copy().get_entries().move_to, col2)
)
self.wait()
matrix = VMobject(matrix_background, matrix)
return matrix
def show_overall_effect(self, matrix):
everything = self.get_mobjects()
everything = list_difference_update(
everything, matrix.get_family()
)
self.play(*list(map(FadeOut, everything)) + [Animation(matrix)])
new_matrix = matrix.copy()
new_matrix.center().to_edge(UP)
self.play(Transform(matrix, new_matrix))
self.wait()
self.remove(matrix)
self.setup()
everything = self.get_mobjects()
self.play(*list(map(FadeIn, everything)) + [Animation(matrix)])
func = self.get_matrix_transformation([[1, 1], [-1, 0]])
bases = VMobject(self.i_hat, self.j_hat)
new_bases = VMobject(*[
Vector(func(v.get_end()), color = v.get_color())
for v in bases.split()
])
self.play(
ApplyPointwiseFunction(func, self.plane),
Transform(bases, new_bases),
Animation(matrix),
run_time = 3
)
self.wait()
class PumpVectorThroughRotationThenShear(RotationThenShear):
def construct(self):
self.setup()
self.add_vector([2, 3])
self.apply_transposed_matrix([[0, 1], [-1, 0]], run_time = 2)
self.apply_transposed_matrix([[1, 0], [1, 1]], run_time = 2)
self.wait()
class ExplainWhyItsMatrixMultiplication(Scene):
def construct(self):
vect = Matrix(["x", "y"])
vect.get_entries().set_color(YELLOW)
rot_matrix = Matrix([[0, -1], [1, 0]])
rot_matrix.set_color(TEAL)
shear_matrix = Matrix([[1, 1], [0, 1]])
shear_matrix.set_color(PINK)
l_paren, r_paren = list(map(TexMobject, ["\\Big(", "\\Big)"]))
for p in l_paren, r_paren:
p.set_height(1.4*vect.get_height())
long_way = VMobject(
shear_matrix, l_paren, rot_matrix, vect, r_paren
)
long_way.arrange_submobjects(buff = 0.1)
long_way.to_edge(LEFT).shift(UP)
equals = TexMobject("=").next_to(long_way, RIGHT)
comp_matrix = Matrix([[1, -1], [1, 0]])
comp_matrix.set_color_columns(X_COLOR, Y_COLOR)
vect_copy = vect.copy()
short_way = VMobject(comp_matrix, vect_copy)
short_way.arrange_submobjects(buff = 0.1)
short_way.next_to(equals, RIGHT)
pairs = [
(rot_matrix, "Rotation"),
(shear_matrix, "Shear"),
(comp_matrix, "Composition"),
]
for matrix, word in pairs:
brace = Brace(matrix)
text = TextMobject(word).next_to(brace, DOWN)
brace.set_color(matrix.get_color())
text.set_color(matrix.get_color())
matrix.add(brace, text)
comp_matrix.split()[-1].set_submobject_colors_by_gradient(TEAL, PINK)
self.add(vect)
groups = [
[rot_matrix],
[l_paren, r_paren, shear_matrix],
[equals, comp_matrix, vect_copy],
]
for group in groups:
self.play(*list(map(Write, group)))
self.wait()
self.play(*list(map(FadeOut, [l_paren, r_paren, vect, vect_copy])))
comp_matrix.add(equals)
matrices = VMobject(shear_matrix, rot_matrix, comp_matrix)
self.play(ApplyMethod(
matrices.arrange_submobjects, buff = 0.1,
aligned_edge = UP
))
self.wait()
arrow = Arrow(rot_matrix.get_right(), shear_matrix.get_left())
arrow.shift((rot_matrix.get_top()[1]+0.2)*UP)
words = TextMobject("Read right to left")
words.submobjects.reverse()
words.next_to(arrow, UP)
functions = TexMobject("f(g(x))")
functions.next_to(words, UP)
self.play(ShowCreation(arrow))
self.play(Write(words))
self.wait()
self.play(Write(functions))
self.wait()
class MoreComplicatedExampleVisually(LinearTransformationScene):
CONFIG = {
"t_matrix1" : [[1, 1], [-2, 0]],
"t_matrix2" : [[0, 1], [2, 0]],
}
def construct(self):
self.setup()
t_matrix1 = np.array(self.t_matrix1)
t_matrix2 = np.array(self.t_matrix2)
t_m1_inv = np.linalg.inv(t_matrix1.transpose()).transpose()
t_m2_inv = np.linalg.inv(t_matrix2.transpose()).transpose()
m1_mob, m2_mob, comp_matrix = self.get_matrices()
self.play(Write(m1_mob))
self.add_foreground_mobject(m1_mob)
self.wait()
self.apply_transposed_matrix(t_matrix1)
self.wait()
self.play(Write(m1_mob.label))
self.add_foreground_mobject(m1_mob.label)
self.wait()
self.apply_transposed_matrix(t_m1_inv, run_time = 0)
self.wait()
self.play(Write(m2_mob))
self.add_foreground_mobject(m2_mob)
self.wait()
self.apply_transposed_matrix(t_matrix2)
self.wait()
self.play(Write(m2_mob.label))
self.add_foreground_mobject(m2_mob.label)
self.wait()
self.apply_transposed_matrix(t_m2_inv, run_time = 0)
self.wait()
for matrix in t_matrix1, t_matrix2:
self.apply_transposed_matrix(matrix, run_time = 1)
self.play(Write(comp_matrix))
self.add_foreground_mobject(comp_matrix)
self.wait()
self.play(*list(map(FadeOut, [
self.background_plane,
self.plane,
self.i_hat,
self.j_hat,
])) + [
Animation(m) for m in self.foreground_mobjects
])
self.remove(self.i_hat, self.j_hat)
self.wait()
def get_matrices(self):
m1_mob = Matrix(np.array(self.t_matrix1).transpose())
m2_mob = Matrix(np.array(self.t_matrix2).transpose())
comp_matrix = Matrix([["?", "?"], ["?", "?"]])
m1_mob.set_color(YELLOW)
m2_mob.set_color(PINK)
comp_matrix.get_entries().set_submobject_colors_by_gradient(YELLOW, PINK)
equals = TexMobject("=")
equals.next_to(comp_matrix, LEFT)
comp_matrix.add(equals)
m1_mob = VMobject(BackgroundRectangle(m1_mob), m1_mob)
m2_mob = VMobject(BackgroundRectangle(m2_mob), m2_mob)
comp_matrix = VMobject(BackgroundRectangle(comp_matrix), comp_matrix)
VMobject(
m2_mob, m1_mob, comp_matrix
).arrange_submobjects(buff = 0.1).to_corner(UP+LEFT).shift(DOWN)
for i, mob in enumerate([m1_mob, m2_mob]):
brace = Brace(mob, UP)
text = TexMobject("M_%d"%(i+1))
text.next_to(brace, UP)
brace.add_background_rectangle()
text.add_background_rectangle()
brace.add(text)
mob.label = brace
return m1_mob, m2_mob, comp_matrix
class MoreComplicatedExampleNumerically(MoreComplicatedExampleVisually):
def get_result(self):
return np.dot(self.t_matrix1, self.t_matrix2).transpose()
def construct(self):
m1_mob, m2_mob, comp_matrix = self.get_matrices()
self.add(m1_mob, m2_mob, m1_mob.label, m2_mob.label, comp_matrix)
result = self.get_result()
col1, col2 = [
VMobject(*m1_mob.split()[1].get_mob_matrix()[:,i])
for i in (0, 1)
]
col1.target_color = X_COLOR
col2.target_color = Y_COLOR
for col in col1, col2:
circle = Circle()
circle.stretch_to_fit_height(m1_mob.get_height())
circle.stretch_to_fit_width(m1_mob.get_width()/2.5)
circle.set_color(col.target_color)
circle.move_to(col)
col.circle = circle
triplets = [
(col1, "i", X_COLOR),
(col2, "j", Y_COLOR),
]
for i, (col, char, color) in enumerate(triplets):
self.add(col)
start_state = self.get_mobjects()
question = TextMobject(
"Where does $\\hat{\\%smath}$ go?"%char
)
question.split()[-4].set_color(color)
question.split()[-5].set_color(color)
question.scale(1.2)
question.shift(DOWN)
first = TextMobject("First here")
first.set_color(color)
first.shift(DOWN+LEFT)
first_arrow = Arrow(
first, col.circle.get_bottom(), color = color
)
second = TextMobject("Then to whatever this is")
second.set_color(color)
second.to_edge(RIGHT).shift(DOWN)
m2_copy = m2_mob.copy()
m2_target = m2_mob.copy()
m2_target.next_to(m2_mob, DOWN, buff = 1)
col_vect = Matrix(col.copy().split())
col_vect.set_color(color)
col_vect.next_to(m2_target, RIGHT, buff = 0.1)
second_arrow = Arrow(second, col_vect, color = color)
new_m2_copy = m2_mob.copy().split()[1]
intermediate = VMobject(
TexMobject("="),
col_vect.copy().get_entries().split()[0],
Matrix(new_m2_copy.get_mob_matrix()[:,0]),
TexMobject("+"),
col_vect.copy().get_entries().split()[1],
Matrix(new_m2_copy.get_mob_matrix()[:,1]),
TexMobject("=")
)
intermediate.arrange_submobjects(buff = 0.1)
intermediate.next_to(col_vect, RIGHT)
product = Matrix(result[:,i])
product.next_to(intermediate, RIGHT)
comp_col = VMobject(*comp_matrix.split()[1].get_mob_matrix()[:,i])
self.play(Write(question, run_time = 1 ))
self.wait()
self.play(
Transform(question, first),
ShowCreation(first_arrow),
ShowCreation(col.circle),
ApplyMethod(col.set_color, col.target_color)
)
self.wait()
self.play(
Transform(m2_copy, m2_target, run_time = 2),
ApplyMethod(col.copy().move_to, col_vect, run_time = 2),
Write(col_vect.get_brackets()),
Transform(first_arrow, second_arrow),
Transform(question, second),
)
self.wait()
self.play(*list(map(FadeOut, [question, first_arrow])))
self.play(Write(intermediate))
self.wait()
self.play(Write(product))
self.wait()
product_entries = product.get_entries()
self.play(
ApplyMethod(comp_col.set_color, BLACK),
ApplyMethod(product_entries.move_to, comp_col)
)
self.wait()
start_state.append(product_entries)
self.play(*[
FadeOut(mob)
for mob in self.get_mobjects()
if mob not in start_state
] + [
Animation(product_entries)
])
self.wait()
class GeneralMultiplication(MoreComplicatedExampleNumerically):
def get_result(self):
entries = list(map(TexMobject, [
"ae+bg", "af+bh", "ce+dg", "cf+dh"
]))
for mob in entries:
mob.split()[0].set_color(PINK)
mob.split()[3].set_color(PINK)
for mob in entries[0], entries[2]:
mob.split()[1].set_color(X_COLOR)
mob.split()[4].set_color(X_COLOR)
for mob in entries[1], entries[3]:
mob.split()[1].set_color(Y_COLOR)
mob.split()[4].set_color(Y_COLOR)
return np.array(entries).reshape((2, 2))
def get_matrices(self):
m1, m2, comp = MoreComplicatedExampleNumerically.get_matrices(self)
self.add(m1, m2, m1.label, m2.label, comp)
m1_entries = m1.split()[1].get_entries()
m2_entries = m2.split()[1].get_entries()
m2_entries_target = VMobject(*[
TexMobject(char).move_to(entry).set_color(entry.get_color())
for entry, char in zip(m2_entries.split(), "abcd")
])
m1_entries_target = VMobject(*[
TexMobject(char).move_to(entry).set_color(entry.get_color())
for entry, char in zip(m1_entries.split(), "efgh")
])
words = TextMobject("This method works generally")
self.play(Write(words, run_time = 2))
self.play(Transform(
m1_entries, m1_entries_target,
submobject_mode = "lagged_start"
))
self.play(Transform(
m2_entries, m2_entries_target,
submobject_mode = "lagged_start"
))
self.wait()
new_comp = Matrix(self.get_result())
new_comp.next_to(comp.split()[1].submobjects[-1], RIGHT)
new_comp.get_entries().set_color(BLACK)
self.play(
Transform(comp.split()[1].get_brackets(), new_comp.get_brackets()),
*[
ApplyMethod(q_mark.move_to, entry)
for q_mark, entry in zip(
comp.split()[1].get_entries().split(),
new_comp.get_entries().split()
)
]
)
self.wait()
self.play(FadeOut(words))
return m1, m2, comp
class MoreComplicatedExampleWithJustIHat(MoreComplicatedExampleVisually):
CONFIG = {
"show_basis_vectors" : False,
"v_coords" : [1, 0],
"v_color" : X_COLOR,
}
def construct(self):
self.setup()
self.add_vector(self.v_coords, self.v_color)
self.apply_transposed_matrix(self.t_matrix1)
self.wait()
self.apply_transposed_matrix(self.t_matrix2)
self.wait()
class MoreComplicatedExampleWithJustJHat(MoreComplicatedExampleWithJustIHat):
CONFIG = {
"v_coords" : [0, 1],
"v_color" : Y_COLOR,
}
class RoteMatrixMultiplication(NumericalMatrixMultiplication):
CONFIG = {
"left_matrix" : [[-3, 1], [2, 5]],
"right_matrix" : [[5, 3], [7, -3]]
}
class NeverForget(TeacherStudentsScene):
def construct(self):
self.setup()
self.teacher_says("Never forget what \\\\ this represents!")
self.random_blink()
self.student_thinks("", student_index = 0)
def warp(point):
point += 2*DOWN+RIGHT
return 20*point/get_norm(point)
self.play(ApplyPointwiseFunction(
warp,
VMobject(*self.get_mobjects())
))
class AskAboutCommutativity(Scene):
def construct(self):
l_m1, l_m2, eq, r_m2, r_m1 = TexMobject([
"M_1", "M_2", "=", "M_2", "M_1"
]).scale(1.5).split()
VMobject(l_m1, r_m1).set_color(YELLOW)
VMobject(l_m2, r_m2).set_color(PINK)
q_marks = TextMobject("???")
q_marks.set_color(TEAL)
q_marks.next_to(eq, UP)
neq = TexMobject("\\neq")
neq.move_to(eq)
self.play(*list(map(Write, [l_m1, l_m2, eq])))
self.play(
Transform(l_m1.copy(), r_m1),
Transform(l_m2.copy(), r_m2),
path_arc = -np.pi,
run_time = 2
)
self.play(Write(q_marks))
self.wait()
self.play(Transform(
VMobject(eq, q_marks),
VMobject(neq),
submobject_mode = "lagged_start"
))
self.wait()
class ShowShear(LinearTransformationScene):
CONFIG = {
"title" : "Shear",
"title_color" : PINK,
"t_matrix" : [[1, 0], [1, 1]]
}
def construct(self):
self.setup()
title = TextMobject(self.title)
title.scale(1.5).to_edge(UP)
title.set_color(self.title_color)
title.add_background_rectangle()
self.add_foreground_mobject(title)
self.wait()
self.apply_transposed_matrix(self.t_matrix)
self.wait()
class ShowRotation(ShowShear):
CONFIG = {
"title" : "$90^\\circ$ rotation",
"title_color" : YELLOW,
"t_matrix" : [[0, 1], [-1, 0]]
}
class FirstShearThenRotation(LinearTransformationScene):
CONFIG = {
"title" : "First shear then rotation",
"t_matrix1" : [[1, 0], [1, 1]],
"t_matrix2" : [[0, 1], [-1, 0]],
"foreground_plane_kwargs" : {
"x_radius" : FRAME_WIDTH,
"y_radius" : FRAME_WIDTH,
"secondary_line_ratio" : 0
},
}
def construct(self):
self.setup()
title_parts = self.title.split(" ")
title = TextMobject(title_parts)
for i, part in enumerate(title_parts):
if part == "rotation":
title.split()[i].set_color(YELLOW)
elif part == "shear":
title.split()[i].set_color(PINK)
title.scale(1.5)
self.add_title(title)
self.apply_transposed_matrix(self.t_matrix1)
self.apply_transposed_matrix(self.t_matrix2)
self.i_hat.rotate(-0.01)##Laziness
self.wait()
self.write_vector_coordinates(self.i_hat, color = X_COLOR)
self.wait()
self.write_vector_coordinates(self.j_hat, color = Y_COLOR)
self.wait()
class RotationThenShear(FirstShearThenRotation):
CONFIG = {
"title" : "First rotation then shear",
"t_matrix1" : [[0, 1], [-1, 0]],
"t_matrix2" : [[1, 0], [1, 1]],
}
class NoticeTheLackOfComputations(TeacherStudentsScene):
def construct(self):
self.setup()
self.teacher_says("""
Notice the lack
of computations!
""")
self.random_blink()
students = self.get_students()
random.shuffle(students)
unit = np.array([-0.5, 0.5])
self.play(*[
ApplyMethod(
pi.change_mode, "pondering",
rate_func = squish_rate_func(smooth, *np.clip(unit+0.5*i, 0, 1))
)
for i, pi in enumerate(students)
])
self.random_blink()
self.wait()
class AskAssociativityQuestion(Scene):
def construct(self):
morty = Mortimer()
morty.scale(0.8)
morty.to_corner(DOWN+RIGHT)
morty.shift(0.5*LEFT)
title = TextMobject("Associativity:")
title.to_corner(UP+LEFT)
lhs = TexMobject(list("(AB)C"))
lp, a, b, rp, c = lhs.split()
rhs = VMobject(*[m.copy() for m in (a, lp, b, c, rp)])
point = VectorizedPoint()
start = VMobject(*[m.copy() for m in (point, a, b, point, c)])
for mob in lhs, rhs, start:
mob.arrange_submobjects(buff = 0.1)
a, lp, b, c, rp = rhs.split()
rhs = VMobject(lp, a, b, rp, c)##Align order to lhs
eq = TexMobject("=")
q_marks = TextMobject("???")
q_marks.set_submobject_colors_by_gradient(TEAL_B, TEAL_D)
q_marks.next_to(eq, UP)
lhs.next_to(eq, LEFT)
rhs.next_to(eq, RIGHT)
start.move_to(lhs)
self.add(morty, title)
self.wait()
self.play(Blink(morty))
self.play(Write(start))
self.wait()
self.play(Transform(start, lhs))
self.wait()
self.play(
Transform(lhs, rhs, path_arc = -np.pi),
Write(eq)
)
self.play(Write(q_marks))
self.play(Blink(morty))
self.play(morty.change_mode, "pondering")
lp, a, b, rp, c = start.split()
self.show_full_matrices(morty, a, b, c, title)
def show_full_matrices(self, morty, a, b, c, title):
everything = self.get_mobjects()
everything.remove(morty)
everything.remove(title)
everything = VMobject(*everything)
matrices = list(map(matrix_to_mobject, [
np.array(list(m)).reshape((2, 2))
for m in ("abcd", "efgh", "ijkl")
]))
VMobject(*matrices).arrange_submobjects()
self.play(everything.to_edge, UP)
for letter, matrix in zip([a, b, c], matrices):
self.play(Transform(
letter.copy(), matrix,
submobject_mode = "lagged_start"
))
self.remove(*self.get_mobjects_from_last_animation())
self.add(matrix)
self.wait()
self.move_matrix_parentheses(morty, matrices)
def move_matrix_parentheses(self, morty, matrices):
m1, m2, m3 = matrices
parens = TexMobject(["(", ")"])
parens.set_height(1.2*m1.get_height())
lp, rp = parens.split()
state1 = VMobject(
VectorizedPoint(m1.get_left()),
m1, m2,
VectorizedPoint(m2.get_right()),
m3
)
state2 = VMobject(*[
m.copy() for m in (lp, m1, m2, rp, m3)
])
state3 = VMobject(*[
m.copy() for m in (m1, lp, m2, m3, rp)
])
for state in state2, state3:
state.arrange_submobjects(RIGHT, buff = 0.1)
m1, lp, m2, m3, rp = state3.split()
state3 = VMobject(lp, m1, m2, rp, m3)
self.play(morty.change_mode, "angry")
for state in state2, state3:
self.play(Transform(state1, state))
self.wait()
self.play(morty.change_mode, "confused")
self.wait()
class ThreeSuccessiveTransformations(LinearTransformationScene):
CONFIG = {
"t_matrices" : [
[[2, 1], [1, 2]],
[[np.cos(-np.pi/6), np.sin(-np.pi/6)], [-np.sin(-np.pi/6), np.cos(-np.pi/6)]],
[[1, 0], [1, 1]]
],
"symbols_str" : "A(BC)",
"include_background_plane" : False,
}
def construct(self):
self.setup()
symbols = TexMobject(list(self.symbols_str))
symbols.scale(1.5)
symbols.to_edge(UP)
a, b, c = None, None, None
for mob, letter in zip(symbols.split(), self.symbols_str):
if letter == "A":
a = mob
elif letter == "B":
b = mob
elif letter == "C":
c = mob
symbols.add_background_rectangle()
self.add_foreground_mobject(symbols)
brace = Brace(c, DOWN)
words = TextMobject("Apply this transformation")
words.add_background_rectangle()
words.next_to(brace, DOWN)
brace.add(words)
self.play(Write(brace, run_time = 1))
self.add_foreground_mobject(brace)
last = VectorizedPoint()
for t_matrix, sym in zip(self.t_matrices, [c, b, a]):
self.play(
brace.next_to, sym, DOWN,
sym.set_color, YELLOW,
last.set_color, WHITE
)
self.apply_transposed_matrix(t_matrix, run_time = 1)
last = sym
self.wait()
class ThreeSuccessiveTransformationsAltParens(ThreeSuccessiveTransformations):
CONFIG = {
"symbols_str" : "(AB)C"
}
class ThreeSuccessiveTransformationsSimple(ThreeSuccessiveTransformations):
CONFIG = {
"symbols_str" : "ABC"
}
class ExplanationTrumpsProof(Scene):
def construct(self):
greater = TexMobject(">")
greater.shift(RIGHT)
explanation = TextMobject("Good explanation")
explanation.set_color(BLUE)
proof = TextMobject("Symbolic proof")
proof.set_color(LIGHT_BROWN)
explanation.next_to(greater, LEFT)
proof.next_to(greater, RIGHT)
explanation.get_center = lambda : explanation.get_right()
proof.get_center = lambda : proof.get_left()
self.play(
Write(explanation),
Write(greater),
Write(proof),
run_time = 1
)
self.play(
explanation.scale_in_place, 1.5,
proof.scale_in_place, 0.7
)
self.wait()
class GoPlay(TeacherStudentsScene):
def construct(self):
self.setup()
self.teacher_says("Go play!", height = 3, width = 5)
self.play(*[
ApplyMethod(student.change_mode, "happy")
for student in self.get_students()
])
self.random_blink()
student = self.get_students()[-1]
bubble = ThoughtBubble(direction = RIGHT, width = 6, height = 5)
bubble.pin_to(student, allow_flipping = False)
bubble.make_green_screen()
self.play(
ShowCreation(bubble),
student.look, UP+LEFT,
)
self.play(student.change_mode, "pondering")
for x in range(3):
self.random_blink()
self.wait(2)
class NextVideo(Scene):
def construct(self):
title = TextMobject("""
Next video: Linear transformations in three dimensions
""")
title.set_width(FRAME_WIDTH - 2)
title.to_edge(UP)
rect = Rectangle(width = 16, height = 9, color = BLUE)
rect.set_height(6)
rect.next_to(title, DOWN)
self.add(title)
self.play(ShowCreation(rect))
self.wait()