3b1b-videos/_2020/ldm.py

1243 lines
36 KiB
Python
Raw Normal View History

from manim_imports_ext import *
import math
class StreamIntro(Scene):
def construct(self):
# Add logo
logo = Logo()
spikes = VGroup(*[
spike
for layer in logo.spike_layers
for spike in layer
])
self.add(*logo.family_members_with_points())
# Add label
label = TextMobject("The lesson will\\\\begin shortly")
label.scale(2)
label.next_to(logo, DOWN)
self.add(label)
self.camera.frame.move_to(DOWN)
for spike in spikes:
point = spike.get_start()
spike.angle = angle_of_vector(point)
anims = []
for spike in spikes:
anims.append(Rotate(
spike, spike.angle * 28 * 2,
about_point=ORIGIN,
rate_func=linear,
))
self.play(*anims, run_time=60 * 5)
self.wait(20)
class OldStreamIntro(Scene):
def construct(self):
morty = Mortimer()
morty.flip()
morty.set_height(2)
morty.to_corner(DL)
self.play(PiCreatureSays(
morty, "The lesson will\\\\begin soon.",
bubble_kwargs={
"height": 2,
"width": 3,
},
target_mode="hooray",
))
bound = AnimatedBoundary(morty.bubble.content, max_stroke_width=1)
self.add(bound, morty.bubble, morty.bubble.content)
self.remove(morty.bubble.content)
morty.bubble.set_fill(opacity=0)
self.camera.frame.scale(0.6, about_edge=DL)
self.play(Blink(morty))
self.wait(5)
self.play(Blink(morty))
self.wait(3)
return
text = TextMobject("The lesson will\\\\begin soon.")
text.set_height(1.5)
text.to_corner(DL, buff=LARGE_BUFF)
self.add(text)
class QuadraticFormula(TeacherStudentsScene):
def construct(self):
formula = TexMobject(
"\\frac{-b \\pm \\sqrt{b^2 - 4ac}}{2a}",
)
formula.next_to(self.students, UP, buff=MED_LARGE_BUFF, aligned_edge=LEFT)
self.add(formula)
self.change_student_modes(
"angry", "tired", "sad",
look_at_arg=formula,
)
self.teacher_says(
"It doesn't have\\\\to be this way.",
bubble_kwargs={
"width": 4,
"height": 3,
}
)
self.wait(5)
self.change_student_modes(
"pondering", "thinking", "erm",
look_at_arg=formula
)
self.wait(12)
class SimplerQuadratic(Scene):
def construct(self):
tex = TexMobject("m \\pm \\sqrt{m^2 - p}")
tex.set_stroke(BLACK, 12, background=True)
tex.scale(1.5)
self.add(tex)
class CosGraphs(Scene):
def construct(self):
axes = Axes(
x_min=-0.75 * TAU,
x_max=0.75 * TAU,
y_min=-1.5,
y_max=1.5,
x_axis_config={
"tick_frequency": PI / 4,
"include_tip": False,
},
y_axis_config={
"tick_frequency": 0.5,
"include_tip": False,
"unit_size": 1.5,
}
)
graph1 = axes.get_graph(np.cos)
graph2 = axes.get_graph(lambda x: np.cos(x)**2)
graph1.set_stroke(YELLOW, 5)
graph2.set_stroke(BLUE, 5)
label1 = TexMobject("\\cos(x)")
label2 = TexMobject("\\cos^2(x)")
label1.match_color(graph1)
label1.set_height(0.75)
label1.next_to(axes.input_to_graph_point(-PI, graph1), DOWN)
label2.match_color(graph2)
label2.set_height(0.75)
label2.next_to(axes.input_to_graph_point(PI, graph2), UP)
for mob in [graph1, graph2, label1, label2]:
mc = mob.copy()
mc.set_stroke(BLACK, 10, background=True)
self.add(mc)
self.add(axes)
self.add(graph1)
self.add(graph2)
self.add(label1)
self.add(label2)
self.embed()
class SineWave(Scene):
def construct(self):
w_axes = self.get_wave_axes()
square, circle, c_axes = self.get_edge_group()
self.add(w_axes)
self.add(square, circle, c_axes)
theta_tracker = ValueTracker(0)
c_dot = Dot(color=YELLOW)
c_line = Line(DOWN, UP, color=GREEN)
w_dot = Dot(color=YELLOW)
w_line = Line(DOWN, UP, color=GREEN)
def update_c_dot(dot, axes=c_axes, tracker=theta_tracker):
theta = tracker.get_value()
dot.move_to(axes.c2p(
np.cos(theta),
np.sin(theta),
))
def update_c_line(line, axes=c_axes, tracker=theta_tracker):
theta = tracker.get_value()
x = np.cos(theta)
y = np.sin(theta)
if y == 0:
y = 1e-6
line.put_start_and_end_on(
axes.c2p(x, 0),
axes.c2p(x, y),
)
def update_w_dot(dot, axes=w_axes, tracker=theta_tracker):
theta = tracker.get_value()
dot.move_to(axes.c2p(theta, np.sin(theta)))
def update_w_line(line, axes=w_axes, tracker=theta_tracker):
theta = tracker.get_value()
x = theta
y = np.sin(theta)
if y == 0:
y = 1e-6
line.put_start_and_end_on(
axes.c2p(x, 0),
axes.c2p(x, y),
)
def get_partial_circle(circle=circle, tracker=theta_tracker):
result = circle.copy()
theta = tracker.get_value()
result.pointwise_become_partial(
circle, 0, clip(theta / TAU, 0, 1),
)
result.set_stroke(RED, width=3)
return result
def get_partial_wave(axes=w_axes, tracker=theta_tracker):
theta = tracker.get_value()
graph = axes.get_graph(np.sin, x_min=0, x_max=theta, step_size=0.025)
graph.set_stroke(BLUE, 3)
return graph
def get_h_line(axes=w_axes, tracker=theta_tracker):
theta = tracker.get_value()
return Line(
axes.c2p(0, 0),
axes.c2p(theta, 0),
stroke_color=RED
)
c_dot.add_updater(update_c_dot)
c_line.add_updater(update_c_line)
w_dot.add_updater(update_w_dot)
w_line.add_updater(update_w_line)
partial_circle = always_redraw(get_partial_circle)
partial_wave = always_redraw(get_partial_wave)
h_line = always_redraw(get_h_line)
self.add(partial_circle)
self.add(partial_wave)
self.add(h_line)
self.add(c_line, c_dot)
self.add(w_line, w_dot)
sin_label = TexMobject(
"\\sin\\left(\\theta\\right)",
tex_to_color_map={"\\theta": RED}
)
sin_label.next_to(w_axes.get_top(), UR)
self.add(sin_label)
self.play(
theta_tracker.set_value, 1.25 * TAU,
run_time=15,
rate_func=linear,
)
def get_wave_axes(self):
wave_axes = Axes(
x_min=0,
x_max=1.25 * TAU,
y_min=-1.0,
y_max=1.0,
x_axis_config={
"tick_frequency": TAU / 8,
"unit_size": 1.0,
},
y_axis_config={
"tick_frequency": 0.5,
"include_tip": False,
"unit_size": 1.5,
}
)
wave_axes.y_axis.add_numbers(
-1, 1, number_config={"num_decimal_places": 1}
)
wave_axes.to_edge(RIGHT, buff=MED_SMALL_BUFF)
pairs = [
(PI / 2, "\\frac{\\pi}{2}"),
(PI, "\\pi"),
(3 * PI / 2, "\\frac{3\\pi}{2}"),
(2 * PI, "2\\pi"),
]
syms = VGroup()
for val, tex in pairs:
sym = TexMobject(tex)
sym.scale(0.5)
sym.next_to(wave_axes.c2p(val, 0), DOWN, MED_SMALL_BUFF)
syms.add(sym)
wave_axes.add(syms)
theta = TexMobject("\\theta")
theta.set_color(RED)
theta.next_to(wave_axes.x_axis.get_end(), UP)
wave_axes.add(theta)
return wave_axes
def get_edge_group(self):
axes_max = 1.25
radius = 1.5
axes = Axes(
x_min=-axes_max,
x_max=axes_max,
y_min=-axes_max,
y_max=axes_max,
axis_config={
"tick_frequency": 0.5,
"include_tip": False,
"numbers_with_elongated_ticks": [-1, 1],
"tick_size": 0.05,
"unit_size": radius,
},
)
axes.to_edge(LEFT, buff=MED_LARGE_BUFF)
background = SurroundingRectangle(axes, buff=MED_SMALL_BUFF)
background.set_stroke(WHITE, 1)
background.set_fill(GREY_E, 1)
circle = Circle(radius=radius)
circle.move_to(axes)
circle.set_stroke(WHITE, 1)
nums = VGroup()
for u in 1, -1:
num = Integer(u)
num.set_height(0.2)
num.set_stroke(BLACK, 3, background=True)
num.next_to(axes.c2p(u, 0), DOWN + u * RIGHT, SMALL_BUFF)
nums.add(num)
axes.add(nums)
return background, circle, axes
class CosWave(SineWave):
CONFIG = {
"include_square": False,
}
def construct(self):
w_axes = self.get_wave_axes()
square, circle, c_axes = self.get_edge_group()
self.add(w_axes)
self.add(square, circle, c_axes)
theta_tracker = ValueTracker(0)
c_dot = Dot(color=YELLOW)
c_line = Line(DOWN, UP, color=GREEN)
w_dot = Dot(color=YELLOW)
w_line = Line(DOWN, UP, color=GREEN)
def update_c_dot(dot, axes=c_axes, tracker=theta_tracker):
theta = tracker.get_value()
dot.move_to(axes.c2p(
np.cos(theta),
np.sin(theta),
))
def update_c_line(line, axes=c_axes, tracker=theta_tracker):
theta = tracker.get_value()
x = np.cos(theta)
y = np.sin(theta)
line.set_points_as_corners([
axes.c2p(0, y),
axes.c2p(x, y),
])
def update_w_dot(dot, axes=w_axes, tracker=theta_tracker):
theta = tracker.get_value()
dot.move_to(axes.c2p(theta, np.cos(theta)))
def update_w_line(line, axes=w_axes, tracker=theta_tracker):
theta = tracker.get_value()
x = theta
y = np.cos(theta)
if y == 0:
y = 1e-6
line.set_points_as_corners([
axes.c2p(x, 0),
axes.c2p(x, y),
])
def get_partial_circle(circle=circle, tracker=theta_tracker):
result = circle.copy()
theta = tracker.get_value()
result.pointwise_become_partial(
circle, 0, clip(theta / TAU, 0, 1),
)
result.set_stroke(RED, width=3)
return result
def get_partial_wave(axes=w_axes, tracker=theta_tracker):
theta = tracker.get_value()
graph = axes.get_graph(np.cos, x_min=0, x_max=theta, step_size=0.025)
graph.set_stroke(PINK, 3)
return graph
def get_h_line(axes=w_axes, tracker=theta_tracker):
theta = tracker.get_value()
return Line(
axes.c2p(0, 0),
axes.c2p(theta, 0),
stroke_color=RED
)
def get_square(line=c_line):
square = Square()
square.set_stroke(WHITE, 1)
square.set_fill(MAROON_B, opacity=0.5)
square.match_width(line)
square.move_to(line, DOWN)
return square
def get_square_graph(axes=w_axes, tracker=theta_tracker):
theta = tracker.get_value()
graph = axes.get_graph(
lambda x: np.cos(x)**2, x_min=0, x_max=theta, step_size=0.025
)
graph.set_stroke(MAROON_B, 3)
return graph
c_dot.add_updater(update_c_dot)
c_line.add_updater(update_c_line)
w_dot.add_updater(update_w_dot)
w_line.add_updater(update_w_line)
h_line = always_redraw(get_h_line)
partial_circle = always_redraw(get_partial_circle)
partial_wave = always_redraw(get_partial_wave)
self.add(partial_circle)
self.add(partial_wave)
self.add(h_line)
self.add(c_line, c_dot)
self.add(w_line, w_dot)
if self.include_square:
self.add(always_redraw(get_square))
self.add(always_redraw(get_square_graph))
cos_label = TexMobject(
"\\cos\\left(\\theta\\right)",
tex_to_color_map={"\\theta": RED}
)
cos_label.next_to(w_axes.get_top(), UR)
self.add(cos_label)
self.play(
theta_tracker.set_value, 1.25 * TAU,
run_time=15,
rate_func=linear,
)
class CosSquare(CosWave):
CONFIG = {
"include_square": True
}
class ComplexNumberPreview(Scene):
def construct(self):
plane = ComplexPlane(axis_config={"stroke_width": 4})
plane.add_coordinates()
z = complex(2, 1)
dot = Dot()
dot.move_to(plane.n2p(z))
label = TexMobject("2+i")
label.set_color(YELLOW)
dot.set_color(YELLOW)
label.next_to(dot, UR, SMALL_BUFF)
label.set_stroke(BLACK, 5, background=True)
line = Line(plane.n2p(0), plane.n2p(z))
arc = Arc(start_angle=0, angle=np.log(z).imag, radius=0.5)
self.add(plane)
self.add(line, arc)
self.add(dot)
self.add(label)
self.embed()
class ComplexMultiplication(Scene):
def construct(self):
# Add plane
plane = ComplexPlane()
plane.add_coordinates()
z = complex(2, 1)
z_dot = Dot(color=PINK)
z_dot.move_to(plane.n2p(z))
z_label = TexMobject("z")
z_label.next_to(z_dot, UR, buff=0.5 * SMALL_BUFF)
z_label.match_color(z_dot)
self.add(plane)
self.add(z_dot)
self.add(z_label)
# Show 1
one_vect = Vector(RIGHT)
one_vect.set_color(YELLOW)
one_vect.target = Vector(plane.n2p(z))
one_vect.target.match_style(one_vect)
z_rhs = TexMobject("=", "z \\cdot 1")
z_rhs[1].match_color(one_vect)
z_rhs.next_to(z_label, RIGHT, 1.5 * SMALL_BUFF, aligned_edge=DOWN)
z_rhs.set_stroke(BLACK, 3, background=True)
one_label, i_label = [l for l in plane.coordinate_labels if l.get_value() == 1]
self.play(GrowArrow(one_vect))
self.wait()
self.add(one_vect, z_dot)
self.play(
MoveToTarget(one_vect),
TransformFromCopy(one_label, z_rhs),
)
self.wait()
# Show i
i_vect = Vector(UP, color=GREEN)
zi_point = plane.n2p(z * complex(0, 1))
i_vect.target = Vector(zi_point)
i_vect.target.match_style(i_vect)
i_vect_label = TexMobject("z \\cdot i")
i_vect_label.match_color(i_vect)
i_vect_label.set_stroke(BLACK, 3, background=True)
i_vect_label.next_to(zi_point, UL, SMALL_BUFF)
self.play(GrowArrow(i_vect))
self.wait()
self.play(
MoveToTarget(i_vect),
TransformFromCopy(i_label, i_vect_label),
run_time=1,
)
self.wait()
self.play(
TransformFromCopy(one_vect, i_vect.target, path_arc=-90 * DEGREES),
)
self.wait()
# Transform plane
plane.generate_target()
for mob in plane.target.family_members_with_points():
if isinstance(mob, Line):
mob.set_stroke(GREY, opacity=0.5)
new_plane = ComplexPlane(faded_line_ratio=0)
self.remove(plane)
self.add(plane, new_plane, *self.mobjects)
new_plane.generate_target()
new_plane.target.apply_complex_function(lambda w, z=z: w * z)
self.play(
MoveToTarget(plane),
MoveToTarget(new_plane),
run_time=6,
rate_func=there_and_back_with_pause
)
self.wait()
# Show Example Point
w = complex(2, -1)
w_dot = Dot(plane.n2p(w), color=WHITE)
one_vects = VGroup(*[Vector(RIGHT) for x in range(2)])
one_vects.arrange(RIGHT, buff=0)
one_vects.move_to(plane.n2p(0), LEFT)
one_vects.set_color(YELLOW)
new_i_vect = Vector(DOWN)
new_i_vect.move_to(plane.n2p(2), UP)
new_i_vect.set_color(GREEN)
vects = VGroup(*one_vects, new_i_vect)
vects.set_opacity(0.8)
w_group = VGroup(*vects, w_dot)
w_group.target = VGroup(
one_vect.copy().set_opacity(0.8),
one_vect.copy().shift(plane.n2p(z)).set_opacity(0.8),
i_vect.copy().rotate(PI, about_point=ORIGIN).shift(2 * plane.n2p(z)).set_opacity(0.8),
Dot(plane.n2p(w * z), color=WHITE)
)
self.play(FadeInFromLarge(w_dot))
self.wait()
self.play(ShowCreation(vects))
self.wait()
self.play(
MoveToTarget(plane),
MoveToTarget(new_plane),
MoveToTarget(w_group),
run_time=2,
path_arc=np.log(z).imag,
)
self.wait()
class RotatePiCreature(Scene):
def construct(self):
randy = Randolph(mode="thinking")
randy.set_height(6)
plane = ComplexPlane(x_min=-12, x_max=12)
plane.add_coordinates()
self.camera.frame.move_to(3 * RIGHT)
self.add(randy)
self.wait()
self.play(Rotate(randy, 30 * DEGREES, run_time=3))
self.wait()
self.play(Rotate(randy, -30 * DEGREES))
self.add(plane, randy)
self.play(
ShowCreation(plane),
randy.set_opacity, 0.75,
)
self.wait()
dots = VGroup()
for mob in randy.family_members_with_points():
for point in mob.get_anchors():
dot = Dot(point)
dot.set_height(0.05)
dots.add(dot)
self.play(ShowIncreasingSubsets(dots))
self.wait()
label = VGroup(
TexMobject("(x + iy)"),
Vector(DOWN),
TexMobject("(\\cos(30^\\circ) + i\\sin(30^\\circ))", "(x + iy)"),
)
label[2][0].set_color(YELLOW)
label.arrange(DOWN)
label.to_corner(DR)
label.shift(3 * RIGHT)
for mob in label:
mob.add_background_rectangle()
self.play(FadeIn(label))
self.wait()
randy.add(dots)
self.play(Rotate(randy, 30 * DEGREES), run_time=3)
self.wait()
class ExpMeaning(Scene):
CONFIG = {
"include_circle": True
}
def construct(self):
# Plane
plane = ComplexPlane(y_min=-6, y_max=6)
plane.shift(1.5 * DOWN)
plane.add_coordinates()
if self.include_circle:
circle = Circle(radius=1)
circle.set_stroke(RED, 1)
circle.move_to(plane.n2p(0))
plane.add(circle)
# Equation
equation = TexMobject(
"\\text{exp}(i\\theta) = ",
"1 + ",
"i\\theta + ",
"{(i\\theta)^2 \\over 2} + ",
"{(i\\theta)^3 \\over 6} + ",
"{(i\\theta)^4 \\over 24} + ",
"\\cdots",
tex_to_color_map={
"\\theta": YELLOW,
"i": GREEN,
},
)
equation.add_background_rectangle(buff=MED_SMALL_BUFF, opacity=1)
equation.to_edge(UL, buff=0)
# Label
theta_tracker = ValueTracker(0)
theta_label = VGroup(
TexMobject("\\theta = "),
DecimalNumber(0, num_decimal_places=4)
)
theta_decimal = theta_label[1]
theta_decimal.add_updater(
lambda m, tt=theta_tracker: m.set_value(tt.get_value())
)
theta_label.arrange(RIGHT, buff=SMALL_BUFF)
theta_label.set_color(YELLOW)
theta_label.add_to_back(BackgroundRectangle(
theta_label,
buff=MED_SMALL_BUFF,
fill_opacity=1,
))
theta_label.next_to(equation, DOWN, aligned_edge=LEFT, buff=0)
# Vectors
def get_vectors(n_vectors=20, plane=plane, tracker=theta_tracker):
last_tip = plane.n2p(0)
z = complex(0, tracker.get_value())
vects = VGroup()
colors = color_gradient([GREEN, YELLOW, RED], 6)
for i, color in zip(range(n_vectors), it.cycle(colors)):
vect = Vector(complex_to_R3(z**i / math.factorial(i)))
vect.set_color(color)
vect.shift(last_tip)
last_tip = vect.get_end()
vects.add(vect)
return vects
vectors = always_redraw(get_vectors)
dot = Dot()
dot.set_height(0.03)
dot.add_updater(lambda m, vs=vectors: m.move_to(vs[-1].get_end()))
self.add(plane)
self.add(vectors)
self.add(dot)
self.add(equation)
self.add(theta_label)
self.play(
theta_tracker.set_value, 1,
run_time=3,
rate_func=smooth,
)
self.wait()
for target in PI, TAU:
self.play(
theta_tracker.set_value, target,
run_time=10,
)
self.wait()
self.embed()
class ExpMeaningWithoutCircle(ExpMeaning):
CONFIG = {
"include_circle": False,
}
class PositionAndVelocityExample(Scene):
def construct(self):
plane = NumberPlane()
self.add(plane)
self.embed()
class EulersFormula(Scene):
def construct(self):
kw = {"tex_to_color_map": {"\\theta": YELLOW}}
formula = TexMobject(
"&e^{i\\theta} = \\\\ &\\cos\\left(\\theta\\right) + i\\cdot\\sin\\left(\\theta\\right)",
)[0]
formula[:4].scale(2, about_edge=UL)
formula[:4].shift(SMALL_BUFF * RIGHT + MED_LARGE_BUFF * UP)
VGroup(formula[2], formula[8], formula[17]).set_color(YELLOW)
formula.scale(1.5)
formula.set_stroke(BLACK, 5, background=True)
self.add(formula)
class EtoILimit(Scene):
def construct(self):
tex = TexMobject(
"\\lim_{n \\to \\infty} \\left(1 + \\frac{it}{n}\\right)^n",
)[0]
VGroup(tex[3], tex[12], tex[14]).set_color(YELLOW)
tex[9].set_color(BLUE)
tex.scale(1.5)
tex.set_stroke(BLACK, 5, background=True)
# self.add(tex)
text = TextMobject("Interest rate\\\\of ", "$\\sqrt{-1}$")
text[1].set_color(BLUE)
text.scale(1.5)
text.set_stroke(BLACK, 5, background=True)
self.add(text)
class ImaginaryInterestRates(Scene):
def construct(self):
plane = ComplexPlane(x_min=-20, x_max=20, y_min=-20, y_max=20)
plane.add_coordinates()
circle = Circle(radius=1)
circle.set_stroke(YELLOW, 1)
self.add(plane, circle)
frame = self.camera.frame
frame.save_state()
frame.generate_target()
frame.target.set_width(25)
frame.target.move_to(8 * RIGHT + 2 * DOWN)
dt_tracker = ValueTracker(1)
def get_vectors(tracker=dt_tracker, plane=plane, T=8):
dt = tracker.get_value()
last_z = 1
vects = VGroup()
for t in np.arange(0, T, dt):
next_z = last_z + complex(0, 1) * last_z * dt
vects.add(Arrow(
plane.n2p(last_z),
plane.n2p(next_z),
buff=0,
))
last_z = next_z
vects.set_submobject_colors_by_gradient(YELLOW, GREEN, BLUE)
return vects
vects = get_vectors()
line = Line()
line.add_updater(lambda m, v=vects: m.put_start_and_end_on(
ORIGIN, v[-1].get_start() if len(v) > 0 else RIGHT,
))
self.add(line)
self.play(
ShowIncreasingSubsets(
vects,
rate_func=linear,
int_func=np.ceil,
),
MoveToTarget(
frame,
rate_func=squish_rate_func(smooth, 0.5, 1),
),
run_time=8,
)
self.wait()
self.play(FadeOut(line))
self.remove(vects)
vects = always_redraw(get_vectors)
self.add(vects)
self.play(
Restore(frame),
dt_tracker.set_value, 0.2,
run_time=5,
)
self.wait()
self.play(dt_tracker.set_value, 0.01, run_time=3)
vects.clear_updaters()
self.wait()
theta_tracker = ValueTracker(0)
def get_arc(tracker=theta_tracker):
theta = tracker.get_value()
arc = Arc(
radius=1,
stroke_width=3,
stroke_color=RED,
start_angle=0,
angle=theta
)
return arc
arc = always_redraw(get_arc)
dot = Dot()
dot.add_updater(lambda m, arc=arc: m.move_to(arc.get_end()))
label = VGroup(
DecimalNumber(0, num_decimal_places=3),
TextMobject("Years")
)
label.arrange(RIGHT, aligned_edge=DOWN)
label.move_to(3 * LEFT + 1.5 * UP)
label[0].set_color(RED)
label[0].add_updater(lambda m, tt=theta_tracker: m.set_value(tt.get_value()))
self.add(BackgroundRectangle(label), label, arc, dot)
for n in range(1, 5):
target = n * PI / 2
self.play(
theta_tracker.set_value, target,
run_time=3
)
self.wait(2)
class Logs(Scene):
def construct(self):
log = TexMobject(
"&\\text{log}(ab) = \\\\ &\\text{log}(a) + \\text{log}(b)",
tex_to_color_map={"a": BLUE, "b": YELLOW},
alignment="",
)
log.scale(1.5)
log.set_stroke(BLACK, 5, background=True)
self.add(log)
class LnX(Scene):
def construct(self):
sym = TexMobject("\\ln(x)")
sym.scale(3)
sym.shift(UP)
sym.set_stroke(BLACK, 5, background=True)
word = TextMobject("Natural?")
word.scale(1.5)
word.set_color(YELLOW)
word.set_stroke(BLACK, 5, background=True)
word.next_to(sym, DOWN, buff=0.5)
arrow = Arrow(word.get_top(), sym[0][1].get_bottom())
self.add(sym, word, arrow)
class HarmonicSum(Scene):
def construct(self):
axes = Axes(
x_min=0,
x_max=13,
y_min=0,
y_max=1.25,
y_axis_config={
"unit_size": 4,
"tick_frequency": 0.25,
}
)
axes.to_corner(DL, buff=1)
axes.x_axis.add_numbers()
axes.y_axis.add_numbers(
*np.arange(0.25, 1.25, 0.25),
number_config={"num_decimal_places": 2},
)
self.add(axes)
graph = axes.get_graph(lambda x: 1 / x, x_min=0.1, x_max=15)
graph_fill = graph.copy()
graph_fill.add_line_to(axes.c2p(15, 0))
graph_fill.add_line_to(axes.c2p(1, 0))
graph_fill.add_line_to(axes.c2p(1, 1))
graph.set_stroke(WHITE, 3)
graph_fill.set_fill(BLUE_E, 0.5)
graph_fill.set_stroke(width=0)
self.add(graph, graph_fill)
bars = VGroup()
bar_labels = VGroup()
for x in range(1, 15):
line = Line(axes.c2p(x, 0), axes.c2p(x + 1, 1 / x))
bar = Rectangle()
bar.set_fill(GREEN_E, 1)
bar.replace(line, stretch=True)
bars.add(bar)
label = TexMobject(f"1 \\over {x}")
label.set_height(0.7)
label.next_to(bar, UP, SMALL_BUFF)
bar_labels.add(label)
bars.set_submobject_colors_by_gradient(GREEN_C, GREEN_E)
bars.set_stroke(WHITE, 1)
bars.set_fill(opacity=0.25)
self.add(bars)
self.add(bar_labels)
self.embed()
class PowerTower(Scene):
def construct(self):
mob = TexMobject("4 = x^{x^{{x^{x^{x^{\cdot^{\cdot^{\cdot}}}}}}}}")
mob[0][-1].shift(0.1 * DL)
mob[0][-2].shift(0.05 * DL)
mob.set_height(4)
mob.set_stroke(BLACK, 5, background=True)
self.add(mob)
class ItoTheI(Scene):
def construct(self):
tex = TexMobject("i^i")
# tex = TexMobject("\\sqrt{-1}^{\\sqrt{-1}}")
tex.set_height(3)
tex.set_stroke(BLACK, 8, background=True)
self.add(tex)
class ComplexExponentialPlay(Scene):
def setup(self):
self.transform_alpha = 0
def construct(self):
# Plane
plane = ComplexPlane(
x_min=-2 * FRAME_WIDTH,
x_max=2 * FRAME_WIDTH,
y_min=-2 * FRAME_HEIGHT,
y_max=2 * FRAME_HEIGHT,
)
plane.add_coordinates()
self.add(plane)
# R Dot
r_dot = Dot(color=YELLOW)
def update_r_dot(dot, point_tracker=self.mouse_drag_point):
point = point_tracker.get_location()
if abs(point[0]) < 0.1:
point[0] = 0
if abs(point[1]) < 0.1:
point[1] = 0
dot.move_to(point)
r_dot.add_updater(update_r_dot)
self.mouse_drag_point.move_to(plane.n2p(1))
# Transformed sample dots
def func(z, dot=r_dot, plane=plane):
r = plane.p2n(dot.get_center())
result = np.exp(r * z)
if abs(result) > 20:
result *= 20 / abs(result)
return result
sample_dots = VGroup()
dot_template = Dot(radius=0.05)
dot_template.set_opacity(0.8)
spacing = 0.05
for x in np.arange(-7, 7, spacing):
dot = dot_template.copy()
dot.set_color(TEAL)
dot.z = x
dot.move_to(plane.n2p(dot.z))
sample_dots.add(dot)
for y in np.arange(-6, 6, spacing):
dot = dot_template.copy()
dot.set_color(MAROON)
dot.z = complex(0, y)
dot.move_to(plane.n2p(dot.z))
sample_dots.add(dot)
special_values = [1, complex(0, 1), -1, complex(0, -1)]
special_dots = VGroup(*[
list(filter(lambda d: abs(d.z - x) < 0.01, sample_dots))[0]
for x in special_values
])
for dot in special_dots:
dot.set_fill(opacity=1)
dot.scale(1.2)
dot.set_stroke(WHITE, 2)
sample_dots.save_state()
def update_sample(sample, f=func, plane=plane, scene=self):
sample.restore()
sample.apply_function_to_submobject_positions(
lambda p: interpolate(
p,
plane.n2p(f(plane.p2n(p))),
scene.transform_alpha,
)
)
return sample
sample_dots.add_updater(update_sample)
# Sample lines
x_line = Line(plane.n2p(plane.x_min), plane.n2p(plane.x_max))
y_line = Line(plane.n2p(plane.y_min), plane.n2p(plane.y_max))
y_line.rotate(90 * DEGREES)
x_line.set_color(GREEN)
y_line.set_color(PINK)
axis_lines = VGroup(x_line, y_line)
for line in axis_lines:
line.insert_n_curves(50)
axis_lines.save_state()
def update_axis_liens(lines=axis_lines, f=func, plane=plane, scene=self):
lines.restore()
lines.apply_function(
lambda p: interpolate(
p,
plane.n2p(f(plane.p2n(p))),
scene.transform_alpha,
)
)
lines.make_smooth()
axis_lines.add_updater(update_axis_liens)
# Labels
labels = VGroup(
TexMobject("f(1)"),
TexMobject("f(i)"),
TexMobject("f(-1)"),
TexMobject("f(-i)"),
)
for label, dot in zip(labels, special_dots):
label.set_height(0.3)
label.match_color(dot)
label.set_stroke(BLACK, 3, background=True)
label.add_background_rectangle(opacity=0.5)
def update_labels(labels, dots=special_dots, scene=self):
for label, dot in zip(labels, dots):
label.next_to(dot, UR, 0.5 * SMALL_BUFF)
label.set_opacity(self.transform_alpha)
labels.add_updater(update_labels)
# Titles
title = TexMobject(
"f(x) =", "\\text{exp}(r\\cdot x)",
tex_to_color_map={"r": YELLOW}
)
title.to_corner(UL)
title.set_stroke(BLACK, 5, background=True)
brace = Brace(title[1:], UP, buff=SMALL_BUFF)
e_pow = TexMobject("e^{rx}", tex_to_color_map={"r": YELLOW})
e_pow.add_background_rectangle()
e_pow.next_to(brace, UP, buff=SMALL_BUFF)
title.add(brace, e_pow)
r_eq = VGroup(
TexMobject("r=", tex_to_color_map={"r": YELLOW}),
DecimalNumber(1)
)
r_eq.arrange(RIGHT, aligned_edge=DOWN)
r_eq.next_to(title, DOWN, aligned_edge=LEFT)
r_eq[0].set_stroke(BLACK, 5, background=True)
r_eq[1].set_color(YELLOW)
r_eq[1].add_updater(lambda m: m.set_value(plane.p2n(r_dot.get_center())))
self.add(title)
self.add(r_eq)
# self.add(axis_lines)
self.add(sample_dots)
self.add(r_dot)
self.add(labels)
# Animations
def update_transform_alpha(mob, alpha, scene=self):
scene.transform_alpha = alpha
frame = self.camera.frame
frame.set_height(10)
r_dot.clear_updaters()
r_dot.move_to(plane.n2p(1))
self.play(
UpdateFromAlphaFunc(
VectorizedPoint(),
update_transform_alpha,
)
)
self.play(r_dot.move_to, plane.n2p(2))
self.wait()
self.play(r_dot.move_to, plane.n2p(PI))
self.wait()
self.play(r_dot.move_to, plane.n2p(np.log(2)))
self.wait()
self.play(r_dot.move_to, plane.n2p(complex(0, np.log(2))), path_arc=90 * DEGREES, run_time=2)
self.wait()
self.play(r_dot.move_to, plane.n2p(complex(0, PI / 2)))
self.wait()
self.play(r_dot.move_to, plane.n2p(np.log(2)), run_time=2)
self.wait()
self.play(frame.set_height, 14)
self.play(r_dot.move_to, plane.n2p(complex(np.log(2), PI)), run_time=3)
self.wait()
self.play(r_dot.move_to, plane.n2p(complex(np.log(2), TAU)), run_time=3)
self.wait()
self.embed()
def on_mouse_scroll(self, point, offset):
frame = self.camera.frame
if self.zoom_on_scroll:
factor = 1 + np.arctan(10 * offset[1])
frame.scale(factor, about_point=ORIGIN)
else:
self.transform_alpha = clip(self.transform_alpha + 5 * offset[1], 0, 1)
class LDMEndScreen(PatreonEndScreen):
CONFIG = {
"scroll_time": 20,
}
class ProbDiagram(Scene):
def construct(self):
square = Square(side_length=1)
square.move_to(ORIGIN, DL)
square.set_stroke(width=0)
square.set_fill(BLUE_E, 1)
frame = self.camera.frame
frame.set_height(1.5)
frame.move_to(square)
tri = Polygon(ORIGIN, UP, UR)
tri.set_fill(BLUE_E, 1)
tri.set_stroke(width=0)
tris = VGroup(tri)
N = 1000
for n in range(1, N):
tri = Polygon(
ORIGIN,
RIGHT + UP / n,
RIGHT + UP / (n + 1),
)
tri.set_stroke(width=0)
color = BLUE_E if (n % 2 == 0) else RED_D
tri.set_fill(color, 1)
tris.add(tri)
self.add(tris)