Merge pull request #264 from 3b1b/gradient

Gradient
This commit is contained in:
Grant Sanderson
2018-08-08 10:13:48 -07:00
committed by GitHub
4 changed files with 1119 additions and 8 deletions

View File

@ -72,9 +72,7 @@ class Matrix(VMobject):
or mobjects
"""
VMobject.__init__(self, **kwargs)
matrix = np.array(matrix)
if matrix.ndim == 1:
matrix = matrix.reshape((matrix.size, 1))
matrix = np.array(matrix, ndmin=1)
mob_matrix = self.matrix_to_mob_matrix(matrix)
self.organize_mob_matrix(mob_matrix)
self.elements = VGroup(*mob_matrix.flatten())
@ -89,11 +87,9 @@ class Matrix(VMobject):
self.add_background_rectangle()
def matrix_to_mob_matrix(self, matrix):
return np.vectorize(
lambda e: self.element_to_mobject(
e, **self.element_to_mobject_config
)
)(matrix)
return np.vectorize(self.element_to_mobject)(
matrix
)
def organize_mob_matrix(self, matrix):
for i, row in enumerate(matrix):

View File

@ -99,6 +99,15 @@ class SingleStringTexMobject(SVGMobject):
if num_lefts != num_rights:
tex = tex.replace("\\left", "\\big")
tex = tex.replace("\\right", "\\big")
for context in ["array"]:
begin_in = ("\\begin{%s}" % context) in tex
end_in = ("\\end{%s}" % context) in tex
if begin_in ^ end_in:
# Just turn this into a blank string,
# which means caller should leave a
# stray \\begin{...} with other symbols
tex = ""
return tex
def remove_stray_braces(self, tex):

393
old_projects/gradient.py Normal file
View File

@ -0,0 +1,393 @@
from big_ol_pile_of_manim_imports import *
class GradientDescentWrapper(Scene):
def construct(self):
title = TextMobject("Gradient descent")
title.to_edge(UP)
rect = ScreenRectangle(height=6)
rect.next_to(title, DOWN)
self.add(title)
self.play(ShowCreation(rect))
self.wait()
class ShowSimpleMultivariableFunction(Scene):
def construct(self):
scale_val = 1.5
func_tex = TexMobject(
"C(", "x_1,", "x_2,", "\\dots,", "x_n", ")", "=",
)
func_tex.scale(scale_val)
func_tex.shift(2 * LEFT)
alt_func_tex = TexMobject(
"C(", "x,", "y", ")", "="
)
alt_func_tex.scale(scale_val)
for tex in func_tex, alt_func_tex:
tex.set_color_by_tex_to_color_map({
"C(": RED,
")": RED,
})
alt_func_tex.move_to(func_tex, RIGHT)
inputs = func_tex[1:-2]
self.add(func_tex)
many_inputs = TexMobject(*[
"x_{%d}, " % d for d in range(1, 25)
])
many_inputs.scale_to_fit_width(FRAME_WIDTH)
many_inputs.to_edge(UL)
inputs_brace = Brace(inputs, UP)
inputs_brace_text = inputs_brace.get_text("Multiple inputs")
decimal = DecimalNumber(0)
decimal.scale(scale_val)
decimal.next_to(tex, RIGHT)
value_tracker = ValueTracker(0)
self.add(ContinualMovement(value_tracker, rate=0.5))
decimal_change = ContinualChangingDecimal(
decimal,
lambda a: 1 + np.sin(value_tracker.get_value())
)
self.add(decimal_change)
output_brace = Brace(decimal, DOWN)
output_brace_text = output_brace.get_text("Single output")
self.wait(2)
self.play(GrowFromCenter(inputs_brace))
self.play(Write(inputs_brace_text))
self.play(GrowFromCenter(output_brace))
self.play(Write(output_brace_text))
self.wait(3)
self.play(
ReplacementTransform(
inputs,
many_inputs[:len(inputs)]
),
LaggedStart(
FadeIn,
many_inputs[len(inputs):]
),
FadeOut(inputs_brace),
FadeOut(inputs_brace_text),
)
self.wait()
self.play(
ReplacementTransform(
func_tex[0], alt_func_tex[0]
),
Write(alt_func_tex[1:3]),
LaggedStart(FadeOutAndShiftDown, many_inputs)
)
self.wait(3)
class ShowGraphWithVectors(ExternallyAnimatedScene):
pass
class ShowFunction(Scene):
def construct(self):
func = TexMobject(
"f(x, y) = e^{-x^2 + \\cos(2y)}",
tex_to_color_map={
"x": BLUE,
"y": RED,
}
)
func.scale(1.5)
self.play(FadeInFromDown(func))
self.wait()
class ShowExampleFunctionGraph(ExternallyAnimatedScene):
pass
class ShowGradient(Scene):
def construct(self):
lhs = TexMobject(
"\\nabla f(x, y)=",
tex_to_color_map={"x": BLUE, "y": RED}
)
vector = Matrix([
["\\partial f / \\partial x"],
["\\partial f / \\partial y"],
], v_buff=1)
gradient = VGroup(lhs, vector)
gradient.arrange_submobjects(RIGHT, buff=SMALL_BUFF)
gradient.scale(1.5)
del_x, del_y = partials = vector.get_entries()
background_rects = VGroup()
for partial, color in zip(partials, [BLUE, RED]):
partial[-1].set_color(color)
partial.rect = SurroundingRectangle(
partial, buff=MED_SMALL_BUFF
)
partial.rect.set_stroke(width=0)
partial.rect.set_fill(color=color, opacity=0.5)
background_rects.add(partial.rect.copy())
background_rects.set_fill(opacity=0.1)
partials.set_fill(opacity=0)
self.play(
LaggedStart(FadeIn, gradient),
LaggedStart(
FadeIn, background_rects,
rate_func=squish_rate_func(smooth, 0.5, 1)
)
)
self.wait()
for partial in partials:
self.play(DrawBorderThenFill(partial.rect))
self.wait()
self.play(FadeOut(partial.rect))
self.wait()
for partial in partials:
self.play(Write(partial))
self.wait()
class ExampleGraphHoldXConstant(ExternallyAnimatedScene):
pass
class ExampleGraphHoldYConstant(ExternallyAnimatedScene):
pass
class TakePartialDerivatives(Scene):
def construct(self):
tex_to_color_map = {
"x": BLUE,
"y": RED,
}
func_tex = TexMobject(
"f", "(", "x", ",", "y", ")", "=",
"e^{", "-x^2", "+ \\cos(2y)}",
tex_to_color_map=tex_to_color_map
)
partial_x = TexMobject(
"{\\partial", "f", "\\over", "\\partial", "x}", "=",
"\\left(", "e^", "{-x^2", "+ \\cos(2y)}", "\\right)",
"(", "-2", "x", ")",
tex_to_color_map=tex_to_color_map,
)
partial_y = TexMobject(
"{\\partial", "f", "\\over", "\\partial", "y}", "=",
"\\left(", "e^", "{-x^2", "+ \\cos(", "2", "y)}", "\\right)",
"(", "-\\sin(", "2", "y)", "\\cdot 2", ")",
tex_to_color_map=tex_to_color_map,
)
partials = VGroup(partial_x, partial_y)
for mob in func_tex, partials:
mob.scale(1.5)
func_tex.move_to(2 * UP + 3 * LEFT)
for partial in partials:
partial.next_to(func_tex, DOWN, buff=LARGE_BUFF)
top_eq_x = func_tex.get_part_by_tex("=").get_center()[0]
low_eq_x = partial.get_part_by_tex("=").get_center()[0]
partial.shift((top_eq_x - low_eq_x) * RIGHT)
index = func_tex.index_of_part_by_tex("e^")
exp_rect = SurroundingRectangle(func_tex[index + 1:], buff=0)
exp_rect.set_stroke(width=0)
exp_rect.set_fill(GREEN, opacity=0.5)
xs = func_tex.get_parts_by_tex("x", substring=False)
ys = func_tex.get_parts_by_tex("y", substring=False)
for terms in xs, ys:
terms.rects = VGroup(*[
SurroundingRectangle(term, buff=0.5 * SMALL_BUFF)
for term in terms
])
terms.arrows = VGroup(*[
Vector(0.5 * DOWN).next_to(rect, UP, SMALL_BUFF)
for rect in terms.rects
])
treat_as_constant = TextMobject("Treat as a constant")
treat_as_constant.next_to(ys.arrows[1], UP)
# Start to show partial_x
self.play(FadeInFromDown(func_tex))
self.wait()
self.play(
ReplacementTransform(func_tex[0].copy(), partial_x[1]),
Write(partial_x[0]),
Write(partial_x[2:4]),
Write(partial_x[6]),
)
self.play(
ReplacementTransform(func_tex[2].copy(), partial_x[4])
)
self.wait()
# Label y as constant
self.play(LaggedStart(ShowCreation, ys.rects))
self.play(
LaggedStart(GrowArrow, ys.arrows, lag_ratio=0.8),
Write(treat_as_constant)
)
self.wait(2)
# Perform partial_x derivative
self.play(FadeIn(exp_rect), Animation(func_tex))
self.wait()
pxi1 = 8
pxi2 = 15
self.play(
ReplacementTransform(
func_tex[7:].copy(),
partial_x[pxi1:pxi2],
),
FadeIn(partial_x[pxi1 - 1:pxi1]),
FadeIn(partial_x[pxi2]),
)
self.wait(2)
self.play(
ReplacementTransform(
partial_x[10:12].copy(),
partial_x[pxi2 + 2:pxi2 + 4],
path_arc=-(TAU / 4)
),
FadeIn(partial_x[pxi2 + 1]),
FadeIn(partial_x[-1]),
)
self.wait(2)
# Swap out partial_x for partial_y
self.play(
FadeOutAndShiftDown(partial_x),
FadeOut(ys.rects),
FadeOut(ys.arrows),
FadeOut(treat_as_constant),
FadeOut(exp_rect),
Animation(func_tex)
)
self.play(FadeInFromDown(partial_y[:7]))
self.wait()
treat_as_constant.next_to(xs.arrows[1], UP, SMALL_BUFF)
self.play(
LaggedStart(ShowCreation, xs.rects),
LaggedStart(GrowArrow, xs.arrows),
Write(treat_as_constant),
lag_ratio=0.8
)
self.wait()
# Show same outer derivative
self.play(
ReplacementTransform(
func_tex[7:].copy(),
partial_x[pxi1:pxi2],
),
FadeIn(partial_x[pxi1 - 2:pxi1]),
FadeIn(partial_x[pxi2]),
)
self.wait()
self.play(
ReplacementTransform(
partial_y[12:16].copy(),
partial_y[pxi2 + 3:pxi2 + 7],
path_arc=-(TAU / 4)
),
FadeIn(partial_y[pxi2 + 2]),
FadeIn(partial_y[-1]),
)
self.wait()
self.play(ReplacementTransform(
partial_y[-5].copy(),
partial_y[-2],
path_arc=-PI
))
self.wait()
class ShowDerivativeAtExamplePoint(Scene):
def construct(self):
tex_to_color_map = {
"x": BLUE,
"y": RED,
}
func_tex = TexMobject(
"f", "(", "x", ",", "y", ")", "=",
"e^{", "-x^2", "+ \\cos(2y)}",
tex_to_color_map=tex_to_color_map
)
gradient_tex = TexMobject(
"\\nabla", "f", "(", "x", ",", "y", ")", "=",
tex_to_color_map=tex_to_color_map
)
partial_vect = Matrix([
["{\\partial f / \\partial x}"],
["{\\partial f / \\partial y}"],
])
partial_vect.get_mob_matrix()[0, 0][-1].set_color(BLUE)
partial_vect.get_mob_matrix()[1, 0][-1].set_color(RED)
result_vector = self.get_result_vector("x", "y")
gradient = VGroup(
gradient_tex,
partial_vect,
TexMobject("="),
result_vector
)
gradient.arrange_submobjects(RIGHT, buff=SMALL_BUFF)
func_tex.to_edge(UP)
gradient.next_to(func_tex, DOWN, buff=LARGE_BUFF)
example_lhs = TexMobject(
"\\nabla", "f", "(", "1", ",", "3", ")", "=",
tex_to_color_map={"1": BLUE, "3": RED},
)
example_result_vector = self.get_result_vector("1", "3")
example_rhs = DecimalMatrix([[-1.92], [0.54]])
example = VGroup(
example_lhs,
example_result_vector,
TexMobject("="),
example_rhs,
)
example.arrange_submobjects(RIGHT, buff=SMALL_BUFF)
example.next_to(gradient, DOWN, LARGE_BUFF)
self.add(func_tex, gradient)
self.wait()
self.play(
ReplacementTransform(gradient_tex.copy(), example_lhs),
ReplacementTransform(result_vector.copy(), example_result_vector),
)
self.wait()
self.play(Write(example[2:]))
self.wait()
def get_result_vector(self, x, y):
result_vector = Matrix([
["e^{-%s^2 + \\cos(2\\cdot %s)} (-2\\cdot %s)" % (x, y, x)],
["e^{-%s^2 + \\cos(2\\cdot %s)} \\big(-\\sin(2\\cdot %s) \\cdot 2\\big)" % (x, y, y)],
], v_buff=1.2, element_alignment_corner=ORIGIN)
x_terms = VGroup(
result_vector.get_mob_matrix()[0, 0][2],
result_vector.get_mob_matrix()[1, 0][2],
result_vector.get_mob_matrix()[0, 0][-2],
)
y_terms = VGroup(
result_vector.get_mob_matrix()[0, 0][11],
result_vector.get_mob_matrix()[1, 0][11],
result_vector.get_mob_matrix()[1, 0][-5],
)
x_terms.set_color(BLUE)
y_terms.set_color(RED)
return result_vector

713
old_projects/mvcr.py Normal file
View File

@ -0,0 +1,713 @@
from big_ol_pile_of_manim_imports import *
class HoldUpMultivariableChainRule(TeacherStudentsScene):
def construct(self):
title = TextMobject("Multivariable chain rule")
title.to_edge(UP, buff=MED_SMALL_BUFF)
screen = ScreenRectangle()
screen.next_to(title, DOWN)
morty = self.teacher
self.add(title)
self.play(
morty.change, "raise_right_hand",
FadeInFromDown(screen)
)
self.change_all_student_modes(
"confused", look_at_arg=screen
)
self.look_at(screen)
self.wait(10)
class ComputationalNetwork(MovingCameraScene):
CONFIG = {
"x_color": YELLOW,
"f_color": BLUE,
"g_color": GREEN,
"h_color": RED,
}
def construct(self):
self.draw_network()
self.walk_through_parts()
self.write_dh_dx_goal()
self.feed_forward_input()
self.compare_x_and_h_wiggling()
self.expand_out_h_as_function_of_x()
self.show_four_derivatives()
self.show_chain_rule()
self.talk_through_mvcr_parts()
self.plug_in_expressions()
self.plug_in_values()
self.discuss_meaning_of_result()
def draw_network(self):
x = TexMobject("x")
f_formula = TexMobject("f", "=", "x", "^2")
g_formula = TexMobject("g", "=", "\\cos(\\pi", "x", ")")
h_formula = TexMobject("h", "=", "f", "^2", "g")
self.tex_to_color_map = {
"x": self.x_color,
"f": self.f_color,
"g": self.g_color,
"h": self.h_color,
}
formulas = VGroup(x, f_formula, g_formula, h_formula)
formula_groups = VGroup()
for formula in formulas:
formula.box = SurroundingRectangle(formula)
formula.box.set_color(WHITE)
formula.group = VGroup(formula, formula.box)
formula.set_color_by_tex_to_color_map(
self.tex_to_color_map
)
formula_groups.add(formula.group)
f_formula.box.match_width(
g_formula.box, stretch=True, about_edge=LEFT
)
fg_group = VGroup(f_formula.group, g_formula.group)
fg_group.arrange_submobjects(DOWN, buff=LARGE_BUFF)
fg_group.to_edge(UP)
x.group.next_to(fg_group, LEFT, buff=2)
h_formula.group.next_to(fg_group, RIGHT, buff=2)
xf_line = Line(x.box.get_right(), f_formula.box.get_left())
xg_line = Line(x.box.get_right(), g_formula.box.get_left())
fh_line = Line(f_formula.box.get_right(), h_formula.box.get_left())
gh_line = Line(g_formula.box.get_right(), h_formula.box.get_left())
graph_edges = VGroup(
xf_line, xg_line, fh_line, gh_line
)
self.play(
Write(x),
FadeIn(x.box),
)
self.play(
ShowCreation(xf_line),
ShowCreation(xg_line),
ReplacementTransform(x.box.copy(), f_formula.box),
ReplacementTransform(x.box.copy(), g_formula.box),
)
self.play(
Write(f_formula),
Write(g_formula),
)
self.play(
ShowCreation(fh_line),
ShowCreation(gh_line),
ReplacementTransform(f_formula.box.copy(), h_formula.box),
ReplacementTransform(g_formula.box.copy(), h_formula.box),
)
self.play(Write(h_formula))
self.wait()
network = VGroup(formula_groups, graph_edges)
self.set_variables_as_attrs(
x, f_formula, g_formula, h_formula,
xf_line, xg_line, fh_line, gh_line,
formulas, formula_groups,
graph_edges, network
)
def walk_through_parts(self):
x = self.x
f_formula = self.f_formula
g_formula = self.g_formula
h_formula = self.h_formula
def indicate(mob):
return ShowCreationThenDestructionAround(
mob,
surrounding_rectangle_config={
"buff": 0.5 * SMALL_BUFF,
"color": mob.get_color()
}
)
for formula in f_formula, g_formula:
self.play(indicate(formula[0]))
self.play(ReplacementTransform(
x.copy(),
formula.get_parts_by_tex("x"),
path_arc=PI / 3
))
self.wait()
self.play(indicate(h_formula[0]))
self.play(ReplacementTransform(
f_formula[0].copy(),
h_formula.get_part_by_tex("f"),
path_arc=PI / 3
))
self.play(ReplacementTransform(
g_formula[0].copy(),
h_formula.get_part_by_tex("g"),
path_arc=PI / 3
))
self.wait()
def write_dh_dx_goal(self):
deriv = TexMobject(
"{dh", "\\over", "dx}", "(", "2", ")"
)
deriv.set_color_by_tex_to_color_map(
self.tex_to_color_map
)
deriv.scale(1.5)
deriv.move_to(DOWN)
self.play(FadeInFromDown(deriv[:3]))
self.play(ShowCreationThenDestructionAround(deriv[:3]))
self.wait(2)
self.play(Write(deriv[3:]))
self.wait()
self.dh_dx_at_two = deriv
def feed_forward_input(self):
formula_groups = self.formula_groups
x, f_formula, g_formula, h_formula = self.formulas
dh_dx_at_two = self.dh_dx_at_two
values = [2, 4, 1, 16]
value_labels = VGroup()
for formula_group, value in zip(formula_groups, values):
label = TexMobject("=", str(value))
eq, value_mob = label
eq.rotate(90 * DEGREES)
eq.next_to(value_mob, UP, SMALL_BUFF)
var = formula_group[0][0]
label[1].match_color(var)
# label.next_to(formula_group, DOWN, SMALL_BUFF)
label.next_to(var, DOWN, SMALL_BUFF)
eq.add_background_rectangle(buff=SMALL_BUFF, opacity=1)
value_labels.add(label)
x_val_label, f_val_label, g_val_label, h_val_label = value_labels
two, four, one, sixteen = [vl[1] for vl in value_labels]
self.play(
ReplacementTransform(
dh_dx_at_two.get_part_by_tex("2").copy(),
two,
),
Write(x_val_label[0])
)
self.wait()
two_copy1 = two.copy()
two_copy2 = two.copy()
four_copy = four.copy()
one_copy = one.copy()
x_in_f = f_formula.get_part_by_tex("x")
x_in_g = g_formula.get_part_by_tex("x")
f_in_h = h_formula.get_part_by_tex("f")
g_in_h = h_formula.get_part_by_tex("g")
self.play(
two_copy1.move_to, x_in_f, DOWN,
x_in_f.set_fill, {"opacity": 0},
)
self.wait()
self.play(Write(f_val_label))
self.wait()
self.play(
two_copy2.move_to, x_in_g, DOWN,
x_in_g.set_fill, {"opacity": 0},
)
self.wait()
self.play(Write(g_val_label))
self.wait()
self.play(
four_copy.move_to, f_in_h, DOWN,
f_in_h.set_fill, {"opacity": 0},
)
self.play(
one_copy.move_to, g_in_h, DOWN,
g_in_h.set_fill, {"opacity": 0},
)
self.wait()
self.play(Write(h_val_label))
self.wait()
self.value_labels = value_labels
self.revert_to_formula_animations = [
ApplyMethod(term.set_fill, {"opacity": 1})
for term in x_in_f, x_in_g, f_in_h, g_in_h
] + [
FadeOut(term)
for term in two_copy1, two_copy2, four_copy, one_copy
]
def compare_x_and_h_wiggling(self):
x_val = self.value_labels[0][1]
h_val = self.value_labels[3][1]
x_line = NumberLine(
x_min=0,
x_max=4,
include_numbers=True,
numbers_to_show=[0, 2, 4],
unit_size=0.75,
)
x_line.next_to(
x_val, DOWN, LARGE_BUFF,
aligned_edge=RIGHT
)
h_line = NumberLine(
x_min=0,
x_max=32,
include_numbers=True,
numbers_with_elongated_ticks=[0, 16, 32],
numbers_to_show=[0, 16, 32],
tick_frequency=1,
tick_size=0.05,
unit_size=1.0 / 12,
)
h_line.next_to(
h_val, DOWN, LARGE_BUFF,
aligned_edge=LEFT
)
x_dot = Dot(color=self.x_color)
x_dot.move_to(x_line.number_to_point(2))
x_arrow = Arrow(self.x.get_bottom(), x_dot.get_top())
x_arrow.match_color(x_dot)
h_dot = Dot(color=self.h_color)
h_dot.move_to(h_line.number_to_point(16))
h_arrow = Arrow(self.h_formula[0].get_bottom(), h_dot.get_top())
h_arrow.match_color(h_dot)
self.play(
ShowCreation(x_line),
ShowCreation(h_line),
)
self.play(
GrowArrow(x_arrow),
GrowArrow(h_arrow),
ReplacementTransform(x_val.copy(), x_dot),
ReplacementTransform(h_val.copy(), h_dot),
)
self.wait()
for x in range(2):
self.play(
x_dot.shift, 0.25 * RIGHT,
h_dot.shift, 0.35 * RIGHT,
rate_func=wiggle,
run_time=1,
)
self.set_variables_as_attrs(
x_line, h_line,
x_dot, h_dot,
x_arrow, h_arrow,
)
def expand_out_h_as_function_of_x(self):
self.play(*self.revert_to_formula_animations)
deriv = self.dh_dx_at_two
expanded_formula = TexMobject(
"h = x^4 \\cos(\\pi x)",
tex_to_color_map=self.tex_to_color_map
)
expanded_formula.move_to(deriv)
cross = Cross(expanded_formula)
self.play(
FadeInFromDown(expanded_formula),
deriv.scale, 1.0 / 1.5,
deriv.shift, DOWN,
)
self.wait()
self.play(ShowCreation(cross))
self.wait()
self.play(
FadeOut(VGroup(expanded_formula, cross)),
deriv.shift, UP,
)
for edge in self.graph_edges:
self.play(ShowCreationThenDestruction(
edge.copy().set_stroke(YELLOW, 6)
))
def show_four_derivatives(self):
lines = self.graph_edges
xf_line, xg_line, fh_line, gh_line = lines
df_dx = TexMobject("df", "\\over", "dx")
dg_dx = TexMobject("dg", "\\over", "dx")
dh_df = TexMobject("\\partial h", "\\over", "\\partial f")
dh_dg = TexMobject("\\partial h", "\\over", "\\partial g")
derivatives = VGroup(df_dx, dg_dx, dh_df, dh_dg)
df_dx.next_to(xf_line.get_center(), UP, SMALL_BUFF)
dg_dx.next_to(xg_line.get_center(), DOWN, SMALL_BUFF)
dh_df.next_to(fh_line.get_center(), UP, SMALL_BUFF)
dh_dg.next_to(gh_line.get_center(), DOWN, SMALL_BUFF)
partial_terms = VGroup(
dh_df[0][0],
dh_df[2][0],
dh_dg[0][0],
dh_dg[2][0],
)
partial_term_rects = VGroup(*[
SurroundingRectangle(pt, buff=0.05)
for pt in partial_terms
])
partial_term_rects.set_stroke(width=0)
partial_term_rects.set_fill(TEAL, 0.5)
self.play(FadeOut(self.value_labels))
for derivative in derivatives:
derivative.set_color_by_tex_to_color_map(self.tex_to_color_map)
derivative.add_to_back(derivative.copy().set_stroke(BLACK, 5))
self.play(FadeInFromDown(derivative))
self.wait()
self.play(
LaggedStart(FadeIn, partial_term_rects),
Animation(derivatives)
)
self.wait()
self.play(
LaggedStart(FadeOut, partial_term_rects),
Animation(derivatives)
)
self.derivatives = derivatives
def show_chain_rule(self):
dh_dx_at_two = self.dh_dx_at_two
dh_dx = dh_dx_at_two[:3]
at_two = dh_dx_at_two[3:]
derivatives = self.derivatives.copy()
df_dx, dg_dx, dh_df, dh_dg = derivatives
frame = self.camera_frame
self.play(
frame.shift, 3 * UP,
dh_dx.to_edge, UP,
dh_dx.shift, 3 * LEFT + 3 * UP,
at_two.set_fill, {"opacity": 0},
)
for deriv in derivatives:
deriv.generate_target()
rhs = VGroup(
TexMobject("="),
df_dx.target, dh_df.target,
TexMobject("+"),
dg_dx.target, dh_dg.target
)
rhs.arrange_submobjects(
RIGHT,
buff=2 * SMALL_BUFF,
)
rhs.next_to(dh_dx, RIGHT)
for deriv in derivatives:
y = rhs[0].get_center()[1]
alt_y = deriv.target[2].get_center()[1]
deriv.target.shift((y - alt_y) * UP)
self.play(
Write(rhs[::3]),
LaggedStart(MoveToTarget, derivatives)
)
self.wait()
self.chain_rule_derivatives = derivatives
self.chain_rule_rhs = rhs
def talk_through_mvcr_parts(self):
derivatives = self.derivatives
cr_derivatives = self.chain_rule_derivatives
df_dx, dg_dx, dh_df, dh_dg = cr_derivatives
df, dx1 = df_dx[1::2]
dg, dx2 = dg_dx[1::2]
del_h1, del_f = dh_df[1::2]
del_h2, del_g = dh_dg[1::2]
terms = VGroup(df, dx1, dg, dx2, del_h1, del_f, del_h2, del_g)
for term in terms:
term.rect = SurroundingRectangle(
term,
buff=0.5 * SMALL_BUFF,
stroke_width=0,
fill_color=TEAL,
fill_opacity=0.5
)
for derivative in derivatives:
derivative.rect = SurroundingRectangle(
derivative,
color=TEAL
)
del_h_sub_f = TexMobject("f")
del_h_sub_f.scale(0.5)
del_h_sub_f.next_to(del_h1.get_corner(DR), RIGHT, buff=0)
del_h_sub_f.set_color(self.f_color)
lines = self.graph_edges
top_lines = lines[::2].copy()
bottom_lines = lines[1::2].copy()
for group in top_lines, bottom_lines:
group.set_stroke(YELLOW, 6)
self.add_foreground_mobjects(cr_derivatives)
rect = dx1.rect.copy()
rect.save_state()
rect.scale(3)
rect.set_fill(opacity=0)
self.play(
rect.restore,
FadeIn(derivatives[0].rect)
)
self.wait()
self.play(Transform(rect, df.rect))
self.wait()
self.play(
rect.replace, df_dx, {"stretch": True},
rect.scale, 1.1,
)
self.wait()
self.play(
Transform(rect, del_f.rect),
FadeOut(derivatives[0].rect),
FadeIn(derivatives[2].rect),
)
self.wait()
self.play(Transform(rect, del_h1.rect))
self.wait()
self.play(ReplacementTransform(
del_f[1].copy(), del_h_sub_f,
path_arc=PI,
))
self.wait()
self.play(
del_h_sub_f.shift, UR,
del_h_sub_f.fade, 1,
rate_func=running_start,
remover=True
)
self.wait()
self.play(
Transform(rect, del_f.rect),
ReplacementTransform(rect.copy(), df.rect),
)
self.wait()
for x in range(3):
self.play(ShowCreationThenDestruction(
top_lines,
submobject_mode="one_at_a_time"
))
self.wait()
self.play(
rect.replace, cr_derivatives[1::2], {"stretch": True},
rect.scale, 1.1,
FadeOut(df.rect),
FadeOut(derivatives[2].rect),
FadeIn(derivatives[1].rect),
FadeIn(derivatives[3].rect),
)
self.wait()
self.play(
Transform(rect, dg.rect),
FadeOut(derivatives[3].rect)
)
self.wait()
self.play(Transform(rect, dx2.rect))
self.wait()
self.play(
Transform(rect, del_h2.rect),
FadeOut(derivatives[1].rect),
FadeIn(derivatives[3].rect),
)
self.wait()
self.play(Transform(rect, del_g.rect))
self.wait()
self.play(
rect.replace, cr_derivatives, {"stretch": True},
rect.scale, 1.1,
FadeOut(derivatives[3].rect)
)
for x in range(3):
self.play(*[
ShowCreationThenDestruction(
group,
submobject_mode="one_at_a_time"
)
for group in top_lines, bottom_lines
])
self.wait()
self.play(FadeOut(rect))
self.remove_foreground_mobject(cr_derivatives)
def plug_in_expressions(self):
lhs = VGroup(
self.dh_dx_at_two[:3],
self.chain_rule_rhs[::3],
self.chain_rule_derivatives,
)
lhs.generate_target()
lhs.target.to_edge(LEFT)
df_dx, dg_dx, dh_df, dh_dg = self.chain_rule_derivatives
formulas = self.formulas
x, f_formula, g_formula, h_formula = formulas
full_derivative = TexMobject(
"=",
"(", "2", "x", ")",
"(", "2", "f", "g", ")",
"+",
"(", "-\\sin(", "\\pi", "x", ")", "\\pi", ")",
"(", "f", "^2", ")"
)
full_derivative.next_to(lhs.target, RIGHT)
full_derivative.set_color_by_tex_to_color_map(
self.tex_to_color_map
)
self.play(MoveToTarget(lhs))
self.play(Write(full_derivative[0]))
# df/dx
self.play(
f_formula.shift, UP,
df_dx.shift, 0.5 * DOWN
)
self.play(
ReplacementTransform(
f_formula[2:].copy(),
full_derivative[2:4],
),
FadeIn(full_derivative[1:5:3])
)
self.wait()
self.play(
f_formula.shift, DOWN,
df_dx.shift, 0.5 * UP
)
self.wait()
# dg/dx
self.play(
g_formula.shift, 0.75 * UP,
dg_dx.shift, 0.5 * DOWN
)
self.play(
ReplacementTransform(
g_formula[2:].copy(),
full_derivative[12:17],
),
FadeIn(full_derivative[11:18:6]),
Write(full_derivative[10]),
)
self.wait()
self.play(
g_formula.shift, 0.75 * DOWN,
dg_dx.shift, 0.5 * UP
)
self.wait()
# dh/df
self.play(
h_formula.shift, UP,
dh_df.shift, 0.5 * DOWN
)
self.wait()
self.play(
ReplacementTransform(
h_formula[2:].copy(),
full_derivative[6:9],
),
FadeIn(full_derivative[5:10:4])
)
self.wait()
self.play(
dh_df.shift, 0.5 * UP
)
# dh/dg
self.play(
dh_dg.shift, 0.5 * DOWN,
)
self.wait()
self.play(
ReplacementTransform(
h_formula[2:].copy(),
full_derivative[19:21],
),
FadeIn(full_derivative[18:22:3])
)
self.wait()
self.play(
h_formula.shift, DOWN,
dh_dg.shift, 0.5 * UP
)
self.wait()
self.full_derivative = full_derivative
def plug_in_values(self):
full_derivative = self.full_derivative
value_labels = self.value_labels
rhs = TexMobject(
"""
=
(2 \\cdot 2)
(2 \\cdot 4 \\cdot 1) +
(-\\sin(\\pi 2)\\pi)(4^2)
""",
tex_to_color_map={
"2": self.x_color,
"4": self.f_color,
"1": self.g_color,
"^2": WHITE,
}
)
rhs.next_to(full_derivative, DOWN, aligned_edge=LEFT)
result = TexMobject("=", "32", "+", "0")
result.next_to(rhs, DOWN, aligned_edge=LEFT)
self.play(LaggedStart(Write, value_labels))
self.wait()
self.play(ReplacementTransform(
full_derivative.copy(), rhs,
submobject_mode="lagged_start",
run_time=2
))
self.wait()
self.play(Write(result))
self.wait()
def discuss_meaning_of_result(self):
x_dot = self.x_dot
h_dot = self.h_dot
for x in range(3):
self.play(
x_dot.shift, 0.25 * RIGHT,
h_dot.shift, RIGHT,
run_time=2,
rate_func=lambda t: wiggle(t, 4)
)
self.wait()