Up to associativity in EoLA chapter 4

This commit is contained in:
Grant Sanderson
2016-07-28 11:16:28 -07:00
parent 418e11fd66
commit 8e48140961
5 changed files with 766 additions and 11 deletions

View File

@ -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"
}

View File

@ -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 "+"]
] ]

View File

@ -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):

View File

@ -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))

View File

@ -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)