mirror of
https://github.com/3b1b/manim.git
synced 2025-08-01 08:54:38 +08:00
Up to associativity in EoLA chapter 4
This commit is contained in:
727
eola/chapter4.py
727
eola/chapter4.py
@ -263,7 +263,8 @@ class IntroduceIdeaOfComposition(RotationThenShear):
|
|||||||
def construct(self):
|
def construct(self):
|
||||||
self.setup()
|
self.setup()
|
||||||
self.show_composition()
|
self.show_composition()
|
||||||
self.track_basis_vectors()
|
matrix = self.track_basis_vectors()
|
||||||
|
self.show_overall_effect(matrix)
|
||||||
|
|
||||||
def show_composition(self):
|
def show_composition(self):
|
||||||
words = TextMobject([
|
words = TextMobject([
|
||||||
@ -281,12 +282,730 @@ class IntroduceIdeaOfComposition(RotationThenShear):
|
|||||||
|
|
||||||
self.apply_transposed_matrix([[0, 1], [-1, 0]], run_time = 2)
|
self.apply_transposed_matrix([[0, 1], [-1, 0]], run_time = 2)
|
||||||
self.apply_transposed_matrix([[1, 0], [1, 1]], run_time = 2)
|
self.apply_transposed_matrix([[1, 0], [1, 1]], run_time = 2)
|
||||||
self.play(Write(words))
|
self.play(
|
||||||
|
ApplyMethod(self.plane.fade),
|
||||||
|
Write(words),
|
||||||
|
Animation(self.i_hat),
|
||||||
|
Animation(self.j_hat),
|
||||||
|
)
|
||||||
self.dither()
|
self.dither()
|
||||||
|
|
||||||
def track_basis_vectors(self):
|
def track_basis_vectors(self):
|
||||||
pass
|
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.highlight(X_COLOR)
|
||||||
|
j_hat.highlight(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.highlight(X_COLOR)
|
||||||
|
j_coords.highlight(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.dither()
|
||||||
|
self.play(ShowCreation(i_background), Write(i_coords), run_time = 2)
|
||||||
|
self.dither()
|
||||||
|
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.dither()
|
||||||
|
self.play(ShowCreation(j_background), Write(j_coords), run_time = 2)
|
||||||
|
self.dither()
|
||||||
|
self.play(
|
||||||
|
ApplyMethod(j_coords.copy().get_entries().move_to, col2)
|
||||||
|
)
|
||||||
|
self.dither()
|
||||||
|
matrix = VMobject(matrix_background, matrix)
|
||||||
|
return matrix
|
||||||
|
|
||||||
|
def show_overall_effect(self, matrix):
|
||||||
|
everything = self.get_mobjects()
|
||||||
|
everything = list_difference_update(
|
||||||
|
everything, matrix.submobject_family()
|
||||||
|
)
|
||||||
|
self.play(*map(FadeOut, everything) + [Animation(matrix)])
|
||||||
|
new_matrix = matrix.copy()
|
||||||
|
new_matrix.center().to_edge(UP)
|
||||||
|
self.play(Transform(matrix, new_matrix))
|
||||||
|
self.dither()
|
||||||
|
self.remove(matrix)
|
||||||
|
|
||||||
|
self.setup()
|
||||||
|
everything = self.get_mobjects()
|
||||||
|
self.play(*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.dither()
|
||||||
|
|
||||||
|
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.dither()
|
||||||
|
|
||||||
|
class ExplainWhyItsMatrixMultiplication(Scene):
|
||||||
|
def construct(self):
|
||||||
|
vect = Matrix(["x", "y"])
|
||||||
|
vect.get_entries().highlight(YELLOW)
|
||||||
|
|
||||||
|
rot_matrix = Matrix([[0, -1], [1, 0]])
|
||||||
|
rot_matrix.highlight(TEAL)
|
||||||
|
shear_matrix = Matrix([[1, 1], [0, 1]])
|
||||||
|
shear_matrix.highlight(PINK)
|
||||||
|
l_paren, r_paren = map(TexMobject, ["\\Big(", "\\Big)"])
|
||||||
|
for p in l_paren, r_paren:
|
||||||
|
p.scale_to_fit_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.highlight_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.highlight(matrix.get_color())
|
||||||
|
text.highlight(matrix.get_color())
|
||||||
|
matrix.add(brace, text)
|
||||||
|
comp_matrix.split()[-1].submobject_gradient_highlight(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(*map(Write, group))
|
||||||
|
self.dither()
|
||||||
|
self.play(*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.dither()
|
||||||
|
|
||||||
|
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.dither()
|
||||||
|
self.play(Write(functions))
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
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.dither()
|
||||||
|
self.apply_transposed_matrix(t_matrix1)
|
||||||
|
self.dither()
|
||||||
|
self.play(Write(m1_mob.label))
|
||||||
|
self.add_foreground_mobject(m1_mob.label)
|
||||||
|
self.dither()
|
||||||
|
self.apply_transposed_matrix(t_m1_inv, run_time = 0)
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
self.play(Write(m2_mob))
|
||||||
|
self.add_foreground_mobject(m2_mob)
|
||||||
|
self.dither()
|
||||||
|
self.apply_transposed_matrix(t_matrix2)
|
||||||
|
self.dither()
|
||||||
|
self.play(Write(m2_mob.label))
|
||||||
|
self.add_foreground_mobject(m2_mob.label)
|
||||||
|
self.dither()
|
||||||
|
self.apply_transposed_matrix(t_m2_inv, run_time = 0)
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
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.dither()
|
||||||
|
self.play(*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.dither()
|
||||||
|
|
||||||
|
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.highlight(YELLOW)
|
||||||
|
m2_mob.highlight(PINK)
|
||||||
|
comp_matrix.get_entries().submobject_gradient_highlight(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.highlight(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].highlight(color)
|
||||||
|
question.split()[-5].highlight(color)
|
||||||
|
question.scale(1.2)
|
||||||
|
question.shift(DOWN)
|
||||||
|
first = TextMobject("First here")
|
||||||
|
first.highlight(color)
|
||||||
|
first.shift(DOWN+LEFT)
|
||||||
|
first_arrow = Arrow(
|
||||||
|
first, col.circle.get_bottom(), color = color
|
||||||
|
)
|
||||||
|
second = TextMobject("Then to whatever this is")
|
||||||
|
second.highlight(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.highlight(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.dither()
|
||||||
|
self.play(
|
||||||
|
Transform(question, first),
|
||||||
|
ShowCreation(first_arrow),
|
||||||
|
ShowCreation(col.circle),
|
||||||
|
ApplyMethod(col.highlight, col.target_color)
|
||||||
|
)
|
||||||
|
self.dither()
|
||||||
|
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.dither()
|
||||||
|
self.play(*map(FadeOut, [question, first_arrow]))
|
||||||
|
self.play(Write(intermediate))
|
||||||
|
self.dither()
|
||||||
|
self.play(Write(product))
|
||||||
|
self.dither()
|
||||||
|
product_entries = product.get_entries()
|
||||||
|
self.play(
|
||||||
|
ApplyMethod(comp_col.highlight, BLACK),
|
||||||
|
ApplyMethod(product_entries.move_to, comp_col)
|
||||||
|
)
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
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.dither()
|
||||||
|
|
||||||
|
class GeneralMultiplication(MoreComplicatedExampleNumerically):
|
||||||
|
def get_result(self):
|
||||||
|
entries = map(TexMobject, [
|
||||||
|
"ae+bg", "af+bh", "ce+dg", "cf+dh"
|
||||||
|
])
|
||||||
|
for mob in entries:
|
||||||
|
mob.split()[0].highlight(PINK)
|
||||||
|
mob.split()[3].highlight(PINK)
|
||||||
|
for mob in entries[0], entries[2]:
|
||||||
|
mob.split()[1].highlight(X_COLOR)
|
||||||
|
mob.split()[4].highlight(X_COLOR)
|
||||||
|
for mob in entries[1], entries[3]:
|
||||||
|
mob.split()[1].highlight(Y_COLOR)
|
||||||
|
mob.split()[4].highlight(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).highlight(entry.get_color())
|
||||||
|
for entry, char in zip(m2_entries.split(), "abcd")
|
||||||
|
])
|
||||||
|
m1_entries_target = VMobject(*[
|
||||||
|
TexMobject(char).move_to(entry).highlight(entry.get_color())
|
||||||
|
for entry, char in zip(m1_entries.split(), "efgh")
|
||||||
|
])
|
||||||
|
|
||||||
|
words = TextMobject("This method works genearlly")
|
||||||
|
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.dither()
|
||||||
|
|
||||||
|
new_comp = Matrix(self.get_result())
|
||||||
|
new_comp.next_to(comp.split()[1].submobjects[-1], RIGHT)
|
||||||
|
new_comp.get_entries().highlight(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.dither()
|
||||||
|
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.dither()
|
||||||
|
self.apply_transposed_matrix(self.t_matrix2)
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
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/np.linalg.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).highlight(YELLOW)
|
||||||
|
VMobject(l_m2, r_m2).highlight(PINK)
|
||||||
|
q_marks = TextMobject("???")
|
||||||
|
q_marks.highlight(TEAL)
|
||||||
|
q_marks.next_to(eq, UP)
|
||||||
|
neq = TexMobject("\\neq")
|
||||||
|
neq.move_to(eq)
|
||||||
|
|
||||||
|
self.play(*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.dither()
|
||||||
|
self.play(Transform(
|
||||||
|
VMobject(eq, q_marks),
|
||||||
|
VMobject(neq),
|
||||||
|
submobject_mode = "lagged_start"
|
||||||
|
))
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
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.highlight(self.title_color)
|
||||||
|
title.add_background_rectangle()
|
||||||
|
self.add_foreground_mobject(title)
|
||||||
|
|
||||||
|
self.dither()
|
||||||
|
self.apply_transposed_matrix(self.t_matrix)
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
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" : 2*SPACE_WIDTH,
|
||||||
|
"y_radius" : 2*SPACE_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].highlight(YELLOW)
|
||||||
|
elif part == "shear":
|
||||||
|
title.split()[i].highlight(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.dither()
|
||||||
|
self.write_vector_coordinates(self.i_hat, color = X_COLOR)
|
||||||
|
self.dither()
|
||||||
|
self.write_vector_coordinates(self.j_hat, color = Y_COLOR)
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
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.dither()
|
||||||
|
|
||||||
|
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.submobject_gradient_highlight(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.dither()
|
||||||
|
self.play(Blink(morty))
|
||||||
|
self.play(Write(start))
|
||||||
|
self.dither()
|
||||||
|
self.play(Transform(start, lhs))
|
||||||
|
self.dither()
|
||||||
|
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 = 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.dither()
|
||||||
|
self.move_matrix_parentheses(morty, matrices)
|
||||||
|
|
||||||
|
def move_matrix_parentheses(self, morty, matrices):
|
||||||
|
m1, m2, m3 = matrices
|
||||||
|
parens = TexMobject(["(", ")"])
|
||||||
|
parens.scale_to_fit_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.dither()
|
||||||
|
self.play(morty.change_mode, "confused")
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
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.highlight, YELLOW,
|
||||||
|
last.highlight, WHITE
|
||||||
|
)
|
||||||
|
self.apply_transposed_matrix(t_matrix, run_time = 1)
|
||||||
|
last = sym
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
class ThreeSuccessiveTransformationsAltParens(ThreeSuccessiveTransformations):
|
||||||
|
CONFIG = {
|
||||||
|
"symbols_str" : "(AB)C"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -8,11 +8,11 @@ from animation.transform import ApplyPointwiseFunction, Transform, \
|
|||||||
ApplyMethod, FadeOut, ApplyFunction
|
ApplyMethod, FadeOut, ApplyFunction
|
||||||
from animation.simple_animations import ShowCreation, Write
|
from animation.simple_animations import ShowCreation, Write
|
||||||
from topics.number_line import NumberPlane, Axes
|
from topics.number_line import NumberPlane, Axes
|
||||||
from topics.geometry import Vector, Line, Circle, Arrow, Dot
|
from topics.geometry import Vector, Line, Circle, Arrow, Dot, BackgroundRectangle
|
||||||
|
|
||||||
from helpers import *
|
from helpers import *
|
||||||
|
|
||||||
VECTOR_LABEL_SCALE_VAL = 1.0
|
VECTOR_LABEL_SCALE_VAL = 0.8
|
||||||
|
|
||||||
def matrix_to_tex_string(matrix):
|
def matrix_to_tex_string(matrix):
|
||||||
matrix = np.array(matrix).astype("string")
|
matrix = np.array(matrix).astype("string")
|
||||||
@ -31,7 +31,8 @@ def matrix_to_tex_string(matrix):
|
|||||||
def matrix_to_mobject(matrix):
|
def matrix_to_mobject(matrix):
|
||||||
return TexMobject(matrix_to_tex_string(matrix))
|
return TexMobject(matrix_to_tex_string(matrix))
|
||||||
|
|
||||||
def vector_coordinate_label(vector_mob, integer_labels = True, n_dim = 2):
|
def vector_coordinate_label(vector_mob, integer_labels = True,
|
||||||
|
n_dim = 2, color = WHITE):
|
||||||
vect = np.array(vector_mob.get_end())
|
vect = np.array(vector_mob.get_end())
|
||||||
if integer_labels:
|
if integer_labels:
|
||||||
vect = np.round(vect).astype(int)
|
vect = np.round(vect).astype(int)
|
||||||
@ -41,11 +42,14 @@ def vector_coordinate_label(vector_mob, integer_labels = True, n_dim = 2):
|
|||||||
label.scale(VECTOR_LABEL_SCALE_VAL)
|
label.scale(VECTOR_LABEL_SCALE_VAL)
|
||||||
|
|
||||||
shift_dir = np.array(vector_mob.get_end())
|
shift_dir = np.array(vector_mob.get_end())
|
||||||
if shift_dir[0] > 0: #Pointing right
|
if shift_dir[0] >= 0: #Pointing right
|
||||||
shift_dir -= label.get_left() + DEFAULT_MOBJECT_TO_MOBJECT_BUFFER*LEFT
|
shift_dir -= label.get_left() + DEFAULT_MOBJECT_TO_MOBJECT_BUFFER*LEFT
|
||||||
else: #Pointing left
|
else: #Pointing left
|
||||||
shift_dir -= label.get_right() + DEFAULT_MOBJECT_TO_MOBJECT_BUFFER*RIGHT
|
shift_dir -= label.get_right() + DEFAULT_MOBJECT_TO_MOBJECT_BUFFER*RIGHT
|
||||||
label.shift(shift_dir)
|
label.shift(shift_dir)
|
||||||
|
label.highlight(color)
|
||||||
|
background = BackgroundRectangle(label)
|
||||||
|
label.submobjects = [background] + label.submobjects
|
||||||
return label
|
return label
|
||||||
|
|
||||||
class Matrix(VMobject):
|
class Matrix(VMobject):
|
||||||
@ -104,9 +108,15 @@ class Matrix(VMobject):
|
|||||||
self.brackets = VMobject(l_bracket, r_bracket)
|
self.brackets = VMobject(l_bracket, r_bracket)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
def highlight_columns(self, *colors):
|
||||||
|
for i, color in enumerate(colors):
|
||||||
|
VMobject(*self.mob_matrix[:,i]).highlight(color)
|
||||||
|
return self
|
||||||
|
|
||||||
def get_mob_matrix(self):
|
def get_mob_matrix(self):
|
||||||
return self.mob_matrix
|
return self.mob_matrix
|
||||||
|
|
||||||
|
|
||||||
def get_entries(self):
|
def get_entries(self):
|
||||||
return VMobject(*self.get_mob_matrix().flatten())
|
return VMobject(*self.get_mob_matrix().flatten())
|
||||||
|
|
||||||
@ -117,7 +127,8 @@ class Matrix(VMobject):
|
|||||||
class NumericalMatrixMultiplication(Scene):
|
class NumericalMatrixMultiplication(Scene):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
"left_matrix" : [[1, 2], [3, 4]],
|
"left_matrix" : [[1, 2], [3, 4]],
|
||||||
"right_matrix" : [[5, 6], [7, 8]]
|
"right_matrix" : [[5, 6], [7, 8]],
|
||||||
|
"use_parens" : True,
|
||||||
}
|
}
|
||||||
def construct(self):
|
def construct(self):
|
||||||
left_string_matrix, right_string_matrix = [
|
left_string_matrix, right_string_matrix = [
|
||||||
@ -143,8 +154,9 @@ class NumericalMatrixMultiplication(Scene):
|
|||||||
mob_matrix = np.array([VMobject()]).repeat(m*n).reshape((m, n))
|
mob_matrix = np.array([VMobject()]).repeat(m*n).reshape((m, n))
|
||||||
for a in range(m):
|
for a in range(m):
|
||||||
for b in range(n):
|
for b in range(n):
|
||||||
|
template = "(%s)(%s)" if self.use_parens else "%s%s"
|
||||||
parts = [
|
parts = [
|
||||||
prefix + "(%s)(%s)"%(left[a][c], right[c][b])
|
prefix + template%(left[a][c], right[c][b])
|
||||||
for c in range(k)
|
for c in range(k)
|
||||||
for prefix in ["" if c == 0 else "+"]
|
for prefix in ["" if c == 0 else "+"]
|
||||||
]
|
]
|
||||||
|
@ -9,7 +9,7 @@ from animation.transform import ApplyPointwiseFunction, Transform, \
|
|||||||
ApplyMethod, FadeOut, ApplyFunction
|
ApplyMethod, FadeOut, ApplyFunction
|
||||||
from animation.simple_animations import ShowCreation, Write
|
from animation.simple_animations import ShowCreation, Write
|
||||||
from topics.number_line import NumberPlane, Axes
|
from topics.number_line import NumberPlane, Axes
|
||||||
from topics.geometry import Vector, Line, Circle, Arrow, Dot
|
from topics.geometry import Vector, Line, Circle, Arrow, Dot, BackgroundRectangle
|
||||||
|
|
||||||
from helpers import *
|
from helpers import *
|
||||||
from eola.matrix import Matrix, VECTOR_LABEL_SCALE_VAL, vector_coordinate_label
|
from eola.matrix import Matrix, VECTOR_LABEL_SCALE_VAL, vector_coordinate_label
|
||||||
@ -55,6 +55,11 @@ class VectorScene(Scene):
|
|||||||
self.add(vector)
|
self.add(vector)
|
||||||
return vector
|
return vector
|
||||||
|
|
||||||
|
def write_vector_coordinates(self, vector, **kwargs):
|
||||||
|
coords = vector_coordinate_label(vector, **kwargs)
|
||||||
|
self.play(Write(coords))
|
||||||
|
return coords
|
||||||
|
|
||||||
def get_basis_vectors(self):
|
def get_basis_vectors(self):
|
||||||
return [
|
return [
|
||||||
Vector(
|
Vector(
|
||||||
@ -303,6 +308,11 @@ class LinearTransformationScene(VectorScene):
|
|||||||
self.moving_vectors.append(vector)
|
self.moving_vectors.append(vector)
|
||||||
return vector
|
return vector
|
||||||
|
|
||||||
|
def write_vector_coordinates(self, vector, **kwargs):
|
||||||
|
coords = VectorScene.write_vector_coordinates(self, vector, **kwargs)
|
||||||
|
self.add_foreground_mobject(coords)
|
||||||
|
return coords
|
||||||
|
|
||||||
def add_transformable_label(self, vector, label, new_label = None, **kwargs):
|
def add_transformable_label(self, vector, label, new_label = None, **kwargs):
|
||||||
label_mob = self.label_vector(vector, label, **kwargs)
|
label_mob = self.label_vector(vector, label, **kwargs)
|
||||||
if new_label:
|
if new_label:
|
||||||
@ -316,6 +326,16 @@ class LinearTransformationScene(VectorScene):
|
|||||||
self.transformable_labels.append(label_mob)
|
self.transformable_labels.append(label_mob)
|
||||||
return label_mob
|
return label_mob
|
||||||
|
|
||||||
|
def add_title(self, title, scale_val = 1.5, animate = False):
|
||||||
|
if not isinstance(title, Mobject):
|
||||||
|
title = TextMobject(title).scale(scale_val)
|
||||||
|
title.to_edge(UP)
|
||||||
|
title.add_background_rectangle()
|
||||||
|
if animate:
|
||||||
|
self.play(Write(title))
|
||||||
|
self.add_foreground_mobject(title)
|
||||||
|
return self
|
||||||
|
|
||||||
def get_matrix_transformation(self, transposed_matrix):
|
def get_matrix_transformation(self, transposed_matrix):
|
||||||
transposed_matrix = np.array(transposed_matrix)
|
transposed_matrix = np.array(transposed_matrix)
|
||||||
if transposed_matrix.shape == (2, 2):
|
if transposed_matrix.shape == (2, 2):
|
||||||
|
@ -133,6 +133,9 @@ def list_update(l1, l2):
|
|||||||
"""
|
"""
|
||||||
return filter(lambda e : e not in l2, l1) + list(l2)
|
return filter(lambda e : e not in l2, l1) + list(l2)
|
||||||
|
|
||||||
|
def list_difference_update(l1, l2):
|
||||||
|
return filter(lambda e : e not in l2, l1)
|
||||||
|
|
||||||
def all_elements_are_instances(iterable, Class):
|
def all_elements_are_instances(iterable, Class):
|
||||||
return all(map(lambda e : isinstance(e, Class), iterable))
|
return all(map(lambda e : isinstance(e, Class), iterable))
|
||||||
|
|
||||||
|
@ -179,6 +179,7 @@ class Mobject(object):
|
|||||||
|
|
||||||
def flip(self, axis = UP):
|
def flip(self, axis = UP):
|
||||||
self.rotate_in_place(np.pi, axis)
|
self.rotate_in_place(np.pi, axis)
|
||||||
|
return self
|
||||||
|
|
||||||
def scale_in_place(self, scale_factor):
|
def scale_in_place(self, scale_factor):
|
||||||
self.do_in_place(self.scale, scale_factor)
|
self.do_in_place(self.scale, scale_factor)
|
||||||
|
Reference in New Issue
Block a user