2018-03-20 12:58:17 -07:00
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
2018-03-06 18:26:07 -08:00
|
|
|
from helpers import *
|
|
|
|
|
|
|
|
from mobject.tex_mobject import TexMobject
|
|
|
|
from mobject import Mobject
|
|
|
|
from mobject.image_mobject import ImageMobject
|
|
|
|
from mobject.vectorized_mobject import *
|
|
|
|
|
|
|
|
from animation.animation import Animation
|
|
|
|
from animation.transform import *
|
|
|
|
from animation.simple_animations import *
|
2018-03-08 13:55:01 -08:00
|
|
|
from animation.compositions import *
|
2018-03-06 18:26:07 -08:00
|
|
|
from animation.playground import *
|
|
|
|
from animation.continual_animation import *
|
|
|
|
from topics.geometry import *
|
|
|
|
from topics.characters import *
|
|
|
|
from topics.functions import *
|
|
|
|
from topics.fractals import *
|
|
|
|
from topics.number_line import *
|
|
|
|
from topics.combinatorics import *
|
|
|
|
from topics.numerals import *
|
|
|
|
from topics.three_dimensions import *
|
|
|
|
from topics.objects import *
|
|
|
|
from topics.probability import *
|
|
|
|
from topics.complex_numbers import *
|
|
|
|
from scene import Scene
|
|
|
|
from scene.reconfigurable_scene import ReconfigurableScene
|
|
|
|
from scene.zoomed_scene import *
|
2018-03-09 17:22:55 -08:00
|
|
|
from scene.moving_camera_scene import *
|
2018-03-06 18:26:07 -08:00
|
|
|
from camera import *
|
|
|
|
from mobject.svg_mobject import *
|
|
|
|
from mobject.tex_mobject import *
|
|
|
|
from topics.graph_scene import *
|
|
|
|
|
2018-03-20 13:44:51 -07:00
|
|
|
from old_projects.uncertainty import Flash
|
2018-03-06 18:26:07 -08:00
|
|
|
from active_projects.WindingNumber import *
|
|
|
|
|
2018-03-08 13:55:01 -08:00
|
|
|
class AltTeacherStudentsScene(TeacherStudentsScene):
|
2018-03-06 18:26:07 -08:00
|
|
|
def setup(self):
|
|
|
|
TeacherStudentsScene.setup(self)
|
|
|
|
self.teacher.set_color(YELLOW_E)
|
|
|
|
|
|
|
|
###############
|
|
|
|
|
|
|
|
|
2018-03-08 13:55:01 -08:00
|
|
|
class IntroSceneWrapper(PiCreatureScene):
|
2018-03-06 18:26:07 -08:00
|
|
|
CONFIG = {
|
2018-03-08 13:55:01 -08:00
|
|
|
"default_pi_creature_kwargs" : {
|
|
|
|
"color" : YELLOW_E,
|
|
|
|
"flip_at_start" : False,
|
|
|
|
"height" : 2,
|
|
|
|
},
|
|
|
|
"default_pi_creature_start_corner" : DOWN+LEFT,
|
2018-03-06 18:26:07 -08:00
|
|
|
}
|
|
|
|
def construct(self):
|
2018-03-08 19:40:49 -08:00
|
|
|
self.introduce_two_words()
|
|
|
|
self.describe_main_topic()
|
|
|
|
self.describe_meta_topic()
|
|
|
|
|
|
|
|
def introduce_two_words(self):
|
2018-03-08 13:55:01 -08:00
|
|
|
morty = self.pi_creature
|
|
|
|
rect = ScreenRectangle(height = 5)
|
|
|
|
rect.to_corner(UP+RIGHT)
|
|
|
|
self.add(rect)
|
|
|
|
|
2018-03-08 19:40:49 -08:00
|
|
|
h_line = Line(LEFT, RIGHT).scale(2)
|
|
|
|
h_line.to_corner(UP+LEFT)
|
|
|
|
h_line.shift(0.5*DOWN)
|
|
|
|
|
|
|
|
main_topic, meta_topic = topics = VGroup(
|
2018-03-08 13:55:01 -08:00
|
|
|
TextMobject("Main topic"),
|
|
|
|
TextMobject("Meta topic"),
|
|
|
|
)
|
2018-03-08 19:40:49 -08:00
|
|
|
topics.next_to(morty, UP)
|
|
|
|
topics.shift_onto_screen()
|
|
|
|
|
|
|
|
self.play(
|
|
|
|
morty.change, "raise_left_hand",
|
|
|
|
FadeInFromDown(main_topic)
|
|
|
|
)
|
|
|
|
self.wait()
|
|
|
|
self.play(
|
|
|
|
morty.change, "raise_right_hand",
|
|
|
|
main_topic.next_to, meta_topic.get_top(), UP, MED_SMALL_BUFF,
|
|
|
|
FadeInFromDown(meta_topic)
|
|
|
|
)
|
|
|
|
self.wait()
|
|
|
|
self.play(
|
|
|
|
morty.change, "happy",
|
|
|
|
main_topic.next_to, h_line, UP,
|
|
|
|
meta_topic.set_fill, {"opacity" : 0.2},
|
|
|
|
)
|
|
|
|
self.play(ShowCreation(h_line))
|
|
|
|
self.wait()
|
|
|
|
|
|
|
|
self.set_variables_as_attrs(h_line, main_topic, meta_topic)
|
|
|
|
|
|
|
|
def describe_main_topic(self):
|
|
|
|
h_line = self.h_line
|
|
|
|
morty = self.pi_creature
|
|
|
|
main_topic = self.main_topic
|
|
|
|
meta_topic = self.meta_topic
|
|
|
|
|
|
|
|
solver = TextMobject("2d equation solver")
|
|
|
|
solver.match_width(h_line)
|
|
|
|
solver.next_to(h_line, DOWN)
|
|
|
|
rainbow_solver1 = solver.copy()
|
|
|
|
rainbow_solver2 = solver.copy()
|
|
|
|
colors = ["RED", "ORANGE", "YELLOW", "GREEN", BLUE, "PURPLE", PINK]
|
|
|
|
rainbow_solver1.gradient_highlight(*colors)
|
|
|
|
rainbow_solver2.gradient_highlight(*reversed(colors))
|
|
|
|
|
|
|
|
|
2018-03-11 15:42:25 -07:00
|
|
|
xy_equation = TexMobject("""
|
|
|
|
\\left[\\begin{array}{c}
|
|
|
|
ye^x \\\\
|
|
|
|
\\sin(|xy|)
|
|
|
|
\\end{array}\\right] =
|
|
|
|
\\left[\\begin{array}{c}
|
|
|
|
y^2 \\\\
|
|
|
|
3y
|
|
|
|
\\end{array}\\right]
|
|
|
|
""")
|
|
|
|
# xy_equation.highlight_by_tex_to_color_map({
|
|
|
|
# "x" : BLUE,
|
|
|
|
# "y" : YELLOW
|
|
|
|
# })
|
|
|
|
xy_equation.scale(0.8)
|
2018-03-08 19:40:49 -08:00
|
|
|
xy_equation.next_to(solver, DOWN, MED_LARGE_BUFF)
|
|
|
|
|
|
|
|
z_equation = TexMobject("z", "^5", "+", "z", "+", "1", "=", "0")
|
|
|
|
z_equation.highlight_by_tex("z", GREEN)
|
|
|
|
z_equation.move_to(xy_equation, UP)
|
2018-03-08 13:55:01 -08:00
|
|
|
|
2018-03-08 19:40:49 -08:00
|
|
|
zeta = TexMobject("\\zeta(s) = 0")
|
|
|
|
zeta[2].highlight(GREEN)
|
|
|
|
zeta.next_to(z_equation, DOWN, MED_LARGE_BUFF)
|
|
|
|
|
|
|
|
self.play(Write(solver))
|
|
|
|
self.play(
|
|
|
|
LaggedStart(FadeIn, xy_equation, run_time = 1),
|
|
|
|
morty.change, "pondering"
|
|
|
|
)
|
|
|
|
self.wait(2)
|
|
|
|
self.play(
|
|
|
|
FadeOut(xy_equation),
|
|
|
|
FadeIn(z_equation)
|
|
|
|
)
|
|
|
|
self.wait()
|
|
|
|
self.play(Write(zeta))
|
|
|
|
self.wait()
|
|
|
|
solver.save_state()
|
|
|
|
for rainbow_solver in rainbow_solver1, rainbow_solver2:
|
|
|
|
self.play(Transform(
|
|
|
|
solver, rainbow_solver,
|
|
|
|
run_time = 2,
|
|
|
|
submobject_mode = "lagged_start"
|
|
|
|
))
|
|
|
|
self.play(solver.restore)
|
|
|
|
self.wait()
|
2018-03-08 13:55:01 -08:00
|
|
|
|
2018-03-08 19:40:49 -08:00
|
|
|
self.play(LaggedStart(
|
|
|
|
FadeOut, VGroup(solver, z_equation, zeta)
|
|
|
|
))
|
|
|
|
self.play(
|
|
|
|
main_topic.move_to, meta_topic,
|
|
|
|
main_topic.set_fill, {"opacity" : 0.2},
|
|
|
|
meta_topic.move_to, main_topic,
|
|
|
|
meta_topic.set_fill, {"opacity" : 1},
|
|
|
|
morty.change, "hesitant",
|
|
|
|
path_arc = TAU/8,
|
|
|
|
)
|
2018-03-06 18:26:07 -08:00
|
|
|
|
2018-03-08 19:40:49 -08:00
|
|
|
def describe_meta_topic(self):
|
|
|
|
h_line = self.h_line
|
|
|
|
morty = self.pi_creature
|
2018-03-06 18:26:07 -08:00
|
|
|
|
2018-03-08 19:40:49 -08:00
|
|
|
words = TextMobject("Seek constructs which \\\\ compose nicely")
|
|
|
|
words.scale(0.7)
|
|
|
|
words.next_to(h_line, DOWN)
|
2018-03-06 18:26:07 -08:00
|
|
|
|
2018-03-08 19:40:49 -08:00
|
|
|
self.play(Write(words))
|
|
|
|
self.play(morty.change, "happy")
|
|
|
|
self.wait(3)
|
2018-03-08 13:55:01 -08:00
|
|
|
|
2018-03-09 17:22:55 -08:00
|
|
|
class Introduce1DFunctionCase(Scene):
|
|
|
|
CONFIG = {
|
|
|
|
"search_range_rect_height" : 0.15,
|
|
|
|
"arrow_opacity" : 1,
|
|
|
|
"show_dotted_line_to_f" : True,
|
|
|
|
"arrow_config": {
|
|
|
|
"max_stem_width_to_tip_width_ratio" : 0.5,
|
|
|
|
"max_tip_length_to_length_ratio" : 0.5,
|
|
|
|
},
|
2018-03-12 14:02:08 -07:00
|
|
|
"show_midpoint_value" : True,
|
2018-03-09 17:22:55 -08:00
|
|
|
}
|
|
|
|
def construct(self):
|
|
|
|
self.show_axes_one_at_a_time()
|
|
|
|
self.show_two_graphs()
|
|
|
|
self.transition_to_sqrt_2_case()
|
|
|
|
self.show_example_binary_search()
|
|
|
|
|
|
|
|
def show_axes_one_at_a_time(self):
|
|
|
|
axes = Axes(
|
|
|
|
x_min = -1, x_max = 3.2,
|
|
|
|
x_axis_config = {
|
|
|
|
"unit_size" : 3,
|
|
|
|
"tick_frequency" : 0.25,
|
|
|
|
"numbers_with_elongated_ticks" : range(-1, 4)
|
|
|
|
},
|
|
|
|
y_min = -2, y_max = 4.5,
|
|
|
|
)
|
|
|
|
axes.to_corner(DOWN+LEFT)
|
|
|
|
axes.x_axis.add_numbers(*range(-1, 4))
|
|
|
|
axes.y_axis.label_direction = LEFT
|
|
|
|
axes.y_axis.add_numbers(-1, *range(1, 5))
|
|
|
|
|
|
|
|
inputs = TextMobject("Inputs")
|
|
|
|
inputs.next_to(axes.x_axis, UP, aligned_edge = RIGHT)
|
|
|
|
|
|
|
|
outputs = TextMobject("Outputs")
|
|
|
|
outputs.next_to(axes.y_axis, UP, SMALL_BUFF)
|
|
|
|
|
|
|
|
self.play(
|
|
|
|
ShowCreation(axes.x_axis),
|
|
|
|
Write(inputs)
|
|
|
|
)
|
|
|
|
self.wait()
|
|
|
|
self.play(
|
|
|
|
ShowCreation(axes.y_axis),
|
|
|
|
FadeOut(axes.x_axis.numbers[1], rate_func = squish_rate_func(smooth, 0, 0.2)),
|
|
|
|
Write(outputs)
|
|
|
|
)
|
|
|
|
self.wait()
|
|
|
|
|
|
|
|
self.axes = axes
|
|
|
|
self.inputs_label = inputs
|
|
|
|
self.outputs_label = outputs
|
|
|
|
|
|
|
|
def show_two_graphs(self):
|
|
|
|
axes = self.axes
|
|
|
|
f_graph = axes.get_graph(
|
|
|
|
lambda x : 2*x*(x - 0.75)*(x - 1.5) + 1,
|
|
|
|
color = BLUE
|
|
|
|
)
|
|
|
|
g_graph = axes.get_graph(
|
|
|
|
lambda x : 1.8*np.cos(TAU*x/2),
|
|
|
|
color = YELLOW
|
|
|
|
)
|
|
|
|
|
|
|
|
label_x_corod = 2
|
|
|
|
f_label = TexMobject("f(x)")
|
|
|
|
f_label.match_color(f_graph)
|
|
|
|
f_label.next_to(axes.input_to_graph_point(label_x_corod, f_graph), LEFT)
|
|
|
|
|
|
|
|
g_label = TexMobject("g(x)")
|
|
|
|
g_label.match_color(g_graph)
|
|
|
|
g_label.next_to(
|
|
|
|
axes.input_to_graph_point(label_x_corod, g_graph), UP, SMALL_BUFF
|
|
|
|
)
|
|
|
|
|
|
|
|
solution = 0.24
|
|
|
|
cross_point = axes.input_to_graph_point(solution, f_graph)
|
|
|
|
l_v_line, r_v_line, v_line = [
|
|
|
|
DashedLine(
|
|
|
|
axes.coords_to_point(x, 0),
|
|
|
|
axes.coords_to_point(x, f_graph.underlying_function(solution)),
|
|
|
|
)
|
|
|
|
for x in axes.x_min, axes.x_max, solution
|
|
|
|
]
|
|
|
|
|
|
|
|
equation = TexMobject("f(x)", "=", "g(x)")
|
|
|
|
equation[0].match_color(f_label)
|
|
|
|
equation[2].match_color(g_label)
|
|
|
|
equation.next_to(cross_point, UP, buff = 1.5, aligned_edge = LEFT)
|
|
|
|
equation_arrow = Arrow(
|
|
|
|
equation.get_bottom(), cross_point,
|
|
|
|
buff = SMALL_BUFF,
|
|
|
|
color = WHITE
|
|
|
|
)
|
|
|
|
equation.target = TexMobject("x^2", "=", "2")
|
|
|
|
equation.target.match_style(equation)
|
|
|
|
equation.target.to_edge(UP)
|
|
|
|
|
|
|
|
for graph, label in (f_graph, f_label), (g_graph, g_label):
|
|
|
|
self.play(
|
|
|
|
ShowCreation(graph),
|
|
|
|
Write(label, rate_func = squish_rate_func(smooth, 0.5, 1)),
|
|
|
|
run_time = 2
|
|
|
|
)
|
|
|
|
self.wait()
|
|
|
|
self.play(
|
|
|
|
ReplacementTransform(r_v_line.copy().fade(1), v_line),
|
|
|
|
ReplacementTransform(l_v_line.copy().fade(1), v_line),
|
|
|
|
run_time = 2
|
|
|
|
)
|
|
|
|
self.play(
|
|
|
|
ReplacementTransform(f_label.copy(), equation[0]),
|
|
|
|
ReplacementTransform(g_label.copy(), equation[2]),
|
|
|
|
Write(equation[1]),
|
|
|
|
GrowArrow(equation_arrow),
|
|
|
|
)
|
|
|
|
for x in range(4):
|
|
|
|
self.play(
|
|
|
|
FadeOut(v_line.copy()),
|
|
|
|
ShowCreation(v_line, rate_func = squish_rate_func(smooth, 0.5, 1)),
|
|
|
|
run_time = 1.5
|
|
|
|
)
|
|
|
|
self.wait()
|
|
|
|
self.play(
|
|
|
|
MoveToTarget(equation, replace_mobject_with_target_in_scene = True),
|
|
|
|
*map(FadeOut, [equation_arrow, v_line])
|
|
|
|
)
|
|
|
|
|
|
|
|
self.set_variables_as_attrs(
|
|
|
|
f_graph, f_label, g_graph, g_label,
|
|
|
|
equation = equation.target
|
|
|
|
)
|
|
|
|
|
|
|
|
def transition_to_sqrt_2_case(self):
|
|
|
|
f_graph = self.f_graph
|
|
|
|
f_label = VGroup(self.f_label)
|
|
|
|
g_graph = self.g_graph
|
|
|
|
g_label = VGroup(self.g_label)
|
|
|
|
axes = self.axes
|
|
|
|
for label in f_label, g_label:
|
|
|
|
for x in range(2):
|
|
|
|
label.add(VectorizedPoint(label.get_center()))
|
|
|
|
for number in axes.y_axis.numbers:
|
|
|
|
number.add_background_rectangle()
|
|
|
|
|
|
|
|
squared_graph = axes.get_graph(lambda x : x**2)
|
|
|
|
squared_graph.match_style(f_graph)
|
|
|
|
two_graph = axes.get_graph(lambda x : 2)
|
|
|
|
two_graph.match_style(g_graph)
|
|
|
|
|
|
|
|
squared_label = TexMobject("f(x)", "=", "x^2")
|
|
|
|
squared_label.next_to(
|
|
|
|
axes.input_to_graph_point(2, squared_graph), RIGHT
|
|
|
|
)
|
|
|
|
squared_label.match_color(squared_graph)
|
|
|
|
two_label = TexMobject("g(x)", "=", "2")
|
|
|
|
two_label.next_to(
|
|
|
|
axes.input_to_graph_point(3, two_graph), UP,
|
|
|
|
)
|
|
|
|
two_label.match_color(two_graph)
|
|
|
|
|
|
|
|
find_sqrt_2 = self.find_sqrt_2 = TextMobject("(Find $\\sqrt{2}$)")
|
|
|
|
find_sqrt_2.next_to(self.equation, DOWN)
|
|
|
|
|
|
|
|
self.play(
|
|
|
|
ReplacementTransform(f_graph, squared_graph),
|
|
|
|
ReplacementTransform(f_label, squared_label),
|
|
|
|
)
|
|
|
|
self.play(
|
|
|
|
ReplacementTransform(g_graph, two_graph),
|
|
|
|
ReplacementTransform(g_label, two_label),
|
|
|
|
Animation(axes.y_axis.numbers)
|
|
|
|
)
|
|
|
|
self.wait()
|
|
|
|
self.play(Write(find_sqrt_2))
|
|
|
|
self.wait()
|
|
|
|
|
|
|
|
self.set_variables_as_attrs(
|
|
|
|
squared_graph, two_graph,
|
|
|
|
squared_label, two_label,
|
|
|
|
)
|
|
|
|
|
|
|
|
def show_example_binary_search(self):
|
|
|
|
self.binary_search(
|
|
|
|
self.squared_graph, self.two_graph,
|
|
|
|
x0 = 1, x1 = 2,
|
|
|
|
n_iterations = 8
|
|
|
|
)
|
|
|
|
|
|
|
|
##
|
|
|
|
|
|
|
|
def binary_search(
|
|
|
|
self,
|
|
|
|
f_graph, g_graph,
|
|
|
|
x0, x1,
|
|
|
|
n_iterations,
|
|
|
|
n_iterations_with_sign_mention = 0,
|
|
|
|
zoom = False,
|
|
|
|
):
|
|
|
|
|
|
|
|
axes = self.axes
|
2018-03-12 22:51:40 -07:00
|
|
|
rect = self.rect = Rectangle()
|
2018-03-09 17:22:55 -08:00
|
|
|
rect.set_stroke(width = 0)
|
|
|
|
rect.set_fill(YELLOW, 0.5)
|
|
|
|
rect.replace(Line(
|
|
|
|
axes.coords_to_point(x0, 0),
|
|
|
|
axes.coords_to_point(x1, 0),
|
|
|
|
), dim_to_match = 0)
|
|
|
|
rect.stretch_to_fit_height(self.search_range_rect_height)
|
|
|
|
|
|
|
|
#Show first left and right
|
|
|
|
mention_signs = n_iterations_with_sign_mention > 0
|
|
|
|
kwargs = {"mention_signs" : mention_signs}
|
|
|
|
leftovers0 = self.compare_graphs_at_x(f_graph, g_graph, x0, **kwargs)
|
|
|
|
self.wait()
|
|
|
|
leftovers1 = self.compare_graphs_at_x(f_graph, g_graph, x1, **kwargs)
|
|
|
|
self.wait()
|
|
|
|
self.play(GrowFromCenter(rect))
|
|
|
|
self.wait()
|
|
|
|
|
|
|
|
all_leftovers = VGroup(leftovers0, leftovers1)
|
|
|
|
end_points = [x0, x1]
|
|
|
|
if mention_signs:
|
|
|
|
sign_word0 = leftovers0.sign_word
|
|
|
|
sign_word1 = leftovers1.sign_word
|
|
|
|
|
2018-03-12 14:02:08 -07:00
|
|
|
midpoint_line = Line(MED_SMALL_BUFF*UP, ORIGIN, color = YELLOW)
|
|
|
|
midpoint_line_update = UpdateFromFunc(
|
|
|
|
midpoint_line, lambda l : l.move_to(rect)
|
|
|
|
)
|
|
|
|
decimal = DecimalNumber(
|
|
|
|
0,
|
|
|
|
num_decimal_points = 3,
|
|
|
|
show_ellipsis = True,
|
|
|
|
)
|
|
|
|
decimal.scale(0.7)
|
|
|
|
decimal_update = ChangingDecimal(
|
|
|
|
decimal, lambda a : axes.x_axis.point_to_number(rect.get_center()),
|
|
|
|
position_update_func = lambda m : m.next_to(
|
|
|
|
midpoint_line, DOWN, SMALL_BUFF,
|
|
|
|
submobject_to_align = decimal[:-1],
|
|
|
|
),
|
|
|
|
)
|
|
|
|
if not self.show_midpoint_value:
|
|
|
|
decimal.set_fill(opacity = 0)
|
|
|
|
midpoint_line.set_stroke(width = 0)
|
|
|
|
|
2018-03-09 17:22:55 -08:00
|
|
|
#Restrict to by a half each time
|
2018-03-12 22:51:40 -07:00
|
|
|
kwargs = {
|
|
|
|
"mention_signs" : False,
|
|
|
|
"show_decimal" : zoom,
|
|
|
|
}
|
2018-03-09 17:22:55 -08:00
|
|
|
for x in range(n_iterations - 1):
|
|
|
|
x_mid = np.mean(end_points)
|
|
|
|
leftovers_mid = self.compare_graphs_at_x(f_graph, g_graph, x_mid, **kwargs)
|
|
|
|
if leftovers_mid.too_high == all_leftovers[0].too_high:
|
|
|
|
index_to_fade = 0
|
|
|
|
else:
|
|
|
|
index_to_fade = 1
|
|
|
|
edge = [RIGHT, LEFT][index_to_fade]
|
|
|
|
to_fade = all_leftovers[index_to_fade]
|
|
|
|
all_leftovers.submobjects[index_to_fade] = leftovers_mid
|
|
|
|
end_points[index_to_fade] = x_mid
|
|
|
|
|
|
|
|
added_anims = []
|
|
|
|
if mention_signs:
|
|
|
|
word = [leftovers0, leftovers1][index_to_fade].sign_word
|
|
|
|
if x < n_iterations_with_sign_mention:
|
|
|
|
added_anims = [word.next_to, leftovers_mid[0].get_end(), -edge]
|
|
|
|
elif word in self.camera.extract_mobject_family_members(self.mobjects):
|
|
|
|
added_anims = [FadeOut(word)]
|
|
|
|
|
|
|
|
rect.generate_target()
|
|
|
|
rect.target.stretch(0.5, 0, about_edge = edge)
|
|
|
|
rect.target.stretch_to_fit_height(self.search_range_rect_height)
|
|
|
|
self.play(
|
|
|
|
MoveToTarget(rect),
|
2018-03-12 14:02:08 -07:00
|
|
|
midpoint_line_update,
|
|
|
|
decimal_update,
|
2018-03-11 15:42:25 -07:00
|
|
|
Animation(all_leftovers),
|
2018-03-09 17:22:55 -08:00
|
|
|
FadeOut(to_fade),
|
|
|
|
*added_anims
|
|
|
|
)
|
|
|
|
if zoom:
|
|
|
|
factor = 2.0/rect.get_width()
|
2018-03-12 22:51:40 -07:00
|
|
|
everything = VGroup(*self.mobjects)
|
|
|
|
decimal_index = everything.submobjects.index(decimal)
|
|
|
|
midpoint_line_index = everything.submobjects.index(midpoint_line)
|
|
|
|
everything.generate_target()
|
|
|
|
everything.target.scale(factor, about_point = rect.get_center())
|
|
|
|
everything.target[decimal_index].scale(1./factor, about_edge = UP)
|
|
|
|
everything.target[midpoint_line_index].scale(1./factor)
|
2018-03-09 17:22:55 -08:00
|
|
|
if factor > 1:
|
|
|
|
self.play(
|
|
|
|
everything.scale, factor,
|
|
|
|
{"about_point" : rect.get_center()}
|
|
|
|
)
|
|
|
|
else:
|
|
|
|
self.wait()
|
|
|
|
|
2018-03-12 14:02:08 -07:00
|
|
|
def compare_graphs_at_x(
|
|
|
|
self, f_graph, g_graph, x,
|
|
|
|
mention_signs = False,
|
|
|
|
show_decimal = False,
|
|
|
|
):
|
2018-03-09 17:22:55 -08:00
|
|
|
axes = self.axes
|
|
|
|
f_point = axes.input_to_graph_point(x, f_graph)
|
|
|
|
g_point = axes.input_to_graph_point(x, g_graph)
|
|
|
|
arrow = Arrow(
|
|
|
|
g_point, f_point, buff = 0,
|
|
|
|
**self.arrow_config
|
|
|
|
)
|
|
|
|
too_high = f_point[1] > g_point[1]
|
|
|
|
if too_high:
|
|
|
|
arrow.set_fill(GREEN, opacity = self.arrow_opacity)
|
|
|
|
else:
|
|
|
|
arrow.set_fill(RED, opacity = self.arrow_opacity)
|
|
|
|
|
|
|
|
leftovers = VGroup(arrow)
|
|
|
|
leftovers.too_high = too_high
|
|
|
|
|
|
|
|
if self.show_dotted_line_to_f:
|
|
|
|
v_line = DashedLine(axes.coords_to_point(x, 0), f_point)
|
|
|
|
self.play(ShowCreation(v_line))
|
|
|
|
leftovers.add(v_line)
|
|
|
|
|
|
|
|
added_anims = []
|
2018-03-12 22:51:40 -07:00
|
|
|
if show_decimal:
|
|
|
|
decimal = DecimalNumber(
|
|
|
|
axes.x_axis.point_to_number(arrow.get_start()),
|
|
|
|
num_decimal_points = 3,
|
|
|
|
# show_ellipsis = True,
|
|
|
|
)
|
|
|
|
height = self.rect.get_height()
|
|
|
|
decimal.scale_to_fit_height(height)
|
|
|
|
next_to_kwargs = {
|
|
|
|
"buff" : height,
|
|
|
|
}
|
|
|
|
if too_high:
|
|
|
|
decimal.next_to(arrow, DOWN, **next_to_kwargs)
|
|
|
|
if hasattr(self, "last_up_arrow_decimal"):
|
|
|
|
added_anims += [FadeOut(self.last_up_arrow_decimal)]
|
|
|
|
self.last_up_arrow_decimal = decimal
|
|
|
|
else:
|
|
|
|
decimal.next_to(arrow, UP, **next_to_kwargs)
|
|
|
|
if hasattr(self, "last_down_arrow_decimal"):
|
|
|
|
added_anims += [FadeOut(self.last_down_arrow_decimal)]
|
|
|
|
self.last_down_arrow_decimal = decimal
|
|
|
|
line = Line(decimal, arrow, buff = 0)
|
|
|
|
# line.match_color(arrow)
|
|
|
|
line.set_stroke(WHITE, 1)
|
|
|
|
decimal.add(line)
|
|
|
|
added_anims += [FadeIn(decimal)]
|
|
|
|
|
2018-03-09 17:22:55 -08:00
|
|
|
if mention_signs:
|
|
|
|
if too_high:
|
|
|
|
sign_word = TextMobject("Positive")
|
|
|
|
sign_word.highlight(GREEN)
|
|
|
|
sign_word.scale(0.7)
|
|
|
|
sign_word.next_to(arrow.get_end(), RIGHT)
|
|
|
|
else:
|
|
|
|
sign_word = TextMobject("Negative")
|
|
|
|
sign_word.highlight(RED)
|
|
|
|
sign_word.scale(0.7)
|
|
|
|
sign_word.next_to(arrow.get_end(), LEFT)
|
|
|
|
sign_word.add_background_rectangle()
|
|
|
|
added_anims += [FadeIn(sign_word)]
|
|
|
|
leftovers.sign_word = sign_word
|
2018-03-12 14:02:08 -07:00
|
|
|
|
2018-03-09 17:22:55 -08:00
|
|
|
self.play(GrowArrow(arrow), *added_anims)
|
|
|
|
|
|
|
|
return leftovers
|
|
|
|
|
2018-03-08 13:55:01 -08:00
|
|
|
class PiCreaturesAreIntrigued(AltTeacherStudentsScene):
|
2018-03-06 18:26:07 -08:00
|
|
|
def construct(self):
|
|
|
|
self.teacher_says(
|
|
|
|
"You can extend \\\\ this to 2d",
|
|
|
|
bubble_kwargs = {"width" : 4, "height" : 3}
|
|
|
|
)
|
|
|
|
self.change_student_modes("pondering", "confused", "erm")
|
|
|
|
self.look_at(self.screen)
|
|
|
|
self.wait(3)
|
|
|
|
|
2018-03-09 17:22:55 -08:00
|
|
|
class TransitionFromEquationSolverToZeroFinder(Introduce1DFunctionCase):
|
|
|
|
CONFIG = {
|
|
|
|
"show_dotted_line_to_f" : False,
|
|
|
|
"arrow_config" : {},
|
2018-03-12 14:02:08 -07:00
|
|
|
"show_midpoint_value" : False,
|
2018-03-09 17:22:55 -08:00
|
|
|
}
|
|
|
|
def construct(self):
|
|
|
|
#Just run through these without animating.
|
|
|
|
self.force_skipping()
|
|
|
|
self.show_axes_one_at_a_time()
|
|
|
|
self.show_two_graphs()
|
|
|
|
self.transition_to_sqrt_2_case()
|
|
|
|
self.revert_to_original_skipping_status()
|
|
|
|
##
|
|
|
|
|
|
|
|
self.transition_to_difference_graph()
|
|
|
|
self.show_binary_search_with_signs()
|
|
|
|
|
|
|
|
def transition_to_difference_graph(self):
|
|
|
|
axes = self.axes
|
|
|
|
equation = x_squared, equals, two = self.equation
|
|
|
|
for s in "-", "0":
|
|
|
|
tex_mob = TexMobject(s)
|
|
|
|
tex_mob.scale(0.01)
|
|
|
|
tex_mob.fade(1)
|
|
|
|
tex_mob.move_to(equation.get_right())
|
|
|
|
equation.add(tex_mob)
|
|
|
|
find_sqrt_2 = self.find_sqrt_2
|
2018-03-11 15:42:25 -07:00
|
|
|
rect = SurroundingRectangle(VGroup(equation, find_sqrt_2))
|
|
|
|
rect.highlight(WHITE)
|
2018-03-09 17:22:55 -08:00
|
|
|
|
|
|
|
f_graph = self.squared_graph
|
|
|
|
g_graph = self.two_graph
|
|
|
|
new_graph = axes.get_graph(
|
|
|
|
lambda x : f_graph.underlying_function(x) - g_graph.underlying_function(x),
|
|
|
|
color = GREEN
|
|
|
|
)
|
|
|
|
zero_graph = axes.get_graph(lambda x : 0)
|
|
|
|
zero_graph.set_stroke(BLACK, 0)
|
|
|
|
|
|
|
|
f_label = self.squared_label
|
|
|
|
g_label = self.two_label
|
|
|
|
new_label = TexMobject("f(x)", "-", "g(x)")
|
|
|
|
new_label[0].match_color(f_label)
|
|
|
|
new_label[2].match_color(g_label)
|
|
|
|
new_label.next_to(
|
|
|
|
axes.input_to_graph_point(2, new_graph),
|
|
|
|
LEFT
|
|
|
|
)
|
|
|
|
|
2018-03-11 15:42:25 -07:00
|
|
|
fg_labels = VGroup(f_label, g_label)
|
|
|
|
fg_labels.generate_target()
|
|
|
|
fg_labels.target.arrange_submobjects(DOWN, aligned_edge = LEFT)
|
|
|
|
fg_labels.target.to_corner(UP+RIGHT)
|
|
|
|
|
2018-03-09 17:22:55 -08:00
|
|
|
new_equation = TexMobject("x^2", "-", "2", "=", "0")
|
|
|
|
new_equation[0].match_style(equation[0])
|
|
|
|
new_equation[2].match_style(equation[2])
|
|
|
|
new_equation.move_to(equation, RIGHT)
|
|
|
|
for tex in equation, new_equation:
|
|
|
|
tex.sort_submobjects_alphabetically()
|
|
|
|
|
2018-03-11 15:42:25 -07:00
|
|
|
self.play(ShowCreation(rect))
|
|
|
|
self.play(FadeOut(rect))
|
2018-03-09 17:22:55 -08:00
|
|
|
self.play(
|
2018-03-11 15:42:25 -07:00
|
|
|
ReplacementTransform(equation, new_equation, path_arc = TAU/4),
|
2018-03-09 17:22:55 -08:00
|
|
|
find_sqrt_2.next_to, new_equation, DOWN,
|
|
|
|
)
|
2018-03-11 15:42:25 -07:00
|
|
|
self.play(MoveToTarget(fg_labels))
|
2018-03-09 17:22:55 -08:00
|
|
|
self.play(
|
|
|
|
ReplacementTransform(f_graph, new_graph),
|
|
|
|
ReplacementTransform(g_graph, zero_graph),
|
|
|
|
)
|
|
|
|
self.play(
|
2018-03-11 15:42:25 -07:00
|
|
|
ReplacementTransform(f_label[0].copy(), new_label[0]),
|
|
|
|
ReplacementTransform(g_label[0].copy(), new_label[2]),
|
2018-03-09 17:22:55 -08:00
|
|
|
Write(new_label[1]),
|
|
|
|
)
|
|
|
|
self.wait()
|
|
|
|
|
|
|
|
self.set_variables_as_attrs(new_graph, zero_graph)
|
|
|
|
|
|
|
|
def show_binary_search_with_signs(self):
|
2018-03-11 15:42:25 -07:00
|
|
|
self.play(FadeOut(self.axes.x_axis.numbers[2]))
|
2018-03-09 17:22:55 -08:00
|
|
|
self.binary_search(
|
|
|
|
self.new_graph, self.zero_graph,
|
|
|
|
1, 2,
|
2018-03-11 15:42:25 -07:00
|
|
|
n_iterations = 9,
|
2018-03-09 17:22:55 -08:00
|
|
|
n_iterations_with_sign_mention = 2,
|
|
|
|
zoom = True,
|
|
|
|
)
|
|
|
|
|
2018-03-08 13:55:01 -08:00
|
|
|
class RewriteEquationWithTeacher(AltTeacherStudentsScene):
|
2018-03-06 18:26:07 -08:00
|
|
|
def construct(self):
|
2018-03-11 15:42:25 -07:00
|
|
|
root_two_equations = VGroup(
|
2018-03-06 18:26:07 -08:00
|
|
|
TexMobject("x^2", "", "=", "2", ""),
|
|
|
|
TexMobject("x^2", "-", "2", "=", "0"),
|
|
|
|
)
|
2018-03-11 15:42:25 -07:00
|
|
|
for equation in root_two_equations:
|
2018-03-06 18:26:07 -08:00
|
|
|
equation.sort_submobjects_alphabetically()
|
|
|
|
for part in equation.get_parts_by_tex("text"):
|
|
|
|
part[2:-1].highlight(YELLOW)
|
|
|
|
part[2:-1].scale(0.9)
|
|
|
|
equation.move_to(self.hold_up_spot, DOWN)
|
|
|
|
|
2018-03-11 15:42:25 -07:00
|
|
|
brace = Brace(root_two_equations[1], UP)
|
|
|
|
f_equals_0 = brace.get_tex("f(x) = 0")
|
|
|
|
|
|
|
|
self.teacher_holds_up(root_two_equations[0])
|
2018-03-06 18:26:07 -08:00
|
|
|
self.wait()
|
2018-03-11 15:42:25 -07:00
|
|
|
self.play(Transform(
|
|
|
|
*root_two_equations,
|
|
|
|
run_time = 1.5,
|
|
|
|
path_arc = TAU/2
|
|
|
|
))
|
|
|
|
self.play(self.get_student_changes(*["pondering"]*3))
|
|
|
|
self.play(
|
|
|
|
GrowFromCenter(brace),
|
|
|
|
self.teacher.change, "happy"
|
|
|
|
)
|
|
|
|
self.play(Write(f_equals_0))
|
2018-03-06 18:26:07 -08:00
|
|
|
self.change_student_modes(*["happy"]*3)
|
2018-03-11 15:42:25 -07:00
|
|
|
self.wait()
|
2018-03-06 18:26:07 -08:00
|
|
|
|
2018-03-11 15:42:25 -07:00
|
|
|
#
|
|
|
|
to_remove = VGroup(root_two_equations[0], brace, f_equals_0)
|
|
|
|
two_d_equation = TexMobject("""
|
|
|
|
\\left[\\begin{array}{c}
|
|
|
|
ye^x \\\\
|
|
|
|
\\sin(xy)
|
|
|
|
\\end{array}\\right] =
|
|
|
|
\\left[\\begin{array}{c}
|
|
|
|
y^2 + x^3 \\\\
|
|
|
|
3y - x
|
|
|
|
\\end{array}\\right]
|
|
|
|
""")
|
|
|
|
complex_equation = TexMobject("z", "^5 + ", "z", " + 1 = 0")
|
|
|
|
z_def = TextMobject(
|
|
|
|
"(", "$z$", " is complex, ", "$a + bi$", ")",
|
|
|
|
arg_separator = ""
|
|
|
|
)
|
|
|
|
complex_group = VGroup(complex_equation, z_def)
|
|
|
|
complex_group.arrange_submobjects(DOWN)
|
|
|
|
for tex in complex_group:
|
|
|
|
tex.highlight_by_tex("z", GREEN)
|
|
|
|
complex_group.move_to(self.hold_up_spot, DOWN)
|
2018-03-07 13:45:32 -08:00
|
|
|
|
2018-03-06 18:26:07 -08:00
|
|
|
self.play(
|
2018-03-11 15:42:25 -07:00
|
|
|
ApplyMethod(
|
|
|
|
to_remove.next_to, SPACE_WIDTH*RIGHT, RIGHT,
|
|
|
|
remover = True,
|
|
|
|
rate_func = running_start,
|
|
|
|
path_arc = -TAU/4,
|
|
|
|
),
|
|
|
|
self.teacher.change, "hesitant",
|
|
|
|
self.get_student_changes(*["erm"]*3)
|
2018-03-06 18:26:07 -08:00
|
|
|
)
|
2018-03-11 15:42:25 -07:00
|
|
|
self.teacher_holds_up(two_d_equation)
|
|
|
|
self.change_all_student_modes("horrified")
|
2018-03-06 18:26:07 -08:00
|
|
|
self.wait()
|
2018-03-11 15:42:25 -07:00
|
|
|
self.play(
|
|
|
|
FadeOut(two_d_equation),
|
|
|
|
FadeInFromDown(complex_group),
|
|
|
|
)
|
|
|
|
self.change_all_student_modes("confused")
|
|
|
|
self.wait(3)
|
2018-03-06 18:26:07 -08:00
|
|
|
|
2018-03-08 20:49:04 -08:00
|
|
|
class InputOutputScene(Scene):
|
|
|
|
CONFIG = {
|
|
|
|
"plane_width" : 6,
|
|
|
|
"plane_height" : 6,
|
|
|
|
"x_shift" : SPACE_WIDTH/2,
|
|
|
|
"y_shift" : MED_LARGE_BUFF,
|
|
|
|
"output_scalar" : 10,
|
|
|
|
"non_renormalized_func" : plane_func_by_wind_spec(
|
|
|
|
(-2, -1, 2),
|
|
|
|
(1, 1, 1),
|
|
|
|
(2, -2, -1),
|
|
|
|
),
|
|
|
|
}
|
|
|
|
|
|
|
|
###
|
|
|
|
|
|
|
|
def func(self, coord_pair):
|
|
|
|
out_coords = np.array(self.non_renormalized_func(coord_pair))
|
|
|
|
out_norm = np.linalg.norm(out_coords)
|
2018-03-11 15:42:25 -07:00
|
|
|
if out_norm > 1:
|
2018-03-08 20:49:04 -08:00
|
|
|
angle = angle_of_vector(out_coords)
|
|
|
|
factor = 0.5-0.1*np.cos(4*angle)
|
|
|
|
target_norm = factor*np.log(out_norm)
|
|
|
|
out_coords *= target_norm / out_norm
|
2018-03-11 15:42:25 -07:00
|
|
|
else:
|
|
|
|
out_coords = (0, 0)
|
2018-03-08 20:49:04 -08:00
|
|
|
return tuple(out_coords)
|
|
|
|
|
|
|
|
def point_function(self, point):
|
|
|
|
in_coords = self.input_plane.point_to_coords(point)
|
|
|
|
out_coords = self.func(in_coords)
|
|
|
|
return self.output_plane.coords_to_point(*out_coords)
|
|
|
|
|
|
|
|
def get_colorings(self):
|
|
|
|
in_cmos = ColorMappedObjectsScene(
|
|
|
|
func = lambda p : self.non_renormalized_func(
|
|
|
|
(p[0]+self.x_shift, p[1]+self.y_shift)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
scalar = self.output_scalar
|
|
|
|
out_cmos = ColorMappedObjectsScene(
|
|
|
|
func = lambda p : (
|
|
|
|
scalar*(p[0]-self.x_shift), scalar*(p[1]+self.y_shift)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
input_coloring = Rectangle(
|
|
|
|
height = self.plane_height,
|
|
|
|
width = self.plane_width,
|
|
|
|
stroke_width = 0,
|
|
|
|
fill_color = WHITE,
|
|
|
|
fill_opacity = 1,
|
|
|
|
)
|
|
|
|
output_coloring = input_coloring.copy()
|
2018-03-12 14:02:08 -07:00
|
|
|
colorings = VGroup(input_coloring, output_coloring)
|
2018-03-08 20:49:04 -08:00
|
|
|
vects = [LEFT, RIGHT]
|
|
|
|
cmos_pair = [in_cmos, out_cmos]
|
|
|
|
for coloring, vect, cmos in zip(colorings, vects, cmos_pair):
|
|
|
|
coloring.move_to(self.x_shift*vect + self.y_shift*DOWN)
|
|
|
|
coloring.color_using_background_image(cmos.background_image_file)
|
|
|
|
return colorings
|
|
|
|
|
|
|
|
def get_planes(self):
|
|
|
|
input_plane = self.input_plane = NumberPlane(
|
|
|
|
x_radius = self.plane_width/2.0,
|
|
|
|
y_radius = self.plane_height/2.0,
|
|
|
|
)
|
|
|
|
output_plane = self.output_plane = input_plane.copy()
|
2018-03-12 14:02:08 -07:00
|
|
|
planes = VGroup(input_plane, output_plane)
|
2018-03-08 20:49:04 -08:00
|
|
|
vects = [LEFT, RIGHT]
|
|
|
|
label_texts = ["Input", "Output"]
|
|
|
|
label_colors = [GREEN, RED]
|
|
|
|
for plane, vect, text, color in zip(planes, vects, label_texts, label_colors):
|
|
|
|
plane.stretch_to_fit_width(self.plane_width)
|
|
|
|
plane.add_coordinates(x_vals = range(-2, 3), y_vals = range(-2, 3))
|
|
|
|
plane.white_parts = VGroup(plane.axes, plane.coordinate_labels)
|
|
|
|
plane.lines_to_fade = VGroup(plane.main_lines, plane.secondary_lines)
|
|
|
|
plane.move_to(vect*SPACE_WIDTH/2 + self.y_shift*DOWN)
|
|
|
|
label = TextMobject(text)
|
|
|
|
label.scale(1.5)
|
|
|
|
label.add_background_rectangle()
|
|
|
|
label.move_to(plane)
|
|
|
|
label.to_edge(UP, buff = MED_SMALL_BUFF)
|
|
|
|
plane.add(label)
|
|
|
|
plane.label = label
|
|
|
|
for submob in plane.submobject_family():
|
|
|
|
if isinstance(submob, TexMobject) and hasattr(submob, "background_rectangle"):
|
|
|
|
submob.remove(submob.background_rectangle)
|
|
|
|
|
|
|
|
return planes
|
|
|
|
|
|
|
|
def get_v_line(self):
|
|
|
|
v_line = Line(UP, DOWN).scale(SPACE_HEIGHT)
|
|
|
|
v_line.set_stroke(WHITE, 5)
|
|
|
|
return v_line
|
|
|
|
|
|
|
|
def get_dots(self, input_plane, output_plane):
|
|
|
|
step = self.dot_density
|
|
|
|
x_min = -3.0
|
|
|
|
x_max = 3.0
|
|
|
|
y_min = -3.0
|
|
|
|
y_max = 3.0
|
|
|
|
dots = VGroup()
|
|
|
|
for x in np.arange(x_min, x_max + step, step):
|
|
|
|
for y in np.arange(y_max, y_min - step, -step):
|
|
|
|
out_coords = self.func((x, y))
|
|
|
|
dot = Dot(radius = self.dot_radius)
|
|
|
|
dot.set_stroke(BLACK, 1)
|
|
|
|
dot.move_to(input_plane.coords_to_point(x, y))
|
|
|
|
dot.original_position = dot.get_center()
|
|
|
|
dot.generate_target()
|
|
|
|
dot.target.move_to(output_plane.coords_to_point(*out_coords))
|
|
|
|
dot.target_color = rgba_to_color(point_to_rgba(
|
|
|
|
tuple(self.output_scalar*np.array(out_coords))
|
|
|
|
))
|
|
|
|
dots.add(dot)
|
|
|
|
return dots
|
|
|
|
|
2018-03-09 17:22:55 -08:00
|
|
|
class IntroduceInputOutputScene(InputOutputScene):
|
|
|
|
CONFIG = {
|
|
|
|
"dot_radius" : 0.05,
|
|
|
|
"dot_density" : 0.25,
|
|
|
|
}
|
|
|
|
def construct(self):
|
|
|
|
self.setup_planes()
|
|
|
|
self.map_single_point_to_point()
|
|
|
|
|
|
|
|
def setup_planes(self):
|
|
|
|
self.input_plane, self.output_plane = self.get_planes()
|
|
|
|
self.v_line = self.get_v_line()
|
|
|
|
self.add(self.input_plane, self.output_plane, self.v_line)
|
|
|
|
|
|
|
|
def map_single_point_to_point(self):
|
|
|
|
input_plane = self.input_plane
|
|
|
|
output_plane = self.output_plane
|
|
|
|
|
|
|
|
#Dots
|
|
|
|
dots = self.get_dots()
|
|
|
|
|
|
|
|
in_dot = dots[int(0.55*len(dots))].copy()
|
|
|
|
out_dot = in_dot.target
|
|
|
|
for mob in in_dot, out_dot:
|
|
|
|
mob.scale(1.5)
|
|
|
|
in_dot.highlight(YELLOW)
|
|
|
|
out_dot.highlight(PINK)
|
|
|
|
|
|
|
|
input_label_arrow = Vector(DOWN+RIGHT)
|
|
|
|
input_label_arrow.next_to(in_dot, UP+LEFT, SMALL_BUFF)
|
|
|
|
input_label = TextMobject("Input point")
|
|
|
|
input_label.next_to(input_label_arrow.get_start(), UP, SMALL_BUFF)
|
|
|
|
for mob in input_label, input_label_arrow:
|
|
|
|
mob.match_color(in_dot)
|
|
|
|
input_label.add_background_rectangle()
|
|
|
|
|
|
|
|
output_label_arrow = Vector(DOWN+LEFT)
|
|
|
|
output_label_arrow.next_to(out_dot, UP+RIGHT, SMALL_BUFF)
|
|
|
|
output_label = TextMobject("Output point")
|
|
|
|
output_label.next_to(output_label_arrow.get_start(), UP, SMALL_BUFF)
|
|
|
|
for mob in output_label, output_label_arrow:
|
|
|
|
mob.match_color(out_dot)
|
|
|
|
output_label.add_background_rectangle()
|
|
|
|
|
|
|
|
path_arc = -TAU/4
|
|
|
|
curved_arrow = Arrow(
|
|
|
|
in_dot, out_dot,
|
|
|
|
buff = SMALL_BUFF,
|
|
|
|
path_arc = path_arc,
|
|
|
|
use_rectangular_stem = False,
|
|
|
|
color = WHITE,
|
|
|
|
)
|
|
|
|
curved_arrow.pointwise_become_partial(curved_arrow, 0, 0.95)
|
|
|
|
function_label = TexMobject("f(", "\\text{2d input}", ")")
|
|
|
|
function_label.next_to(curved_arrow, UP)
|
|
|
|
function_label.add_background_rectangle()
|
|
|
|
|
|
|
|
|
|
|
|
self.play(LaggedStart(GrowFromCenter, dots))
|
|
|
|
self.play(LaggedStart(
|
|
|
|
MoveToTarget, dots,
|
|
|
|
path_arc = path_arc
|
|
|
|
))
|
|
|
|
self.wait()
|
|
|
|
self.play(FadeOut(dots))
|
|
|
|
self.play(
|
|
|
|
GrowFromCenter(in_dot),
|
|
|
|
GrowArrow(input_label_arrow),
|
|
|
|
FadeIn(input_label)
|
|
|
|
)
|
|
|
|
self.wait()
|
|
|
|
self.play(
|
|
|
|
ShowCreation(curved_arrow),
|
|
|
|
ReplacementTransform(
|
|
|
|
in_dot.copy(), out_dot,
|
|
|
|
path_arc = path_arc
|
|
|
|
),
|
|
|
|
FadeIn(function_label),
|
|
|
|
)
|
|
|
|
self.play(
|
|
|
|
GrowArrow(output_label_arrow),
|
|
|
|
FadeIn(output_label)
|
|
|
|
)
|
|
|
|
self.wait()
|
|
|
|
self.play(*map(FadeOut, [
|
|
|
|
input_label_arrow, input_label,
|
|
|
|
output_label_arrow, output_label,
|
|
|
|
curved_arrow, function_label,
|
|
|
|
]))
|
|
|
|
|
|
|
|
#General movements and wiggles
|
|
|
|
out_dot_continual_update = self.get_output_dot_continual_update(in_dot, out_dot)
|
|
|
|
self.add(out_dot_continual_update)
|
|
|
|
|
|
|
|
for vect in UP, RIGHT:
|
|
|
|
self.play(
|
|
|
|
in_dot.shift, 0.25*vect,
|
|
|
|
rate_func = lambda t : wiggle(t, 8),
|
|
|
|
run_time = 2
|
|
|
|
)
|
|
|
|
for vect in compass_directions(4, UP+RIGHT):
|
|
|
|
self.play(Rotating(
|
|
|
|
in_dot, about_point = in_dot.get_corner(vect),
|
|
|
|
radians = TAU,
|
|
|
|
run_time = 1
|
|
|
|
))
|
|
|
|
self.wait()
|
|
|
|
for coords in (-2, 2), (-2, -2), (2, -2), (1.5, 1.5):
|
|
|
|
self.play(
|
|
|
|
in_dot.move_to, input_plane.coords_to_point(*coords),
|
|
|
|
path_arc = -TAU/4,
|
|
|
|
run_time = 2
|
|
|
|
)
|
|
|
|
self.wait()
|
|
|
|
|
|
|
|
###
|
|
|
|
|
|
|
|
def get_dots(self):
|
|
|
|
input_plane = self.input_plane
|
|
|
|
dots = VGroup()
|
|
|
|
step = self.dot_density
|
|
|
|
x_max = input_plane.x_radius
|
|
|
|
x_min = -x_max
|
|
|
|
y_max = input_plane.y_radius
|
|
|
|
y_min = -y_max
|
|
|
|
|
|
|
|
reverse = False
|
|
|
|
for x in np.arange(x_min+step, x_max, step):
|
|
|
|
y_range = list(np.arange(x_min+step, x_max, step))
|
|
|
|
if reverse:
|
|
|
|
y_range.reverse()
|
|
|
|
reverse = not reverse
|
|
|
|
for y in y_range:
|
|
|
|
dot = Dot(radius = self.dot_radius)
|
|
|
|
dot.move_to(input_plane.coords_to_point(x, y))
|
|
|
|
dot.generate_target()
|
|
|
|
dot.target.move_to(self.point_function(dot.get_center()))
|
|
|
|
dots.add(dot)
|
|
|
|
return dots
|
|
|
|
|
|
|
|
def get_output_dot_continual_update(self, input_dot, output_dot):
|
|
|
|
return ContinualUpdateFromFunc(
|
|
|
|
output_dot,
|
|
|
|
lambda od : od.move_to(self.point_function(input_dot.get_center()))
|
|
|
|
)
|
|
|
|
|
|
|
|
class IntroduceVectorField(IntroduceInputOutputScene):
|
|
|
|
CONFIG = {
|
|
|
|
"dot_density" : 0.5,
|
|
|
|
}
|
|
|
|
def construct(self):
|
|
|
|
self.setup_planes()
|
|
|
|
input_plane, output_plane = self.input_plane, self.output_plane
|
|
|
|
dots = self.get_dots()
|
|
|
|
|
|
|
|
in_dot = dots[0].copy()
|
|
|
|
in_dot.move_to(input_plane.coords_to_point(1.5, 1.5))
|
|
|
|
out_dot = in_dot.copy()
|
|
|
|
out_dot_continual_update = self.get_output_dot_continual_update(in_dot, out_dot)
|
|
|
|
for mob in in_dot, out_dot:
|
|
|
|
mob.scale(1.5)
|
|
|
|
in_dot.highlight(YELLOW)
|
|
|
|
out_dot.highlight(PINK)
|
|
|
|
|
|
|
|
out_vector = Arrow(
|
|
|
|
LEFT, RIGHT,
|
|
|
|
color = out_dot.get_color(),
|
|
|
|
)
|
|
|
|
out_vector.set_stroke(BLACK, 1)
|
|
|
|
continual_out_vector_update = ContinualUpdateFromFunc(
|
|
|
|
out_vector, lambda ov : ov.put_start_and_end_on(
|
|
|
|
output_plane.coords_to_point(0, 0),
|
|
|
|
out_dot.get_center(),
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
in_vector = out_vector.copy()
|
|
|
|
def update_in_vector(in_vector):
|
|
|
|
Transform(in_vector, out_vector).update(1)
|
|
|
|
in_vector.scale(0.5)
|
|
|
|
in_vector.shift(in_dot.get_center() - in_vector.get_start())
|
|
|
|
continual_in_vector_update = ContinualUpdateFromFunc(
|
|
|
|
in_vector, update_in_vector
|
|
|
|
)
|
|
|
|
continual_updates = [
|
|
|
|
out_dot_continual_update,
|
|
|
|
continual_out_vector_update,
|
|
|
|
continual_in_vector_update
|
|
|
|
]
|
|
|
|
|
|
|
|
self.add(in_dot, out_dot)
|
|
|
|
self.play(GrowArrow(out_vector, run_time = 2))
|
|
|
|
self.wait()
|
|
|
|
self.add_foreground_mobjects(in_dot)
|
|
|
|
self.play(ReplacementTransform(out_vector.copy(), in_vector))
|
|
|
|
self.wait()
|
|
|
|
self.add(*continual_updates)
|
|
|
|
path = Square().rotate(-90*DEGREES)
|
|
|
|
path.replace(Line(
|
|
|
|
input_plane.coords_to_point(-1.5, -1.5),
|
|
|
|
input_plane.coords_to_point(1.5, 1.5),
|
|
|
|
), stretch = True)
|
|
|
|
in_vectors = VGroup()
|
|
|
|
self.add(in_vectors)
|
|
|
|
for a in np.linspace(0, 1, 25):
|
|
|
|
self.play(
|
|
|
|
in_dot.move_to, path.point_from_proportion(a),
|
|
|
|
run_time = 0.2,
|
|
|
|
rate_func = None,
|
|
|
|
)
|
|
|
|
in_vectors.add(in_vector.copy())
|
|
|
|
|
|
|
|
# Full vector field
|
|
|
|
newer_in_vectors = VGroup()
|
|
|
|
self.add(newer_in_vectors)
|
|
|
|
for dot in dots:
|
|
|
|
self.play(in_dot.move_to, dot, run_time = 1./15)
|
|
|
|
newer_in_vectors.add(in_vector.copy())
|
|
|
|
self.remove(*continual_updates)
|
|
|
|
self.remove()
|
|
|
|
self.play(*map(FadeOut, [
|
|
|
|
out_dot, out_vector, in_vectors, in_dot, in_vector
|
|
|
|
]))
|
|
|
|
self.wait()
|
|
|
|
target_length = 0.4
|
|
|
|
for vector in newer_in_vectors:
|
|
|
|
vector.generate_target()
|
|
|
|
if vector.get_length() == 0:
|
|
|
|
continue
|
|
|
|
factor = target_length / vector.get_length()
|
|
|
|
vector.target.scale(factor, about_point = vector.get_start())
|
|
|
|
|
|
|
|
self.play(LaggedStart(MoveToTarget, newer_in_vectors))
|
|
|
|
self.wait()
|
2018-03-08 20:49:04 -08:00
|
|
|
|
2018-03-08 19:40:49 -08:00
|
|
|
class TwoDScreenInOurThreeDWorld(AltTeacherStudentsScene, ThreeDScene):
|
|
|
|
def construct(self):
|
|
|
|
self.ask_about_2d_functions()
|
|
|
|
self.show_3d()
|
|
|
|
|
|
|
|
def ask_about_2d_functions(self):
|
|
|
|
in_plane = NumberPlane(x_radius = 2.5, y_radius = 2.5)
|
|
|
|
in_plane.add_coordinates()
|
|
|
|
in_plane.scale_to_fit_height(3)
|
|
|
|
out_plane = in_plane.copy()
|
|
|
|
|
|
|
|
in_text = TextMobject("Input space")
|
|
|
|
out_text = TextMobject("Output space")
|
|
|
|
VGroup(in_text, out_text).scale(0.75)
|
|
|
|
in_text.next_to(in_plane, UP, SMALL_BUFF)
|
|
|
|
out_text.next_to(out_plane, UP, SMALL_BUFF)
|
|
|
|
in_plane.add(in_text)
|
|
|
|
out_plane.add(out_text)
|
|
|
|
|
2018-03-09 17:22:55 -08:00
|
|
|
arrow = Arrow(
|
|
|
|
LEFT, RIGHT,
|
|
|
|
path_arc = -TAU/4,
|
|
|
|
use_rectangular_stem = False,
|
|
|
|
color = WHITE
|
|
|
|
)
|
|
|
|
arrow.pointwise_become_partial(arrow, 0.0, 0.97)
|
2018-03-08 19:40:49 -08:00
|
|
|
group = VGroup(in_plane, arrow, out_plane)
|
|
|
|
group.arrange_submobjects(RIGHT)
|
|
|
|
arrow.shift(UP)
|
|
|
|
group.move_to(self.students)
|
|
|
|
group.to_edge(UP)
|
|
|
|
|
|
|
|
dots = VGroup()
|
|
|
|
dots_target = VGroup()
|
|
|
|
for x in np.arange(-2.5, 3.0, 0.5):
|
|
|
|
for y in np.arange(-2.5, 3.0, 0.5):
|
|
|
|
dot = Dot(radius = 0.05)
|
|
|
|
dot.move_to(in_plane.coords_to_point(x, y))
|
|
|
|
dot.generate_target()
|
|
|
|
dot.target.move_to(out_plane.coords_to_point(
|
|
|
|
x + 0.25*np.cos(5*y), y + 0.25*np.sin(3*x)
|
|
|
|
))
|
|
|
|
dots.add(dot)
|
|
|
|
dots_target.add(dot.target)
|
|
|
|
dots.gradient_highlight(YELLOW, RED)
|
|
|
|
dots_target.gradient_highlight(YELLOW, RED)
|
|
|
|
|
|
|
|
self.play(
|
|
|
|
self.teacher.change, "raise_right_hand",
|
|
|
|
Write(in_plane, run_time = 1)
|
|
|
|
)
|
|
|
|
self.play(
|
|
|
|
ShowCreation(arrow),
|
|
|
|
ReplacementTransform(
|
|
|
|
in_plane.copy(), out_plane,
|
|
|
|
path_arc = -TAU/4,
|
|
|
|
)
|
|
|
|
)
|
|
|
|
self.play(
|
|
|
|
LaggedStart(GrowFromCenter, dots, run_time = 1),
|
|
|
|
self.get_student_changes(*3*["erm"]),
|
|
|
|
)
|
|
|
|
self.play(LaggedStart(MoveToTarget, dots, path_arc = -TAU/4))
|
|
|
|
self.wait(3)
|
|
|
|
|
|
|
|
|
|
|
|
def show_3d(self):
|
|
|
|
laptop = Laptop().scale(2)
|
|
|
|
laptop.rotate(-TAU/12, DOWN)
|
|
|
|
laptop.rotate(-5*TAU/24, LEFT)
|
|
|
|
laptop.rotate(TAU/8, LEFT)
|
|
|
|
laptop.scale(2.3*SPACE_WIDTH/laptop.screen_plate.get_width())
|
|
|
|
laptop.shift(-laptop.screen_plate.get_center() + 0.1*IN)
|
|
|
|
should_shade_in_3d(laptop)
|
|
|
|
|
|
|
|
everything = VGroup(laptop, *self.mobjects)
|
|
|
|
everything.generate_target()
|
|
|
|
# for mob in everything.target.submobject_family():
|
|
|
|
# if isinstance(mob, PiCreature):
|
|
|
|
# mob.change_mode("confused")
|
|
|
|
everything.target.rotate(TAU/12, LEFT)
|
|
|
|
everything.target.rotate(TAU/16, UP)
|
|
|
|
everything.target.shift(4*UP)
|
|
|
|
|
|
|
|
self.move_camera(
|
|
|
|
distance = 12,
|
|
|
|
run_time = 4,
|
|
|
|
added_anims = [MoveToTarget(everything, run_time = 4)],
|
|
|
|
)
|
|
|
|
self.add(AmbientRotation(everything, axis = UP, rate = 3*DEGREES))
|
|
|
|
self.wait(10)
|
|
|
|
|
2018-03-11 17:12:53 -07:00
|
|
|
class EveryOutputPointHasAColor(ColorMappedObjectsScene):
|
|
|
|
CONFIG = {
|
|
|
|
"func" : lambda p : p,
|
|
|
|
"dot_spacing" : 0.1,
|
|
|
|
"dot_radius" : 0.01,
|
|
|
|
}
|
|
|
|
def construct(self):
|
|
|
|
full_rect = FullScreenRectangle()
|
|
|
|
full_rect.set_fill(WHITE, 1)
|
|
|
|
full_rect.set_stroke(WHITE, 0)
|
|
|
|
full_rect.color_using_background_image(self.background_image_file)
|
|
|
|
|
|
|
|
title = TextMobject("Output Space")
|
|
|
|
title.scale(1.5)
|
|
|
|
title.to_edge(UP, buff = MED_SMALL_BUFF)
|
|
|
|
title.set_stroke(BLACK, 1)
|
2018-03-13 14:08:49 -07:00
|
|
|
# self.add_foreground_mobjects(title)
|
2018-03-11 17:12:53 -07:00
|
|
|
|
|
|
|
plane = NumberPlane()
|
|
|
|
plane.fade(0.5)
|
|
|
|
plane.axes.set_stroke(WHITE, 3)
|
2018-03-13 14:08:49 -07:00
|
|
|
# plane.add(BackgroundRectangle(title))
|
2018-03-11 17:12:53 -07:00
|
|
|
self.add(plane)
|
|
|
|
|
|
|
|
|
|
|
|
dots = VGroup()
|
|
|
|
step = self.dot_spacing
|
|
|
|
for x in np.arange(-SPACE_WIDTH, SPACE_WIDTH+step, step):
|
|
|
|
for y in np.arange(-SPACE_HEIGHT, SPACE_HEIGHT+step, step):
|
|
|
|
dot = Dot(color = WHITE)
|
|
|
|
dot.color_using_background_image(self.background_image_file)
|
|
|
|
dot.move_to(x*RIGHT + y*UP)
|
|
|
|
dots.add(dot)
|
|
|
|
random.shuffle(dots.submobjects)
|
|
|
|
|
2018-03-12 14:02:08 -07:00
|
|
|
m = 3 #exponential factor
|
|
|
|
n = 1
|
|
|
|
dot_groups = VGroup()
|
|
|
|
while n <= len(dots):
|
|
|
|
dot_groups.add(dots[n-1:m*n-1])
|
|
|
|
n *= m
|
2018-03-11 17:12:53 -07:00
|
|
|
self.play(LaggedStart(
|
2018-03-12 14:02:08 -07:00
|
|
|
LaggedStart, dot_groups,
|
|
|
|
lambda dg : (GrowFromCenter, dg),
|
2018-03-11 17:12:53 -07:00
|
|
|
run_time = 8,
|
2018-03-12 14:02:08 -07:00
|
|
|
lag_ratio = 0.2,
|
2018-03-11 17:12:53 -07:00
|
|
|
))
|
|
|
|
|
2018-03-08 20:49:04 -08:00
|
|
|
class DotsHoppingToColor(InputOutputScene):
|
2018-03-07 13:45:32 -08:00
|
|
|
CONFIG = {
|
|
|
|
"dot_radius" : 0.05,
|
2018-03-08 13:55:01 -08:00
|
|
|
"dot_density" : 0.25,
|
2018-03-07 13:45:32 -08:00
|
|
|
}
|
|
|
|
def construct(self):
|
|
|
|
input_coloring, output_coloring = self.get_colorings()
|
|
|
|
input_plane, output_plane = self.get_planes()
|
2018-03-08 20:49:04 -08:00
|
|
|
v_line = self.get_v_line()
|
2018-03-06 18:26:07 -08:00
|
|
|
|
2018-03-07 13:45:32 -08:00
|
|
|
dots = self.get_dots(input_plane, output_plane)
|
2018-03-06 18:26:07 -08:00
|
|
|
|
2018-03-07 13:45:32 -08:00
|
|
|
right_half_block = Rectangle(
|
|
|
|
height = 2*SPACE_HEIGHT,
|
|
|
|
width = SPACE_WIDTH - SMALL_BUFF,
|
|
|
|
stroke_width = 0,
|
|
|
|
fill_color = BLACK,
|
|
|
|
fill_opacity = 0.8,
|
|
|
|
)
|
|
|
|
right_half_block.to_edge(RIGHT, buff = 0)
|
2018-03-06 18:26:07 -08:00
|
|
|
|
2018-03-07 13:45:32 -08:00
|
|
|
#Introduce parts
|
|
|
|
self.add(input_plane, output_plane, v_line)
|
|
|
|
self.play(
|
|
|
|
FadeIn(output_coloring),
|
|
|
|
Animation(output_plane),
|
|
|
|
output_plane.white_parts.highlight, BLACK,
|
|
|
|
output_plane.lines_to_fade.set_stroke, {"width" : 0},
|
|
|
|
)
|
|
|
|
self.wait()
|
|
|
|
self.play(LaggedStart(GrowFromCenter, dots, run_time = 3))
|
|
|
|
self.wait()
|
2018-03-06 18:26:07 -08:00
|
|
|
|
2018-03-07 13:45:32 -08:00
|
|
|
#Hop over and back
|
|
|
|
self.play(LaggedStart(
|
|
|
|
MoveToTarget, dots,
|
|
|
|
path_arc = -TAU/4,
|
|
|
|
run_time = 3,
|
|
|
|
))
|
|
|
|
self.wait()
|
|
|
|
self.play(LaggedStart(
|
|
|
|
ApplyMethod, dots,
|
|
|
|
lambda d : (d.set_fill, d.target_color),
|
|
|
|
))
|
|
|
|
self.wait()
|
|
|
|
self.play(LaggedStart(
|
|
|
|
ApplyMethod, dots,
|
|
|
|
lambda d : (d.move_to, d.original_position),
|
|
|
|
path_arc = TAU/4,
|
|
|
|
run_time = 3,
|
|
|
|
))
|
|
|
|
self.wait()
|
|
|
|
self.play(
|
|
|
|
FadeIn(input_coloring),
|
|
|
|
Animation(input_plane),
|
|
|
|
input_plane.white_parts.highlight, BLACK,
|
|
|
|
input_plane.lines_to_fade.set_stroke, {"width" : 0},
|
2018-03-08 13:55:01 -08:00
|
|
|
FadeOut(dots),
|
2018-03-07 13:45:32 -08:00
|
|
|
)
|
|
|
|
self.wait()
|
|
|
|
|
|
|
|
#Cover output half
|
|
|
|
right_half_block.save_state()
|
|
|
|
right_half_block.next_to(SPACE_WIDTH*RIGHT, RIGHT)
|
|
|
|
self.play(right_half_block.restore)
|
|
|
|
self.wait()
|
|
|
|
|
2018-03-08 13:55:01 -08:00
|
|
|
# Show yellow points
|
2018-03-07 14:33:34 -08:00
|
|
|
inspector = DashedLine(
|
|
|
|
ORIGIN, TAU*UP,
|
2018-03-08 13:55:01 -08:00
|
|
|
dashed_segment_length = TAU/24,
|
2018-03-07 14:33:34 -08:00
|
|
|
fill_opacity = 0,
|
|
|
|
stroke_width = 3,
|
|
|
|
stroke_color = WHITE,
|
|
|
|
)
|
2018-03-08 13:55:01 -08:00
|
|
|
inspector.add(*inspector.copy().highlight(BLACK).shift((TAU/24)*UP))
|
2018-03-07 14:33:34 -08:00
|
|
|
inspector.apply_complex_function(np.exp)
|
2018-03-08 13:55:01 -08:00
|
|
|
inspector.scale(0.15)
|
2018-03-07 14:33:34 -08:00
|
|
|
|
|
|
|
inspector_image = inspector.copy()
|
|
|
|
def update_inspector_image(inspector_image):
|
2018-03-08 19:40:49 -08:00
|
|
|
inspector_image.move_to(self.point_function(inspector.get_center()))
|
2018-03-07 14:33:34 -08:00
|
|
|
|
|
|
|
inspector_image_update_anim = UpdateFromFunc(
|
|
|
|
inspector_image, update_inspector_image
|
|
|
|
)
|
2018-03-08 20:49:04 -08:00
|
|
|
pink_points_label = TextMobject("Pink points")
|
|
|
|
pink_points_label.scale(0.7)
|
|
|
|
pink_points_label.highlight(BLACK)
|
2018-03-07 14:33:34 -08:00
|
|
|
|
|
|
|
self.play(
|
2018-03-08 20:49:04 -08:00
|
|
|
inspector.move_to, input_plane.coords_to_point(-2.75, 2.75),
|
2018-03-07 14:33:34 -08:00
|
|
|
inspector.set_stroke, {"width" : 2},
|
|
|
|
)
|
2018-03-08 20:49:04 -08:00
|
|
|
pink_points_label.next_to(inspector, RIGHT)
|
2018-03-07 14:33:34 -08:00
|
|
|
self.play(
|
|
|
|
Rotating(
|
2018-03-08 20:49:04 -08:00
|
|
|
inspector, about_point = inspector.get_center(),
|
2018-03-07 14:33:34 -08:00
|
|
|
rate_func = smooth,
|
|
|
|
run_time = 2,
|
|
|
|
),
|
2018-03-08 20:49:04 -08:00
|
|
|
Write(pink_points_label)
|
2018-03-07 14:33:34 -08:00
|
|
|
)
|
|
|
|
self.wait()
|
|
|
|
self.play(right_half_block.next_to, SPACE_WIDTH*RIGHT, RIGHT)
|
|
|
|
inspector_image_update_anim.update(0)
|
|
|
|
self.play(ReplacementTransform(
|
|
|
|
inspector.copy(), inspector_image,
|
|
|
|
path_arc = -TAU/4,
|
|
|
|
))
|
|
|
|
self.play(
|
|
|
|
ApplyMethod(
|
|
|
|
inspector.move_to,
|
2018-03-08 20:49:04 -08:00
|
|
|
input_plane.coords_to_point(-2, 0),
|
2018-03-07 14:33:34 -08:00
|
|
|
path_arc = -TAU/8,
|
|
|
|
run_time = 3,
|
|
|
|
),
|
|
|
|
inspector_image_update_anim
|
|
|
|
)
|
|
|
|
self.play(
|
|
|
|
ApplyMethod(
|
|
|
|
inspector.move_to,
|
2018-03-08 20:49:04 -08:00
|
|
|
input_plane.coords_to_point(-2.75, 2.75),
|
|
|
|
path_arc = TAU/8,
|
2018-03-07 14:33:34 -08:00
|
|
|
run_time = 3,
|
|
|
|
),
|
|
|
|
inspector_image_update_anim
|
|
|
|
)
|
2018-03-08 20:49:04 -08:00
|
|
|
self.play(FadeOut(pink_points_label))
|
2018-03-07 14:33:34 -08:00
|
|
|
|
|
|
|
# Show black zero
|
|
|
|
zeros = tuple(it.starmap(input_plane.coords_to_point, [
|
2018-03-11 15:42:25 -07:00
|
|
|
(-2., -1), (1, 1), (2, -2),
|
2018-03-07 14:33:34 -08:00
|
|
|
]))
|
|
|
|
for x in range(2):
|
|
|
|
for zero in zeros:
|
2018-03-11 15:42:25 -07:00
|
|
|
path = ParametricFunction(
|
|
|
|
bezier([
|
|
|
|
inspector.get_center(),
|
|
|
|
input_plane.coords_to_point(0, 0),
|
|
|
|
zero
|
|
|
|
]),
|
|
|
|
t_min = 0, t_max = 1
|
|
|
|
)
|
2018-03-07 14:33:34 -08:00
|
|
|
self.play(
|
2018-03-11 15:42:25 -07:00
|
|
|
MoveAlongPath(inspector, path, run_time = 2),
|
2018-03-07 14:33:34 -08:00
|
|
|
inspector_image_update_anim,
|
|
|
|
)
|
|
|
|
self.wait()
|
2018-03-08 13:55:01 -08:00
|
|
|
self.play(FadeOut(VGroup(inspector, inspector_image)))
|
|
|
|
|
|
|
|
# Show all dots and slowly fade them out
|
|
|
|
for dot in dots:
|
|
|
|
dot.scale(1.5)
|
|
|
|
self.play(
|
|
|
|
FadeOut(input_coloring),
|
|
|
|
input_plane.white_parts.highlight, WHITE,
|
|
|
|
LaggedStart(GrowFromCenter, dots)
|
|
|
|
)
|
|
|
|
self.wait()
|
|
|
|
random.shuffle(dots.submobjects)
|
|
|
|
self.play(LaggedStart(
|
|
|
|
FadeOut, dots,
|
|
|
|
lag_ratio = 0.05,
|
|
|
|
run_time = 10,
|
|
|
|
))
|
2018-03-07 14:33:34 -08:00
|
|
|
|
2018-03-08 13:55:01 -08:00
|
|
|
# Ask about whether a region contains a zero
|
|
|
|
question = TextMobject("Does this region \\\\ contain a zero?")
|
|
|
|
question.add_background_rectangle(opacity = 1)
|
|
|
|
question.next_to(input_plane.label, DOWN)
|
|
|
|
square = Square()
|
|
|
|
square.match_background_image_file(input_coloring)
|
|
|
|
square.move_to(input_plane)
|
2018-03-07 14:33:34 -08:00
|
|
|
|
2018-03-08 13:55:01 -08:00
|
|
|
self.play(ShowCreation(square), Write(question))
|
|
|
|
self.wait()
|
|
|
|
quads = [
|
|
|
|
(0, 0.5, 6, 6.25),
|
|
|
|
(1, 1, 0.5, 2),
|
|
|
|
(-1, -1, 3, 4.5),
|
|
|
|
(0, 1.25, 5, 1.7),
|
|
|
|
(-2, -1, 1, 1),
|
|
|
|
]
|
|
|
|
for x, y, width, height in quads:
|
|
|
|
self.play(
|
|
|
|
square.stretch_to_fit_width, width,
|
|
|
|
square.stretch_to_fit_height, height,
|
|
|
|
square.move_to, input_plane.coords_to_point(x, y)
|
|
|
|
)
|
|
|
|
self.wait()
|
2018-03-07 14:33:34 -08:00
|
|
|
|
2018-03-08 13:55:01 -08:00
|
|
|
class SoWeFoundTheZeros(AltTeacherStudentsScene):
|
|
|
|
def construct(self):
|
|
|
|
self.student_says(
|
|
|
|
"Aha! So we \\\\ found the solutions!",
|
|
|
|
target_mode = "hooray",
|
|
|
|
student_index = 2,
|
|
|
|
bubble_kwargs = {"direction" : LEFT},
|
|
|
|
)
|
|
|
|
self.wait()
|
|
|
|
self.teacher_says(
|
|
|
|
"Er...only \\\\ kind of",
|
|
|
|
target_mode = "hesitant"
|
|
|
|
)
|
|
|
|
self.wait(3)
|
2018-03-06 18:26:07 -08:00
|
|
|
|
2018-03-11 17:12:53 -07:00
|
|
|
class Rearrange2DEquation(AltTeacherStudentsScene):
|
|
|
|
def construct(self):
|
|
|
|
f_tex, g_tex, h_tex = [
|
|
|
|
"%s(\\text{2d point})"%char
|
|
|
|
for char in "f", "g", "h"
|
|
|
|
]
|
|
|
|
zero_tex = "\\vec{\\textbf{0}}"
|
|
|
|
equations = VGroup(
|
|
|
|
TexMobject(g_tex, "", "=", h_tex, ""),
|
|
|
|
TexMobject(g_tex, "-", h_tex, "=", zero_tex),
|
|
|
|
)
|
|
|
|
equations.move_to(self.hold_up_spot, DOWN)
|
|
|
|
equations.shift_onto_screen()
|
|
|
|
|
|
|
|
brace = Brace(equations[1], UP)
|
|
|
|
zero_eq = brace.get_tex("%s = %s"%(f_tex, zero_tex))
|
|
|
|
|
|
|
|
for equation in equations:
|
|
|
|
equation.highlight_by_tex(g_tex, BLUE)
|
|
|
|
equation.highlight_by_tex(h_tex, YELLOW)
|
|
|
|
equation.sort_submobjects_alphabetically()
|
|
|
|
|
|
|
|
|
|
|
|
self.teacher_holds_up(equations[0])
|
|
|
|
self.change_all_student_modes("pondering")
|
|
|
|
self.play(Transform(
|
|
|
|
*equations,
|
|
|
|
run_time = 1.5,
|
|
|
|
path_arc = TAU/2
|
|
|
|
))
|
|
|
|
self.play(
|
|
|
|
Succession(
|
|
|
|
GrowFromCenter(brace),
|
|
|
|
Write(zero_eq, run_time = 1)
|
|
|
|
),
|
|
|
|
self.get_student_changes(*["happy"]*3)
|
|
|
|
)
|
|
|
|
self.play(*[
|
|
|
|
ApplyMethod(pi.change, "thinking", self.screen)
|
|
|
|
for pi in self.pi_creatures
|
|
|
|
])
|
|
|
|
self.wait(3)
|
|
|
|
|
|
|
|
class SearchForZerosInInputSpace(ColorMappedObjectsScene):
|
|
|
|
CONFIG = {
|
|
|
|
"func" : example_plane_func,
|
|
|
|
}
|
|
|
|
def construct(self):
|
|
|
|
title = TextMobject("Input space")
|
|
|
|
title.scale(2)
|
|
|
|
title.to_edge(UP)
|
|
|
|
title.set_stroke(BLACK, 1)
|
|
|
|
title.add_background_rectangle()
|
|
|
|
|
|
|
|
plane = NumberPlane()
|
|
|
|
plane.fade(0.5)
|
|
|
|
plane.axes.set_stroke(WHITE, 3)
|
|
|
|
|
|
|
|
self.add(plane, title)
|
|
|
|
|
|
|
|
looking_glass = Circle()
|
|
|
|
looking_glass.set_stroke(WHITE, 3)
|
|
|
|
looking_glass.set_fill(WHITE, 0.6)
|
|
|
|
looking_glass.color_using_background_image(self.background_image_file)
|
2018-03-12 14:02:08 -07:00
|
|
|
question = TextMobject("Which points go to 0?")
|
2018-03-11 17:12:53 -07:00
|
|
|
question.next_to(looking_glass, DOWN)
|
2018-03-12 14:02:08 -07:00
|
|
|
question.add_background_rectangle()
|
2018-03-11 17:12:53 -07:00
|
|
|
|
|
|
|
mover = VGroup(looking_glass, question)
|
|
|
|
mover.move_to(4*LEFT + UP)
|
|
|
|
|
|
|
|
self.play(FadeIn(mover))
|
|
|
|
points = [4*RIGHT+UP, 2*RIGHT+2*DOWN, 2*LEFT+2*DOWN, 3*RIGHT+2.5*DOWN]
|
|
|
|
for point in points:
|
|
|
|
self.play(mover.move_to, point, run_time = 1.5)
|
|
|
|
self.wait()
|
|
|
|
|
2018-03-12 14:02:08 -07:00
|
|
|
class OneDRegionBoundary(Scene):
|
|
|
|
CONFIG = {
|
|
|
|
"graph_color" : BLUE,
|
|
|
|
"region_rect_height" : 0.1,
|
|
|
|
}
|
|
|
|
def construct(self):
|
|
|
|
x0 = self.x0 = 3
|
|
|
|
x1 = self.x1 = 6
|
|
|
|
fx0 = self.fx0 = -2
|
|
|
|
fx1 = self.fx1 = 2
|
|
|
|
|
|
|
|
axes = self.axes = Axes(
|
|
|
|
x_min = -1, x_max = 10,
|
|
|
|
y_min = -3, y_max = 3,
|
|
|
|
)
|
|
|
|
axes.center()
|
|
|
|
axes.set_stroke(width = 2)
|
|
|
|
|
|
|
|
input_word = TextMobject("Input")
|
|
|
|
input_word.next_to(axes.x_axis, UP, SMALL_BUFF, RIGHT)
|
|
|
|
output_word = TextMobject("Output")
|
|
|
|
output_word.next_to(axes.y_axis, UP)
|
|
|
|
axes.add(input_word, output_word)
|
|
|
|
self.add(axes)
|
|
|
|
|
|
|
|
graph = self.get_graph_part(1, 1)
|
|
|
|
alt_graphs = [
|
|
|
|
self.get_graph_part(*points)
|
|
|
|
for points in [
|
|
|
|
(-1, -2),
|
|
|
|
(-1, -1, -1),
|
|
|
|
(1, 1, 1),
|
|
|
|
(-0.75, 0, 1.75),
|
|
|
|
(-3, -2, -1),
|
|
|
|
]
|
|
|
|
]
|
|
|
|
|
|
|
|
#Region and boundary
|
|
|
|
line = Line(axes.coords_to_point(x0, 0), axes.coords_to_point(x1, 0))
|
|
|
|
region = Rectangle(
|
|
|
|
stroke_width = 0,
|
|
|
|
fill_color = YELLOW,
|
|
|
|
fill_opacity = 0.5,
|
|
|
|
height = self.region_rect_height
|
|
|
|
)
|
|
|
|
region.match_width(line, stretch = True)
|
|
|
|
region.move_to(line)
|
|
|
|
|
|
|
|
region_words = TextMobject("Input region")
|
|
|
|
region_words.scale_to_fit_width(0.8*region.get_width())
|
|
|
|
region_words.next_to(region, UP)
|
|
|
|
|
|
|
|
x0_arrow, x1_arrow = arrows = VGroup(*[
|
|
|
|
Arrow(
|
|
|
|
axes.coords_to_point(x, 0),
|
|
|
|
axes.coords_to_point(x, fx),
|
|
|
|
color = color,
|
|
|
|
buff = 0
|
|
|
|
)
|
|
|
|
for x, fx, color in (x0, fx0, RED), (x1, fx1, GREEN)
|
|
|
|
])
|
|
|
|
minus = TexMobject("-")
|
|
|
|
minus.match_color(x0_arrow)
|
|
|
|
minus.next_to(x0_arrow, UP)
|
|
|
|
plus = TexMobject("+")
|
|
|
|
plus.match_color(x1_arrow)
|
|
|
|
plus.next_to(x1_arrow, DOWN)
|
|
|
|
signs = VGroup(plus, minus)
|
|
|
|
|
|
|
|
|
|
|
|
self.play(
|
|
|
|
GrowFromCenter(region),
|
|
|
|
FadeIn(region_words)
|
|
|
|
)
|
|
|
|
self.wait()
|
|
|
|
self.play(*it.chain(
|
|
|
|
map(GrowArrow, arrows),
|
|
|
|
map(Write, signs)
|
|
|
|
))
|
|
|
|
self.wait()
|
|
|
|
self.play(
|
|
|
|
ShowCreation(graph),
|
|
|
|
FadeOut(region_words),
|
|
|
|
)
|
|
|
|
self.wait()
|
|
|
|
for alt_graph in alt_graphs + alt_graphs:
|
|
|
|
self.play(Transform(graph, alt_graph, path_arc = 0.1*TAU))
|
|
|
|
self.wait()
|
|
|
|
|
|
|
|
|
|
|
|
###
|
|
|
|
|
|
|
|
def get_graph_part(self, *interim_values):
|
|
|
|
result = VMobject()
|
|
|
|
result.set_stroke(self.graph_color, 3)
|
|
|
|
result.set_fill(opacity = 0)
|
|
|
|
values = [self.fx0] + list(interim_values) + [self.fx1]
|
|
|
|
result.set_points_smoothly([
|
|
|
|
self.axes.coords_to_point(x, fx)
|
|
|
|
for x, fx in zip(
|
|
|
|
np.linspace(self.x0, self.x1, len(values)),
|
|
|
|
values
|
|
|
|
)
|
|
|
|
])
|
|
|
|
return result
|
|
|
|
|
|
|
|
class DirectionOfA2DFunctionAlongABoundary(InputOutputScene):
|
|
|
|
def construct(self):
|
|
|
|
colorings = self.get_colorings()
|
|
|
|
colorings.set_fill(opacity = 0.25)
|
|
|
|
input_plane, output_plane = planes = self.get_planes()
|
|
|
|
for plane in planes:
|
|
|
|
plane.lines_to_fade.set_stroke(width = 0)
|
|
|
|
v_line = self.get_v_line()
|
|
|
|
|
|
|
|
rect = Rectangle()
|
|
|
|
rect.set_stroke(WHITE, 5)
|
|
|
|
rect.set_fill(WHITE, 0)
|
|
|
|
line = Line(
|
|
|
|
input_plane.coords_to_point(-0.75, 2.5),
|
|
|
|
input_plane.coords_to_point(2.5, -1.5),
|
|
|
|
)
|
|
|
|
rect.replace(line, stretch = True)
|
|
|
|
rect.insert_n_anchor_points(50)
|
|
|
|
rect.match_background_image_file(colorings[0])
|
|
|
|
|
|
|
|
rect_image = rect.copy()
|
|
|
|
rect_image.match_background_image_file(colorings[1])
|
|
|
|
def update_rect_image(rect_image):
|
|
|
|
rect_image.points = np.array(rect.points)
|
|
|
|
rect_image.apply_function(self.point_function)
|
|
|
|
rect_image_update_anim = UpdateFromFunc(rect_image, update_rect_image)
|
|
|
|
|
|
|
|
|
|
|
|
def get_input_point():
|
|
|
|
return rect.points[-1]
|
|
|
|
|
|
|
|
def get_output_coords():
|
|
|
|
in_coords = input_plane.point_to_coords(get_input_point())
|
|
|
|
return self.func(in_coords)
|
2018-03-11 17:12:53 -07:00
|
|
|
|
2018-03-12 14:02:08 -07:00
|
|
|
def get_angle():
|
|
|
|
return angle_of_vector(get_output_coords())
|
2018-03-11 17:12:53 -07:00
|
|
|
|
2018-03-12 14:02:08 -07:00
|
|
|
def get_color():
|
|
|
|
return rev_to_color(get_angle()/TAU) #Negative?
|
2018-03-11 17:12:53 -07:00
|
|
|
|
|
|
|
|
2018-03-12 14:02:08 -07:00
|
|
|
out_vect = Vector(RIGHT, color = WHITE)
|
|
|
|
out_vect_update_anim = UpdateFromFunc(
|
|
|
|
out_vect,
|
|
|
|
lambda ov : ov.put_start_and_end_on(
|
|
|
|
output_plane.coords_to_point(0, 0),
|
|
|
|
rect_image.points[-1]
|
|
|
|
).highlight(get_color())
|
|
|
|
)
|
|
|
|
|
|
|
|
dot = Dot()
|
|
|
|
dot.set_stroke(BLACK, 1)
|
|
|
|
dot_update_anim = UpdateFromFunc(
|
|
|
|
dot, lambda d : d.move_to(get_input_point()).set_fill(get_color())
|
|
|
|
)
|
|
|
|
|
|
|
|
in_vect = Vector(RIGHT)
|
|
|
|
def update_in_vect(in_vect):
|
|
|
|
in_vect.put_start_and_end_on(ORIGIN, 0.5*RIGHT)
|
|
|
|
in_vect.rotate(get_angle())
|
|
|
|
in_vect.highlight(get_color())
|
|
|
|
in_vect.shift(get_input_point() - in_vect.get_start())
|
|
|
|
return in_vect
|
|
|
|
in_vect_update_anim = UpdateFromFunc(in_vect, update_in_vect)
|
|
|
|
|
|
|
|
self.add(colorings, planes, v_line)
|
|
|
|
|
|
|
|
self.play(
|
|
|
|
GrowArrow(out_vect),
|
|
|
|
GrowArrow(in_vect),
|
|
|
|
Animation(dot),
|
|
|
|
)
|
|
|
|
self.play(
|
|
|
|
ShowCreation(rect),
|
|
|
|
ShowCreation(rect_image),
|
|
|
|
out_vect_update_anim,
|
|
|
|
in_vect_update_anim,
|
|
|
|
dot_update_anim,
|
|
|
|
rate_func = bezier([0, 0, 1, 1]),
|
|
|
|
run_time = 10,
|
|
|
|
)
|
|
|
|
|
2018-03-11 15:42:25 -07:00
|
|
|
class AskAboutHowToGeneralizeSigns(AltTeacherStudentsScene):
|
|
|
|
def construct(self):
|
|
|
|
# 2d plane
|
|
|
|
plane = NumberPlane(x_radius = 2.5, y_radius = 2.5)
|
|
|
|
plane.scale(0.8)
|
|
|
|
plane.to_corner(UP+LEFT)
|
|
|
|
plane.add_coordinates()
|
|
|
|
|
|
|
|
dot = Dot(color = YELLOW)
|
|
|
|
label = TextMobject("Sign?")
|
|
|
|
label.add_background_rectangle()
|
|
|
|
label.scale(0.5)
|
|
|
|
label.next_to(dot, UP, SMALL_BUFF)
|
|
|
|
dot.add(label)
|
|
|
|
dot.move_to(plane.coords_to_point(1, 1))
|
|
|
|
dot.save_state()
|
|
|
|
dot.fade(1)
|
|
|
|
dot.center()
|
|
|
|
|
|
|
|
question = TextMobject(
|
|
|
|
"Wait...what would \\\\ positive and negative \\\\ be in 2d?",
|
|
|
|
)
|
|
|
|
# question.highlight_by_tex_to_color_map({
|
|
|
|
# "+" : "green",
|
|
|
|
# "textminus" : "red"
|
|
|
|
# })
|
|
|
|
|
2018-03-11 17:12:53 -07:00
|
|
|
|
2018-03-11 15:42:25 -07:00
|
|
|
self.student_says(
|
|
|
|
question,
|
|
|
|
target_mode = "sassy",
|
|
|
|
student_index = 2,
|
|
|
|
added_anims = [
|
|
|
|
self.teacher.change, "plain",
|
|
|
|
],
|
|
|
|
bubble_kwargs = {"direction" : LEFT},
|
|
|
|
run_time = 1,
|
|
|
|
)
|
|
|
|
self.play(
|
|
|
|
Write(plane, run_time = 1),
|
|
|
|
self.students[0].change, "confused",
|
|
|
|
self.students[1].change, "confused",
|
|
|
|
)
|
|
|
|
self.play(dot.restore)
|
|
|
|
for coords in (-1, 1), (1, -1), (0, -2), (-2, 1):
|
|
|
|
self.wait(0.5)
|
|
|
|
self.play(dot.move_to, plane.coords_to_point(*coords))
|
|
|
|
self.wait()
|
|
|
|
|
2018-03-09 17:22:55 -08:00
|
|
|
class HypothesisAboutFullyColoredBoundary(ColorMappedObjectsScene):
|
|
|
|
CONFIG = {
|
|
|
|
"func" : plane_func_from_complex_func(lambda z : z**3),
|
|
|
|
}
|
|
|
|
def construct(self):
|
|
|
|
ColorMappedObjectsScene.construct(self)
|
|
|
|
square = Square(side_length = 4)
|
|
|
|
square.color_using_background_image(self.background_image_file)
|
|
|
|
hypothesis = TextMobject(
|
|
|
|
"Working Hypothesis: \\\\",
|
2018-03-12 14:02:08 -07:00
|
|
|
"If a 2d function hits outputs of all possible colors \\\\" +
|
|
|
|
"on the boundary of a 2d region,",
|
|
|
|
"that region \\\\ contains a zero.",
|
|
|
|
alignment = "",
|
2018-03-09 17:22:55 -08:00
|
|
|
)
|
2018-03-12 14:02:08 -07:00
|
|
|
hypothesis[0].next_to(hypothesis[1:], UP)
|
2018-03-09 17:22:55 -08:00
|
|
|
hypothesis[0].highlight(YELLOW)
|
2018-03-12 14:02:08 -07:00
|
|
|
s = hypothesis[1].get_tex_string()
|
|
|
|
s = filter(lambda c : c not in string.whitespace, s)
|
|
|
|
n = s.index("colors")
|
|
|
|
hypothesis[1][n:n+len("colors")].gradient_highlight(
|
|
|
|
# RED, GOLD_E, YELLOW, GREEN, BLUE, PINK,
|
|
|
|
BLUE, PINK, YELLOW,
|
|
|
|
)
|
2018-03-09 17:22:55 -08:00
|
|
|
hypothesis.to_edge(UP)
|
2018-03-12 14:02:08 -07:00
|
|
|
square.next_to(hypothesis, DOWN, MED_LARGE_BUFF)
|
2018-03-09 17:22:55 -08:00
|
|
|
|
|
|
|
self.add(hypothesis[0])
|
|
|
|
self.play(
|
|
|
|
LaggedStart(FadeIn, hypothesis[1]),
|
2018-03-12 14:02:08 -07:00
|
|
|
ShowCreation(square, run_time = 8)
|
2018-03-09 17:22:55 -08:00
|
|
|
)
|
|
|
|
self.play(LaggedStart(FadeIn, hypothesis[2]))
|
|
|
|
self.play(square.set_fill, {"opacity" : 1}, run_time = 2)
|
|
|
|
self.wait()
|
|
|
|
|
2018-03-08 13:55:01 -08:00
|
|
|
class PiCreatureAsksWhatWentWrong(PiCreatureScene):
|
|
|
|
def construct(self):
|
|
|
|
randy = self.pi_creature
|
|
|
|
randy.set_color(YELLOW_E)
|
|
|
|
randy.flip()
|
|
|
|
randy.to_corner(DOWN+LEFT)
|
|
|
|
question = TextMobject("What went wrong?")
|
|
|
|
question.next_to(randy, UP)
|
|
|
|
question.shift_onto_screen()
|
|
|
|
question.save_state()
|
|
|
|
question.shift(DOWN).fade(1)
|
|
|
|
|
|
|
|
self.play(randy.change, "erm")
|
|
|
|
self.wait(2)
|
|
|
|
self.play(
|
|
|
|
Animation(VectorizedPoint(ORIGIN)),
|
|
|
|
question.restore,
|
|
|
|
randy.change, "confused",
|
|
|
|
)
|
|
|
|
self.wait(5)
|
2018-03-06 18:26:07 -08:00
|
|
|
|
2018-03-08 20:49:04 -08:00
|
|
|
class ForeverNarrowingLoop(InputOutputScene):
|
2018-03-12 14:02:08 -07:00
|
|
|
CONFIG = {
|
|
|
|
"target_coords" : (1, 1),
|
|
|
|
"input_plane_corner" : UP+RIGHT,
|
|
|
|
"shrink_time" : 20,
|
|
|
|
}
|
2018-03-08 19:40:49 -08:00
|
|
|
def construct(self):
|
|
|
|
input_coloring, output_coloring = colorings = VGroup(*self.get_colorings())
|
|
|
|
input_plane, output_plane = planes = VGroup(*self.get_planes())
|
|
|
|
for plane in planes:
|
|
|
|
plane.white_parts.highlight(BLACK)
|
|
|
|
plane.lines_to_fade.set_stroke(width = 0)
|
|
|
|
|
|
|
|
v_line = Line(UP, DOWN).scale(SPACE_HEIGHT)
|
|
|
|
v_line.set_stroke(WHITE, 5)
|
|
|
|
|
|
|
|
self.add(colorings, v_line, planes)
|
|
|
|
self.play(*it.chain(
|
|
|
|
[
|
|
|
|
ApplyMethod(coloring.set_fill, {"opacity" : 0.2})
|
|
|
|
for coloring in colorings
|
|
|
|
],
|
|
|
|
[
|
|
|
|
ApplyMethod(plane.white_parts.highlight, WHITE)
|
|
|
|
for plane in planes
|
|
|
|
]
|
|
|
|
), run_time = 2)
|
|
|
|
|
|
|
|
# circle
|
|
|
|
circle = Circle(color = WHITE, radius = 2.25)
|
|
|
|
circle.flip(axis = RIGHT)
|
|
|
|
circle.insert_n_anchor_points(50)
|
2018-03-12 14:02:08 -07:00
|
|
|
circle.next_to(
|
|
|
|
input_coloring.get_corner(self.input_plane_corner),
|
|
|
|
-self.input_plane_corner,
|
|
|
|
SMALL_BUFF
|
|
|
|
)
|
2018-03-08 19:40:49 -08:00
|
|
|
circle.set_stroke(width = 5)
|
|
|
|
circle_image = circle.copy()
|
|
|
|
circle.match_background_image_file(input_coloring)
|
|
|
|
circle_image.match_background_image_file(output_coloring)
|
|
|
|
|
|
|
|
def update_circle_image(circle_image):
|
|
|
|
circle_image.points = circle.points
|
|
|
|
circle_image.apply_function(self.point_function)
|
|
|
|
circle_image.make_smooth()
|
|
|
|
|
|
|
|
circle_image_update_anim = UpdateFromFunc(
|
|
|
|
circle_image, update_circle_image
|
|
|
|
)
|
|
|
|
|
|
|
|
self.play(
|
|
|
|
ShowCreation(circle),
|
|
|
|
ShowCreation(circle_image),
|
|
|
|
run_time = 3,
|
|
|
|
rate_func = bezier([0, 0, 1, 1])
|
|
|
|
)
|
|
|
|
self.play(
|
2018-03-11 15:42:25 -07:00
|
|
|
circle.scale, 0,
|
2018-03-12 14:02:08 -07:00
|
|
|
circle.move_to, input_plane.coords_to_point(*self.target_coords),
|
2018-03-08 19:40:49 -08:00
|
|
|
circle_image_update_anim,
|
2018-03-12 14:02:08 -07:00
|
|
|
run_time = self.shrink_time,
|
2018-03-08 19:40:49 -08:00
|
|
|
rate_func = bezier([0, 0, 1, 1])
|
|
|
|
)
|
|
|
|
|
2018-03-12 14:02:08 -07:00
|
|
|
class AltForeverNarrowingLoop(ForeverNarrowingLoop):
|
|
|
|
CONFIG = {
|
|
|
|
"target_coords" : (-2, -1),
|
|
|
|
"input_plane_corner" : DOWN+LEFT,
|
|
|
|
"shrink_time" : 3,
|
|
|
|
}
|
|
|
|
|
2018-03-08 19:40:49 -08:00
|
|
|
class FailureOfComposition(ColorMappedObjectsScene):
|
|
|
|
CONFIG = {
|
|
|
|
"func" : lambda p : (
|
|
|
|
np.cos(TAU*p[1]/3.5),
|
|
|
|
np.sin(TAU*p[1]/3.5)
|
|
|
|
)
|
|
|
|
}
|
|
|
|
def construct(self):
|
|
|
|
ColorMappedObjectsScene.construct(self)
|
|
|
|
|
|
|
|
big_square = Square(side_length = 4)
|
|
|
|
big_square.move_to(ORIGIN, RIGHT)
|
|
|
|
small_squares = VGroup(*[
|
|
|
|
Square(side_length = 2) for x in range(2)
|
|
|
|
])
|
|
|
|
small_squares.match_width(big_square, stretch = True)
|
|
|
|
small_squares.arrange_submobjects(DOWN, buff = 0)
|
|
|
|
small_squares.move_to(big_square)
|
|
|
|
small_squares.space_out_submobjects(1.1)
|
|
|
|
all_squares = VGroup(big_square, *small_squares)
|
|
|
|
all_squares.set_stroke(width = 6)
|
|
|
|
|
|
|
|
for square in all_squares:
|
|
|
|
square.highlight(WHITE)
|
|
|
|
square.color_using_background_image(self.background_image_file)
|
|
|
|
|
|
|
|
question = TextMobject("Does my border go through every color?")
|
|
|
|
question.to_edge(UP)
|
|
|
|
no_answers = VGroup()
|
|
|
|
yes_answers = VGroup()
|
|
|
|
for square in all_squares:
|
|
|
|
if square is big_square:
|
|
|
|
square.answer = TextMobject("Yes")
|
|
|
|
square.answer.highlight(GREEN)
|
|
|
|
yes_answers.add(square.answer)
|
|
|
|
else:
|
|
|
|
square.answer = TextMobject("No")
|
|
|
|
square.answer.highlight(RED)
|
|
|
|
no_answers.add(square.answer)
|
|
|
|
square.answer.move_to(square)
|
|
|
|
|
|
|
|
no_answers_in_equation = no_answers.copy()
|
|
|
|
yes_answers_in_equation = yes_answers.copy()
|
|
|
|
plus, equals = plus_equals = TexMobject("+=")
|
|
|
|
equation = VGroup(
|
|
|
|
no_answers_in_equation[0], plus,
|
|
|
|
no_answers_in_equation[1], equals,
|
|
|
|
yes_answers_in_equation
|
|
|
|
)
|
|
|
|
equation.arrange_submobjects(RIGHT, buff = SMALL_BUFF)
|
|
|
|
equation.next_to(big_square, RIGHT, MED_LARGE_BUFF)
|
|
|
|
q_marks = TexMobject("???")
|
|
|
|
q_marks.next_to(equals, UP)
|
2018-03-06 18:26:07 -08:00
|
|
|
|
|
|
|
|
2018-03-08 19:40:49 -08:00
|
|
|
self.add(question)
|
|
|
|
self.play(LaggedStart(ShowCreation, small_squares, lag_ratio = 0.8))
|
|
|
|
self.play(LaggedStart(Write, no_answers))
|
|
|
|
self.wait()
|
|
|
|
self.play(
|
|
|
|
small_squares.arrange_submobjects, DOWN, {"buff" : 0},
|
|
|
|
small_squares.move_to, big_square,
|
|
|
|
no_answers.space_out_submobjects, 0.9,
|
|
|
|
)
|
|
|
|
self.add(big_square)
|
|
|
|
no_answers_copy = no_answers.copy()
|
|
|
|
small_squares.save_state()
|
|
|
|
self.play(
|
|
|
|
Transform(no_answers, no_answers_in_equation),
|
|
|
|
Write(plus_equals),
|
|
|
|
small_squares.set_stroke, {"width" : 0},
|
|
|
|
)
|
|
|
|
self.play(
|
|
|
|
Write(yes_answers),
|
|
|
|
Write(yes_answers_in_equation),
|
|
|
|
)
|
2018-03-08 20:49:04 -08:00
|
|
|
self.play(LaggedStart(FadeIn, q_marks, run_time = 1, lag_ratio = 0.8))
|
2018-03-08 19:40:49 -08:00
|
|
|
self.wait(2)
|
|
|
|
self.play(
|
|
|
|
small_squares.restore,
|
|
|
|
FadeOut(yes_answers),
|
|
|
|
FadeIn(no_answers_copy),
|
|
|
|
)
|
|
|
|
self.wait()
|
|
|
|
self.play(
|
|
|
|
small_squares.set_stroke, {"width" : 0},
|
|
|
|
FadeOut(no_answers_copy),
|
|
|
|
FadeIn(yes_answers),
|
|
|
|
)
|
|
|
|
self.wait()
|
|
|
|
|
|
|
|
# We can find a better notion of what we want
|
|
|
|
|
|
|
|
cross = Cross(question)
|
|
|
|
|
|
|
|
self.play(
|
|
|
|
ShowCreation(cross, run_time = 2),
|
|
|
|
FadeOut(equation),
|
|
|
|
FadeOut(no_answers),
|
|
|
|
FadeOut(q_marks),
|
|
|
|
FadeOut(yes_answers),
|
|
|
|
)
|
|
|
|
|
|
|
|
x, plus, y = x_plus_y = TexMobject("x+y")
|
|
|
|
x_plus_y.move_to(big_square)
|
|
|
|
x_plus_y.save_state()
|
|
|
|
x.move_to(no_answers_copy[0])
|
|
|
|
y.move_to(no_answers_copy[1])
|
|
|
|
plus.fade(1)
|
|
|
|
|
|
|
|
for square, char in zip(small_squares, [x, y]):
|
|
|
|
ghost = square.copy()
|
|
|
|
ghost.set_stroke(width = 5)
|
|
|
|
ghost.background_image_file = None
|
|
|
|
self.play(
|
|
|
|
small_squares.restore,
|
|
|
|
ShowPassingFlash(ghost),
|
|
|
|
Write(char)
|
|
|
|
)
|
|
|
|
self.wait()
|
|
|
|
ghost = big_square.copy()
|
|
|
|
ghost.background_image_file = None
|
|
|
|
self.play(
|
|
|
|
small_squares.set_stroke, {"width" : 0},
|
|
|
|
x_plus_y.restore,
|
|
|
|
)
|
|
|
|
self.play(ShowPassingFlash(ghost))
|
|
|
|
self.wait()
|
|
|
|
|
2018-03-20 13:44:51 -07:00
|
|
|
class PathContainingZero(InputOutputScene, PiCreatureScene):
|
|
|
|
CONFIG = {
|
|
|
|
"default_pi_creature_kwargs" : {
|
|
|
|
"flip_at_start" : False,
|
|
|
|
"height" : 1.5,
|
|
|
|
},
|
|
|
|
"default_pi_creature_start_corner" : DOWN+LEFT,
|
|
|
|
}
|
|
|
|
def construct(self):
|
|
|
|
self.setup_planes()
|
|
|
|
self.draw_path_hitting_zero()
|
|
|
|
self.comment_on_zero()
|
|
|
|
|
|
|
|
def setup_planes(self):
|
|
|
|
colorings = VGroup(*self.get_colorings())
|
|
|
|
self.input_coloring, self.output_coloring = colorings
|
|
|
|
colorings.set_fill(opacity = 0.3)
|
|
|
|
|
|
|
|
planes = VGroup(*self.get_planes())
|
|
|
|
self.input_plane, self.output_plane = planes
|
|
|
|
for plane in planes:
|
|
|
|
# plane.white_parts.highlight(BLACK)
|
|
|
|
plane.lines_to_fade.set_stroke(width = 0)
|
|
|
|
|
|
|
|
v_line = Line(UP, DOWN).scale(SPACE_HEIGHT)
|
|
|
|
v_line.set_stroke(WHITE, 5)
|
|
|
|
|
|
|
|
self.add(colorings, planes)
|
|
|
|
self.add(v_line)
|
|
|
|
|
|
|
|
def draw_path_hitting_zero(self):
|
|
|
|
morty = self.pi_creature
|
|
|
|
|
|
|
|
path = self.path = VMobject(
|
|
|
|
stroke_width = 5,
|
|
|
|
stroke_color = WHITE,
|
|
|
|
fill_opacity = 0,
|
|
|
|
)
|
|
|
|
path.match_background_image_file(self.input_coloring)
|
|
|
|
path.set_points_smoothly(list(it.starmap(
|
|
|
|
self.input_plane.coords_to_point,
|
|
|
|
[(1, 2.5), (2.5, 2.5), (2, 0.5), (1, 1), (0.5, 1), (0.5, 2), (1, 2.5)]
|
|
|
|
)))
|
|
|
|
|
|
|
|
out_path = self.out_path = path.copy()
|
|
|
|
out_path.apply_function(self.point_function)
|
|
|
|
out_path.match_background_image_file(self.output_coloring)
|
|
|
|
out_path.make_smooth()
|
|
|
|
|
|
|
|
self.play(
|
|
|
|
Flash(
|
|
|
|
VectorizedPoint(self.output_plane.coords_to_point(0, 0)),
|
|
|
|
color = WHITE,
|
|
|
|
flash_radius = 0.3,
|
|
|
|
line_length = 0.2,
|
|
|
|
num_lines = 13,
|
|
|
|
rate_func = squish_rate_func(smooth, 0.5, 0.6),
|
|
|
|
),
|
|
|
|
morty.change, "pondering",
|
|
|
|
*[
|
|
|
|
ShowCreation(mob, rate_func = bezier([0, 0, 1, 1]))
|
|
|
|
for mob in path, out_path
|
|
|
|
],
|
|
|
|
run_time = 5
|
|
|
|
)
|
|
|
|
|
|
|
|
def comment_on_zero(self):
|
|
|
|
morty = self.pi_creature
|
|
|
|
|
|
|
|
words = TextMobject(
|
|
|
|
"Output is zero \\\\",
|
|
|
|
"which has no direction"
|
|
|
|
)
|
|
|
|
origin = self.output_plane.coords_to_point(0, 0)
|
|
|
|
words.to_edge(DOWN, buff = LARGE_BUFF)
|
|
|
|
background_rect = BackgroundRectangle(
|
|
|
|
words, buff = SMALL_BUFF,
|
|
|
|
opacity = 1.0
|
|
|
|
)
|
|
|
|
background_rect.stretch_to_fit_width(0.1)
|
|
|
|
|
|
|
|
arrow = Arrow(words.get_top(), origin)
|
|
|
|
|
|
|
|
circles = VGroup()
|
|
|
|
for point in self.input_plane.coords_to_point(1, 1), origin:
|
|
|
|
circle = Circle(color = BLACK, radius = 0.5, stroke_width = 0)
|
|
|
|
circle.move_to(point)
|
|
|
|
circle.generate_target()
|
|
|
|
circle.target.scale(0)
|
|
|
|
circle.target.set_stroke(width = 4)
|
|
|
|
circles.add(circle)
|
|
|
|
in_circle, out_circle = circles
|
|
|
|
|
|
|
|
new_words = TextMobject(
|
|
|
|
"But we want $\\vec{\\textbf{x}}$ \\\\",
|
|
|
|
"where $f(\\vec{\\textbf{x}}) = 0$",
|
|
|
|
)
|
|
|
|
new_words.move_to(words)
|
|
|
|
|
|
|
|
self.play(
|
|
|
|
FadeIn(background_rect),
|
|
|
|
Write(words[0]),
|
|
|
|
GrowArrow(arrow),
|
|
|
|
)
|
|
|
|
self.play(
|
|
|
|
Write(words[1]),
|
|
|
|
morty.change, "pleading",
|
|
|
|
MoveToTarget(out_circle, run_time = 2)
|
|
|
|
)
|
|
|
|
self.wait()
|
|
|
|
self.play(FadeOut(words))
|
|
|
|
self.play(
|
|
|
|
FadeIn(new_words),
|
|
|
|
morty.change, "happy"
|
|
|
|
)
|
|
|
|
self.play(MoveToTarget(in_circle, run_time = 2))
|
|
|
|
self.play(morty.change, "hooray")
|
|
|
|
self.wait(3)
|
|
|
|
|
2018-03-20 16:32:47 -07:00
|
|
|
class BackToEquationSolving(AltTeacherStudentsScene):
|
|
|
|
def construct(self):
|
|
|
|
self.teacher_says(
|
|
|
|
"Back to solving \\\\ equations"
|
|
|
|
)
|
|
|
|
self.change_all_student_modes("hooray")
|
|
|
|
self.play(*[
|
|
|
|
ApplyMethod(pi.look_at, self.screen)
|
|
|
|
for pi in self.pi_creatures
|
|
|
|
])
|
|
|
|
self.wait(3)
|
|
|
|
|
|
|
|
class SearchSpacePerimeterVsArea(Scene):
|
|
|
|
def construct(self):
|
|
|
|
pass
|
2018-03-20 13:44:51 -07:00
|
|
|
|
2018-03-20 12:58:17 -07:00
|
|
|
class EndingCredits(Scene):
|
|
|
|
def construct(self):
|
|
|
|
text = TextMobject(
|
|
|
|
"Written and animated by: \\\\",
|
|
|
|
"Sridhar Ramesh \\\\",
|
|
|
|
"Grant Sanderson"
|
|
|
|
)
|
|
|
|
text[0].shift(MED_SMALL_BUFF*UP)
|
|
|
|
self.play(LaggedStart(FadeIn, text))
|
|
|
|
self.wait()
|
2018-03-06 18:26:07 -08:00
|
|
|
|
2018-03-20 12:58:17 -07:00
|
|
|
class MentionQAndA(TeacherStudentsScene):
|
|
|
|
def construct(self):
|
|
|
|
pass
|
2018-03-06 18:26:07 -08:00
|
|
|
|
2018-03-20 12:58:17 -07:00
|
|
|
class PatreonScroll(Scene):
|
|
|
|
CONFIG = {
|
|
|
|
"specific_patrons" : [
|
|
|
|
"Juan Benet",
|
|
|
|
"Chloe Zhou",
|
|
|
|
"Ross Garber",
|
|
|
|
"Randall Hunt",
|
|
|
|
"Desmos",
|
|
|
|
"Burt Humburg",
|
|
|
|
"CrypticSwarm",
|
|
|
|
"Sergei",
|
|
|
|
"Devin Scott",
|
|
|
|
"George John",
|
|
|
|
"Akash Kumar",
|
|
|
|
"Felix Tripier",
|
|
|
|
"Arthur Zey",
|
|
|
|
"David Kedmey",
|
|
|
|
"Ali Yahya",
|
|
|
|
"Mayank M. Mehrotra",
|
|
|
|
"Lukas Biewald",
|
|
|
|
"Yana Chernobilsky",
|
|
|
|
"Kaustuv DeBiswas",
|
|
|
|
"Yu Jun",
|
|
|
|
"Dave Nicponski",
|
|
|
|
"Damion Kistler",
|
|
|
|
"Patrick Mézard",
|
|
|
|
"Jordan Scales",
|
|
|
|
"Markus Persson",
|
|
|
|
"Britt Selvitelle",
|
|
|
|
"Jonathan Wilson",
|
|
|
|
"Ryan Atallah",
|
|
|
|
"Joseph John Cox",
|
|
|
|
"Luc Ritchie",
|
|
|
|
"Steven Tomlinson",
|
|
|
|
"Mèngzi Yì",
|
|
|
|
"Jameel Syed",
|
|
|
|
"Bong Choung",
|
|
|
|
"Ignacio Freiberg",
|
|
|
|
"Zhilong Yang",
|
|
|
|
"Karl Niu",
|
|
|
|
"Dan Esposito (Guardion)",
|
|
|
|
"Michael Kunze",
|
|
|
|
"Giovanni Filippi",
|
|
|
|
"Eric Younge",
|
|
|
|
"Prasant Jagannath",
|
|
|
|
"Cody Brocious",
|
|
|
|
"Jacob Kohl",
|
|
|
|
"James H. Park",
|
|
|
|
"Norton Wang",
|
|
|
|
"Kevin Le",
|
|
|
|
"Alexander Feldman",
|
|
|
|
"Tianyu Ge",
|
|
|
|
"David MacCumber",
|
|
|
|
"Oliver Steele",
|
|
|
|
"Yaw Etse",
|
|
|
|
"David B",
|
|
|
|
"Waleed Hamied",
|
|
|
|
"George Chiesa",
|
|
|
|
"Supershabam",
|
|
|
|
"Samantha D. Suplee",
|
|
|
|
"Delton Ding",
|
|
|
|
"Thomas Tarler",
|
|
|
|
"Jonathan Eppele",
|
|
|
|
"Isak Hietala",
|
|
|
|
"1stViewMaths",
|
|
|
|
"Jacob Magnuson",
|
|
|
|
"Mark Govea",
|
|
|
|
"Clark Gaebel",
|
|
|
|
"Mathias Jansson",
|
|
|
|
"David Clark",
|
|
|
|
"Michael Gardner",
|
|
|
|
"Mads Elvheim",
|
|
|
|
"Awoo",
|
|
|
|
"Dr David G. Stork",
|
|
|
|
"Ted Suzman",
|
|
|
|
"Linh Tran",
|
|
|
|
"Andrew Busey",
|
|
|
|
"John Haley",
|
|
|
|
"Ankalagon",
|
|
|
|
"Eric Lavault",
|
|
|
|
"Boris Veselinovich",
|
|
|
|
"Julian Pulgarin",
|
|
|
|
"Jeff Linse",
|
|
|
|
"Cooper Jones",
|
|
|
|
"Ryan Dahl",
|
|
|
|
"Robert Teed",
|
|
|
|
"Jason Hise",
|
|
|
|
"Meshal Alshammari",
|
|
|
|
"Bernd Sing",
|
|
|
|
"James Thornton",
|
|
|
|
"Mustafa Mahdi",
|
|
|
|
"Mathew Bramson",
|
|
|
|
"Jerry Ling",
|
|
|
|
"Shìmín Ku$\\overline{\\text{a}}$ng",
|
|
|
|
"Rish Kundalia",
|
|
|
|
"Achille Brighton",
|
|
|
|
"Ripta Pasay",
|
|
|
|
],
|
|
|
|
"random_seed" : 3,
|
|
|
|
}
|
|
|
|
def construct(self):
|
|
|
|
patreon_logo = PatreonLogo()
|
|
|
|
patreon_logo.to_corner(UP+RIGHT)
|
|
|
|
patreon_logo.shift(SMALL_BUFF*LEFT)
|
|
|
|
self.add(patreon_logo)
|
|
|
|
|
|
|
|
patrons = VGroup(*map(TextMobject, self.specific_patrons))
|
|
|
|
patrons.scale(0.75)
|
|
|
|
random.shuffle(patrons.submobjects)
|
|
|
|
patrons.arrange_submobjects(DOWN, aligned_edge = LEFT)
|
|
|
|
patrons.next_to(ORIGIN, DOWN)
|
|
|
|
patrons.to_edge(RIGHT)
|
|
|
|
|
|
|
|
# patorons = patrons[:10] ##TO remove
|
|
|
|
|
|
|
|
scroll = AmbientMovement(patrons, direction = UP, rate = 1)
|
|
|
|
def patrons_opacity_update(patrons):
|
|
|
|
for patron in patrons:
|
|
|
|
y = patron.get_center()[1]
|
|
|
|
if y > 3.5:
|
|
|
|
patrons.remove(patron)
|
|
|
|
alpha = smooth(np.clip(2.5 - y, 0, 1))
|
|
|
|
patron.set_fill(opacity = alpha)
|
|
|
|
opacity_update = ContinualUpdateFromFunc(patrons, patrons_opacity_update)
|
|
|
|
|
|
|
|
self.add(scroll, opacity_update)
|
|
|
|
self.wait(55)
|
2018-03-06 18:26:07 -08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|