Files
manim/eola/chapter6.py
2016-08-09 14:17:40 -07:00

843 lines
27 KiB
Python

from mobject.tex_mobject import TexMobject
from mobject import Mobject
from mobject.image_mobject import ImageMobject
from mobject.vectorized_mobject import VMobject
from animation.animation import Animation
from animation.transform import *
from animation.simple_animations import *
from topics.geometry import *
from topics.characters import *
from topics.functions import *
from topics.number_line import *
from topics.numerals import *
from scene import Scene
from camera import Camera
from mobject.svg_mobject import *
from mobject.tex_mobject import *
from mobject.vectorized_mobject import *
from eola.matrix import *
from eola.two_d_space import *
from ka_playgrounds.circuits import Resistor, Source, LongResistor
class OpeningQuote(Scene):
def construct(self):
words = TextMobject([
"The question you raise, ",
"``how can such a formulation lead to computations?''",
"doesn't bother me in the least! Throughout my whole life "
"as a mathematician, the possibility of making explicit, "
"elegant computations has always come out by itself, as a "
"byproduct of a ",
"thorough conceptual understanding."
], separate_list_arg_with_spaces = False)
words.scale_to_fit_width(2*SPACE_WIDTH - 2)
words.to_edge(UP)
words.split()[1].highlight(BLUE)
words.split()[3].highlight(GREEN)
author = TextMobject(["-Grothendieck", "(a hero of mine)"])
author.split()[0].highlight(YELLOW)
author.next_to(words, DOWN, buff = 0.5)
self.play(FadeIn(words))
self.dither(2)
self.play(Write(author, run_time = 3))
self.dither()
class ListTerms(Scene):
def construct(self):
title = TextMobject("Under the light of linear transformations")
title.highlight(YELLOW)
title.to_edge(UP)
randy = Randolph().to_corner()
words = VMobject(*map(TextMobject, [
"Inverse matrices",
"Column space",
"Rank",
"Null space",
]))
words.arrange_submobjects(DOWN, aligned_edge = LEFT)
words.next_to(title, DOWN, aligned_edge = LEFT)
words.shift(RIGHT)
self.add(title, randy)
for i, word in enumerate(words.split()):
self.play(Write(word), run_time = 1)
if i%2 == 0:
self.play(Blink(randy))
else:
self.dither()
self.dither()
class NoComputations(TeacherStudentsScene):
def construct(self):
self.setup()
self.student_says(
"Will you cover \\\\ computations?",
pi_creature_target_mode = "raise_left_hand"
)
self.random_blink()
self.teacher_says(
"Well...uh...no",
pi_creature_target_mode = "guilty",
)
self.play(*[
ApplyMethod(student.change_mode, mode)
for student, mode in zip(
self.get_students(),
["dejected", "confused", "angry"]
)
])
self.random_blink()
self.dither()
new_words = self.teacher.bubble.position_mobject_inside(
TextMobject([
"Search",
"``Gaussian elimination'' \\\\",
"and",
"``Row echelon form''",
])
)
new_words.split()[1].highlight(YELLOW)
new_words.split()[3].highlight(GREEN)
self.play(
Transform(self.teacher.bubble.content, new_words),
self.teacher.change_mode, "speaking"
)
self.play(*[
ApplyMethod(student.change_mode, "pondering")
for student in self.get_students()
])
self.random_blink()
class UsefulnessOfMatrices(Scene):
def construct(self):
title = TextMobject("Usefulness of matrices")
title.highlight(YELLOW)
title.to_edge(UP)
self.add(title)
self.dither(3) #Play some 3d linear transform over this
equations = TexMobject("""
6x - 3y + 2z &= 7 \\\\
x + 2y + 5z &= 0 \\\\
2x - 8y - z &= -2 \\\\
""")
equations.to_edge(RIGHT, buff = 2)
syms = VMobject(*np.array(equations.split())[[1, 4, 7]])
new_syms = VMobject(*[
m.copy().highlight(c)
for m, c in zip(syms.split(), [X_COLOR, Y_COLOR, Z_COLOR])
])
new_syms.arrange_submobjects(RIGHT, buff = 0.5)
new_syms.next_to(equations, LEFT, buff = 3)
sym_brace = Brace(new_syms, DOWN)
unknowns = sym_brace.get_text("Unknown variables")
eq_brace = Brace(equations, DOWN)
eq_words = eq_brace.get_text("Equations")
self.play(Write(equations))
self.dither()
self.play(Transform(syms.copy(), new_syms, path_arc = np.pi/2))
for brace, words in (sym_brace, unknowns), (eq_brace, eq_words):
self.play(
GrowFromCenter(brace),
Write(words)
)
self.dither()
class CircuitDiagram(Scene):
def construct(self):
self.add(TextMobject("Voltages").to_edge(UP))
source = Source()
p1, p2 = source.get_top(), source.get_bottom()
r1 = Resistor(p1, p1+2*RIGHT)
r2 = LongResistor(p1+2*RIGHT, p2+2*RIGHT)
r3 = Resistor(p1+2*RIGHT, p1+2*2*RIGHT)
l1 = Line(p1+2*2*RIGHT, p2+2*2*RIGHT)
l2 = Line(p2+2*2*RIGHT, p2)
circuit = VMobject(source, r1, r2, r3, l1, l2)
circuit.center()
v1 = TexMobject("v_1").next_to(r1, UP)
v2 = TexMobject("v_2").next_to(r2, RIGHT)
v3 = TexMobject("v_3").next_to(r3, UP)
unknowns = VMobject(v1, v2, v3)
unknowns.highlight(BLUE)
self.play(ShowCreation(circuit))
self.dither()
self.play(Write(unknowns))
self.dither()
class StockLine(VMobject):
CONFIG = {
"num_points" : 15,
"step_range" : 2
}
def generate_points(self):
points = [ORIGIN]
for x in range(self.num_points):
step_size = self.step_range*(random.random() - 0.5)
points.append(points[-1] + 0.5*RIGHT + step_size*UP)
self.set_anchor_points(points, mode = "corners")
class StockPrices(Scene):
def construct(self):
self.add(TextMobject("Stock prices").to_edge(UP))
x_axis = Line(ORIGIN, SPACE_WIDTH*RIGHT)
y_axis = Line(ORIGIN, SPACE_HEIGHT*UP)
everyone = VMobject(x_axis, y_axis)
stock_lines = []
for color in TEAL, PINK, YELLOW, RED, BLUE:
sl = StockLine(color = color)
sl.move_to(y_axis.get_center(), side_to_align = LEFT)
everyone.add(sl)
stock_lines.append(sl)
everyone.center()
self.add(x_axis, y_axis)
self.play(ShowCreation(
VMobject(*stock_lines),
run_time = 3,
submobject_mode = "lagged_start"
))
self.dither()
class MachineLearningNetwork(Scene):
def construct(self):
self.add(TextMobject("Machine learning parameters").to_edge(UP))
layers = []
for i, num_nodes in enumerate([3, 4, 4, 1]):
layer = VMobject(*[
Circle(radius = 0.5, color = YELLOW)
for x in range(num_nodes)
])
for j, mob in enumerate(layer.split()):
sym = TexMobject("x_{%d, %d}"%(i, j))
sym.move_to(mob)
mob.add(sym)
layer.arrange_submobjects(DOWN, buff = 0.5)
layer.center()
layers.append(layer)
VMobject(*layers).arrange_submobjects(RIGHT, buff = 1.5)
lines = VMobject()
for l_layer, r_layer in zip(layers, layers[1:]):
for l_node, r_node in it.product(l_layer.split(), r_layer.split()):
lines.add(Line(l_node, r_node))
lines.submobject_gradient_highlight(BLUE_E, BLUE_A)
for mob in VMobject(*layers), lines:
self.play(Write(mob), run_time = 2)
self.dither()
class SystemOfEquations(Scene):
def construct(self):
equations = self.get_equations()
self.show_linearity_rules(equations)
self.describe_organization(equations)
self.factor_into_matrix(equations)
def get_equations(self):
matrix = Matrix([
[2, 5, 3],
[4, 0, 8],
[1, 3, 0]
])
mob_matrix = matrix.get_mob_matrix()
rhs = map(TexMobject, map(str, [-3, 0, 2]))
variables = map(TexMobject, list("xyz"))
for v, color in zip(variables, [X_COLOR, Y_COLOR, Z_COLOR]):
v.highlight(color)
equations = VMobject()
for row in mob_matrix:
equation = VMobject(*it.chain(*zip(
row,
[v.copy() for v in variables],
map(TexMobject, list("++="))
)))
equation.arrange_submobjects(
RIGHT, buff = 0.1,
aligned_edge = DOWN
)
equation.split()[4].shift(0.1*DOWN)
equation.split()[-1].next_to(equation.split()[-2], RIGHT)
equations.add(equation)
equations.arrange_submobjects(DOWN, aligned_edge = RIGHT)
for eq, rhs_elem in zip(equations.split(), rhs):
rhs_elem.next_to(eq, RIGHT)
eq.add(rhs_elem)
equations.center()
self.play(Write(equations))
self.add(equations)
return equations
def show_linearity_rules(self, equations):
top_equation = equations.split()[0]
other_equations = VMobject(*equations.split()[1:])
other_equations.save_state()
scaled_vars = VMobject(*[
VMobject(*top_equation.split()[3*i:3*i+2])
for i in range(3)
])
scaled_vars.save_state()
isolated_scaled_vars = scaled_vars.copy()
isolated_scaled_vars.scale(1.5)
isolated_scaled_vars.next_to(top_equation, UP)
scalars = VMobject(*[m.split()[0] for m in scaled_vars.split()])
plusses = np.array(top_equation.split())[[2, 5]]
self.play(other_equations.fade, 0.7)
self.play(Transform(scaled_vars, isolated_scaled_vars))
self.play(scalars.highlight, YELLOW, submobject_mode = "lagged_start")
self.play(*[
ApplyMethod(m.scale_in_place, 1.2, rate_func = there_and_back)
for m in scalars.split()
])
self.dither()
self.remove(scalars)
self.play(scaled_vars.restore)
self.play(*[
ApplyMethod(p.scale_in_place, 1.5, rate_func = there_and_back)
for p in plusses
])
self.dither()
self.show_nonlinearity_examples()
self.play(other_equations.restore)
def show_nonlinearity_examples(self):
squared = TexMobject("x^2")
squared.split()[0].highlight(X_COLOR)
sine = TexMobject("\\sin(x)")
sine.split()[-2].highlight(X_COLOR)
product = TexMobject("xy")
product.split()[0].highlight(X_COLOR)
product.split()[1].highlight(Y_COLOR)
words = TextMobject("Not allowed!")
words.highlight(RED)
words.to_corner(UP+LEFT, buff = 1)
arrow = Vector(RIGHT, color = RED)
arrow.next_to(words, RIGHT)
for mob in squared, sine, product:
mob.scale(1.7)
mob.next_to(arrow.get_end(), RIGHT, buff = 0.5)
circle_slash = Circle(color = RED)
line = Line(LEFT, RIGHT, color = RED)
line.rotate(np.pi/4)
circle_slash.add(line)
circle_slash.next_to(arrow, RIGHT)
def draw_circle_slash(mob):
circle_slash.replace(mob)
circle_slash.scale_in_place(1.4)
self.play(ShowCreation(circle_slash), run_time = 0.5)
self.dither(0.5)
self.play(FadeOut(circle_slash), run_time = 0.5)
self.play(
Write(squared),
Write(words, run_time = 1),
ShowCreation(arrow),
)
draw_circle_slash(squared)
for mob in sine, product:
self.play(Transform(squared, mob))
draw_circle_slash(mob)
self.play(*map(FadeOut, [words, arrow, squared]))
self.dither()
def describe_organization(self, equations):
variables = VMobject(*it.chain(*[
eq.split()[:-2]
for eq in equations.split()
]))
variables.words = "Throw variables on the left"
constants = VMobject(*[
eq.split()[-1]
for eq in equations.split()
])
constants.words = "Lingering constants on the right"
xs, ys, zs = [
VMobject(*[
eq.split()[i]
for eq in equations.split()
])
for i in 1, 4, 7
]
ys.words = "Vertically align variables"
colors = [PINK, YELLOW, BLUE_B, BLUE_C, BLUE_D]
for mob, color in zip([variables, constants, xs, ys, zs], colors):
mob.square = Square(color = color)
mob.square.replace(mob, stretch = True)
mob.square.scale_in_place(1.1)
if hasattr(mob, "words"):
mob.words = TextMobject(mob.words)
mob.words.highlight(color)
mob.words.next_to(mob.square, UP)
ys.square.add(xs.square, zs.square)
zero_circles = VMobject(*[
Circle().replace(mob).scale_in_place(1.3)
for mob in [
VMobject(*equations.split()[i].split()[j:j+2])
for i, j in (1, 3), (2, 6)
]
])
zero_circles.highlight(PINK)
zero_circles.words = TextMobject("Add zeros as needed")
zero_circles.words.highlight(zero_circles.get_color())
zero_circles.words.next_to(equations, UP)
for mob in variables, constants, ys:
self.play(
FadeIn(mob.square),
FadeIn(mob.words)
)
self.dither()
self.play(*map(FadeOut, [mob.square, mob.words]))
self.play(
ShowCreation(zero_circles),
Write(zero_circles.words, run_time = 1)
)
self.dither()
self.play(*map(FadeOut, [zero_circles, zero_circles.words]))
self.dither()
title = TextMobject("``Linear system of equations''")
title.scale(1.5)
title.to_edge(UP)
self.play(Write(title))
self.dither()
self.play(FadeOut(title))
def factor_into_matrix(self, equations):
coefficients = np.array([
np.array(eq.split())[[0, 3, 6]]
for eq in equations.split()
])
variable_arrays = np.array([
np.array(eq.split())[[1, 4, 7]]
for eq in equations.split()
])
rhs_entries = np.array([
eq.split()[-1]
for eq in equations.split()
])
matrix = Matrix(copy.deepcopy(coefficients))
x_array = Matrix(copy.deepcopy(variable_arrays[0]))
v_array = Matrix(copy.deepcopy(rhs_entries))
equals = TexMobject("=")
ax_equals_v = VMobject(matrix, x_array, equals, v_array)
ax_equals_v.arrange_submobjects(RIGHT)
ax_equals_v.to_edge(RIGHT)
all_brackets = [
mob.get_brackets()
for mob in matrix, x_array, v_array
]
self.play(equations.to_edge, LEFT)
arrow = Vector(RIGHT, color = YELLOW)
arrow.next_to(ax_equals_v, LEFT)
self.play(ShowCreation(arrow))
self.play(*it.chain(*[
[
Transform(
m1.copy(), m2,
run_time = 2,
path_arc = -np.pi/2
)
for m1, m2 in zip(
start_array.flatten(),
matrix_mobject.get_entries().split()
)
]
for start_array, matrix_mobject in [
(coefficients, matrix),
(variable_arrays[0], x_array),
(variable_arrays[1], x_array),
(variable_arrays[2], x_array),
(rhs_entries, v_array)
]
]))
self.play(*[
Write(mob)
for mob in all_brackets + [equals]
])
self.dither()
self.label_matrix_product(matrix, x_array, v_array)
def label_matrix_product(self, matrix, x_array, v_array):
matrix.words = "Coefficients"
matrix.symbol = "A"
x_array.words = "Variables"
x_array.symbol = "\\vec{\\textbf{x}}"
v_array.words = "Constants"
v_array.symbol = "\\vec{\\textbf{v}}"
parts = matrix, x_array, v_array
for mob in parts:
mob.brace = Brace(mob, UP)
mob.words = mob.brace.get_text(mob.words)
mob.words.shift_onto_screen()
mob.symbol = TexMobject(mob.symbol)
mob.brace.put_at_tip(mob.symbol)
x_array.words.submobject_gradient_highlight(
X_COLOR, Y_COLOR, Z_COLOR
)
x_array.symbol.highlight(PINK)
v_array.symbol.highlight(YELLOW)
for mob in parts:
self.play(
GrowFromCenter(mob.brace),
FadeIn(mob.words)
)
self.dither()
self.play(*map(FadeOut, [mob.brace, mob.words]))
self.dither()
for mob in parts:
self.play(
FadeIn(mob.brace),
Write(mob.symbol)
)
compact_equation = VMobject(*[
mob.symbol for mob in parts
])
compact_equation.submobjects.insert(
2, TexMobject("=").next_to(x_array, RIGHT)
)
compact_equation.target = compact_equation.copy()
compact_equation.target.arrange_submobjects(buff = 0.1)
compact_equation.target.to_edge(UP)
self.play(Transform(
compact_equation.copy(),
compact_equation.target
))
self.dither()
class LinearSystemTransformationScene(LinearTransformationScene):
def setup(self):
LinearTransformationScene.setup(self)
equation = TexMobject([
"A",
"\\vec{\\textbf{x}}",
"=",
"\\vec{\\textbf{v}}",
])
equation.scale(1.5)
equation.next_to(ORIGIN, LEFT).to_edge(UP)
equation.add_background_rectangle()
self.add_foreground_mobject(equation)
self.equation = equation
self.A, self.x, eq, self.v = equation.split()[1].split()
self.x.highlight(PINK)
self.v.highlight(YELLOW)
class MentionThatItsATransformation(LinearSystemTransformationScene):
CONFIG = {
"t_matrix" : np.array([[2, 1], [2, 3]])
}
def construct(self):
self.setup()
brace = Brace(self.A)
words = brace.get_text("Transformation")
words.add_background_rectangle()
self.play(GrowFromCenter(brace), Write(words, run_time = 1))
self.add_foreground_mobject(words, brace)
self.apply_transposed_matrix(self.t_matrix)
self.dither()
class LookForX(MentionThatItsATransformation):
CONFIG = {
"show_basis_vectors" : False
}
def construct(self):
self.setup()
v = [-4, - 1]
x = np.linalg.solve(self.t_matrix.T, v)
v = Vector(v, color = YELLOW)
x = Vector(x, color = PINK)
v_label = self.get_vector_label(v, "v", color = YELLOW)
x_label = self.get_vector_label(x, "x", color = PINK)
for label in x_label, v_label:
label.add_background_rectangle()
self.play(
ShowCreation(v),
Write(v_label)
)
self.add_foreground_mobject(v_label)
x = self.add_vector(x, animate = False)
self.play(
ShowCreation(x),
Write(x_label)
)
self.dither()
self.add(VMobject(x, x_label).copy().fade())
self.apply_transposed_matrix(self.t_matrix)
self.dither()
class SystemOfTwoEquationsTwoUnknowns(Scene):
def construct(self):
system = TexMobject("""
2x + 2y &= -4 \\\\
1x + 3y &= -1
""")
system.to_edge(UP)
for indices, color in ((1, 9), X_COLOR), ((4, 12), Y_COLOR):
for i in indices:
system.split()[i].highlight(color)
matrix = Matrix([[2, 2], [1, 3]])
v = Matrix([-4, -1])
x = Matrix(["x", "y"])
x.get_entries().submobject_gradient_highlight(X_COLOR, Y_COLOR)
matrix_system = VMobject(
matrix, x, TexMobject("="), v
)
matrix_system.arrange_submobjects(RIGHT)
matrix_system.next_to(system, DOWN, buff = 1)
self.add(system)
self.play(Write(matrix_system))
self.dither()
class ShowBijectivity(LinearTransformationScene):
CONFIG = {
"show_basis_vectors" : False,
"t_matrix" : np.array([[0, -1], [2, 1]])
}
def construct(self):
self.setup()
vectors = VMobject(*[
Vector([x, y])
for x, y in it.product(*[
np.arange(-int(val)+0.5, int(val)+0.5)
for val in SPACE_WIDTH, SPACE_HEIGHT
])
])
vectors.submobject_gradient_highlight(BLUE_E, PINK)
dots = VMobject(*[
Dot(v.get_end(), color = v.get_color())
for v in vectors.split()
])
titles = [
TextMobject([
"Each vector lands on\\\\",
"exactly one vector"
]),
TextMobject([
"Every vector has \\\\",
"been landed on"
])
]
for title in titles:
title.to_edge(UP)
background = BackgroundRectangle(VMobject(*titles))
self.add_foreground_mobject(background, titles[0])
kwargs = {
"submobject_mode" : "lagged_start",
"run_time" : 2
}
anims = map(Animation, self.foreground_mobjects)
self.play(ShowCreation(vectors, **kwargs), *anims)
self.play(Transform(vectors, dots, **kwargs), *anims)
self.dither()
self.add_transformable_mobject(vectors)
self.apply_transposed_matrix(self.t_matrix)
self.dither()
self.play(Transform(*titles))
self.dither()
self.apply_transposed_matrix(
np.linalg.inv(self.t_matrix.T).T
)
self.dither()
class LabeledExample(LinearSystemTransformationScene):
CONFIG = {
"title" : "",
"t_matrix" : [[0, 0], [0, 0]],
}
def setup(self):
LinearSystemTransformationScene.setup(self)
title = TextMobject(self.title)
title.scale(1.5)
title.next_to(self.equation, DOWN)
title.add_background_rectangle()
self.add_foreground_mobject(title)
self.title = title
def construct(self):
self.setup()
self.dither()
self.apply_transposed_matrix(self.t_matrix)
self.dither()
class SquishExmapleWithWords(LabeledExample):
CONFIG = {
"title" : "$A$ squishes things to a lower dimension",
"t_matrix" : [[-2, -1], [2, 1]]
}
class FullRankExmapleWithWords(LabeledExample):
CONFIG = {
"title" : "$A$ keeps things 2D",
"t_matrix" : [[3, 0], [2, 1]]
}
class SquishExmapleDet(SquishExmapleWithWords):
CONFIG = {
"title" : "$\\det(A) = 0$",
}
class FullRankExmapleDet(FullRankExmapleWithWords):
CONFIG = {
"title" : "$\\det(A) \\ne 0$",
}
class PlayInReverse(FullRankExmapleDet):
CONFIG = {
"show_basis_vectors" : False
}
def construct(self):
FullRankExmapleDet.construct(self)
v = self.add_vector([-2, -2], color = YELLOW)
v_label = self.label_vector(v, "v", color = YELLOW)
self.add(v.copy())
self.apply_inverse_transpose(self.t_matrix)
self.play(v.highlight, PINK)
self.label_vector(v, "x", color = PINK)
self.dither()
class DescribeInverse(LinearTransformationScene):
CONFIG = {
"show_matrix" : False
}
def construct(self):
self.setup()
title = TextMobject("Transformation:")
new_title = TextMobject("Inverse transformation:")
if self.show_matrix:
matrix = Matrix(self.t_matrix.T)
inv_matrix = Matrix(np.linalg.inv(self.t_matrix.T).astype('int'))
else:
matrix, inv_matrix = map(TexMobject, ["A", "A^{-1}"])
for m, text in (matrix, title), (inv_matrix, new_title):
m.rect = BackgroundRectangle(m)
m = VMobject(m.rect, m)
text.add_background_rectangle()
m.next_to(text, RIGHT)
text.add(m)
if text.get_width() > 2*SPACE_WIDTH-1:
text.scale_to_fit_width(2*SPACE_WIDTH-1)
text.center().to_edge(UP)
self.add_foreground_mobject(title)
self.apply_transposed_matrix(self.t_matrix)
self.dither()
self.play(Transform(title, new_title))
self.apply_inverse_transpose(self.t_matrix)
self.dither()
class ClockwiseCounterclockwise(DescribeInverse):
CONFIG = {
"t_matrix" : [[0, 1], [-1, 0]],
"show_matrix" : True,
}
class ShearInverseShear(DescribeInverse):
CONFIG = {
"t_matrix" : [[1, 0], [1, 1]],
"show_matrix" : True,
}
class MultiplyToIdentity(LinearTransformationScene):
def construct(self):
self.setup()
lhs = TexMobject("A", "A^{-1}", "=")
lhs.scale(1.5)
A, A_inv, eq = lhs.split()
identity = Matrix([[1, 0], [0, 1]])
identity.highlight_columns(X_COLOR, Y_COLOR)
identity.next_to(eq, RIGHT)
VMobject(lhs, identity).center().to_corner(UP+RIGHT)
for mob in A, A_inv, eq:
mob.add_to_back(BackgroundRectangle(mob))
identity.background = BackgroundRectangle(identity)
col1 = VMobject(*identity.get_mob_matrix()[:,0])
col2 = VMobject(*identity.get_mob_matrix()[:,1])
A.text = "Transformation"
A_inv.text = "Inverse transformation"
product = VMobject(A, A_inv)
product.text = "Matrix multiplication"
identity.text = "The transformation \\\\ that does nothing"
for mob in A, A_inv, product, identity:
mob.brace = Brace(mob)
mob.text = mob.brace.get_text(mob.text)
mob.text.add_background_rectangle()
self.add_foreground_mobject(A, A_inv)
brace, text = A.brace, A.text
self.play(GrowFromCenter(brace), Write(text), run_time = 1)
self.add_foreground_mobject(brace, text)
self.apply_transposed_matrix(self.t_matrix)
self.play(
Transform(brace, A_inv.brace),
Transform(text, A_inv.text),
)
self.apply_inverse_transpose(self.t_matrix)
self.dither()
self.play(
Transform(brace, product.brace),
Transform(text, product.text)
)
self.dither()
self.play(
Write(identity.background),
Write(identity.get_brackets()),
Write(eq),
Transform(brace, identity.brace),
Transform(text, identity.text)
)
self.dither()
self.play(Write(col1))
self.dither()
self.play(Write(col2))
self.dither()