mirror of
https://github.com/3b1b/manim.git
synced 2025-04-13 09:47:07 +00:00
2572 lines
84 KiB
Python
2572 lines
84 KiB
Python
from big_ol_pile_of_manim_imports import *
|
|
from old_projects.eola.chapter1 import plane_wave_homotopy
|
|
from old_projects.eola.chapter3 import ColumnsToBasisVectors
|
|
from old_projects.eola.chapter5 import NameDeterminant, Blob
|
|
from old_projects.eola.chapter9 import get_small_bubble
|
|
from old_projects.eola.chapter10 import ExampleTranformationScene
|
|
|
|
class Student(PiCreature):
|
|
CONFIG = {
|
|
"name" : "Student"
|
|
}
|
|
def get_name(self):
|
|
text = TextMobject(self.name)
|
|
text.add_background_rectangle()
|
|
text.next_to(self, DOWN)
|
|
return text
|
|
|
|
class PhysicsStudent(Student):
|
|
CONFIG = {
|
|
"color" : PINK,
|
|
"name" : "Physics student"
|
|
}
|
|
|
|
class CSStudent(Student):
|
|
CONFIG = {
|
|
"color" : PURPLE_E,
|
|
"flip_at_start" : True,
|
|
"name" : "CS Student"
|
|
}
|
|
|
|
class OpeningQuote(Scene):
|
|
def construct(self):
|
|
words = TextMobject(
|
|
"``Such",
|
|
"axioms,",
|
|
"together with other unmotivated definitions,",
|
|
"serve mathematicians mainly by making it",
|
|
"difficult for the uninitiated",
|
|
"to master their subject, thereby elevating its authority.''",
|
|
enforce_new_line_structure = False,
|
|
alignment = "",
|
|
)
|
|
words.set_color_by_tex("axioms,", BLUE)
|
|
words.set_color_by_tex("difficult for the uninitiated", RED)
|
|
words.set_width(FRAME_WIDTH - 2)
|
|
words.to_edge(UP)
|
|
author = TextMobject("-Vladmir Arnold")
|
|
author.set_color(YELLOW)
|
|
author.next_to(words, DOWN, buff = MED_LARGE_BUFF)
|
|
|
|
self.play(Write(words, run_time = 8))
|
|
self.wait()
|
|
self.play(FadeIn(author))
|
|
self.wait(3)
|
|
|
|
class RevisitOriginalQuestion(TeacherStudentsScene):
|
|
def construct(self):
|
|
self.teacher_says("Let's revisit ", "\\\\ an old question")
|
|
self.random_blink()
|
|
question = TextMobject("What are ", "vectors", "?", arg_separator = "")
|
|
question.set_color_by_tex("vectors", YELLOW)
|
|
self.teacher_says(
|
|
question,
|
|
added_anims = [
|
|
ApplyMethod(self.get_students()[i].change_mode, mode)
|
|
for i, mode in enumerate([
|
|
"pondering", "raise_right_hand", "erm"
|
|
])
|
|
]
|
|
)
|
|
self.random_blink(2)
|
|
|
|
class WhatIsA2DVector(LinearTransformationScene):
|
|
CONFIG = {
|
|
"v_coords" : [1, 2],
|
|
"show_basis_vectors" : False,
|
|
"include_background_plane" : False,
|
|
"foreground_plane_kwargs" : {
|
|
"x_radius" : FRAME_WIDTH,
|
|
"y_radius" : FRAME_HEIGHT,
|
|
"secondary_line_ratio" : 1
|
|
},
|
|
}
|
|
def construct(self):
|
|
self.plane.fade()
|
|
self.introduce_vector_and_space()
|
|
self.bring_in_students()
|
|
|
|
def introduce_vector_and_space(self):
|
|
v = Vector(self.v_coords)
|
|
coords = Matrix(self.v_coords)
|
|
coords.add_to_back(BackgroundRectangle(coords))
|
|
coords.next_to(v.get_end(), RIGHT)
|
|
|
|
two_d_vector = TextMobject(
|
|
"``Two-dimensional ", "vector", "''",
|
|
arg_separator = ""
|
|
)
|
|
two_d_vector.set_color_by_tex("vector", YELLOW)
|
|
two_d_vector.add_background_rectangle()
|
|
two_d_vector.to_edge(UP)
|
|
|
|
self.play(
|
|
Write(two_d_vector),
|
|
ShowCreation(v),
|
|
Write(coords),
|
|
run_time = 2
|
|
)
|
|
self.wait()
|
|
self.v, self.coords = v, coords
|
|
|
|
def bring_in_students(self):
|
|
everything = self.get_mobjects()
|
|
v, coords = self.v, self.coords
|
|
physics_student = PhysicsStudent()
|
|
cs_student = CSStudent()
|
|
students = [physics_student, cs_student]
|
|
for student, vect in zip(students, [LEFT, RIGHT]):
|
|
student.change_mode("confused")
|
|
student.to_corner(DOWN+vect, buff = MED_LARGE_BUFF)
|
|
student.look_at(v)
|
|
student.bubble = get_small_bubble(
|
|
student, height = 4, width = 4,
|
|
)
|
|
self.play(*list(map(FadeIn, students)))
|
|
self.play(Blink(physics_student))
|
|
self.wait()
|
|
for student, vect in zip(students, [RIGHT, LEFT]):
|
|
for mob in v, coords:
|
|
mob.target = mob.copy()
|
|
mob.target.scale(0.7)
|
|
arrow = TexMobject("\\Rightarrow")
|
|
group = VGroup(v.target, arrow, coords.target)
|
|
group.arrange(vect)
|
|
student.bubble.add_content(group)
|
|
student.v, student.coords = v.copy(), coords.copy()
|
|
student.arrow = arrow
|
|
|
|
self.play(
|
|
student.change_mode, "pondering",
|
|
ShowCreation(student.bubble),
|
|
Write(arrow),
|
|
Transform(student.v, v.target),
|
|
Transform(student.coords, coords.target),
|
|
)
|
|
self.play(Blink(student))
|
|
self.wait()
|
|
anims = []
|
|
for student in students:
|
|
v, coords = student.v, student.coords
|
|
v.target = v.copy()
|
|
coords.target = coords.copy()
|
|
group = VGroup(v.target, coords.target)
|
|
group.arrange(DOWN)
|
|
group.set_height(coords.get_height())
|
|
group.next_to(student.arrow, RIGHT)
|
|
student.q_marks = TexMobject("???")
|
|
student.q_marks.set_color_by_gradient(BLUE, YELLOW)
|
|
student.q_marks.next_to(student.arrow, LEFT)
|
|
anims += [
|
|
Write(student.q_marks),
|
|
MoveToTarget(v),
|
|
MoveToTarget(coords),
|
|
student.change_mode, "erm",
|
|
student.look_at, student.bubble
|
|
]
|
|
cs_student.v.save_state()
|
|
cs_student.coords.save_state()
|
|
self.play(*anims)
|
|
for student in students:
|
|
self.play(Blink(student))
|
|
self.wait()
|
|
self.play(*it.chain(
|
|
list(map(FadeOut, everything + [
|
|
physics_student.bubble,
|
|
physics_student.v,
|
|
physics_student.coords,
|
|
physics_student.arrow,
|
|
physics_student.q_marks,
|
|
cs_student.q_marks,
|
|
])),
|
|
[ApplyMethod(s.change_mode, "plain") for s in students],
|
|
list(map(Animation, [cs_student.bubble, cs_student.arrow])),
|
|
[mob.restore for mob in (cs_student.v, cs_student.coords)],
|
|
))
|
|
bubble = cs_student.get_bubble(SpeechBubble, width = 4, height = 3)
|
|
bubble.set_fill(BLACK, opacity = 1)
|
|
bubble.next_to(cs_student, UP+LEFT)
|
|
bubble.write("Consider higher \\\\ dimensions")
|
|
self.play(
|
|
cs_student.change_mode, "speaking",
|
|
ShowCreation(bubble),
|
|
Write(bubble.content)
|
|
)
|
|
self.play(Blink(physics_student))
|
|
self.wait()
|
|
|
|
class HigherDimensionalVectorsNumerically(Scene):
|
|
def construct(self):
|
|
words = VGroup(*list(map(TextMobject, [
|
|
"4D vector",
|
|
"5D vector",
|
|
"100D vector",
|
|
])))
|
|
words.arrange(RIGHT, buff = LARGE_BUFF*2)
|
|
words.to_edge(UP)
|
|
vectors = VGroup(*list(map(Matrix, [
|
|
[3, 1, 4, 1],
|
|
[5, 9, 2, 6, 5],
|
|
[3, 5, 8, "\\vdots", 0, 8, 6]
|
|
])))
|
|
colors = [YELLOW, MAROON_B, GREEN]
|
|
for word, vector, color in zip(words, vectors, colors):
|
|
vector.shift(word.get_center()[0]*RIGHT)
|
|
word.set_color(color)
|
|
vector.set_color(color)
|
|
|
|
for word in words:
|
|
self.play(FadeIn(word))
|
|
self.play(Write(vectors))
|
|
self.wait()
|
|
for index, dim, direction in (0, 4, RIGHT), (2, 100, LEFT):
|
|
v = vectors[index]
|
|
v.target = v.copy()
|
|
brace = Brace(v, direction)
|
|
brace.move_to(v)
|
|
v.target.next_to(brace, -direction)
|
|
text = brace.get_text("%d numbers"%dim)
|
|
self.play(
|
|
MoveToTarget(v),
|
|
GrowFromCenter(brace),
|
|
Write(text)
|
|
)
|
|
entries = v.get_entries()
|
|
num_entries = len(list(entries))
|
|
self.play(*[
|
|
Transform(
|
|
entries[i],
|
|
entries[i].copy().scale_in_place(1.2).set_color(WHITE),
|
|
rate_func = squish_rate_func(
|
|
there_and_back,
|
|
i/(2.*num_entries),
|
|
i/(2.*num_entries)+0.5
|
|
),
|
|
run_time = 2
|
|
)
|
|
for i in range(num_entries)
|
|
])
|
|
self.wait()
|
|
|
|
class HyperCube(VMobject):
|
|
CONFIG = {
|
|
"color" : BLUE_C,
|
|
"color2" : BLUE_D,
|
|
"dims" : 4,
|
|
}
|
|
def generate_points(self):
|
|
corners = np.array(list(map(np.array, it.product(*[(-1, 1)]*self.dims))))
|
|
def project(four_d_array):
|
|
result = four_d_array[:3]
|
|
w = four_d_array[self.dims-1]
|
|
scalar = interpolate(0.8, 1.2 ,(w+1)/2.)
|
|
return scalar*result
|
|
for a1, a2 in it.combinations(corners, 2):
|
|
if sum(a1==a2) != self.dims-1:
|
|
continue
|
|
self.add(Line(project(a1), project(a2)))
|
|
self.pose_at_angle()
|
|
self.set_color_by_gradient(self.color, self.color2)
|
|
|
|
class AskAbout4DPhysicsStudent(Scene):
|
|
def construct(self):
|
|
physy = PhysicsStudent().to_edge(DOWN).shift(2*LEFT)
|
|
compy = CSStudent().to_edge(DOWN).shift(2*RIGHT)
|
|
for pi1, pi2 in (physy, compy), (compy, physy):
|
|
pi1.look_at(pi2.eyes)
|
|
physy.bubble = physy.get_bubble(SpeechBubble, width = 5, height = 4.5)
|
|
|
|
line = Line(LEFT, RIGHT, color = BLUE_B)
|
|
square = Square(color = BLUE_C)
|
|
square.scale_in_place(0.5)
|
|
cube = HyperCube(color = BLUE_D, dims = 3)
|
|
hyper_cube = HyperCube()
|
|
thought_mobs = []
|
|
for i, mob in enumerate([line, square, cube, hyper_cube]):
|
|
mob.set_height(2)
|
|
tex = TexMobject("%dD"%(i+1))
|
|
tex.next_to(mob, UP)
|
|
group = VGroup(mob, tex)
|
|
thought_mobs.append(group)
|
|
group.shift(
|
|
physy.bubble.get_top() -\
|
|
tex.get_top() + MED_SMALL_BUFF*DOWN
|
|
)
|
|
line.shift(DOWN)
|
|
curr_mob = thought_mobs[0]
|
|
|
|
self.add(compy, physy)
|
|
self.play(
|
|
compy.change_mode, "confused",
|
|
physy.change_mode, "hooray",
|
|
ShowCreation(physy.bubble),
|
|
Write(curr_mob, run_time = 1),
|
|
)
|
|
self.play(Blink(compy))
|
|
for i, mob in enumerate(thought_mobs[1:]):
|
|
self.play(Transform(curr_mob, mob))
|
|
self.remove(curr_mob)
|
|
curr_mob = mob
|
|
self.add(curr_mob)
|
|
if i%2 == 1:
|
|
self.play(Blink(physy))
|
|
else:
|
|
self.wait()
|
|
self.play(Blink(compy))
|
|
self.wait()
|
|
|
|
class ManyCoordinateSystems(LinearTransformationScene):
|
|
CONFIG = {
|
|
"v_coords" : [2, 1],
|
|
"include_background_plane" : False,
|
|
"foreground_plane_kwargs" : {
|
|
"x_radius" : FRAME_WIDTH,
|
|
"y_radius" : FRAME_WIDTH,
|
|
"secondary_line_ratio" : 1
|
|
},
|
|
}
|
|
def construct(self):
|
|
self.title = TextMobject("Many possible coordinate systems")
|
|
self.title.add_background_rectangle()
|
|
self.title.to_edge(UP)
|
|
self.add_foreground_mobject(self.title)
|
|
self.v = Vector(self.v_coords)
|
|
self.play(ShowCreation(self.v))
|
|
self.add_foreground_mobject(self.v)
|
|
|
|
t_matrices = [
|
|
[[0.5, 0.5], [-0.5, 0.5]],
|
|
[[1, -1], [-3, -1]],
|
|
[[-1, 2], [-0.5, -1]],
|
|
]
|
|
movers = [self.plane, self.i_hat, self.j_hat]
|
|
for mover in movers:
|
|
mover.save_state()
|
|
for t_matrix in t_matrices:
|
|
self.animate_coordinates()
|
|
self.play(*it.chain(
|
|
list(map(FadeOut, movers)),
|
|
list(map(Animation, self.foreground_mobjects))
|
|
))
|
|
for mover in movers:
|
|
mover.restore()
|
|
self.apply_transposed_matrix(t_matrix, run_time = 0)
|
|
self.play(*it.chain(
|
|
list(map(FadeIn, movers)),
|
|
list(map(Animation, self.foreground_mobjects))
|
|
))
|
|
self.animate_coordinates()
|
|
|
|
|
|
def animate_coordinates(self):
|
|
self.i_hat.save_state()
|
|
self.j_hat.save_state()
|
|
cob_matrix = np.array([
|
|
self.i_hat.get_end()[:2],
|
|
self.j_hat.get_end()[:2]
|
|
]).T
|
|
inv_cob = np.linalg.inv(cob_matrix)
|
|
coords = np.dot(inv_cob, self.v_coords)
|
|
array = Matrix(list(map(DecimalNumber, coords)))
|
|
array.get_entries()[0].set_color(X_COLOR)
|
|
array.get_entries()[1].set_color(Y_COLOR)
|
|
array.add_to_back(BackgroundRectangle(array))
|
|
for entry in array.get_entries():
|
|
entry.add_to_back(BackgroundRectangle(entry))
|
|
array.next_to(self.title, DOWN)
|
|
|
|
self.i_hat.target = self.i_hat.copy().scale(coords[0])
|
|
self.j_hat.target = self.j_hat.copy().scale(coords[1])
|
|
coord1, coord2 = array.get_entries().copy()
|
|
for coord, vect in (coord1, self.i_hat), (coord2, self.j_hat):
|
|
coord.target = coord.copy().next_to(
|
|
vect.target.get_end()/2,
|
|
rotate_vector(vect.get_end(), -np.pi/2)
|
|
)
|
|
|
|
self.play(Write(array, run_time = 1))
|
|
self.wait()
|
|
self.play(*list(map(MoveToTarget, [self.i_hat, coord1])))
|
|
self.play(*list(map(MoveToTarget, [self.j_hat, coord2])))
|
|
self.play(VGroup(self.j_hat, coord2).shift, self.i_hat.get_end())
|
|
self.wait(2)
|
|
self.play(
|
|
self.i_hat.restore,
|
|
self.j_hat.restore,
|
|
*list(map(FadeOut, [array, coord1, coord2]))
|
|
)
|
|
|
|
class DeterminantAndEigenvectorDontCare(LinearTransformationScene):
|
|
CONFIG = {
|
|
"t_matrix" : [[3, 1], [1, 2]],
|
|
"include_background_plane" : False,
|
|
"show_basis_vectors" : False,
|
|
"foreground_plane_kwargs" : {
|
|
"x_radius" : FRAME_WIDTH,
|
|
"y_radius" : FRAME_HEIGHT,
|
|
"secondary_line_ratio" : 1
|
|
},
|
|
}
|
|
def construct(self):
|
|
words = TextMobject(
|
|
"Determinant",
|
|
"and",
|
|
"eigenvectors",
|
|
"don't \\\\ care about the coordinate system"
|
|
)
|
|
words.set_color_by_tex("Determinant", YELLOW)
|
|
words.set_color_by_tex("eigenvectors", MAROON_B)
|
|
words.add_background_rectangle()
|
|
words.to_edge(UP)
|
|
dark_yellow = Color(rgb = interpolate(
|
|
color_to_rgb(YELLOW),
|
|
color_to_rgb(BLACK),
|
|
0.5
|
|
))
|
|
|
|
blob = Blob(
|
|
stroke_color = YELLOW,
|
|
fill_color = dark_yellow,
|
|
fill_opacity = 1,
|
|
)
|
|
blob.shift(2*LEFT+UP)
|
|
det_label = TexMobject("A")
|
|
det_label = VGroup(
|
|
VectorizedPoint(det_label.get_left()).set_color(WHITE),
|
|
det_label
|
|
)
|
|
det_label_target = TexMobject("\\det(M)\\cdot", "A")
|
|
det_label.move_to(blob)
|
|
|
|
eigenvectors = VGroup(*self.get_eigenvectors())
|
|
|
|
self.add_foreground_mobject(words)
|
|
self.wait()
|
|
self.play(
|
|
FadeIn(blob),
|
|
Write(det_label)
|
|
)
|
|
self.play(
|
|
ShowCreation(
|
|
eigenvectors,
|
|
run_time = 2,
|
|
),
|
|
Animation(words)
|
|
)
|
|
self.wait()
|
|
|
|
self.add_transformable_mobject(blob)
|
|
self.add_moving_mobject(det_label, det_label_target)
|
|
for vector in eigenvectors:
|
|
self.add_vector(vector, animate = False)
|
|
self.remove(self.plane)
|
|
non_plane_mobs = self.get_mobjects()
|
|
self.add(self.plane, *non_plane_mobs)
|
|
|
|
cob_matrices = [
|
|
None,
|
|
[[1, -1], [-3, -1]],
|
|
[[-1, 2], [-0.5, -1]],
|
|
]
|
|
def special_rate_func(t):
|
|
if t < 0.3:
|
|
return smooth(t/0.3)
|
|
if t > 0.7:
|
|
return smooth((1-t)/0.3)
|
|
return 1
|
|
for cob_matrix in cob_matrices:
|
|
if cob_matrix is not None:
|
|
self.play(
|
|
FadeOut(self.plane),
|
|
*list(map(Animation, non_plane_mobs))
|
|
)
|
|
transform = self.get_matrix_transformation(cob_matrix)
|
|
self.plane.apply_function(transform)
|
|
self.play(
|
|
FadeIn(self.plane),
|
|
*list(map(Animation, non_plane_mobs))
|
|
)
|
|
self.wait()
|
|
self.apply_transposed_matrix(
|
|
self.t_matrix,
|
|
rate_func = special_rate_func,
|
|
run_time = 8
|
|
)
|
|
|
|
|
|
|
|
|
|
def get_eigenvectors(self):
|
|
vals, (eig_matrix) = np.linalg.eig(self.t_matrix.T)
|
|
v1, v2 = eig_matrix.T
|
|
result = []
|
|
for v in v1, v2:
|
|
vectors = VGroup(*[
|
|
Vector(u*x*v)
|
|
for x in range(7, 0, -1)
|
|
for u in [-1, 1]
|
|
])
|
|
vectors.set_color_by_gradient(MAROON_A, MAROON_C)
|
|
result += list(vectors)
|
|
return result
|
|
|
|
class WhatIsSpace(Scene):
|
|
def construct(self):
|
|
physy = PhysicsStudent()
|
|
compy = CSStudent()
|
|
physy.to_edge(DOWN).shift(4*LEFT)
|
|
compy.to_edge(DOWN).shift(4*RIGHT)
|
|
physy.make_eye_contact(compy)
|
|
|
|
physy.bubble = get_small_bubble(physy)
|
|
vector = Vector([1, 2])
|
|
physy.bubble.add_content(vector)
|
|
compy.bubble = compy.get_bubble(SpeechBubble, width = 6, height = 4)
|
|
compy.bubble.set_fill(BLACK, opacity = 1)
|
|
compy.bubble.write("What exactly do\\\\ you mean by ``space''?")
|
|
|
|
self.add(compy, physy)
|
|
self.play(
|
|
physy.change_mode, "pondering",
|
|
ShowCreation(physy.bubble),
|
|
ShowCreation(vector)
|
|
)
|
|
self.play(
|
|
compy.change_mode, "sassy",
|
|
ShowCreation(compy.bubble),
|
|
Write(compy.bubble.content)
|
|
)
|
|
self.play(Blink(physy))
|
|
self.wait()
|
|
self.play(Blink(compy))
|
|
self.wait()
|
|
|
|
class OtherVectorishThings(TeacherStudentsScene):
|
|
def construct(self):
|
|
words = TextMobject(
|
|
"There are other\\\\",
|
|
"vectorish",
|
|
"things..."
|
|
)
|
|
words.set_color_by_tex("vectorish", YELLOW)
|
|
self.teacher_says(words)
|
|
self.change_student_modes(
|
|
"pondering", "raise_right_hand", "erm"
|
|
)
|
|
self.random_blink(2)
|
|
words = TextMobject("...like", "functions")
|
|
words.set_color_by_tex("functions", PINK)
|
|
self.teacher_says(words)
|
|
self.change_student_modes(*["pondering"]*3)
|
|
self.random_blink(2)
|
|
self.teacher_thinks("")
|
|
self.zoom_in_on_thought_bubble(self.get_teacher().bubble)
|
|
|
|
class FunctionGraphScene(Scene):
|
|
CONFIG = {
|
|
"graph_colors" : [RED, YELLOW, PINK],
|
|
"default_functions" : [
|
|
lambda x : (x**3 - 9*x)/20.,
|
|
lambda x : -(x**2)/8.+1
|
|
],
|
|
"default_names" : ["f", "g", "h"],
|
|
"x_min" : -4,
|
|
"x_max" : 4,
|
|
"line_to_line_buff" : 0.03
|
|
}
|
|
def setup(self):
|
|
self.axes = Axes(
|
|
x_min = self.x_min,
|
|
x_max = self.x_max,
|
|
)
|
|
self.add(self.axes)
|
|
self.graphs = []
|
|
|
|
def get_function_graph(self, func = None, animate = True,
|
|
add = True, **kwargs):
|
|
index = len(self.graphs)
|
|
if func is None:
|
|
func = self.default_functions[
|
|
index%len(self.default_functions)
|
|
]
|
|
default_color = self.graph_colors[index%len(self.graph_colors)]
|
|
kwargs["color"] = kwargs.get("color", default_color)
|
|
kwargs["x_min"] = kwargs.get("x_min", self.x_min)
|
|
kwargs["x_max"] = kwargs.get("x_max", self.x_max)
|
|
graph = FunctionGraph(func, **kwargs)
|
|
if animate:
|
|
self.play(ShowCreation(graph))
|
|
if add:
|
|
self.add(graph)
|
|
self.graphs.append(graph)
|
|
return graph
|
|
|
|
def get_index(self, function_graph):
|
|
if function_graph not in self.graphs:
|
|
self.graphs.append(function_graph)
|
|
return self.graphs.index(function_graph)
|
|
|
|
def get_output_lines(self, function_graph, num_steps = None, nudge = True):
|
|
index = self.get_index(function_graph)
|
|
num_steps = num_steps or function_graph.num_steps
|
|
lines = VGroup()
|
|
nudge_size = index*self.line_to_line_buff
|
|
x_min, x_max = function_graph.x_min, function_graph.x_max
|
|
for x in np.linspace(x_min, x_max, num_steps):
|
|
if nudge:
|
|
x += nudge_size
|
|
y = function_graph.function(x)
|
|
lines.add(Line(x*RIGHT, x*RIGHT+y*UP))
|
|
lines.set_color(function_graph.get_color())
|
|
return lines
|
|
|
|
def add_lines(self, output_lines):
|
|
self.play(ShowCreation(
|
|
output_lines,
|
|
lag_ratio = 0.5,
|
|
run_time = 2
|
|
))
|
|
|
|
|
|
def label_graph(self, function_graph, name = None, animate = True):
|
|
index = self.get_index(function_graph)
|
|
name = name or self.default_names[index%len(self.default_names)]
|
|
label = TexMobject("%s(x)"%name)
|
|
label.next_to(function_graph.point_from_proportion(1), RIGHT)
|
|
label.shift_onto_screen()
|
|
label.set_color(function_graph.get_color())
|
|
if animate:
|
|
self.play(Write(label))
|
|
else:
|
|
self.add(label)
|
|
return label
|
|
|
|
class AddTwoFunctions(FunctionGraphScene):
|
|
def construct(self):
|
|
f_graph = self.get_function_graph()
|
|
g_graph = self.get_function_graph()
|
|
def sum_func(x):
|
|
return f_graph.get_function()(x)+g_graph.get_function()(x)
|
|
sum_graph = self.get_function_graph(sum_func, animate = False)
|
|
self.remove(sum_graph)
|
|
f_label = self.label_graph(f_graph)
|
|
g_label = self.label_graph(g_graph)
|
|
|
|
f_lines = self.get_output_lines(f_graph)
|
|
g_lines = self.get_output_lines(g_graph)
|
|
sum_lines = self.get_output_lines(sum_graph, nudge = False)
|
|
|
|
curr_x_point = f_lines[0].get_start()
|
|
sum_def = self.get_sum_definition(DecimalNumber(curr_x_point[0]))
|
|
# sum_def.set_width(FRAME_X_RADIUS-1)
|
|
sum_def.to_corner(UP+LEFT)
|
|
arrow = Arrow(sum_def[2].get_bottom(), curr_x_point, color = WHITE)
|
|
prefix = sum_def[0]
|
|
suffix = VGroup(*sum_def[1:])
|
|
rect = BackgroundRectangle(sum_def)
|
|
brace = Brace(prefix)
|
|
brace.add(brace.get_text("New function").shift_onto_screen())
|
|
|
|
self.play(
|
|
Write(prefix, run_time = 2),
|
|
FadeIn(brace)
|
|
)
|
|
self.wait()
|
|
for lines in f_lines, g_lines:
|
|
self.add_lines(lines)
|
|
self.play(*list(map(FadeOut, [f_graph, g_graph])))
|
|
self.wait()
|
|
self.play(FadeOut(brace))
|
|
fg_group = VGroup(*list(f_label)+list(g_label))
|
|
self.play(
|
|
FadeIn(rect),
|
|
Animation(prefix),
|
|
Transform(fg_group, suffix),
|
|
)
|
|
self.remove(prefix, fg_group)
|
|
self.add(sum_def)
|
|
self.play(ShowCreation(arrow))
|
|
|
|
self.show_line_addition(f_lines[0], g_lines[0], sum_lines[0])
|
|
self.wait()
|
|
|
|
curr_x_point = f_lines[1].get_start()
|
|
new_sum_def = self.get_sum_definition(DecimalNumber(curr_x_point[0]))
|
|
new_sum_def.to_corner(UP+LEFT)
|
|
new_arrow = Arrow(sum_def[2].get_bottom(), curr_x_point, color = WHITE)
|
|
self.play(
|
|
Transform(sum_def, new_sum_def),
|
|
Transform(arrow, new_arrow),
|
|
)
|
|
self.show_line_addition(f_lines[1], g_lines[1], sum_lines[1])
|
|
self.wait()
|
|
|
|
final_sum_def = self.get_sum_definition(TexMobject("x"))
|
|
final_sum_def.to_corner(UP+LEFT)
|
|
self.play(
|
|
FadeOut(rect),
|
|
Transform(sum_def, final_sum_def),
|
|
FadeOut(arrow)
|
|
)
|
|
self.show_line_addition(*it.starmap(VGroup, [
|
|
f_lines[2:], g_lines[2:], sum_lines[2:]
|
|
]))
|
|
self.play(ShowCreation(sum_graph))
|
|
|
|
def get_sum_definition(self, input_mob):
|
|
result = VGroup(*it.chain(
|
|
TexMobject("(f+g)", "("),
|
|
[input_mob.copy()],
|
|
TexMobject(")", "=", "f("),
|
|
[input_mob.copy()],
|
|
TexMobject(")", "+", "g("),
|
|
[input_mob.copy()],
|
|
TexMobject(")")
|
|
))
|
|
result.arrange()
|
|
result[0].set_color(self.graph_colors[2])
|
|
VGroup(result[5], result[7]).set_color(self.graph_colors[0])
|
|
VGroup(result[9], result[11]).set_color(self.graph_colors[1])
|
|
return result
|
|
|
|
|
|
def show_line_addition(self, f_lines, g_lines, sum_lines):
|
|
g_lines.target = g_lines.copy()
|
|
dots = VGroup()
|
|
dots.target = VGroup()
|
|
for f_line, g_line in zip(f_lines, g_lines.target):
|
|
align_perfectly = f_line.get_end()[1]*g_line.get_end()[1] > 0
|
|
dot = Dot(g_line.get_end(), radius = 0.07)
|
|
g_line.shift(f_line.get_end()-g_line.get_start())
|
|
dot.target = Dot(g_line.get_end())
|
|
if not align_perfectly:
|
|
g_line.shift(self.line_to_line_buff*RIGHT)
|
|
dots.add(dot)
|
|
dots.target.add(dot.target)
|
|
for group in dots, dots.target:
|
|
group.set_color(sum_lines[0].get_color())
|
|
self.play(ShowCreation(dots))
|
|
if len(list(g_lines)) == 1:
|
|
kwargs = {}
|
|
else:
|
|
kwargs = {
|
|
"lag_ratio" : 0.5,
|
|
"run_time" : 3
|
|
}
|
|
self.play(*[
|
|
MoveToTarget(mob, **kwargs)
|
|
for mob in (g_lines, dots)
|
|
])
|
|
# self.play(
|
|
# *[mob.fade for mob in g_lines, f_lines]+[
|
|
# Animation(dots)
|
|
# ])
|
|
self.wait()
|
|
|
|
class AddVectorsCoordinateByCoordinate(Scene):
|
|
def construct(self):
|
|
v1 = Matrix(["x_1", "y_1", "z_1"])
|
|
v2 = Matrix(["x_2", "y_2", "z_2"])
|
|
v_sum = Matrix(["x_1 + x_2", "y_1 + y_2", "z_1 + z_2"])
|
|
for v in v1, v2, v_sum:
|
|
v.get_entries()[0].set_color(X_COLOR)
|
|
v.get_entries()[1].set_color(Y_COLOR)
|
|
v.get_entries()[2].set_color(Z_COLOR)
|
|
plus, equals = TexMobject("+=")
|
|
VGroup(v1, plus, v2, equals, v_sum).arrange()
|
|
|
|
self.add(v1, plus, v2)
|
|
self.wait()
|
|
self.play(
|
|
Write(equals),
|
|
Write(v_sum.get_brackets())
|
|
)
|
|
self.play(
|
|
Transform(v1.get_entries().copy(), v_sum.get_entries()),
|
|
Transform(v2.get_entries().copy(), v_sum.get_entries()),
|
|
)
|
|
self.wait()
|
|
|
|
class ScaleFunction(FunctionGraphScene):
|
|
def construct(self):
|
|
graph = self.get_function_graph(
|
|
lambda x : self.default_functions[0](x),
|
|
animate = False
|
|
)
|
|
scaled_graph = self.get_function_graph(
|
|
lambda x : graph.get_function()(x)*2,
|
|
animate = False, add = False
|
|
)
|
|
graph_lines = self.get_output_lines(graph)
|
|
scaled_lines = self.get_output_lines(scaled_graph, nudge = False)
|
|
|
|
f_label = self.label_graph(graph, "f", animate = False)
|
|
two_f_label = self.label_graph(scaled_graph, "(2f)", animate = False)
|
|
self.remove(two_f_label)
|
|
|
|
title = TexMobject("(2f)", "(x) = 2", "f", "(x)")
|
|
title.set_color_by_tex("(2f)", scaled_graph.get_color())
|
|
title.set_color_by_tex("f", graph.get_color())
|
|
title.next_to(ORIGIN, LEFT, buff = MED_SMALL_BUFF)
|
|
title.to_edge(UP)
|
|
self.add(title)
|
|
|
|
self.add_lines(graph_lines)
|
|
self.wait()
|
|
self.play(Transform(graph_lines, scaled_lines))
|
|
self.play(ShowCreation(scaled_graph))
|
|
self.play(Write(two_f_label))
|
|
self.play(FadeOut(graph_lines))
|
|
self.wait()
|
|
|
|
class ScaleVectorByCoordinates(Scene):
|
|
def construct(self):
|
|
two, dot, equals = TexMobject("2 \\cdot =")
|
|
v1 = Matrix(list("xyz"))
|
|
v1.get_entries().set_color_by_gradient(X_COLOR, Y_COLOR, Z_COLOR)
|
|
v2 = v1.copy()
|
|
two_targets = VGroup(*[
|
|
two.copy().next_to(entry, LEFT)
|
|
for entry in v2.get_entries()
|
|
])
|
|
v2.get_brackets()[0].next_to(two_targets, LEFT)
|
|
v2.add(two_targets)
|
|
VGroup(two, dot, v1, equals, v2).arrange()
|
|
|
|
self.add(two, dot, v1)
|
|
self.play(
|
|
Write(equals),
|
|
Write(v2.get_brackets())
|
|
)
|
|
self.play(
|
|
Transform(two.copy(), two_targets),
|
|
Transform(v1.get_entries().copy(), v2.get_entries())
|
|
)
|
|
self.wait()
|
|
|
|
class ShowSlopes(Animation):
|
|
CONFIG = {
|
|
"line_color" : YELLOW,
|
|
"dx" : 0.01,
|
|
"rate_func" : None,
|
|
"run_time" : 5
|
|
}
|
|
def __init__(self, graph, **kwargs):
|
|
digest_config(self, kwargs, locals())
|
|
line = Line(LEFT, RIGHT, color = self.line_color)
|
|
line.save_state()
|
|
Animation.__init__(self, line, **kwargs)
|
|
|
|
def interpolate_mobject(self, alpha):
|
|
f = self.graph.point_from_proportion
|
|
low, high = list(map(f, np.clip([alpha-self.dx, alpha+self.dx], 0, 1)))
|
|
slope = (high[1]-low[1])/(high[0]-low[0])
|
|
self.mobject.restore()
|
|
self.mobject.rotate(np.arctan(slope))
|
|
self.mobject.move_to(f(alpha))
|
|
|
|
class FromVectorsToFunctions(VectorScene):
|
|
def construct(self):
|
|
self.show_vector_addition_and_scaling()
|
|
self.bring_in_functions()
|
|
self.show_derivative()
|
|
|
|
def show_vector_addition_and_scaling(self):
|
|
self.plane = self.add_plane()
|
|
self.plane.fade()
|
|
words1 = TextMobject("Vector", "addition")
|
|
words2 = TextMobject("Vector", "scaling")
|
|
for words in words1, words2:
|
|
words.add_background_rectangle()
|
|
words.next_to(ORIGIN, RIGHT).to_edge(UP)
|
|
self.add(words1)
|
|
|
|
v = self.add_vector([2, -1], color = MAROON_B)
|
|
w = self.add_vector([3, 2], color = YELLOW)
|
|
w.save_state()
|
|
self.play(w.shift, v.get_end())
|
|
vw_sum = self.add_vector(w.get_end(), color = PINK)
|
|
self.wait()
|
|
self.play(
|
|
Transform(words1, words2),
|
|
FadeOut(vw_sum),
|
|
w.restore
|
|
)
|
|
self.add(
|
|
v.copy().fade(),
|
|
w.copy().fade()
|
|
)
|
|
self.play(v.scale, 2)
|
|
self.play(w.scale, -0.5)
|
|
self.wait()
|
|
|
|
def bring_in_functions(self):
|
|
everything = VGroup(*self.get_mobjects())
|
|
axes = Axes()
|
|
axes.shift(FRAME_WIDTH*LEFT)
|
|
|
|
fg_scene_config = FunctionGraphScene.CONFIG
|
|
graph = FunctionGraph(fg_scene_config["default_functions"][0])
|
|
graph.set_color(MAROON_B)
|
|
func_tex = TexMobject("\\frac{1}{9}x^3 - x")
|
|
func_tex.set_color(graph.get_color())
|
|
func_tex.shift(5.5*RIGHT+2*UP)
|
|
|
|
words = VGroup(*[
|
|
TextMobject(words).add_background_rectangle()
|
|
for words in [
|
|
"Linear transformations",
|
|
"Null space",
|
|
"Dot products",
|
|
"Eigen-everything",
|
|
]
|
|
])
|
|
words.set_color_by_gradient(BLUE_B, BLUE_D)
|
|
words.arrange(DOWN, aligned_edge = LEFT)
|
|
words.to_corner(UP+LEFT)
|
|
self.play(FadeIn(
|
|
words,
|
|
lag_ratio = 0.5,
|
|
run_time = 3
|
|
))
|
|
self.wait()
|
|
self.play(*[
|
|
ApplyMethod(mob.shift, FRAME_WIDTH*RIGHT)
|
|
for mob in (axes, everything)
|
|
] + [Animation(words)]
|
|
)
|
|
self.play(ShowCreation(graph), Animation(words))
|
|
self.play(Write(func_tex, run_time = 2))
|
|
self.wait(2)
|
|
|
|
top_word = words[0]
|
|
words.remove(top_word)
|
|
self.play(
|
|
FadeOut(words),
|
|
top_word.shift, top_word.get_center()[0]*LEFT
|
|
)
|
|
self.wait()
|
|
self.func_tex = func_tex
|
|
self.graph = graph
|
|
|
|
def show_derivative(self):
|
|
func_tex, graph = self.func_tex, self.graph
|
|
new_graph = FunctionGraph(lambda x : (x**2)/3.-1)
|
|
new_graph.set_color(YELLOW)
|
|
|
|
func_tex.generate_target()
|
|
lp, rp = parens = TexMobject("()")
|
|
parens.set_height(func_tex.get_height())
|
|
L, equals = TexMobject("L=")
|
|
deriv = TexMobject("\\frac{d}{dx}")
|
|
new_func = TexMobject("\\frac{1}{3}x^2 - 1")
|
|
new_func.set_color(YELLOW)
|
|
group = VGroup(
|
|
L, lp, func_tex.target, rp,
|
|
equals, new_func
|
|
)
|
|
group.arrange()
|
|
group.shift(2*UP).to_edge(LEFT, buff = MED_LARGE_BUFF)
|
|
rect = BackgroundRectangle(group)
|
|
group.add_to_back(rect)
|
|
deriv.move_to(L, aligned_edge = RIGHT)
|
|
|
|
self.play(
|
|
MoveToTarget(func_tex),
|
|
*list(map(Write, [L, lp, rp, equals, new_func]))
|
|
)
|
|
self.remove(func_tex)
|
|
self.add(func_tex.target)
|
|
self.wait()
|
|
faded_graph = graph.copy().fade()
|
|
self.add(faded_graph)
|
|
self.play(
|
|
Transform(graph, new_graph, run_time = 2),
|
|
Animation(group)
|
|
)
|
|
self.wait()
|
|
self.play(Transform(L, deriv))
|
|
self.play(ShowSlopes(faded_graph))
|
|
self.wait()
|
|
|
|
class TransformationsAndOperators(TeacherStudentsScene):
|
|
def construct(self):
|
|
self.student_says("""
|
|
Are these the same
|
|
as ``linear operators''?
|
|
""", student_index = 0)
|
|
self.random_blink()
|
|
teacher = self.get_teacher()
|
|
bubble = teacher.get_bubble(SpeechBubble, height = 2, width = 2)
|
|
bubble.set_fill(BLACK, opacity = 1)
|
|
bubble.write("Yup!")
|
|
self.play(
|
|
teacher.change_mode, "hooray",
|
|
ShowCreation(bubble),
|
|
Write(bubble.content, run_time = 1)
|
|
)
|
|
self.random_blink(2)
|
|
|
|
class ManyFunctions(FunctionGraphScene):
|
|
def construct(self):
|
|
randy = Randolph().to_corner(DOWN+LEFT)
|
|
self.add(randy)
|
|
for i in range(100):
|
|
if i < 3:
|
|
run_time = 1
|
|
self.wait()
|
|
elif i < 10:
|
|
run_time = 0.4
|
|
else:
|
|
run_time = 0.2
|
|
added_anims = []
|
|
if i == 3:
|
|
added_anims = [randy.change_mode, "confused"]
|
|
if i == 10:
|
|
added_anims = [randy.change_mode, "pleading"]
|
|
self.add_random_function(
|
|
run_time = run_time,
|
|
added_anims = added_anims
|
|
)
|
|
|
|
def add_random_function(self, run_time = 1, added_anims = []):
|
|
coefs = np.random.randint(-3, 3, np.random.randint(3, 8))
|
|
def func(x):
|
|
return sum([c*x**(i) for i, c, in enumerate(coefs)])
|
|
graph = self.get_function_graph(func, animate = False)
|
|
if graph.get_height() > FRAME_HEIGHT:
|
|
graph.stretch_to_fit_height(FRAME_HEIGHT)
|
|
graph.shift(graph.point_from_proportion(0.5)[1]*DOWN)
|
|
graph.shift(interpolate(-3, 3, random.random())*UP)
|
|
graph.set_color(random_bright_color())
|
|
self.play(
|
|
ShowCreation(graph, run_time = run_time),
|
|
*added_anims
|
|
)
|
|
|
|
class WhatDoesLinearMean(TeacherStudentsScene):
|
|
def construct(self):
|
|
words = TextMobject("""
|
|
What does it mean for
|
|
a transformation of functions
|
|
to be """, "linear", "?",
|
|
arg_separator = ""
|
|
)
|
|
words.set_color_by_tex("linear", BLUE)
|
|
self.student_says(words)
|
|
self.change_student_modes("pondering")
|
|
self.random_blink(4)
|
|
|
|
class FormalDefinitionOfLinear(LinearTransformationScene):
|
|
CONFIG = {
|
|
"show_basis_vectors" : False,
|
|
"include_background_plane" : False,
|
|
"t_matrix" : [[1, 1], [-0.5, 1]],
|
|
"w_coords" : [1, 1],
|
|
"v_coords" : [1, -2],
|
|
"foreground_plane_kwargs" : {
|
|
"x_radius" : FRAME_WIDTH,
|
|
"y_radius" : FRAME_HEIGHT,
|
|
"secondary_line_ratio" : 1
|
|
},
|
|
}
|
|
def construct(self):
|
|
self.plane.fade()
|
|
self.write_properties()
|
|
self.show_additive_property()
|
|
self.show_scaling_property()
|
|
self.add_words()
|
|
|
|
def write_properties(self):
|
|
title = TextMobject(
|
|
"Formal definition of linearity"
|
|
)
|
|
title.add_background_rectangle()
|
|
title.to_edge(UP)
|
|
h_line = Line(LEFT, RIGHT).scale(FRAME_X_RADIUS)
|
|
h_line.next_to(title, DOWN)
|
|
|
|
v_tex, w_tex = ["\\vec{\\textbf{%s}}"%s for s in "vw"]
|
|
tex_sets = [
|
|
[
|
|
("\\text{Additivity: }",),
|
|
("L(", v_tex, "+", w_tex, ")"),
|
|
("=", "L(", v_tex, ")", "+", "L(", w_tex, ")"),
|
|
],
|
|
[
|
|
("\\text{Scaling: }",),
|
|
("L(", "c", v_tex, ")"),
|
|
("=", "c", "L(", v_tex, ")"),
|
|
],
|
|
]
|
|
properties = VGroup()
|
|
for tex_set in tex_sets:
|
|
words = VGroup(*it.starmap(TexMobject, tex_set))
|
|
for word in words:
|
|
word.set_color_by_tex(v_tex, YELLOW)
|
|
word.set_color_by_tex(w_tex, MAROON_B)
|
|
word.set_color_by_tex("c", GREEN)
|
|
words.arrange()
|
|
words.lhs = words[1]
|
|
words.rhs = words[2]
|
|
words.add_to_back(BackgroundRectangle(words))
|
|
# words.scale(0.8)
|
|
properties.add(words)
|
|
properties.arrange(DOWN, aligned_edge = LEFT, buff = MED_SMALL_BUFF)
|
|
properties.next_to(h_line, DOWN, buff = MED_LARGE_BUFF).to_edge(LEFT)
|
|
|
|
self.play(Write(title), ShowCreation(h_line))
|
|
self.wait()
|
|
for words in properties:
|
|
self.play(Write(words))
|
|
self.wait()
|
|
self.add_foreground_mobject(title, h_line, *properties)
|
|
self.additivity, self.scaling = properties
|
|
|
|
def show_additive_property(self):
|
|
self.plane.save_state()
|
|
|
|
v = self.add_vector(self.v_coords)
|
|
v_label = self.add_transformable_label(v, "v", direction = "right")
|
|
w = self.add_vector(self.w_coords, color = MAROON_B)
|
|
w_label = self.add_transformable_label(w, "w", direction = "left")
|
|
w_group = VGroup(w, w_label)
|
|
w_group.save_state()
|
|
self.play(w_group.shift, v.get_end())
|
|
vw_sum = self.add_vector(w.get_end(), color = PINK)
|
|
v_label_copy, w_label_copy = v_label.copy(), w_label.copy()
|
|
v_label_copy.generate_target()
|
|
w_label_copy.generate_target()
|
|
plus = TexMobject("+")
|
|
vw_label = VGroup(v_label_copy.target, plus, w_label_copy.target)
|
|
vw_label.arrange()
|
|
vw_label.next_to(vw_sum.get_end(), RIGHT)
|
|
self.play(
|
|
MoveToTarget(v_label_copy),
|
|
MoveToTarget(w_label_copy),
|
|
Write(plus)
|
|
)
|
|
vw_label_copy = vw_label.copy()
|
|
vw_label = VGroup(
|
|
VectorizedPoint(vw_label.get_left()),
|
|
vw_label,
|
|
VectorizedPoint(vw_label.get_right()),
|
|
)
|
|
self.remove(v_label_copy, w_label_copy, plus)
|
|
self.add(vw_label)
|
|
self.play(
|
|
w_group.restore,
|
|
)
|
|
vw_label.target = VGroup(
|
|
TexMobject("L(").scale(0.8),
|
|
vw_label_copy,
|
|
TexMobject(")").scale(0.8),
|
|
)
|
|
vw_label.target.arrange()
|
|
for mob in vw_label, vw_label.target:
|
|
mob.add_to_back(BackgroundRectangle(mob))
|
|
|
|
transform = self.get_matrix_transformation(self.t_matrix)
|
|
point = transform(vw_sum.get_end())
|
|
vw_label.target.next_to(point, UP)
|
|
self.apply_transposed_matrix(
|
|
self.t_matrix,
|
|
added_anims = [MoveToTarget(vw_label)]
|
|
)
|
|
self.wait()
|
|
self.play(w_group.shift, v.get_end())
|
|
v_label_copy, w_label_copy = v_label.copy(), w_label.copy()
|
|
v_label_copy.generate_target()
|
|
w_label_copy.generate_target()
|
|
equals, plus = TexMobject("=+")
|
|
rhs = VGroup(
|
|
equals, v_label_copy.target,
|
|
plus, w_label_copy.target
|
|
)
|
|
rhs.arrange()
|
|
rhs.next_to(vw_label, RIGHT)
|
|
rect = BackgroundRectangle(rhs)
|
|
self.play(*it.chain(
|
|
list(map(Write, [rect, equals, plus])),
|
|
list(map(MoveToTarget, [v_label_copy, w_label_copy])),
|
|
))
|
|
to_fade = [self.plane, v, v_label, w_group, vw_label, vw_sum]
|
|
to_fade += self.get_mobjects_from_last_animation()
|
|
|
|
self.wait()
|
|
self.play(*it.chain(
|
|
list(map(FadeOut, to_fade)),
|
|
list(map(Animation, self.foreground_mobjects))
|
|
))
|
|
self.plane.restore()
|
|
self.play(FadeIn(self.plane), *list(map(Animation, self.foreground_mobjects)))
|
|
self.transformable_mobjects = []
|
|
self.moving_vectors = []
|
|
self.transformable_labels = []
|
|
self.moving_mobjects = []
|
|
self.add_transformable_mobject(self.plane)
|
|
self.add(*self.foreground_mobjects)
|
|
|
|
def show_scaling_property(self):
|
|
v = self.add_vector([1, -1])
|
|
v_label = self.add_transformable_label(v, "v")
|
|
scaled_v = v.copy().scale(2)
|
|
scaled_v_label = TexMobject("c\\vec{\\textbf{v}}")
|
|
scaled_v_label.set_color(YELLOW)
|
|
scaled_v_label[0].set_color(GREEN)
|
|
scaled_v_label.next_to(scaled_v.get_end(), RIGHT)
|
|
scaled_v_label.add_background_rectangle()
|
|
v_copy, v_label_copy = v.copy(), v_label.copy()
|
|
self.play(
|
|
Transform(v_copy, scaled_v),
|
|
Transform(v_label_copy, scaled_v_label),
|
|
)
|
|
self.remove(v_copy, v_label_copy)
|
|
self.add(scaled_v_label)
|
|
self.add_vector(scaled_v, animate = False)
|
|
self.wait()
|
|
|
|
transform = self.get_matrix_transformation(self.t_matrix)
|
|
point = transform(scaled_v.get_end())
|
|
scaled_v_label.target = TexMobject("L(", "c", "\\vec{\\textbf{v}}", ")")
|
|
scaled_v_label.target.set_color_by_tex("c", GREEN)
|
|
scaled_v_label.target.set_color_by_tex("\\vec{\\textbf{v}}", YELLOW)
|
|
scaled_v_label.target.scale(0.8)
|
|
scaled_v_label.target.next_to(point, RIGHT)
|
|
scaled_v_label.target.add_background_rectangle()
|
|
|
|
self.apply_transposed_matrix(
|
|
self.t_matrix,
|
|
added_anims = [MoveToTarget(scaled_v_label)]
|
|
)
|
|
self.wait()
|
|
scaled_v = v.copy().scale(2)
|
|
rhs = TexMobject("=", "c", "L(", "\\vec{\\textbf{v}}", ")")
|
|
rhs.set_color_by_tex("c", GREEN)
|
|
rhs.set_color_by_tex("\\vec{\\textbf{v}}", YELLOW)
|
|
rhs.add_background_rectangle()
|
|
rhs.scale(0.8)
|
|
rhs.next_to(scaled_v_label, RIGHT)
|
|
v_copy = v.copy()
|
|
self.add(v_copy)
|
|
self.play(Transform(v, scaled_v))
|
|
self.play(Write(rhs))
|
|
self.wait()
|
|
faders = [
|
|
scaled_v_label, scaled_v, v_copy,
|
|
v, rhs
|
|
] + self.transformable_labels + self.moving_vectors
|
|
self.play(*list(map(FadeOut, faders)))
|
|
|
|
def add_words(self):
|
|
randy = Randolph().shift(LEFT).to_edge(DOWN)
|
|
bubble = randy.get_bubble(SpeechBubble, width = 6, height = 4)
|
|
bubble.set_fill(BLACK, opacity = 0.8)
|
|
bubble.shift(0.5*DOWN)
|
|
VGroup(randy, bubble).to_edge(RIGHT, buff = 0)
|
|
words = TextMobject(
|
|
"Linear transformations\\\\",
|
|
"preserve",
|
|
"addition and \\\\ scalar multiplication",
|
|
)
|
|
words.scale(0.9)
|
|
words.set_color_by_tex("preserve", YELLOW)
|
|
bubble.add_content(words)
|
|
|
|
self.play(FadeIn(randy))
|
|
self.play(
|
|
ShowCreation(bubble),
|
|
Write(words),
|
|
randy.change_mode, "speaking",
|
|
)
|
|
self.play(Blink(randy))
|
|
self.wait()
|
|
|
|
class CalcStudentsKnowThatDerivIsLinear(TeacherStudentsScene):
|
|
def construct(self):
|
|
words = TextMobject(
|
|
"""Calc students subconsciously
|
|
know that""",
|
|
"$\\dfrac{d}{dx}$",
|
|
"is linear"
|
|
)
|
|
words.set_color_by_tex("$\\dfrac{d}{dx}$", BLUE)
|
|
self.teacher_says(words)
|
|
self.change_student_modes(
|
|
"pondering", "confused", "erm"
|
|
)
|
|
self.random_blink(3)
|
|
|
|
class DerivativeIsLinear(Scene):
|
|
def construct(self):
|
|
self.add_title()
|
|
self.prepare_text()
|
|
self.show_additivity()
|
|
self.show_scaling()
|
|
|
|
def add_title(self):
|
|
title = TextMobject("Derivative is linear")
|
|
title.to_edge(UP)
|
|
self.add(title)
|
|
|
|
def prepare_text(self):
|
|
v_tex, w_tex = ["\\vec{\\textbf{%s}}"%s for s in "vw"]
|
|
additivity = TexMobject(
|
|
"L(", v_tex, "+", w_tex, ")", "=",
|
|
"L(", v_tex, ")+L(", w_tex, ")"
|
|
)
|
|
scaling = TexMobject(
|
|
"L(", "c", v_tex, ")=", "c", "L(", v_tex, ")"
|
|
)
|
|
for text in additivity, scaling:
|
|
text.set_color_by_tex(v_tex, YELLOW)
|
|
text.set_color_by_tex(w_tex, MAROON_B)
|
|
text.set_color_by_tex("c", GREEN)
|
|
|
|
deriv_tex = "\\dfrac{d}{dx}"
|
|
deriv_additivity = TexMobject(
|
|
deriv_tex, "(", "x^3", "+", "x^2", ")", "=",
|
|
deriv_tex, "(", "x^3", ")", "+",
|
|
deriv_tex, "(", "x^2", ")"
|
|
)
|
|
deriv_scaling = TexMobject(
|
|
deriv_tex, "(", "4", "x^3", ")", "=",
|
|
"4", deriv_tex, "(", "x^3", ")"
|
|
)
|
|
for text in deriv_additivity, deriv_scaling:
|
|
text.set_color_by_tex("x^3", YELLOW)
|
|
text.set_color_by_tex("x^2", MAROON_B)
|
|
text.set_color_by_tex("4", GREEN)
|
|
|
|
self.additivity = additivity
|
|
self.scaling = scaling
|
|
self.deriv_additivity = deriv_additivity
|
|
self.deriv_scaling = deriv_scaling
|
|
|
|
def show_additivity(self):
|
|
general, deriv = self.additivity, self.deriv_additivity
|
|
group = VGroup(general, deriv )
|
|
group.arrange(DOWN, buff = 1.5)
|
|
|
|
inner_sum = VGroup(*deriv[2:2+3])
|
|
outer_sum_deriv = VGroup(deriv[0], deriv[1], deriv[5])
|
|
inner_func1 = deriv[9]
|
|
outer_deriv1 = VGroup(deriv[7], deriv[8], deriv[10])
|
|
plus = deriv[11]
|
|
inner_func2 = deriv[14]
|
|
outer_deriv2 = VGroup(deriv[12], deriv[13], deriv[15])
|
|
|
|
self.play(FadeIn(group))
|
|
self.wait()
|
|
self.point_out(inner_sum)
|
|
self.point_out(outer_sum_deriv)
|
|
self.wait()
|
|
self.point_out(outer_deriv1, outer_deriv2)
|
|
self.point_out(inner_func1, inner_func2)
|
|
self.point_out(plus)
|
|
self.wait()
|
|
self.play(FadeOut(group))
|
|
|
|
def show_scaling(self):
|
|
general, deriv = self.scaling, self.deriv_scaling
|
|
group = VGroup(general, deriv)
|
|
group.arrange(DOWN, buff = 1.5)
|
|
|
|
inner_scaling = VGroup(*deriv[2:4])
|
|
lhs_deriv = VGroup(deriv[0], deriv[1], deriv[4])
|
|
rhs_deriv = VGroup(*deriv[7:])
|
|
outer_scaling = deriv[6]
|
|
|
|
self.play(FadeIn(group))
|
|
self.wait()
|
|
self.point_out(inner_scaling)
|
|
self.point_out(lhs_deriv)
|
|
self.wait()
|
|
self.point_out(rhs_deriv)
|
|
self.point_out(outer_scaling)
|
|
self.wait()
|
|
|
|
def point_out(self, *terms):
|
|
anims = []
|
|
for term in terms:
|
|
anims += [
|
|
term.scale_in_place, 1.2,
|
|
term.set_color, RED,
|
|
]
|
|
self.play(
|
|
*anims,
|
|
run_time = 1,
|
|
rate_func = there_and_back
|
|
)
|
|
|
|
class ProposeDerivativeAsMatrix(TeacherStudentsScene):
|
|
def construct(self):
|
|
self.teacher_says(
|
|
"""
|
|
Let's describe the
|
|
derivative with
|
|
a matrix
|
|
""",
|
|
target_mode = "hooray"
|
|
)
|
|
self.random_blink()
|
|
self.change_student_modes("pondering", "confused", "erm")
|
|
self.random_blink(3)
|
|
|
|
class PolynomialsHaveArbitrarilyLargeDegree(Scene):
|
|
def construct(self):
|
|
polys = VGroup(*list(map(TexMobject, [
|
|
"x^{300} + 9x^2",
|
|
"4x^{4{,}000{,}000{,}000} + 1",
|
|
"3x^{\\left(10^{100}\\right)}",
|
|
"\\vdots"
|
|
])))
|
|
polys.set_color_by_gradient(BLUE_B, BLUE_D)
|
|
polys.arrange(DOWN, buff = MED_LARGE_BUFF)
|
|
polys.scale(1.3)
|
|
|
|
arrow = TexMobject("\\Rightarrow").scale(1.5)
|
|
|
|
brace = Brace(
|
|
Line(UP, DOWN).scale(FRAME_Y_RADIUS).shift(FRAME_X_RADIUS*RIGHT),
|
|
LEFT
|
|
)
|
|
words = TextMobject("Infinitely many")
|
|
words.scale(1.5)
|
|
words.next_to(brace, LEFT)
|
|
arrow.next_to(words, LEFT)
|
|
polys.next_to(arrow, LEFT)
|
|
|
|
self.play(Write(polys))
|
|
self.wait()
|
|
self.play(
|
|
FadeIn(arrow),
|
|
Write(words),
|
|
GrowFromCenter(brace)
|
|
)
|
|
self.wait()
|
|
|
|
class GeneneralPolynomialCoordinates(Scene):
|
|
def construct(self):
|
|
poly = TexMobject(
|
|
"a_n", "x^n", "+",
|
|
"a_{n-1}", "x^{n-1}", "+",
|
|
"\\cdots",
|
|
"a_1", "x", "+",
|
|
"a_0",
|
|
)
|
|
poly.set_color_by_tex("a_n", YELLOW)
|
|
poly.set_color_by_tex("a_{n-1}", MAROON_B)
|
|
poly.set_color_by_tex("a_1", RED)
|
|
poly.set_color_by_tex("a_0", GREEN)
|
|
poly.scale(1.3)
|
|
|
|
array = Matrix(
|
|
["a_0", "a_1", "\\vdots", "a_{n-1}", "a_n", "0", "\\vdots"]
|
|
)
|
|
array.get_entries()[0].set_color(GREEN)
|
|
array.get_entries()[1].set_color(RED)
|
|
array.get_entries()[3].set_color(MAROON_B)
|
|
array.get_entries()[4].set_color(YELLOW)
|
|
array.scale(1.2)
|
|
|
|
equals = TexMobject("=").scale(1.3)
|
|
group = VGroup(poly, equals, array)
|
|
group.arrange()
|
|
group.to_edge(RIGHT)
|
|
|
|
pre_entries = VGroup(
|
|
poly[-1], poly[-4], poly[-5],
|
|
poly[3], poly[0],
|
|
VectorizedPoint(poly.get_left()),
|
|
VectorizedPoint(poly.get_left()),
|
|
)
|
|
|
|
self.add(poly, equals, array.get_brackets())
|
|
self.wait()
|
|
self.play(
|
|
Transform(pre_entries.copy(), array.get_entries())
|
|
)
|
|
self.wait()
|
|
|
|
class SimplePolynomialCoordinates(Scene):
|
|
def construct(self):
|
|
matrix = Matrix(["5", "3", "1", "0", "\\vdots"])
|
|
matrix.to_edge(LEFT)
|
|
self.play(Write(matrix))
|
|
self.wait()
|
|
|
|
class IntroducePolynomialSpace(Scene):
|
|
def construct(self):
|
|
self.add_title()
|
|
self.show_polynomial_cloud()
|
|
self.split_individual_polynomial()
|
|
self.list_basis_functions()
|
|
self.show_example_coordinates()
|
|
self.derivative_as_matrix()
|
|
|
|
def add_title(self):
|
|
title = TextMobject("Our current space: ", "All polynomials")
|
|
title.to_edge(UP)
|
|
title[1].set_color(BLUE)
|
|
self.play(Write(title))
|
|
self.wait()
|
|
self.title = title
|
|
|
|
def show_polynomial_cloud(self):
|
|
cloud = ThoughtBubble()[-1]
|
|
cloud.stretch_to_fit_height(6)
|
|
cloud.center()
|
|
|
|
|
|
polys = VGroup(
|
|
TexMobject("x^2", "+", "3", "x", "+", "5"),
|
|
TexMobject("4x^7-5x^2"),
|
|
TexMobject("x^{100}+2x^{99}+3x^{98}"),
|
|
TexMobject("3x-7"),
|
|
TexMobject("x^{1{,}000{,}000{,}000}+1"),
|
|
TexMobject("\\vdots"),
|
|
)
|
|
polys.set_color_by_gradient(BLUE_B, BLUE_D)
|
|
polys.arrange(DOWN, buff = MED_SMALL_BUFF)
|
|
polys.next_to(cloud.get_top(), DOWN, buff = MED_LARGE_BUFF)
|
|
|
|
self.play(ShowCreation(cloud))
|
|
for poly in polys:
|
|
self.play(Write(poly), run_time = 1)
|
|
self.wait()
|
|
self.poly1, self.poly2 = polys[0], polys[1]
|
|
polys.remove(self.poly1)
|
|
self.play(
|
|
FadeOut(cloud),
|
|
FadeOut(polys),
|
|
self.poly1.next_to, ORIGIN, LEFT,
|
|
self.poly1.set_color, WHITE
|
|
)
|
|
|
|
def split_individual_polynomial(self):
|
|
leading_coef = TexMobject("1")
|
|
leading_coef.next_to(self.poly1[0], LEFT, aligned_edge = DOWN)
|
|
self.poly1.add_to_back(leading_coef)
|
|
one = TexMobject("\\cdot", "1")
|
|
one.next_to(self.poly1[-1], RIGHT, aligned_edge = DOWN)
|
|
self.poly1.add(one)
|
|
for mob in leading_coef, one:
|
|
mob.set_color(BLACK)
|
|
|
|
brace = Brace(self.poly1)
|
|
brace.text = brace.get_text("Already written as \\\\ a linear combination")
|
|
|
|
index_to_color = {
|
|
0 : WHITE,
|
|
1 : Z_COLOR,
|
|
4 : Y_COLOR,
|
|
7 : X_COLOR,
|
|
}
|
|
self.play(
|
|
GrowFromCenter(brace),
|
|
Write(brace.text),
|
|
*[
|
|
ApplyMethod(self.poly1[index].set_color, color)
|
|
for index, color in list(index_to_color.items())
|
|
]
|
|
)
|
|
self.wait()
|
|
self.brace = brace
|
|
|
|
def list_basis_functions(self):
|
|
title = TextMobject("Basis functions")
|
|
title.next_to(self.title, DOWN, buff = MED_SMALL_BUFF)
|
|
title.to_edge(RIGHT)
|
|
h_line = Line(ORIGIN, RIGHT).scale(title.get_width())
|
|
h_line.next_to(title, DOWN)
|
|
|
|
x_cubed = TexMobject("x^3")
|
|
x_cubed.set_color(MAROON_B)
|
|
x_cubed.to_corner(DOWN+RIGHT).shift(2*(DOWN+RIGHT))
|
|
basis_group = VGroup(
|
|
self.poly1[7][1],
|
|
self.poly1[4],
|
|
self.poly1[1],
|
|
x_cubed
|
|
).copy()
|
|
basis_group.generate_target()
|
|
basis_group.target.arrange(
|
|
DOWN, buff = 0.75*LARGE_BUFF, aligned_edge = LEFT
|
|
)
|
|
basis_group.target.to_edge(RIGHT, buff = MED_LARGE_BUFF)
|
|
dots = TexMobject("\\vdots")
|
|
dots.next_to(basis_group.target, DOWN, buff = MED_SMALL_BUFF, aligned_edge = LEFT)
|
|
|
|
basis_functions = [
|
|
TexMobject("b_%d(x)"%i, "=")
|
|
for i in range(len(list(basis_group)))
|
|
]
|
|
for basis_func, term in zip(basis_functions, basis_group.target):
|
|
basis_func.set_color(term.get_color())
|
|
basis_func.next_to(term, LEFT)
|
|
for i in 2, 3:
|
|
basis_functions[i].shift(SMALL_BUFF*DOWN)
|
|
|
|
self.play(
|
|
FadeIn(title),
|
|
ShowCreation(h_line),
|
|
MoveToTarget(basis_group),
|
|
Write(dots)
|
|
)
|
|
for basis_func in basis_functions:
|
|
self.play(Write(basis_func, run_time = 1))
|
|
self.play(Write(dots))
|
|
self.wait()
|
|
self.basis = basis_group
|
|
self.basis_functions = basis_functions
|
|
|
|
def show_example_coordinates(self):
|
|
coords = Matrix(["5", "3", "1", "0", "0", "\\vdots"])
|
|
for i, color in enumerate([X_COLOR, Y_COLOR, Z_COLOR]):
|
|
coords[i].set_color(color)
|
|
self.poly1.generate_target()
|
|
equals = TexMobject("=").next_to(coords, LEFT)
|
|
self.poly1.target.next_to(equals, LEFT)
|
|
entries = coords.get_entries()
|
|
entries.save_state()
|
|
entries.set_fill(opacity = 0)
|
|
|
|
self.play(
|
|
MoveToTarget(self.poly1),
|
|
Write(equals),
|
|
FadeOut(self.brace),
|
|
FadeOut(self.brace.text)
|
|
)
|
|
for entry, index in zip(entries, [6, 3, 0]):
|
|
entry.move_to(self.poly1[index])
|
|
self.play(Write(coords.get_brackets()))
|
|
self.play(
|
|
entries.restore,
|
|
lag_ratio = 0.5,
|
|
run_time = 3
|
|
)
|
|
self.wait()
|
|
target = self.poly1.copy()
|
|
terms = [
|
|
VGroup(*target[6:8]),
|
|
VGroup(target[5], *target[3:5]),
|
|
VGroup(target[2], *target[0:2]),
|
|
]
|
|
target[5].next_to(target[3], LEFT)
|
|
target[2].next_to(target[0], LEFT)
|
|
more_terms = [
|
|
TexMobject("+0", "x^3").set_color_by_tex("x^3", MAROON_B),
|
|
TexMobject("+0", "x^4").set_color_by_tex("x^4", YELLOW),
|
|
TexMobject("\\vdots")
|
|
]
|
|
for entry, term in zip(entries, terms+more_terms):
|
|
term.next_to(entry, LEFT, buff = LARGE_BUFF)
|
|
more_terms[-1].shift(MED_SMALL_BUFF*LEFT)
|
|
|
|
self.play(Transform(self.poly1, target))
|
|
self.wait()
|
|
self.play(FadeIn(
|
|
VGroup(*more_terms),
|
|
lag_ratio = 0.5,
|
|
run_time = 2
|
|
))
|
|
self.wait()
|
|
|
|
self.play(*list(map(FadeOut, [self.poly1]+more_terms)))
|
|
self.poly2.next_to(equals, LEFT)
|
|
self.poly2.shift(MED_SMALL_BUFF*UP)
|
|
self.poly2.set_color(WHITE)
|
|
self.poly2[0].set_color(TEAL)
|
|
VGroup(*self.poly2[3:5]).set_color(Z_COLOR)
|
|
new_coords = Matrix(["0", "0", "-5", "0", "0", "0", "0", "4", "\\vdots"])
|
|
new_coords.get_entries()[2].set_color(Z_COLOR)
|
|
new_coords.get_entries()[7].set_color(TEAL)
|
|
new_coords.set_height(6)
|
|
new_coords.move_to(coords, aligned_edge = LEFT)
|
|
self.play(
|
|
Write(self.poly2),
|
|
Transform(coords, new_coords)
|
|
)
|
|
self.wait()
|
|
for i, mob in (2, VGroup(*self.poly2[3:5])), (7, self.poly2[0]):
|
|
self.play(
|
|
new_coords.get_entries()[i].scale_in_place, 1.3,
|
|
mob.scale_in_place, 1.3,
|
|
rate_func = there_and_back
|
|
)
|
|
self.remove(*self.get_mobjects_from_last_animation())
|
|
self.add(self.poly2)
|
|
self.wait()
|
|
self.play(*list(map(FadeOut, [self.poly2, coords, equals])))
|
|
|
|
def derivative_as_matrix(self):
|
|
matrix = Matrix([
|
|
[
|
|
str(j) if j == i+1 else "0"
|
|
for j in range(4)
|
|
] + ["\\cdots"]
|
|
for i in range(4)
|
|
] + [
|
|
["\\vdots"]*4 + ["\\ddots"]
|
|
])
|
|
matrix.shift(2*LEFT)
|
|
diag_entries = VGroup(*[
|
|
matrix.get_mob_matrix()[i, i+1]
|
|
for i in range(3)
|
|
])
|
|
##Horrible
|
|
last_col = VGroup(*matrix.get_mob_matrix()[:,-1])
|
|
last_col_top = last_col.get_top()
|
|
last_col.arrange(DOWN, buff = 0.83)
|
|
last_col.move_to(last_col_top, aligned_edge = UP+RIGHT)
|
|
##End horrible
|
|
matrix.set_column_colors(X_COLOR, Y_COLOR, Z_COLOR, MAROON_B)
|
|
|
|
deriv = TexMobject("\\dfrac{d}{dx}")
|
|
equals = TexMobject("=")
|
|
equals.next_to(matrix, LEFT)
|
|
deriv.next_to(equals, LEFT)
|
|
|
|
self.play(FadeIn(deriv), FadeIn(equals))
|
|
self.play(Write(matrix))
|
|
self.wait()
|
|
diag_entries.save_state()
|
|
diag_entries.generate_target()
|
|
diag_entries.target.scale_in_place(1.2)
|
|
diag_entries.target.set_color(YELLOW)
|
|
for anim in MoveToTarget(diag_entries), diag_entries.restore:
|
|
self.play(
|
|
anim,
|
|
lag_ratio = 0.5,
|
|
run_time = 1.5,
|
|
)
|
|
self.wait()
|
|
matrix.generate_target()
|
|
matrix.target.to_corner(DOWN+LEFT).shift(0.25*UP)
|
|
deriv.generate_target()
|
|
deriv.target.next_to(
|
|
matrix.target, UP,
|
|
buff = MED_SMALL_BUFF,
|
|
aligned_edge = LEFT
|
|
)
|
|
deriv.target.shift(0.25*RIGHT)
|
|
self.play(
|
|
FadeOut(equals),
|
|
*list(map(MoveToTarget, [matrix, deriv]))
|
|
)
|
|
|
|
poly = TexMobject(
|
|
"(", "1", "x^3", "+",
|
|
"5", "x^2", "+",
|
|
"4", "x", "+",
|
|
"5", ")"
|
|
)
|
|
coefs = VGroup(*np.array(poly)[[10, 7, 4, 1]])
|
|
VGroup(*poly[1:3]).set_color(MAROON_B)
|
|
VGroup(*poly[4:6]).set_color(Z_COLOR)
|
|
VGroup(*poly[7:9]).set_color(Y_COLOR)
|
|
VGroup(*poly[10:11]).set_color(X_COLOR)
|
|
poly.next_to(deriv)
|
|
self.play(FadeIn(poly))
|
|
|
|
array = Matrix(list(coefs.copy()) + [TexMobject("\\vdots")])
|
|
array.next_to(matrix, RIGHT)
|
|
self.play(Write(array.get_brackets()))
|
|
to_remove = []
|
|
for coef, entry in zip(coefs, array.get_entries()):
|
|
self.play(Transform(coef.copy(), entry))
|
|
to_remove += self.get_mobjects_from_last_animation()
|
|
self.play(Write(array.get_entries()[-1]))
|
|
to_remove += self.get_mobjects_from_last_animation()
|
|
self.remove(*to_remove)
|
|
self.add(array)
|
|
|
|
eq1, eq2 = TexMobject("="), TexMobject("=")
|
|
eq1.next_to(poly)
|
|
eq2.next_to(array)
|
|
|
|
poly_result = TexMobject(
|
|
"3", "x^2", "+",
|
|
"10", "x", "+",
|
|
"4"
|
|
)
|
|
poly_result.next_to(eq1)
|
|
brace = Brace(poly_result, buff = 0)
|
|
|
|
self.play(*list(map(Write, [eq1, eq2, brace])))
|
|
|
|
result_coefs = VGroup(*np.array(poly_result)[[6, 3, 0]])
|
|
VGroup(*poly_result[0:2]).set_color(MAROON_B)
|
|
VGroup(*poly_result[3:5]).set_color(Z_COLOR)
|
|
VGroup(*poly_result[6:]).set_color(Y_COLOR)
|
|
result_terms = [
|
|
VGroup(*poly_result[6:]),
|
|
VGroup(*poly_result[3:6]),
|
|
VGroup(*poly_result[0:3]),
|
|
]
|
|
relevant_entries = VGroup(*array.get_entries()[1:4])
|
|
dots = [TexMobject("\\cdot") for x in range(3)]
|
|
result_entries = []
|
|
for entry, diag_entry, dot in zip(relevant_entries, diag_entries, dots):
|
|
entry.generate_target()
|
|
diag_entry.generate_target()
|
|
group = VGroup(diag_entry.target, dot, entry.target)
|
|
group.arrange()
|
|
result_entries.append(group)
|
|
result_array = Matrix(
|
|
result_entries + [
|
|
TexMobject("0"),
|
|
TexMobject("\\vdots")
|
|
]
|
|
)
|
|
result_array.next_to(eq2)
|
|
|
|
rects = [
|
|
Rectangle(
|
|
color = YELLOW
|
|
).replace(
|
|
VGroup(*matrix.get_mob_matrix()[i,:]),
|
|
stretch = True
|
|
).stretch_in_place(1.1, 0).stretch_in_place(1.3, 1)
|
|
for i in range(3)
|
|
]
|
|
vert_rect = Rectangle(color = YELLOW)
|
|
vert_rect.replace(array.get_entries(), stretch = True)
|
|
vert_rect.stretch_in_place(1.1, 1)
|
|
vert_rect.stretch_in_place(1.5, 0)
|
|
tuples = list(zip(
|
|
relevant_entries,
|
|
diag_entries,
|
|
result_entries,
|
|
rects,
|
|
result_terms,
|
|
coefs[1:]
|
|
))
|
|
self.play(Write(result_array.get_brackets()))
|
|
for entry, diag_entry, result_entry, rect, result_term, coef in tuples:
|
|
self.play(FadeIn(rect), FadeIn(vert_rect))
|
|
self.wait()
|
|
self.play(
|
|
entry.scale_in_place, 1.2,
|
|
diag_entry.scale_in_place, 1.2,
|
|
)
|
|
diag_entry_target, dot, entry_target = result_entry
|
|
self.play(
|
|
Transform(entry.copy(), entry_target),
|
|
Transform(diag_entry.copy(), diag_entry_target),
|
|
entry.scale_in_place, 1/1.2,
|
|
diag_entry.scale_in_place, 1/1.2,
|
|
Write(dot)
|
|
)
|
|
self.wait()
|
|
self.play(Transform(coef.copy(), VGroup(result_term)))
|
|
self.wait()
|
|
self.play(FadeOut(rect), FadeOut(vert_rect))
|
|
self.play(*list(map(Write, result_array.get_entries()[3:])))
|
|
self.wait()
|
|
|
|
class MatrixVectorMultiplicationAndDerivative(TeacherStudentsScene):
|
|
def construct(self):
|
|
mv_mult = VGroup(
|
|
Matrix([[3, 1], [0, 2]]).set_column_colors(X_COLOR, Y_COLOR),
|
|
Matrix(["x", "y"]).set_column_colors(YELLOW)
|
|
)
|
|
mv_mult.arrange()
|
|
mv_mult.scale(0.75)
|
|
arrow = TexMobject("\\Leftrightarrow")
|
|
deriv = TexMobject("\\dfrac{df}{dx}")
|
|
group = VGroup(mv_mult, arrow, deriv)
|
|
group.arrange(buff = MED_SMALL_BUFF)
|
|
arrow.set_color(BLACK)
|
|
|
|
teacher = self.get_teacher()
|
|
bubble = teacher.get_bubble(SpeechBubble, height = 4)
|
|
bubble.add_content(group)
|
|
|
|
self.play(
|
|
teacher.change_mode, "speaking",
|
|
ShowCreation(bubble),
|
|
Write(group)
|
|
)
|
|
self.random_blink()
|
|
group.generate_target()
|
|
group.target.scale(0.8)
|
|
words = TextMobject("Linear transformations")
|
|
h_line = Line(ORIGIN, RIGHT).scale(words.get_width())
|
|
h_line.next_to(words, DOWN)
|
|
group.target.next_to(h_line, DOWN, buff = MED_SMALL_BUFF)
|
|
group.target[1].set_color(WHITE)
|
|
new_group = VGroup(words, h_line, group.target)
|
|
bubble.add_content(new_group)
|
|
|
|
self.play(
|
|
MoveToTarget(group),
|
|
ShowCreation(h_line),
|
|
Write(words),
|
|
self.get_teacher().change_mode, "hooray"
|
|
)
|
|
self.change_student_modes(*["pondering"]*3)
|
|
self.random_blink(3)
|
|
|
|
class CompareTermsInLinearAlgebraToFunction(Scene):
|
|
def construct(self):
|
|
l_title = TextMobject("Linear algebra \\\\ concepts")
|
|
r_title = TextMobject("Alternate names when \\\\ applied to functions")
|
|
for title, vect in (l_title, LEFT), (r_title, RIGHT):
|
|
title.to_edge(UP)
|
|
title.shift(vect*FRAME_X_RADIUS/2)
|
|
h_line = Line(LEFT, RIGHT).scale(FRAME_X_RADIUS)
|
|
h_line.shift(
|
|
VGroup(l_title, r_title).get_bottom()[1]*UP + SMALL_BUFF*DOWN
|
|
)
|
|
v_line = Line(UP, DOWN).scale(FRAME_Y_RADIUS)
|
|
VGroup(h_line, v_line).set_color(BLUE)
|
|
|
|
self.add(l_title, r_title)
|
|
self.play(*list(map(ShowCreation, [h_line, v_line])))
|
|
self.wait()
|
|
|
|
lin_alg_concepts = VGroup(*list(map(TextMobject, [
|
|
"Linear transformations",
|
|
"Dot products",
|
|
"Eigenvectors",
|
|
])))
|
|
function_concepts = VGroup(*list(map(TextMobject, [
|
|
"Linear operators",
|
|
"Inner products",
|
|
"Eigenfunctions",
|
|
])))
|
|
for concepts, vect in (lin_alg_concepts, LEFT), (function_concepts, RIGHT):
|
|
concepts.arrange(DOWN, buff = MED_LARGE_BUFF, aligned_edge = LEFT)
|
|
concepts.next_to(h_line, DOWN, buff = LARGE_BUFF)
|
|
concepts.shift(vect*FRAME_X_RADIUS/2)
|
|
concepts.set_color_by_gradient(YELLOW_B, YELLOW_C)
|
|
|
|
for concept in concepts:
|
|
self.play(Write(concept, run_time = 1))
|
|
self.wait()
|
|
|
|
class BackToTheQuestion(TeacherStudentsScene):
|
|
def construct(self):
|
|
self.student_says(
|
|
"""
|
|
Wait...so how does
|
|
this relate to what vectors
|
|
really are?
|
|
""",
|
|
target_mode = "confused"
|
|
)
|
|
self.random_blink(2)
|
|
self.teacher_says(
|
|
"""
|
|
There are many different
|
|
vector-ish things
|
|
"""
|
|
)
|
|
self.random_blink(2)
|
|
|
|
class YouAsAMathematician(Scene):
|
|
def construct(self):
|
|
mathy = Mathematician()
|
|
mathy.to_corner(DOWN+LEFT)
|
|
words = TextMobject("You as a mathematician")
|
|
words.shift(2*UP)
|
|
arrow = Arrow(words.get_bottom(), mathy.get_corner(UP+RIGHT))
|
|
bubble = mathy.get_bubble()
|
|
|
|
equations = self.get_content()
|
|
bubble.add_content(equations)
|
|
|
|
self.add(mathy)
|
|
self.play(Write(words, run_time = 2))
|
|
self.play(
|
|
ShowCreation(arrow),
|
|
mathy.change_mode, "wave_1",
|
|
mathy.look, OUT
|
|
)
|
|
self.play(Blink(mathy))
|
|
self.wait()
|
|
self.play(
|
|
FadeOut(words),
|
|
FadeOut(arrow),
|
|
mathy.change_mode, "pondering",
|
|
ShowCreation(bubble),
|
|
)
|
|
self.play(Write(equations))
|
|
self.play(Blink(mathy))
|
|
self.wait()
|
|
|
|
bubble.write("Does this make any sense \\\\ for functions too?")
|
|
self.play(
|
|
equations.next_to, mathy.eyes, RIGHT, 2*LARGE_BUFF,
|
|
mathy.change_mode, "confused",
|
|
mathy.look, RIGHT,
|
|
Write(bubble.content)
|
|
)
|
|
self.wait()
|
|
self.play(Blink(mathy))
|
|
|
|
def get_content(self):
|
|
v_tex = "\\vec{\\textbf{v}}"
|
|
eigen_equation = TexMobject("A", v_tex, "=", "\\lambda", v_tex)
|
|
v_ne_zero = TexMobject(v_tex, "\\ne \\vec{\\textbf{0}}")
|
|
det_equation = TexMobject("\\det(A-", "\\lambda", "I)=0")
|
|
arrow = TexMobject("\\Rightarrow")
|
|
|
|
for tex in eigen_equation, v_ne_zero, det_equation:
|
|
tex.set_color_by_tex(v_tex, YELLOW)
|
|
tex.set_color_by_tex("\\lambda", MAROON_B)
|
|
|
|
lhs = VGroup(eigen_equation, v_ne_zero)
|
|
lhs.arrange(DOWN)
|
|
group = VGroup(lhs, arrow, det_equation)
|
|
group.arrange(buff = MED_SMALL_BUFF)
|
|
return group
|
|
|
|
class ShowVectorSpaces(Scene):
|
|
def construct(self):
|
|
title = TextMobject("Vector spaces")
|
|
title.to_edge(UP)
|
|
h_line = Line(LEFT, RIGHT).scale(FRAME_X_RADIUS)
|
|
h_line.next_to(title, DOWN)
|
|
|
|
v_lines = [
|
|
Line(
|
|
h_line.get_center(), FRAME_Y_RADIUS*DOWN
|
|
).shift(vect*FRAME_X_RADIUS/3.)
|
|
for vect in (LEFT, RIGHT)
|
|
]
|
|
vectors = self.get_vectors()
|
|
vectors.shift(LEFT*FRAME_X_RADIUS*(2./3))
|
|
arrays = self.get_arrays()
|
|
functions = self.get_functions()
|
|
functions.shift(RIGHT*FRAME_X_RADIUS*(2./3))
|
|
|
|
self.add(h_line, *v_lines)
|
|
self.play(ShowCreation(
|
|
vectors,
|
|
run_time = 3
|
|
))
|
|
self.play(Write(arrays))
|
|
self.play(Write(functions))
|
|
self.wait()
|
|
self.play(Write(title))
|
|
|
|
def get_vectors(self, n_vectors = 10):
|
|
vectors = VGroup(*[
|
|
Vector(RIGHT).scale(scalar).rotate(angle)
|
|
for scalar, angle in zip(
|
|
2*np.random.random(n_vectors)+0.5,
|
|
np.linspace(0, 6, n_vectors)
|
|
)
|
|
])
|
|
vectors.set_color_by_gradient(YELLOW, MAROON_B)
|
|
return vectors
|
|
|
|
def get_arrays(self):
|
|
arrays = VGroup(*[
|
|
VGroup(*[
|
|
Matrix(np.random.randint(-9, 9, 2))
|
|
for x in range(4)
|
|
])
|
|
for x in range(3)
|
|
])
|
|
for subgroup in arrays:
|
|
subgroup.arrange(DOWN, buff = MED_SMALL_BUFF)
|
|
arrays.arrange(RIGHT)
|
|
arrays.scale(0.7)
|
|
arrays.set_color_by_gradient(YELLOW, MAROON_B)
|
|
return arrays
|
|
|
|
def get_functions(self):
|
|
axes = Axes()
|
|
axes.scale(0.3)
|
|
functions = VGroup(*[
|
|
FunctionGraph(func, x_min = -4, x_max = 4)
|
|
for func in [
|
|
lambda x : x**3 - 9*x,
|
|
lambda x : x**3 - 4*x,
|
|
lambda x : x**2 - 1,
|
|
]
|
|
])
|
|
functions.stretch_to_fit_width(FRAME_X_RADIUS/2.)
|
|
functions.stretch_to_fit_height(6)
|
|
functions.set_color_by_gradient(YELLOW, MAROON_B)
|
|
functions.center()
|
|
return VGroup(axes, functions)
|
|
|
|
class ToolsOfLinearAlgebra(Scene):
|
|
def construct(self):
|
|
words = VGroup(*list(map(TextMobject, [
|
|
"Linear transformations",
|
|
"Null space",
|
|
"Eigenvectors",
|
|
"Dot products",
|
|
"$\\vdots$"
|
|
])))
|
|
words.arrange(DOWN, aligned_edge = LEFT, buff = MED_SMALL_BUFF)
|
|
words[-1].next_to(words[-2], DOWN)
|
|
self.play(FadeIn(
|
|
words,
|
|
lag_ratio = 0.5,
|
|
run_time = 3
|
|
))
|
|
self.wait()
|
|
|
|
class MathematicianSpeakingToAll(Scene):
|
|
def construct(self):
|
|
mathy = Mathematician().to_corner(DOWN+LEFT)
|
|
others = VGroup(*[
|
|
Randolph().flip().set_color(color)
|
|
for color in (BLUE_D, GREEN_E, GOLD_E, BLUE_C)
|
|
])
|
|
others.arrange()
|
|
others.scale(0.8)
|
|
others.to_corner(DOWN+RIGHT)
|
|
|
|
bubble = mathy.get_bubble(SpeechBubble)
|
|
bubble.write("""
|
|
I don't want to think
|
|
about all y'all's crazy
|
|
vector spaces
|
|
""")
|
|
|
|
self.add(mathy, others)
|
|
self.play(
|
|
ShowCreation(bubble),
|
|
Write(bubble.content),
|
|
mathy.change_mode, "sassy",
|
|
mathy.look_at, others
|
|
)
|
|
self.play(Blink(others[3]))
|
|
self.wait()
|
|
thought_bubble = mathy.get_bubble(ThoughtBubble)
|
|
self.play(
|
|
FadeOut(bubble.content),
|
|
Transform(bubble, thought_bubble),
|
|
mathy.change_mode, "speaking",
|
|
mathy.look_at, bubble,
|
|
*[ApplyMethod(pi.look_at, bubble) for pi in others]
|
|
)
|
|
|
|
vect = -bubble.get_bubble_center()
|
|
def func(point):
|
|
centered = point+vect
|
|
return 10*centered/get_norm(centered)
|
|
self.play(*[
|
|
ApplyPointwiseFunction(func, mob)
|
|
for mob in self.get_mobjects()
|
|
])
|
|
|
|
class ListAxioms(Scene):
|
|
def construct(self):
|
|
title = TextMobject("Rules for vectors addition and scaling")
|
|
title.to_edge(UP)
|
|
h_line = Line(LEFT, RIGHT).scale(FRAME_X_RADIUS)
|
|
h_line.next_to(title, DOWN)
|
|
self.add(title, h_line)
|
|
|
|
u_tex, v_tex, w_tex = ["\\vec{\\textbf{%s}}"%s for s in "uvw"]
|
|
axioms = VGroup(*it.starmap(TexMobject, [
|
|
(
|
|
"1. \\,",
|
|
u_tex, "+", "(", v_tex, "+", w_tex, ")=(",
|
|
u_tex, "+", v_tex, ")+", w_tex
|
|
),
|
|
( "2. \\,",
|
|
v_tex, "+", w_tex, "=", w_tex, "+", v_tex
|
|
),
|
|
(
|
|
"3. \\,",
|
|
"\\text{There is a vector }", "\\textbf{0}",
|
|
"\\text{ such that }", "\\textbf{0}+", v_tex,
|
|
"=", v_tex, "\\text{ for all }", v_tex
|
|
),
|
|
(
|
|
"4. \\,",
|
|
"\\text{For every vector }", v_tex,
|
|
"\\text{ there is a vector }", "-", v_tex,
|
|
"\\text{ so that }", v_tex, "+", "(-", v_tex, ")=\\textbf{0}"
|
|
),
|
|
( "5. \\,",
|
|
"a", "(", "b", v_tex, ")=(", "a", "b", ")", v_tex
|
|
),
|
|
(
|
|
"6. \\,",
|
|
"1", v_tex, "=", v_tex
|
|
),
|
|
(
|
|
"7. \\,",
|
|
"a", "(", v_tex, "+", w_tex, ")", "=",
|
|
"a", v_tex, "+", "a", w_tex
|
|
),
|
|
(
|
|
"8. \\,",
|
|
"(", "a", "+", "b", ")", v_tex, "=",
|
|
"a", v_tex, "+", "b", v_tex
|
|
),
|
|
]))
|
|
tex_color_pairs = [
|
|
(v_tex, YELLOW),
|
|
(w_tex, MAROON_B),
|
|
(u_tex, PINK),
|
|
("a", BLUE),
|
|
("b", GREEN)
|
|
|
|
]
|
|
for axiom in axioms:
|
|
for tex, color in tex_color_pairs:
|
|
axiom.set_color_by_tex(tex, color)
|
|
axioms.arrange(
|
|
DOWN, buff = MED_LARGE_BUFF,
|
|
aligned_edge = LEFT
|
|
)
|
|
axioms.set_width(FRAME_WIDTH-1)
|
|
axioms.next_to(h_line, DOWN, buff = MED_SMALL_BUFF)
|
|
|
|
self.play(FadeIn(
|
|
axioms,
|
|
lag_ratio = 0.5,
|
|
run_time = 5
|
|
))
|
|
self.wait()
|
|
axioms_word = TextMobject("``Axioms''")
|
|
axioms_word.set_color(YELLOW)
|
|
axioms_word.scale(2)
|
|
axioms_word.shift(FRAME_X_RADIUS*RIGHT/2, FRAME_Y_RADIUS*DOWN/2)
|
|
self.play(Write(axioms_word, run_time = 3))
|
|
self.wait()
|
|
|
|
class AxiomsAreInterface(Scene):
|
|
def construct(self):
|
|
mathy = Mathematician().to_edge(LEFT)
|
|
mathy.change_mode("pondering")
|
|
others = [
|
|
Randolph().flip().set_color(color)
|
|
for color in (BLUE_D, GREEN_E, GOLD_E, BLUE_C)
|
|
]
|
|
others = VGroup(
|
|
VGroup(*others[:2]),
|
|
VGroup(*others[2:]),
|
|
)
|
|
for group in others:
|
|
group.arrange(RIGHT)
|
|
others.arrange(DOWN)
|
|
others.scale(0.8)
|
|
others.to_edge(RIGHT)
|
|
VGroup(mathy, others).to_edge(DOWN)
|
|
double_arrow = DoubleArrow(mathy, others)
|
|
|
|
axioms, are, rules_of_nature = words = TextMobject(
|
|
"Axioms", "are", "rules of nature"
|
|
)
|
|
words.to_edge(UP)
|
|
axioms.set_color(YELLOW)
|
|
an_interface = TextMobject("an interface")
|
|
an_interface.next_to(rules_of_nature, DOWN)
|
|
red_line = Line(
|
|
rules_of_nature.get_left(),
|
|
rules_of_nature.get_right(),
|
|
color = RED
|
|
)
|
|
|
|
self.play(Write(words))
|
|
self.wait()
|
|
self.play(ShowCreation(red_line))
|
|
self.play(Transform(
|
|
rules_of_nature.copy(),
|
|
an_interface
|
|
))
|
|
self.wait()
|
|
self.play(FadeIn(mathy))
|
|
self.play(
|
|
ShowCreation(double_arrow),
|
|
FadeIn(others, lag_ratio = 0.5, run_time = 2)
|
|
)
|
|
self.play(axioms.copy().next_to, double_arrow, UP)
|
|
self.play(Blink(mathy))
|
|
self.wait()
|
|
|
|
class VectorSpaceOfPiCreatures(Scene):
|
|
def construct(self):
|
|
creatures = self.add_creatures()
|
|
self.show_sum(creatures)
|
|
|
|
def add_creatures(self):
|
|
creatures = VGroup(*[
|
|
VGroup(*[
|
|
PiCreature()
|
|
for x in range(4)
|
|
]).arrange(RIGHT, buff = 1.5)
|
|
for y in range(4)
|
|
]).arrange(DOWN, buff = 1.5)
|
|
creatures = VGroup(*it.chain(*creatures))
|
|
creatures.set_height(FRAME_HEIGHT-1)
|
|
for pi in creatures:
|
|
pi.change_mode(random.choice([
|
|
"pondering", "pondering",
|
|
"happy", "happy", "happy",
|
|
"confused",
|
|
"angry", "erm", "sassy", "hooray",
|
|
"speaking", "tired",
|
|
"plain", "plain"
|
|
]))
|
|
if random.random() < 0.5:
|
|
pi.flip()
|
|
pi.shift(0.5*(random.random()-0.5)*RIGHT)
|
|
pi.shift(0.5*(random.random()-0.5)*UP)
|
|
pi.set_color(random.choice([
|
|
BLUE_B, BLUE_C, BLUE_D, BLUE_E,
|
|
MAROON_B, MAROON_C, MAROON_D, MAROON_E,
|
|
GREY_BROWN, GREY_BROWN, GREY,
|
|
YELLOW_C, YELLOW_D, YELLOW_E
|
|
]))
|
|
pi.scale_in_place(random.random()+0.5)
|
|
|
|
self.play(FadeIn(
|
|
creatures,
|
|
lag_ratio = 0.5,
|
|
run_time = 3
|
|
))
|
|
self.wait()
|
|
return creatures
|
|
|
|
def show_sum(self, creatures):
|
|
def is_valid(pi1, pi2, pi3):
|
|
if len(set([pi.get_color() for pi in (pi1, pi2, pi3)])) < 3:
|
|
return False
|
|
if pi1.is_flipped()^pi2.is_flipped():
|
|
return False
|
|
return True
|
|
pi1, pi2, pi3 = pis = [random.choice(creatures) for x in range(3)]
|
|
while not is_valid(pi1, pi2, pi3):
|
|
pi1, pi2, pi3 = pis = [random.choice(creatures) for x in range(3)]
|
|
creatures.remove(*pis)
|
|
|
|
transform = Transform(pi1.copy(), pi2.copy())
|
|
transform.update(0.5)
|
|
sum_pi = transform.mobject
|
|
sum_pi.set_height(pi1.get_height()+pi2.get_height())
|
|
for pi in pis:
|
|
pi.generate_target()
|
|
plus, equals = TexMobject("+=")
|
|
sum_equation = VGroup(
|
|
pi1.target, plus, pi2.target,
|
|
equals, sum_pi
|
|
)
|
|
sum_equation.arrange().center()
|
|
|
|
scaled_pi3 = pi3.copy().scale(2)
|
|
equals2 = TexMobject("=")
|
|
two = TexMobject("2 \\cdot")
|
|
scale_equation = VGroup(
|
|
two, pi3.target, equals2, scaled_pi3
|
|
)
|
|
scale_equation.arrange()
|
|
|
|
VGroup(sum_equation, scale_equation).arrange(
|
|
DOWN, buff = MED_SMALL_BUFF
|
|
)
|
|
|
|
self.play(FadeOut(creatures))
|
|
self.play(*it.chain(
|
|
list(map(MoveToTarget, [pi1, pi2, pi3])),
|
|
list(map(Write, [plus, equals, two, equals2])),
|
|
))
|
|
self.play(
|
|
Transform(pi1.copy(), sum_pi),
|
|
Transform(pi2.copy(), sum_pi),
|
|
Transform(pi3.copy(), scaled_pi3)
|
|
)
|
|
self.remove(*self.get_mobjects_from_last_animation())
|
|
self.add(sum_pi, scaled_pi3)
|
|
for pi in pi1, sum_pi, scaled_pi3, pi3:
|
|
self.play(Blink(pi))
|
|
|
|
class MathematicianDoesntHaveToThinkAboutThat(Scene):
|
|
def construct(self):
|
|
mathy = Mathematician().to_corner(DOWN+LEFT)
|
|
bubble = mathy.get_bubble(ThoughtBubble, height = 4)
|
|
words = TextMobject("I don't have to worry", "\\\\ about that madness!")
|
|
bubble.add_content(words)
|
|
new_words = TextMobject("So long as I", "\\\\ work abstractly")
|
|
bubble.add_content(new_words)
|
|
|
|
self.play(
|
|
mathy.change_mode, "hooray",
|
|
ShowCreation(bubble),
|
|
Write(words)
|
|
)
|
|
self.play(Blink(mathy))
|
|
self.wait()
|
|
self.play(
|
|
mathy.change_mode, "pondering",
|
|
Transform(words, new_words)
|
|
)
|
|
self.play(Blink(mathy))
|
|
self.wait()
|
|
|
|
class TextbooksAreAbstract(TeacherStudentsScene):
|
|
def construct(self):
|
|
self.student_says(
|
|
"""
|
|
All the textbooks I found
|
|
are pretty abstract.
|
|
""",
|
|
target_mode = "pleading"
|
|
)
|
|
self.random_blink(3)
|
|
self.teacher_says(
|
|
"""
|
|
For each new concept,
|
|
contemplate it for 2d space
|
|
with grid lines...
|
|
"""
|
|
)
|
|
self.change_student_modes("pondering")
|
|
self.random_blink(2)
|
|
self.teacher_says(
|
|
"...then in some different\\\\",
|
|
"context, like a function space"
|
|
)
|
|
self.change_student_modes(*["pondering"]*2)
|
|
self.random_blink()
|
|
self.teacher_says(
|
|
"Only then should you\\\\",
|
|
"think from the axioms",
|
|
target_mode = "surprised"
|
|
)
|
|
self.change_student_modes(*["pondering"]*3)
|
|
self.random_blink()
|
|
|
|
class LastAskWhatAreVectors(TeacherStudentsScene):
|
|
def construct(self):
|
|
self.student_says(
|
|
"So...what are vectors?",
|
|
target_mode = "erm"
|
|
)
|
|
self.random_blink()
|
|
self.teacher_says(
|
|
"""
|
|
The form they take
|
|
doesn't really matter
|
|
"""
|
|
)
|
|
self.random_blink()
|
|
|
|
class WhatIsThree(Scene):
|
|
def construct(self):
|
|
what_is, three, q_mark = words = TextMobject(
|
|
"What is ", "3", "?",
|
|
arg_separator = ""
|
|
)
|
|
words.scale(1.5)
|
|
self.play(Write(words))
|
|
self.wait()
|
|
self.play(
|
|
FadeOut(what_is),
|
|
FadeOut(q_mark),
|
|
three.center
|
|
)
|
|
|
|
triplets = [
|
|
VGroup(*[
|
|
PiCreature(color = color).scale(0.4)
|
|
for color in (BLUE_E, BLUE_C, BLUE_D)
|
|
]),
|
|
VGroup(*[HyperCube().scale(0.3) for x in range(3)]),
|
|
VGroup(*[Vector(RIGHT) for x in range(3)]),
|
|
TexMobject("""
|
|
\\Big\\{
|
|
\\emptyset,
|
|
\\{\\emptyset\\},
|
|
\\{\\{\\emptyset\\}, \\emptyset\\}
|
|
\\Big\\}
|
|
""")
|
|
]
|
|
directions = [UP+LEFT, UP+RIGHT, DOWN+LEFT, DOWN+RIGHT]
|
|
for group, vect in zip(triplets, directions):
|
|
if isinstance(group, TexMobject):
|
|
pass
|
|
elif isinstance(group[0], Vector):
|
|
group.arrange(RIGHT)
|
|
group.set_color_by_gradient(YELLOW, MAROON_B)
|
|
else:
|
|
m1, m2, m3 = group
|
|
m2.next_to(m1, buff = MED_SMALL_BUFF)
|
|
m3.next_to(VGroup(m1, m2), DOWN, buff = MED_SMALL_BUFF)
|
|
group.next_to(three, vect, buff = LARGE_BUFF)
|
|
self.play(FadeIn(group))
|
|
self.wait()
|
|
self.play(*[
|
|
Transform(
|
|
trip, three,
|
|
lag_ratio = 0.5,
|
|
run_time = 2
|
|
)
|
|
for trip in triplets
|
|
])
|
|
|
|
class IStillRecommendConcrete(TeacherStudentsScene):
|
|
def construct(self):
|
|
self.teacher_says("""
|
|
I still recommend
|
|
thinking concretely
|
|
""")
|
|
self.random_blink(2)
|
|
self.student_thinks("")
|
|
self.zoom_in_on_thought_bubble()
|
|
|
|
class AbstractionIsThePrice(Scene):
|
|
def construct(self):
|
|
words = TextMobject(
|
|
"Abstractness", "is the price\\\\"
|
|
"of", "generality"
|
|
)
|
|
words.set_color_by_tex("Abstractness", YELLOW)
|
|
words.set_color_by_tex("generality", BLUE)
|
|
self.play(Write(words))
|
|
self.wait()
|
|
|
|
class ThatsAWrap(TeacherStudentsScene):
|
|
def construct(self):
|
|
self.teacher_says("That's all for now!")
|
|
self.random_blink(2)
|
|
|
|
class GoodLuck(TeacherStudentsScene):
|
|
def construct(self):
|
|
self.teacher_says(
|
|
"Good luck with \\\\ your future learning!",
|
|
target_mode = "hooray"
|
|
)
|
|
self.change_student_modes(*["happy"]*3)
|
|
self.random_blink(3)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|