3b1b-manim/from_3b1b/active/ldm.py
2020-05-30 16:49:57 -07:00

1445 lines
42 KiB
Python

from manimlib.imports import *
from from_3b1b.active.bayes.beta_helpers 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,
"specific_patrons": [
"1stViewMaths",
"Adam Dřínek",
"Adam Margulies",
"Aidan Shenkman",
"Alan Stein",
"Alex Mijalis",
"Alexander Mai",
"Alexis Olson",
"Ali Yahya",
"Andreas Snekloth Kongsgaard",
"Andrew Busey",
"Andrew Cary",
"Andrew R. Whalley",
"Anthony Losego",
"Aravind C V",
"Arjun Chakroborty",
"Arthur Zey",
"Ashwin Siddarth",
"Augustine Lim",
"Austin Goodman",
"Avi Finkel",
"Awoo",
"Axel Ericsson",
"Ayan Doss",
"AZsorcerer",
"Barry Fam",
"Bartosz Burclaf",
"Ben Delo",
"Bernd Sing",
"Bill Gatliff",
"Bob Sanderson",
"Boris Veselinovich",
"Bradley Pirtle",
"Brandon Huang",
"Brendan Shah",
"Brian Cloutier",
"Brian Staroselsky",
"Britt Selvitelle",
"Britton Finley",
"Burt Humburg",
"Calvin Lin",
"Charles Southerland",
"Charlie N",
"Chenna Kautilya",
"Chris Connett",
"Chris Druta",
"Christian Kaiser",
"cinterloper",
"Clark Gaebel",
"Colwyn Fritze-Moor",
"Cooper Jones",
"Corey Ogburn",
"D. Sivakumar",
"Dan Herbatschek",
"Daniel Herrera C",
"Darrell Thomas",
"Dave B",
"Dave Cole",
"Dave Kester",
"dave nicponski",
"David B. Hill",
"David Clark",
"David Gow",
"Delton Ding",
"Eduardo Rodriguez",
"Emilio Mendoza Palafox",
"emptymachine",
"Eric Younge",
"Eryq Ouithaqueue",
"Federico Lebron",
"Fernando Via Canel",
"Frank R. Brown, Jr.",
"Giovanni Filippi",
"Goodwine",
"Hal Hildebrand",
"Heptonion",
"Hitoshi Yamauchi",
"Ivan Sorokin",
"Jacob Baxter",
"Jacob Harmon",
"Jacob Hartmann",
"Jacob Magnuson",
"Jalex Stark",
"Jameel Syed",
"James Beall",
"Jason Hise",
"Jayne Gabriele",
"Jean-Manuel Izaret",
"Jeff Dodds",
"Jeff Linse",
"Jeff Straathof",
"Jeffrey Wolberg",
"Jimmy Yang",
"Joe Pregracke",
"Johan Auster",
"John C. Vesey",
"John Camp",
"John Haley",
"John Le",
"John Luttig",
"John Rizzo",
"John V Wertheim",
"Jonathan Heckerman",
"Jonathan Wilson",
"Joseph John Cox",
"Joseph Kelly",
"Josh Kinnear",
"Joshua Claeys",
"Joshua Ouellette",
"Juan Benet",
"Julien Dubois",
"Kai-Siang Ang",
"Kanan Gill",
"Karl Niu",
"Kartik Cating-Subramanian",
"Kaustuv DeBiswas",
"Killian McGuinness",
"kkm",
"Klaas Moerman",
"Kristoffer Börebäck",
"Kros Dai",
"L0j1k",
"Lael S Costa",
"LAI Oscar",
"Lambda GPU Workstations",
"Laura Gast",
"Lee Redden",
"Linh Tran",
"Luc Ritchie",
"Ludwig Schubert",
"Lukas Biewald",
"Lukas Zenick",
"Magister Mugit",
"Magnus Dahlström",
"Magnus Hiie",
"Manoj Rewatkar",
"Mark B Bahu",
"Mark Heising",
"Mark Hopkins",
"Mark Mann",
"Martin Price",
"Mathias Jansson",
"Matt Godbolt",
"Matt Langford",
"Matt Roveto",
"Matt Russell",
"Matteo Delabre",
"Matthew Bouchard",
"Matthew Cocke",
"Maxim Nitsche",
"Michael Bos",
"Michael Day",
"Michael Hardel",
"Michael W White",
"Mihran Vardanyan",
"Mirik Gogri",
"Molly Mackinlay",
"Mustafa Mahdi",
"Márton Vaitkus",
"Nate Heckmann",
"Nero Li",
"Nicholas Cahill",
"Nikita Lesnikov",
"Oleg Leonov",
"Oliver Steele",
"Omar Zrien",
"Omer Tuchfeld",
"Patrick Lucas",
"Pavel Dubov",
"Pesho Ivanov",
"Petar Veličković",
"Peter Ehrnstrom",
"Peter Francis",
"Peter Mcinerney",
"Pierre Lancien",
"Pradeep Gollakota",
"Rafael Bove Barrios",
"Raghavendra Kotikalapudi",
"Randy C. Will",
"rehmi post",
"Rex Godby",
"Ripta Pasay",
"Rish Kundalia",
"Roman Sergeychik",
"Roobie",
"Ryan Atallah",
"Samuel Judge",
"SansWord Huang",
"Scott Gray",
"Scott Walter, Ph.D.",
"soekul",
"Solara570",
"Stephen Shanahan",
"Steve Huynh",
"Steve Muench",
"Steve Sperandeo",
"Steven Siddals",
"Stevie Metke",
"Sundar Subbarayan",
"Sunil Nagaraj",
"supershabam",
"Suteerth Vishnu",
"Suthen Thomas",
"Tal Einav",
"Taras Bobrovytsky",
"Tauba Auerbach",
"Ted Suzman",
"Thomas J Sargent",
"Thomas Tarler",
"Tianyu Ge",
"Tihan Seale",
"Tim Erbes",
"Tim Kazik",
"Tomasz Legutko",
"Tyler Herrmann",
"Tyler Parcell",
"Tyler VanValkenburg",
"Tyler Veness",
"Vassili Philippov",
"Vasu Dubey",
"Veritasium",
"Vignesh Ganapathi Subramanian",
"Vinicius Reis",
"Vladimir Solomatin",
"Wooyong Ee",
"Xuanji Li",
"Yana Chernobilsky",
"Yavor Ivanov",
"YinYangBalance.Asia",
"Yu Jun",
"Yurii Monastyrshyn",
],
}