3b1b-manim/old_projects/efvgt.py

3435 lines
107 KiB
Python
Raw Normal View History

2017-02-23 14:13:30 -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 *
from animation.playground 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.complex_numbers import *
2017-02-23 14:13:30 -08:00
from scene import Scene
from scene.zoomed_scene import ZoomedScene
from scene.reconfigurable_scene import ReconfigurableScene
from camera import Camera
from mobject.svg_mobject import *
from mobject.tex_mobject import *
2017-03-02 00:43:13 -08:00
from eoc.chapter1 import PatreonThanks
2017-02-27 15:56:22 -08:00
ADDER_COLOR = GREEN
MULTIPLIER_COLOR = YELLOW
def normalize(vect):
norm = np.linalg.norm(vect)
if norm == 0:
return OUT
else:
return vect/norm
def get_composite_rotation_angle_and_axis(angles, axes):
2017-02-27 15:56:22 -08:00
angle1, axis1 = 0, OUT
for angle2, axis2 in zip(angles, axes):
## Figure out what (angle3, axis3) is the same
## as first applying (angle1, axis1), then (angle2, axis2)
axis2 = normalize(axis2)
dot = np.dot(axis2, axis1)
cross = np.cross(axis2, axis1)
angle3 = 2*np.arccos(
np.cos(angle2/2)*np.cos(angle1/2) - \
np.sin(angle2/2)*np.sin(angle1/2)*dot
)
2017-02-27 15:56:22 -08:00
axis3 = (
np.sin(angle2/2)*np.cos(angle1/2)*axis2 + \
np.cos(angle2/2)*np.sin(angle1/2)*axis1 + \
np.sin(angle2/2)*np.sin(angle1/2)*cross
)
axis3 = normalize(axis3)
angle1, axis1 = angle3, axis3
2017-02-27 15:56:22 -08:00
if angle1 > np.pi:
angle1 -= 2*np.pi
return angle1, axis1
2017-02-23 14:13:30 -08:00
class ConfettiSpiril(Animation):
CONFIG = {
"x_start" : 0,
2017-02-27 15:56:22 -08:00
"spiril_radius" : 0.5,
2017-02-23 14:13:30 -08:00
"num_spirils" : 4,
"run_time" : 10,
"rate_func" : None,
}
def __init__(self, mobject, **kwargs):
digest_config(self, kwargs)
mobject.next_to(self.x_start*RIGHT + SPACE_HEIGHT*UP, UP)
self.total_vert_shift = \
2*SPACE_HEIGHT + mobject.get_height() + 2*MED_SMALL_BUFF
Animation.__init__(self, mobject, **kwargs)
def update_submobject(self, submobject, starting_submobject, alpha):
submobject.points = np.array(starting_submobject.points)
def update_mobject(self, alpha):
Animation.update_mobject(self, alpha)
angle = alpha*self.num_spirils*2*np.pi
vert_shift = alpha*self.total_vert_shift
start_center = self.mobject.get_center()
self.mobject.shift(self.spiril_radius*OUT)
self.mobject.rotate(angle, axis = UP, about_point = start_center)
self.mobject.shift(vert_shift*DOWN)
class Anniversary(TeacherStudentsScene):
CONFIG = {
"num_confetti_squares" : 50,
}
def construct(self):
self.celebrate()
self.complain()
def celebrate(self):
title = TextMobject("2 year Anniversary!")
title.scale(1.5)
title.to_edge(UP)
first_video = Rectangle(
height = 2, width = 2*(16.0/9),
stroke_color = WHITE,
fill_color = "#111111",
fill_opacity = 0.75,
)
first_video.next_to(self.get_teacher(), UP+LEFT)
first_video.shift(RIGHT)
formula = TexMobject("e^{\\pi i} = -1")
formula.move_to(first_video)
first_video.add(formula)
hats = self.get_party_hats()
confetti_spirils = self.get_confetti_animations()
self.play(
Write(title, run_time = 2),
*[
ApplyMethod(pi.change_mode, "hooray")
for pi in self.get_pi_creatures()
]
)
self.play(
DrawBorderThenFill(
hats,
submobject_mode = "lagged_start",
rate_func = None,
run_time = 2,
),
*confetti_spirils + [
Succession(
Animation(pi, run_time = 2),
ApplyMethod(pi.look, UP+LEFT),
ApplyMethod(pi.look, UP+RIGHT),
Animation(pi),
ApplyMethod(pi.look_at, first_video),
rate_func = None
)
for pi in self.get_students()
] + [
Succession(
Animation(self.get_teacher(), run_time = 2),
Blink(self.get_teacher()),
Animation(self.get_teacher(), run_time = 2),
ApplyMethod(self.get_teacher().change_mode, "raise_right_hand"),
rate_func = None
),
DrawBorderThenFill(
first_video,
run_time = 10,
rate_func = squish_rate_func(smooth, 0.5, 0.7)
)
]
)
self.change_student_modes(*["confused"]*3)
def complain(self):
self.student_says(
"Why were you \\\\ talking so fast?",
2017-02-23 14:13:30 -08:00
student_index = 0,
target_mode = "sassy",
)
self.change_student_modes(*["sassy"]*3)
self.play(self.get_teacher().change_mode, "shruggie")
2017-02-23 14:13:30 -08:00
self.dither(2)
def get_party_hats(self):
hats = VGroup(*[
PartyHat(
pi_creature = pi,
height = 0.5*pi.get_height()
)
for pi in self.get_pi_creatures()
])
max_angle = np.pi/6
for hat in hats:
hat.rotate(
random.random()*2*max_angle - max_angle,
about_point = hat.get_bottom()
)
return hats
def get_confetti_animations(self):
colors = [RED, YELLOW, GREEN, BLUE, PURPLE, RED]
confetti_squares = [
Square(
side_length = 0.2,
stroke_width = 0,
fill_opacity = 0.5,
fill_color = random.choice(colors),
)
for x in range(self.num_confetti_squares)
]
confetti_spirils = [
ConfettiSpiril(
square,
x_start = 2*random.random()*SPACE_WIDTH - SPACE_WIDTH,
rate_func = squish_rate_func(lambda t : t, a, a+0.5)
)
for a, square in zip(
np.linspace(0, 0.5, self.num_confetti_squares),
confetti_squares
)
]
return confetti_spirils
2017-03-02 00:43:13 -08:00
class HomomophismPreview(Scene):
def construct(self):
raise Exception("Meant as a place holder, not to be excecuted")
class WatchingScreen(PiCreatureScene):
CONFIG = {
"screen_height" : 5.5
}
def create_pi_creatures(self):
randy = Randolph().to_corner(DOWN+LEFT)
return VGroup(randy)
2017-02-23 14:13:30 -08:00
def construct(self):
screen = Rectangle(height = 9, width = 16)
screen.scale_to_fit_height(self.screen_height)
screen.to_corner(UP+RIGHT)
self.add(screen)
for mode in "erm", "pondering", "confused":
self.dither()
self.change_mode(mode)
self.play(Animation(screen))
self.dither()
class LetsStudyTheBasics(TeacherStudentsScene):
def construct(self):
2017-03-02 00:43:13 -08:00
self.teacher_says("Let's learn some \\\\ group theory!")
self.change_student_modes(*["hooray"]*3)
self.dither(2)
2017-02-23 14:13:30 -08:00
2017-03-03 17:33:06 -08:00
class JustGiveMeAQuickExplanation(TeacherStudentsScene):
def construct(self):
self.student_says(
"I ain't got \\\\ time for this!",
target_mode = "angry",
)
self.play(*it.chain(*[
[
pi.change_mode, "hesitant",
pi.look_at, self.get_students()[1].eyes
]
for pi in self.get_students()[::2]
]))
self.dither(2)
class QuickExplanation(ComplexTransformationScene):
CONFIG = {
"plane_config" : {
"x_line_frequency" : 1,
"y_line_frequency" : 1,
"secondary_line_ratio" : 1,
"space_unit_to_x_unit" : 1.5,
"space_unit_to_y_unit" : 1.5,
},
"background_fade_factor" : 0.2,
"background_label_scale_val" : 0.7,
"velocity_color" : RED,
"position_color" : YELLOW,
}
def construct(self):
# self.add_transformable_plane()
self.add_equation()
self.add_explanation()
self.add_vectors()
def add_equation(self):
equation = TexMobject(
"\\frac{d(e^{it})}{dt}",
"=",
"i", "e^{it}"
)
equation[0].highlight(self.velocity_color)
equation[-1].highlight(self.position_color)
equation.add_background_rectangle()
brace = Brace(equation, UP)
equation.add(brace)
brace_text = TextMobject(
"Velocity vector", "is a",
"$90^\\circ$ \\\\ rotation",
"of", "position vector"
)
brace_text[0].highlight(self.velocity_color)
brace_text[-1].highlight(self.position_color)
brace_text.add_background_rectangle()
brace_text.scale(0.8)
brace_text.to_corner(UP+LEFT, buff = MED_SMALL_BUFF)
equation.next_to(brace_text, DOWN)
self.add_foreground_mobjects(brace_text, equation)
self.brace_text = brace_text
def add_explanation(self):
words = TextMobject("""
Only a walk around the unit
circle at rate 1 satisfies both
this property and e^0 = 1.
""")
words.scale(0.8)
words.add_background_rectangle()
words.to_corner(UP+RIGHT, buff = MED_SMALL_BUFF)
arrow = Arrow(RIGHT, 1.5*LEFT, color = WHITE)
arrow.to_edge(UP)
self.add(words, arrow)
def add_vectors(self):
right = self.z_to_point(1)
s_vector = Arrow(
ORIGIN, right,
tip_length = 0.2,
buff = 0,
color = self.position_color,
)
2017-02-23 14:13:30 -08:00
v_vector = s_vector.copy().rotate(np.pi/2)
v_vector.highlight(self.velocity_color)
circle = Circle(
radius = self.z_to_point(1)[0],
color = self.position_color
)
2017-02-23 14:13:30 -08:00
self.dither(2)
self.play(ShowCreation(s_vector))
self.play(ReplacementTransform(
s_vector.copy(), v_vector, path_arc = np.pi/2
))
self.dither()
self.play(v_vector.shift, right)
self.dither()
self.vectors = VGroup(s_vector, v_vector)
kwargs = {
"rate_func" : None,
"run_time" : 5,
}
rotation = Rotating(self.vectors, about_point = ORIGIN, **kwargs)
self.play(
ShowCreation(circle, **kwargs),
rotation
)
self.play(rotation)
self.play(rotation)
2017-02-23 14:13:30 -08:00
class SymmetriesOfSquare(ThreeDScene):
CONFIG = {
"square_config" : {
"side_length" : 2,
"stroke_width" : 0,
"fill_color" : BLUE,
"fill_opacity" : 0.75,
},
"dashed_line_config" : {},
}
def construct(self):
self.add_title()
self.ask_about_square_symmetry()
self.talk_through_90_degree_rotation()
self.talk_through_vertical_flip()
self.confused_by_lack_of_labels()
self.add_labels()
self.show_full_group()
self.show_top_actions()
self.show_bottom_actions()
self.name_dihedral_group()
def add_title(self):
title = TextMobject("Groups", "$\\leftrightarrow$", "Symmetry")
title.to_edge(UP)
2017-02-23 14:13:30 -08:00
for index in 0, 2:
self.play(Write(title[index], run_time = 1))
self.play(GrowFromCenter(title[1]))
self.dither()
self.title = title
def ask_about_square_symmetry(self):
brace = Brace(self.title[-1])
q_marks = brace.get_text("???")
self.square = Square(**self.square_config)
self.play(DrawBorderThenFill(self.square))
self.play(GrowFromCenter(brace), Write(q_marks))
self.rotate_square()
self.dither()
for axis in UP, UP+RIGHT:
self.flip_square(axis)
self.dither()
self.rotate_square(-np.pi)
self.dither()
self.play(*map(FadeOut, [brace, q_marks]))
def talk_through_90_degree_rotation(self):
2017-02-23 22:30:09 -08:00
arcs = self.get_rotation_arcs(self.square, np.pi/2)
self.play(*map(ShowCreation, arcs))
self.dither()
self.rotate_square(np.pi/2, run_time = 2)
self.dither()
self.play(FadeOut(arcs))
self.dither()
def talk_through_vertical_flip(self):
self.flip_square(UP, run_time = 2)
self.dither()
def confused_by_lack_of_labels(self):
randy = Randolph(mode = "confused")
2017-02-23 22:30:09 -08:00
randy.next_to(self.square, LEFT, buff = LARGE_BUFF)
randy.to_edge(DOWN)
self.play(FadeIn(randy))
for axis in OUT, RIGHT, UP:
self.rotate_square(
angle = np.pi, axis = axis,
added_anims = [randy.look_at, self.square.points[0]]
)
self.play(Blink(randy))
self.dither()
self.randy = randy
def add_labels(self):
2017-02-27 15:56:22 -08:00
self.add_randy_to_square(self.square)
2017-02-23 22:30:09 -08:00
self.play(
2017-02-27 15:56:22 -08:00
FadeIn(self.square.randy),
2017-02-23 22:30:09 -08:00
self.randy.change_mode, "happy",
2017-02-27 15:56:22 -08:00
self.randy.look_at, self.square.randy.eyes
2017-02-23 22:30:09 -08:00
)
self.play(Blink(self.randy))
self.play(FadeOut(self.randy))
self.dither()
def show_full_group(self):
2017-02-23 22:30:09 -08:00
new_title = TextMobject("Group", "of", "symmetries")
new_title.move_to(self.title)
all_squares = VGroup(*[
self.square.copy().scale(0.5)
for x in range(8)
])
all_squares.arrange_submobjects(RIGHT, buff = LARGE_BUFF)
top_squares = VGroup(*all_squares[:4])
bottom_squares = VGroup(*all_squares[4:])
bottom_squares.next_to(top_squares, DOWN, buff = LARGE_BUFF)
all_squares.scale_to_fit_width(2*SPACE_WIDTH-2*LARGE_BUFF)
all_squares.center()
all_squares.to_edge(DOWN, buff = LARGE_BUFF)
self.play(ReplacementTransform(self.square, all_squares[0]))
self.play(ReplacementTransform(self.title, new_title))
self.title = new_title
self.play(*[
ApplyMethod(mob.highlight, GREY)
for mob in self.title[1:]
])
for square, angle in zip(all_squares[1:4], [np.pi/2, np.pi, -np.pi/2]):
arcs = self.get_rotation_arcs(square, angle, MED_SMALL_BUFF)
self.play(*map(FadeIn, [square, arcs]))
square.rotation_kwargs = {"angle" : angle}
self.rotate_square(square = square, **square.rotation_kwargs)
square.add(arcs)
for square, axis in zip(bottom_squares, [RIGHT, RIGHT+UP, UP, UP+LEFT]):
axis_line = self.get_axis_line(square, axis)
self.play(FadeIn(square))
self.play(ShowCreation(axis_line))
square.rotation_kwargs = {"angle" : np.pi, "axis" : axis}
self.rotate_square(square = square, **square.rotation_kwargs)
square.add(axis_line)
self.dither()
self.all_squares = all_squares
def show_top_actions(self):
2017-02-23 22:30:09 -08:00
all_squares = self.all_squares
self.play(Indicate(all_squares[0]))
self.dither()
2017-02-27 15:56:22 -08:00
self.play(*[
2017-02-23 22:30:09 -08:00
Rotate(
square,
rate_func = lambda t : -there_and_back(t),
run_time = 3,
about_point = square.get_center(),
**square.rotation_kwargs
)
for square in all_squares[1:4]
2017-02-27 15:56:22 -08:00
])
2017-02-23 22:30:09 -08:00
self.dither()
def show_bottom_actions(self):
2017-02-23 22:30:09 -08:00
for square in self.all_squares[4:]:
self.rotate_square(
square = square,
rate_func = there_and_back,
run_time = 2,
**square.rotation_kwargs
)
self.dither()
def name_dihedral_group(self):
2017-02-23 22:30:09 -08:00
new_title = TextMobject(
"``Dihedral group'' of order 8"
)
new_title.to_edge(UP)
self.play(FadeOut(self.title))
self.play(FadeIn(new_title))
self.dither()
##########
def rotate_square(
self,
angle = np.pi/2,
axis = OUT,
square = None,
show_axis = False,
added_anims = None,
**kwargs
):
if square is None:
assert hasattr(self, "square")
square = self.square
added_anims = added_anims or []
2017-02-23 22:30:09 -08:00
rotation = Rotate(
square,
angle = angle,
axis = axis,
about_point = square.get_center(),
**kwargs
)
if hasattr(square, "labels"):
for label in rotation.target_mobject.labels:
label.rotate_in_place(-angle, axis)
if show_axis:
2017-02-23 22:30:09 -08:00
axis_line = self.get_axis_line(square, axis)
self.play(
ShowCreation(axis_line),
Animation(square)
)
self.play(rotation, *added_anims)
if show_axis:
self.play(
FadeOut(axis_line),
Animation(square)
)
def flip_square(self, axis = UP, **kwargs):
self.rotate_square(
angle = np.pi,
axis = axis,
show_axis = True,
**kwargs
)
2017-02-23 14:13:30 -08:00
2017-02-23 22:30:09 -08:00
def get_rotation_arcs(self, square, angle, angle_buff = SMALL_BUFF):
square_radius = np.linalg.norm(
square.points[0] - square.get_center()
)
arc = Arc(
radius = square_radius + SMALL_BUFF,
start_angle = np.pi/4 + np.sign(angle)*angle_buff,
angle = angle - np.sign(angle)*2*angle_buff,
color = YELLOW
)
arc.add_tip()
2017-02-27 15:56:22 -08:00
if abs(angle) < 3*np.pi/4:
angle_multiple_range = range(1, 4)
else:
angle_multiple_range = [2]
2017-02-23 22:30:09 -08:00
arcs = VGroup(arc, *[
arc.copy().rotate(i*np.pi/2)
for i in angle_multiple_range
2017-02-23 22:30:09 -08:00
])
arcs.move_to(square[0])
2017-02-23 14:13:30 -08:00
2017-02-23 22:30:09 -08:00
return arcs
2017-02-23 14:13:30 -08:00
2017-02-23 22:30:09 -08:00
def get_axis_line(self, square, axis):
axis_line = DashedLine(2*axis, -2*axis, **self.dashed_line_config)
2017-02-23 22:30:09 -08:00
axis_line.replace(square, dim_to_match = np.argmax(np.abs(axis)))
axis_line.scale_in_place(1.2)
return axis_line
2017-02-23 14:13:30 -08:00
def add_labels_and_dots(self, square):
labels = VGroup()
dots = VGroup()
for tex, vertex in zip("ABCD", square.get_anchors()):
label = TexMobject(tex)
label.add_background_rectangle()
label.next_to(vertex, vertex-square.get_center(), SMALL_BUFF)
labels.add(label)
dot = Dot(vertex, color = WHITE)
dots.add(dot)
square.add(labels, dots)
square.labels = labels
square.dots = dots
2017-02-27 15:56:22 -08:00
def add_randy_to_square(self, square, mode = "pondering"):
randy = Randolph(mode = mode)
randy.scale_to_fit_height(0.75*square.get_height())
randy.move_to(square)
square.add(randy)
square.randy = randy
class ManyGroupsAreInfinite(TeacherStudentsScene):
def construct(self):
self.teacher_says("Many groups are infinite")
self.change_student_modes(*["pondering"]*3)
self.dither(2)
class CircleSymmetries(Scene):
CONFIG = {
"circle_radius" : 2,
}
def construct(self):
self.add_circle_and_title()
self.show_range_of_angles()
self.associate_rotations_with_points()
def add_circle_and_title(self):
title = TextMobject("Group of rotations")
title.to_edge(UP)
circle = self.get_circle()
self.play(Write(title), ShowCreation(circle, run_time = 2))
self.dither()
angles = [
np.pi/2, -np.pi/3, 5*np.pi/6,
3*np.pi/2 + 0.1
]
angles.append(-sum(angles))
for angle in angles:
self.play(Rotate(circle, angle = angle))
self.dither()
self.circle = circle
def show_range_of_angles(self):
self.add_radial_line()
arc_circle = self.get_arc_circle()
theta = TexMobject("\\theta = ")
theta_value = DecimalNumber(0.00)
theta_value.next_to(theta, RIGHT)
theta_group = VGroup(theta, theta_value)
theta_group.next_to(arc_circle, UP)
def theta_value_update(theta_value, alpha):
new_theta_value = DecimalNumber(alpha*2*np.pi)
new_theta_value.scale_to_fit_height(theta.get_height())
new_theta_value.next_to(theta, RIGHT)
Transform(theta_value, new_theta_value).update(1)
return new_theta_value
self.play(FadeIn(theta_group))
for rate_func in smooth, lambda t : smooth(1-t):
self.play(
Rotate(self.circle, 2*np.pi-0.001),
ShowCreation(arc_circle),
UpdateFromAlphaFunc(theta_value, theta_value_update),
run_time = 7,
rate_func = rate_func
)
self.dither()
self.play(FadeOut(theta_group))
self.dither()
def associate_rotations_with_points(self):
zero_dot = Dot(self.circle.point_from_proportion(0))
zero_dot.highlight(RED)
zero_arrow = Arrow(UP+RIGHT, ORIGIN)
zero_arrow.highlight(zero_dot.get_color())
zero_arrow.next_to(zero_dot, UP+RIGHT, buff = SMALL_BUFF)
self.play(
ShowCreation(zero_arrow),
DrawBorderThenFill(zero_dot)
)
self.circle.add(zero_dot)
self.dither()
for alpha in 0.2, 0.6, 0.4, 0.8:
point = self.circle.point_from_proportion(alpha)
dot = Dot(point, color = YELLOW)
vect = np.sign(point)
arrow = Arrow(vect, ORIGIN)
arrow.next_to(dot, vect, buff = SMALL_BUFF)
arrow.highlight(dot.get_color())
angle = alpha*2*np.pi
self.play(
ShowCreation(arrow),
DrawBorderThenFill(dot)
)
self.play(
Rotate(self.circle, angle, run_time = 2),
Animation(dot)
)
self.dither()
self.play(
Rotate(self.circle, -angle, run_time = 2),
FadeOut(dot),
FadeOut(arrow),
)
self.dither()
####
def get_circle(self):
circle = Circle(color = MAROON_B, radius = self.circle_radius)
circle.ticks = VGroup()
for alpha in np.arange(0, 1, 1./8):
point = circle.point_from_proportion(alpha)
tick = Line((1 - 0.05)*point, (1 + 0.05)*point)
circle.ticks.add(tick)
circle.add(circle.ticks)
return circle
def add_radial_line(self):
radius = Line(
self.circle.get_center(),
self.circle.point_from_proportion(0)
)
static_radius = radius.copy().highlight(GREY)
self.play(ShowCreation(radius))
self.add(static_radius, radius)
self.circle.radius = radius
self.circle.static_radius = static_radius
self.circle.add(radius)
def get_arc_circle(self):
arc_radius = self.circle_radius/5.0
arc_circle = Circle(
radius = arc_radius,
color = WHITE
)
return arc_circle
class GroupOfCubeSymmetries(ThreeDScene):
CONFIG = {
2017-02-27 15:56:22 -08:00
"cube_opacity" : 0.5,
"cube_colors" : [BLUE],
"put_randy_on_cube" : True,
}
def construct(self):
title = TextMobject("Group of cube symmetries")
title.to_edge(UP)
self.add(title)
cube = self.get_cube()
2017-02-27 15:56:22 -08:00
face_centers = [face.get_center() for face in cube[0:7:2]]
angle_axis_pairs = zip(3*[np.pi/2], face_centers)
for i in range(3):
ones = np.ones(3)
ones[i] = -1
axis = np.dot(ones, face_centers)
angle_axis_pairs.append((2*np.pi/3, axis))
for angle, axis in angle_axis_pairs:
self.play(Rotate(
cube, angle = angle, axis = axis,
run_time = 2
))
self.dither()
def get_cube(self):
cube = Cube(fill_opacity = self.cube_opacity)
cube.gradient_highlight(*self.cube_colors)
2017-02-27 15:56:22 -08:00
if self.put_randy_on_cube:
randy = Randolph(mode = "pondering")
2017-02-28 22:32:43 -08:00
# randy.pupils.shift(0.01*OUT)
# randy.add(randy.pupils.copy().shift(0.02*IN))
# for submob in randy.submobject_family():
# submob.part_of_three_d_mobject = True
2017-02-27 15:56:22 -08:00
randy.scale(0.5)
face = cube[1]
randy.move_to(face)
face.add(randy)
pose_matrix = self.get_pose_matrix()
cube.apply_function(
lambda p : np.dot(p, pose_matrix.T),
maintain_smoothness = False
)
return cube
def get_pose_matrix(self):
return np.dot(
rotation_matrix(np.pi/8, UP),
rotation_matrix(np.pi/24, RIGHT)
)
class HowDoSymmetriesPlayWithEachOther(TeacherStudentsScene):
def construct(self):
self.teacher_says(
"How do symmetries \\\\ play with each other?",
target_mode = "hesitant",
)
self.change_student_modes("pondering", "maybe", "confused")
self.dither(2)
class AddSquareSymmetries(SymmetriesOfSquare):
def construct(self):
square = Square(**self.square_config)
square.flip(RIGHT)
square.shift(DOWN)
2017-02-27 15:56:22 -08:00
self.add_randy_to_square(square, mode = "shruggie")
alt_square = square.copy()
equals = TexMobject("=")
equals.move_to(square)
equation_square = Square(**self.square_config)
equation = VGroup(
equation_square, TexMobject("+"),
equation_square.copy(), TexMobject("="),
equation_square.copy(),
)
equation[0].add(self.get_rotation_arcs(
equation[0], np.pi/2,
))
equation[2].add(self.get_axis_line(equation[4], UP))
equation[4].add(self.get_axis_line(equation[4], UP+RIGHT))
for mob in equation[::2]:
mob.scale(0.5)
equation.arrange_submobjects(RIGHT)
equation.to_edge(UP)
arcs = self.get_rotation_arcs(square, np.pi/2)
self.add(square)
self.play(FadeIn(arcs))
self.rotate_square(
square = square, angle = np.pi/2,
added_anims = map(FadeIn, equation[:2])
)
self.dither()
self.play(FadeOut(arcs))
self.flip_square(
square = square, axis = UP,
added_anims = map(FadeIn, equation[2:4])
)
self.dither()
alt_square.next_to(equals, RIGHT, buff = LARGE_BUFF)
alt_square.save_state()
alt_square.move_to(square)
alt_square.set_fill(opacity = 0)
self.play(
square.next_to, equals, LEFT, LARGE_BUFF,
alt_square.restore,
Write(equals)
)
self.flip_square(
square = alt_square, axis = UP+RIGHT,
added_anims = map(FadeIn, equation[4:]),
)
self.dither(2)
## Reiterate composition
self.rotate_square(square = square, angle = np.pi/2)
self.flip_square(square = square, axis = UP)
self.dither()
self.flip_square(square = alt_square, axis = UP+RIGHT)
self.dither()
class AddCircleSymmetries(CircleSymmetries):
def construct(self):
circle = self.circle = self.get_circle()
arc_circle = self.get_arc_circle()
angles = [3*np.pi/2, 2*np.pi/3, np.pi/6]
arcs = [
arc_circle.copy().scale(scalar)
for scalar in [1, 1.2, 1.4]
]
2017-02-23 14:13:30 -08:00
equation = TexMobject(
"270^\\circ", "+", "120^\\circ", "=", "30^\\circ",
)
equation.to_edge(UP)
colors = [BLUE, YELLOW, GREEN]
for color, arc, term in zip(colors, arcs, equation[::2]):
arc.highlight(color)
term.highlight(color)
self.play(FadeIn(circle))
self.add_radial_line()
alt_radius = circle.radius.copy()
alt_radius.highlight(GREY)
alt_circle = circle.copy()
equals = TexMobject("=")
equals.move_to(circle)
def rotate(circle, angle, arc, terms):
self.play(
Rotate(circle, angle, in_place = True),
ShowCreation(
arc,
rate_func = lambda t : (angle/(2*np.pi))*smooth(t)
),
Write(VGroup(*terms)),
run_time = 2,
)
2017-02-23 14:13:30 -08:00
rotate(circle, angles[0], arcs[0], equation[:2])
self.dither()
circle.add(alt_radius)
rotate(circle, angles[1], arcs[1], equation[2:4])
self.play(FadeOut(alt_radius))
circle.remove(alt_radius)
self.dither()
2017-02-23 14:13:30 -08:00
circle.add(circle.static_radius)
circle.add(*arcs[:2])
2017-02-23 14:13:30 -08:00
alt_static_radius = circle.static_radius.copy()
alt_circle.add(alt_static_radius)
alt_circle.next_to(equals, RIGHT, buff = LARGE_BUFF)
alt_circle.save_state()
alt_circle.move_to(circle)
alt_circle.set_stroke(width = 0)
self.play(
circle.next_to, equals, LEFT, LARGE_BUFF,
alt_circle.restore,
Write(equals)
)
arcs[2].shift(alt_circle.get_center())
alt_circle.remove(alt_static_radius)
self.dither()
rotate(alt_circle, angles[2], arcs[2], equation[4:])
self.dither()
self.play(
Rotate(arcs[1], angles[0], about_point = circle.get_center())
)
self.dither(2)
for term, arc in zip(equation[::2], arcs):
self.play(*[
ApplyMethod(mob.scale_in_place, 1.2, rate_func = there_and_back)
for mob in term, arc
])
self.dither()
2017-02-23 14:13:30 -08:00
class AddCubeSymmetries(GroupOfCubeSymmetries):
CONFIG = {
"angle_axis_pairs" : [
(np.pi/2, RIGHT),
2017-02-27 15:56:22 -08:00
(np.pi/2, UP),
],
"cube_opacity" : 0.5,
"cube_colors" : [BLUE],
}
def construct(self):
angle_axis_pairs = list(self.angle_axis_pairs)
angle_axis_pairs.append(
self.get_composition_angle_and_axis()
)
self.pose_matrix = self.get_pose_matrix()
cube = self.get_cube()
equation = cube1, plus, cube2, equals, cube3 = VGroup(
cube, TexMobject("+"),
cube.copy(), TexMobject("="),
cube.copy()
)
equation.arrange_submobjects(RIGHT, buff = MED_LARGE_BUFF)
equation.center()
self.add(cube1)
self.rotate_cube(cube1, *angle_axis_pairs[0])
cube_copy = cube1.copy()
cube_copy.set_fill(opacity = 0)
self.play(
cube_copy.move_to, cube2,
cube_copy.set_fill, None, self.cube_opacity,
Write(plus)
)
self.rotate_cube(cube_copy, *angle_axis_pairs[1])
self.play(Write(equals))
self.play(DrawBorderThenFill(cube3, run_time = 1))
self.rotate_cube(cube3, *angle_axis_pairs[2])
self.dither(2)
times = TexMobject("\\times")
times.scale(1.5)
times.move_to(plus)
times.highlight(RED)
self.dither()
self.play(ReplacementTransform(plus, times))
self.play(Indicate(times))
self.dither()
for cube, (angle, axis) in zip([cube1, cube_copy, cube3], angle_axis_pairs):
2017-02-27 15:56:22 -08:00
self.rotate_cube(
cube, -angle, axis, add_arrows = False,
rate_func = there_and_back,
run_time = 1.5
)
self.dither()
2017-02-27 15:56:22 -08:00
def rotate_cube(self, cube, angle, axis, add_arrows = True, **kwargs):
axis = np.dot(axis, self.pose_matrix.T)
anims = []
if add_arrows:
arrows = VGroup(*[
Arc(
start_angle = np.pi/12+a, angle = 5*np.pi/6,
color = YELLOW
).add_tip()
for a in 0, np.pi
])
arrows.scale_to_fit_height(1.5*cube.get_height())
z_to_axis = z_to_vector(axis)
arrows.apply_function(
lambda p : np.dot(p, z_to_axis.T),
maintain_smoothness = False
)
arrows.move_to(cube)
arrows.shift(-axis*cube.get_height()/2/np.linalg.norm(axis))
anims += map(ShowCreation, arrows)
anims.append(
2017-02-27 15:56:22 -08:00
Rotate(
cube, axis = axis, angle = angle, in_place = True,
**kwargs
)
)
self.play(*anims, run_time = 1.5)
def get_composition_angle_and_axis(self):
return get_composite_rotation_angle_and_axis(
*zip(*self.angle_axis_pairs)
)
class DihedralGroupStructure(SymmetriesOfSquare):
CONFIG = {
"dashed_line_config" : {
"dashed_segment_length" : 0.1
},
2017-02-27 15:56:22 -08:00
"filed_sum_scale_factor" : 0.4,
"num_rows" : 5,
}
def construct(self):
angle_axis_pairs = [
(np.pi/2, OUT),
(np.pi, OUT),
(-np.pi/2, OUT),
# (np.pi, RIGHT),
# (np.pi, UP+RIGHT),
(np.pi, UP),
(np.pi, UP+LEFT),
]
2017-02-27 15:56:22 -08:00
pair_pairs = list(it.product(*[angle_axis_pairs]*2))
random.shuffle(pair_pairs)
for pair_pair in pair_pairs[:4]:
sum_expression = self.demonstrate_sum(pair_pair)
self.file_away_sum(sum_expression)
for pair_pair in pair_pairs[4:]:
2017-02-27 15:56:22 -08:00
should_skip_animations = self.skip_animations
self.skip_animations = True
sum_expression = self.demonstrate_sum(pair_pair)
self.file_away_sum(sum_expression)
2017-02-27 15:56:22 -08:00
self.skip_animations = should_skip_animations
self.play(FadeIn(sum_expression))
self.dither(3)
def demonstrate_sum(self, angle_axis_pairs):
angle_axis_pairs = list(angle_axis_pairs) + [
get_composite_rotation_angle_and_axis(
*zip(*angle_axis_pairs)
)
]
prototype_square = Square(**self.square_config)
prototype_square.flip(RIGHT)
2017-02-27 15:56:22 -08:00
self.add_randy_to_square(prototype_square)
# self.add_labels_and_dots(prototype_square)
prototype_square.scale(0.7)
expression = s1, plus, s2, equals, s3 = VGroup(
2017-02-27 15:56:22 -08:00
prototype_square, TexMobject("+").scale(2),
prototype_square.copy(), TexMobject("=").scale(2),
prototype_square.copy()
)
final_expression = VGroup()
for square, (angle, axis) in zip([s1, s2, s3], angle_axis_pairs):
2017-02-27 15:56:22 -08:00
if np.cos(angle) > 0.5:
square.action_illustration = VectorizedPoint()
elif np.argmax(np.abs(axis)) == 2: ##Axis is in z direction
square.action_illustration = self.get_rotation_arcs(
square, angle
)
else:
square.action_illustration = self.get_axis_line(
square, axis
)
square.add(square.action_illustration)
final_expression.add(square.action_illustration)
square.rotation_kwargs = {
"square" : square,
"angle" : angle,
"axis" : axis,
}
expression.arrange_submobjects()
2017-02-27 15:56:22 -08:00
expression.scale_to_fit_width(SPACE_WIDTH+1)
expression.to_edge(RIGHT, buff = SMALL_BUFF)
for square in s1, s2, s3:
square.remove(square.action_illustration)
self.play(FadeIn(s1))
self.play(*map(ShowCreation, s1.action_illustration))
self.rotate_square(**s1.rotation_kwargs)
2017-02-27 15:56:22 -08:00
s1_copy = s1.copy()
self.play(
2017-02-27 15:56:22 -08:00
# FadeIn(s2),
s1_copy.move_to, s2,
Write(plus)
)
2017-02-27 15:56:22 -08:00
Transform(s2, s1_copy).update(1)
self.remove(s1_copy)
self.add(s2)
self.play(*map(ShowCreation, s2.action_illustration))
self.rotate_square(**s2.rotation_kwargs)
2017-02-27 15:56:22 -08:00
self.play(
Write(equals),
FadeIn(s3)
)
self.play(*map(ShowCreation, s3.action_illustration))
self.rotate_square(**s3.rotation_kwargs)
self.dither()
final_expression.add(*expression)
return final_expression
def file_away_sum(self, sum_expression):
if not hasattr(self, "num_sum_expressions"):
self.num_sum_expressions = 0
target = sum_expression.copy()
target.scale(self.filed_sum_scale_factor)
y_index = self.num_sum_expressions%self.num_rows
y_prop = float(y_index)/(self.num_rows-1)
y = interpolate(SPACE_HEIGHT-LARGE_BUFF, -SPACE_HEIGHT+LARGE_BUFF, y_prop)
x_index = self.num_sum_expressions//self.num_rows
x_spacing = 2*SPACE_WIDTH/3
x = (x_index-1)*x_spacing
target.move_to(x*RIGHT + y*UP)
self.play(Transform(sum_expression, target))
self.dither()
2017-02-23 14:13:30 -08:00
self.num_sum_expressions += 1
self.last_sum_expression = sum_expression
2017-02-23 14:13:30 -08:00
2017-02-27 15:56:22 -08:00
class ThisIsAVeryGeneralIdea(Scene):
def construct(self):
groups = TextMobject("Groups")
groups.to_edge(UP)
groups.highlight(BLUE)
examples = VGroup(*map(TextMobject, [
"Square matrices \\\\ \\small (Where $\\det(M) \\ne 0$)",
"Molecular \\\\ symmetry",
"Cryptography",
"Numbers",
]))
numbers = examples[-1]
examples.arrange_submobjects(buff = LARGE_BUFF)
examples.scale_to_fit_width(2*SPACE_WIDTH-1)
examples.move_to(UP)
lines = VGroup(*[
Line(groups.get_bottom(), ex.get_top(), buff = MED_SMALL_BUFF)
for ex in examples
])
lines.highlight(groups.get_color())
2017-02-23 14:13:30 -08:00
2017-02-27 15:56:22 -08:00
self.add(groups)
2017-02-23 14:13:30 -08:00
2017-02-27 15:56:22 -08:00
for example, line in zip(examples, lines):
self.play(
ShowCreation(line),
Write(example, run_time = 2)
)
self.dither()
self.play(
VGroup(*examples[:-1]).fade, 0.7,
VGroup(*lines[:-1]).fade, 0.7,
)
2017-02-23 14:13:30 -08:00
2017-02-27 15:56:22 -08:00
self.play(
numbers.scale, 1.2, numbers.get_corner(UP+RIGHT),
)
self.dither(2)
2017-02-23 14:13:30 -08:00
2017-02-27 15:56:22 -08:00
sub_categories = VGroup(*map(TextMobject, [
"Numbers \\\\ (Additive)",
"Numbers \\\\ (Multiplicative)",
]))
sub_categories.arrange_submobjects(RIGHT, buff = MED_LARGE_BUFF)
sub_categories.next_to(numbers, DOWN, 1.5*LARGE_BUFF)
sub_categories.to_edge(RIGHT)
sub_categories[0].highlight(ADDER_COLOR)
sub_categories[1].highlight(MULTIPLIER_COLOR)
sub_lines = VGroup(*[
Line(numbers.get_bottom(), sc.get_top(), buff = MED_SMALL_BUFF)
for sc in sub_categories
])
sub_lines.highlight(numbers.get_color())
2017-02-23 14:13:30 -08:00
2017-02-27 15:56:22 -08:00
self.play(*it.chain(
map(ShowCreation, sub_lines),
map(Write, sub_categories)
))
self.dither()
2017-02-23 14:13:30 -08:00
2017-02-27 15:56:22 -08:00
class NumbersAsActionsQ(TeacherStudentsScene):
def construct(self):
self.student_says(
"Numbers are actions?",
target_mode = "confused",
)
self.change_student_modes("pondering", "confused", "erm")
self.play(self.get_teacher().change_mode, "happy")
self.dither(3)
class AdditiveGroupOfReals(Scene):
CONFIG = {
"number_line_center" : UP,
"shadow_line_center" : DOWN,
"zero_color" : GREEN_B,
"x_min" : -2*SPACE_WIDTH,
"x_max" : 2*SPACE_WIDTH,
2017-02-27 15:56:22 -08:00
}
def construct(self):
self.add_number_line()
self.show_example_slides(3, -7)
self.write_group_of_slides()
self.show_example_slides(2, 6, -1, -3)
self.mark_zero()
self.show_example_slides_labeled(3, -2)
self.comment_on_zero_as_identity()
self.show_example_slides_labeled(
5.5, added_anims = [self.get_write_name_of_group_anim()]
)
self.show_example_additions((3, 2), (2, -5), (-4, 4))
def add_number_line(self):
number_line = NumberLine(
x_min = self.x_min,
x_max = self.x_max,
2017-02-27 15:56:22 -08:00
)
number_line.shift(self.number_line_center)
shadow_line = NumberLine(color = GREY, stroke_width = 2)
shadow_line.shift(self.shadow_line_center)
for line in number_line, shadow_line:
line.add_numbers()
shadow_line.numbers.fade(0.25)
shadow_line.save_state()
shadow_line.highlight(BLACK)
shadow_line.move_to(number_line)
self.play(*map(Write, number_line), run_time = 1)
self.play(shadow_line.restore, Animation(number_line))
self.dither()
self.number_line = number_line
self.shadow_line = shadow_line
def show_example_slides(self, *nums):
for num in nums:
zero_point = self.number_line.number_to_point(0)
num_point = self.number_line.number_to_point(num)
arrow = Arrow(zero_point, num_point, buff = 0)
arrow.highlight(ADDER_COLOR)
arrow.shift(MED_LARGE_BUFF*UP)
self.play(ShowCreation(arrow))
self.play(
self.number_line.shift,
num_point - zero_point,
run_time = 2
)
self.play(FadeOut(arrow))
def write_group_of_slides(self):
title = TextMobject("Group of line symmetries")
title.to_edge(UP)
self.play(Write(title))
self.title = title
def mark_zero(self):
dot = Dot(
self.number_line.number_to_point(0),
color = self.zero_color
)
arrow = Arrow(dot, color = self.zero_color)
words = TextMobject("Follow zero")
words.next_to(arrow.get_start(), UP)
words.highlight(self.zero_color)
2017-02-23 14:13:30 -08:00
2017-02-27 15:56:22 -08:00
self.play(
ShowCreation(arrow),
DrawBorderThenFill(dot),
Write(words),
)
self.dither()
self.play(*map(FadeOut, [arrow, words]))
2017-02-23 14:13:30 -08:00
2017-02-27 15:56:22 -08:00
self.number_line.add(dot)
2017-02-23 14:13:30 -08:00
2017-02-27 15:56:22 -08:00
def show_example_slides_labeled(self, *nums, **kwargs):
for num in nums:
line = DashedLine(
self.number_line.number_to_point(num)+MED_LARGE_BUFF*UP,
self.shadow_line.number_to_point(num)+MED_LARGE_BUFF*DOWN,
)
vect = self.number_line.number_to_point(num) - \
self.number_line.number_to_point(0)
self.play(ShowCreation(line))
self.dither()
self.play(self.number_line.shift, vect, run_time = 2)
self.dither()
if "added_anims" in kwargs:
self.play(*kwargs["added_anims"])
self.dither()
self.play(
self.number_line.shift, -vect,
FadeOut(line)
)
2017-02-23 14:13:30 -08:00
2017-02-27 15:56:22 -08:00
def comment_on_zero_as_identity(self):
line = DashedLine(
self.number_line.number_to_point(0)+MED_LARGE_BUFF*UP,
self.shadow_line.number_to_point(0)+MED_LARGE_BUFF*DOWN,
)
words = TexMobject("0 \\leftrightarrow \\text{Do nothing}")
words.shift(line.get_top()+MED_SMALL_BUFF*UP - words[0].get_bottom())
2017-02-23 14:13:30 -08:00
2017-02-27 15:56:22 -08:00
self.play(
ShowCreation(line),
Write(words)
)
self.dither(2)
self.play(*map(FadeOut, [line, words]))
2017-02-23 14:13:30 -08:00
2017-02-27 15:56:22 -08:00
def get_write_name_of_group_anim(self):
new_title = TextMobject("Additive group of real numbers")
VGroup(*new_title[-len("realnumbers"):]).highlight(BLUE)
VGroup(*new_title[:len("Additive")]).highlight(ADDER_COLOR)
new_title.to_edge(UP)
return Transform(self.title, new_title)
def show_example_additions(self, *num_pairs):
for num_pair in num_pairs:
num_mobs = VGroup()
arrows = VGroup()
self.number_line.save_state()
for num in num_pair:
zero_point, num_point, arrow, num_mob = \
self.get_adder_mobs(num)
if len(num_mobs) > 0:
last_num_mob = num_mobs[0]
x = num_mob.get_center()[0]
if x < last_num_mob.get_right()[0] and x > last_num_mob.get_left()[0]:
num_mob.next_to(last_num_mob, RIGHT)
num_mobs.add(num_mob)
arrows.add(arrow)
self.play(
ShowCreation(arrow),
Write(num_mob, run_time = 1)
)
self.play(
self.number_line.shift,
num_point - zero_point
)
self.dither()
#Reset
self.play(
FadeOut(num_mobs),
FadeOut(self.number_line)
)
ApplyMethod(self.number_line.restore).update(1)
self.play(FadeIn(self.number_line))
#Sum arrow
num = sum(num_pair)
zero_point, sum_point, arrow, sum_mob = \
self.get_adder_mobs(sum(num_pair))
VGroup(arrow, sum_mob).shift(MED_LARGE_BUFF*UP)
arrows.add(arrow)
self.play(
ShowCreation(arrow),
Write(sum_mob, run_time = 1)
)
self.dither()
self.play(
self.number_line.shift,
num_point - zero_point,
run_time = 2
)
self.dither()
self.play(
self.number_line.restore,
*map(FadeOut, [arrows, sum_mob])
)
def get_adder_mobs(self, num):
zero_point = self.number_line.number_to_point(0)
num_point = self.number_line.number_to_point(num)
arrow = Arrow(zero_point, num_point, buff = 0)
arrow.highlight(ADDER_COLOR)
arrow.shift(MED_SMALL_BUFF*UP)
if num == 0:
arrow = DashedLine(UP, ORIGIN)
arrow.move_to(zero_point)
elif num < 0:
arrow.highlight(RED)
arrow.shift(SMALL_BUFF*UP)
sign = "+" if num >= 0 else ""
num_mob = TexMobject(sign + str(num))
num_mob.next_to(arrow, UP)
num_mob.highlight(arrow.get_color())
return zero_point, num_point, arrow, num_mob
class AdditiveGroupOfComplexNumbers(ComplexTransformationScene):
CONFIG = {
"x_min" : -2*int(SPACE_WIDTH),
"x_max" : 2*int(SPACE_WIDTH),
"y_min" : -2*SPACE_HEIGHT,
"y_max" : 2*SPACE_HEIGHT,
"example_points" : [
complex(3, 2),
complex(1, -3),
]
}
def construct(self):
self.add_plane()
2017-03-02 00:43:13 -08:00
self.show_preview_example_slides()
2017-02-27 15:56:22 -08:00
self.show_vertical_slide()
self.show_example_point()
self.show_example_addition()
self.write_group_name()
self.show_some_random_slides()
def add_plane(self):
self.add_transformable_plane(animate = True)
zero_dot = Dot(
self.z_to_point(0),
color = ADDER_COLOR
)
self.play(ShowCreation(zero_dot))
self.plane.add(zero_dot)
self.plane.zero_dot = zero_dot
2017-02-27 15:56:22 -08:00
self.dither()
2017-03-02 00:43:13 -08:00
def show_preview_example_slides(self):
example_vect = 2*UP+RIGHT
for vect in example_vect, -example_vect:
self.play(self.plane.shift, vect, run_time = 2)
self.dither()
2017-02-27 15:56:22 -08:00
def show_vertical_slide(self):
dots = VGroup(*[
Dot(self.z_to_point(complex(0, i)))
for i in range(1, 4)
])
dots.highlight(YELLOW)
labels = VGroup(*self.imag_labels[-3:])
arrow = Arrow(ORIGIN, dots[-1].get_center(), buff = 0)
arrow.highlight(ADDER_COLOR)
self.plane.save_state()
for dot, label in zip(dots, labels):
self.play(
Indicate(label),
ShowCreation(dot)
)
self.add_foreground_mobjects(dots)
self.dither()
2017-03-02 00:43:13 -08:00
Scene.play(self, ShowCreation(arrow))
self.add_foreground_mobjects(arrow)
2017-02-27 15:56:22 -08:00
self.play(
self.plane.shift, dots[-1].get_center(),
run_time = 2
)
self.dither()
self.play(FadeOut(arrow))
2017-03-02 00:43:13 -08:00
self.foreground_mobjects.remove(arrow)
2017-02-27 15:56:22 -08:00
self.play(
self.plane.shift, 6*DOWN,
2017-03-02 00:43:13 -08:00
run_time = 3,
2017-02-27 15:56:22 -08:00
)
2017-03-02 00:43:13 -08:00
self.dither()
2017-02-27 15:56:22 -08:00
self.play(self.plane.restore, run_time = 2)
self.foreground_mobjects.remove(dots)
self.play(FadeOut(dots))
def show_example_point(self):
z = self.example_points[0]
point = self.z_to_point(z)
dot = Dot(point, color = YELLOW)
arrow = Vector(point, buff = dot.radius)
arrow.highlight(dot.get_color())
label = TexMobject("%d + %di"%(z.real, z.imag))
label.next_to(point, UP)
label.highlight(dot.get_color())
label.add_background_rectangle()
real_arrow = Vector(self.z_to_point(z.real))
imag_arrow = Vector(self.z_to_point(z - z.real))
VGroup(real_arrow, imag_arrow).highlight(ADDER_COLOR)
self.play(
Write(label),
DrawBorderThenFill(dot)
)
self.dither()
self.play(ShowCreation(arrow))
self.add_foreground_mobjects(label, dot, arrow)
self.dither()
self.slide(z)
self.dither()
self.play(FadeOut(self.plane))
self.plane.restore()
self.plane.set_stroke(width = 0)
self.play(self.plane.restore)
self.play(ShowCreation(real_arrow))
self.add_foreground_mobjects(real_arrow)
self.slide(z.real)
self.dither()
self.play(ShowCreation(imag_arrow))
self.dither()
self.play(imag_arrow.shift, self.z_to_point(z.real))
self.add_foreground_mobjects(imag_arrow)
self.slide(z - z.real)
self.dither()
self.foreground_mobjects.remove(real_arrow)
self.foreground_mobjects.remove(imag_arrow)
self.play(*map(FadeOut, [real_arrow, imag_arrow, self.plane]))
self.plane.restore()
self.plane.set_stroke(width = 0)
2017-02-27 15:56:22 -08:00
self.play(self.plane.restore)
self.z1 = z
self.arrow1 = arrow
self.dot1 = dot
self.label1 = label
def show_example_addition(self):
z1 = self.z1
arrow1 = self.arrow1
dot1 = self.dot1
label1 = self.label1
z2 = self.example_points[1]
point2 = self.z_to_point(z2)
dot2 = Dot(point2, color = TEAL)
arrow2 = Vector(
point2,
buff = dot2.radius,
color = dot2.get_color()
)
label2 = TexMobject(
"%d %di"%(z2.real, z2.imag)
)
label2.next_to(point2, UP+RIGHT)
label2.highlight(dot2.get_color())
label2.add_background_rectangle()
self.play(ShowCreation(arrow2))
self.play(
DrawBorderThenFill(dot2),
Write(label2)
)
self.add_foreground_mobjects(arrow2, dot2, label2)
self.dither()
self.slide(z1)
arrow2_copy = arrow2.copy()
self.play(arrow2_copy.shift, self.z_to_point(z1))
self.add_foreground_mobjects(arrow2_copy)
self.slide(z2)
self.play(FadeOut(arrow2_copy))
self.foreground_mobjects.remove(arrow2_copy)
self.dither()
##Break into components
real_arrow, imag_arrow = component_arrows = [
Vector(
self.z_to_point(z),
color = ADDER_COLOR
)
for z in [
z1.real+z2.real,
complex(0, z1.imag+z2.imag),
]
]
imag_arrow.shift(real_arrow.get_end())
plus = TexMobject("+").next_to(
real_arrow.get_center(), UP+RIGHT
)
plus.add_background_rectangle()
rp1, rp2, ip1, ip2 = label_parts = [
VGroup(label1[1][0].copy()),
VGroup(label2[1][0].copy()),
VGroup(*label1[1][2:]).copy(),
VGroup(*label2[1][1:]).copy(),
]
for part in label_parts:
part.generate_target()
rp1.target.next_to(plus, LEFT)
rp2.target.next_to(plus, RIGHT)
ip1.target.next_to(imag_arrow.get_center(), RIGHT)
ip1.target.shift(SMALL_BUFF*DOWN)
ip2.target.next_to(ip1.target, RIGHT)
real_background_rect = BackgroundRectangle(
VGroup(rp1.target, rp2.target)
)
imag_background_rect = BackgroundRectangle(
VGroup(ip1.target, ip2.target)
)
self.play(
ShowCreation(real_arrow),
ShowCreation(
real_background_rect,
rate_func = squish_rate_func(smooth, 0.75, 1),
),
Write(plus),
*map(MoveToTarget, [rp1, rp2])
)
self.dither()
self.play(
ShowCreation(imag_arrow),
ShowCreation(
imag_background_rect,
rate_func = squish_rate_func(smooth, 0.75, 1),
),
*map(MoveToTarget, [ip1, ip2])
)
self.dither(2)
to_remove = [
arrow1, dot1, label1,
arrow2, dot2, label2,
real_background_rect,
imag_background_rect,
plus,
] + label_parts + component_arrows
for mob in to_remove:
if mob in self.foreground_mobjects:
self.foreground_mobjects.remove(mob)
self.play(*map(FadeOut, to_remove))
self.play(self.plane.restore, run_time = 2)
self.dither()
def write_group_name(self):
title = TextMobject(
"Additive", "group of", "complex numbers"
)
title[0].highlight(ADDER_COLOR)
title[2].highlight(BLUE)
title.add_background_rectangle()
title.to_edge(UP, buff = MED_SMALL_BUFF)
self.play(Write(title))
self.add_foreground_mobjects(title)
self.dither()
def show_some_random_slides(self):
example_slides = [
complex(3),
complex(0, 2),
complex(-4, -1),
complex(-2, -1),
complex(4, 2),
]
for z in example_slides:
self.slide(z)
self.dither()
#########
def slide(self, z, *added_anims, **kwargs):
kwargs["run_time"] = kwargs.get("run_time", 2)
self.play(
ApplyMethod(
self.plane.shift, self.z_to_point(z),
**kwargs
),
*added_anims
)
2017-02-23 14:13:30 -08:00
class SchizophrenicNumbers(Scene):
def construct(self):
v_line = DashedLine(
SPACE_HEIGHT*UP,
SPACE_HEIGHT*DOWN
)
left_title = TextMobject("Additive group")
left_title.shift(SPACE_WIDTH*LEFT/2)
right_title = TextMobject("Multiplicative group")
right_title.shift(SPACE_WIDTH*RIGHT/2)
VGroup(left_title, right_title).to_edge(UP)
self.add(v_line, left_title, right_title)
numbers = VGroup(
Randolph(mode = "happy").scale(0.2),
TexMobject("3").shift(UP+LEFT),
TexMobject("5.83").shift(UP+RIGHT),
TexMobject("\\sqrt{2}").shift(DOWN+LEFT),
TexMobject("2-i").shift(DOWN+RIGHT),
)
for number in numbers:
number.highlight(ADDER_COLOR)
number.scale(1.5)
if isinstance(number, PiCreature):
continue
number.eyes = Eyes(number[0], height = 0.1)
number.add(number.eyes)
numbers[3].eyes.next_to(numbers[3][1], UP, buff = 0)
numbers.shift(SPACE_WIDTH*LEFT/2)
self.play(FadeIn(numbers))
self.blink_numbers(numbers)
self.dither()
self.add(numbers.copy())
for number in numbers:
number.generate_target()
number.target.shift(SPACE_WIDTH*RIGHT)
number.target.eyes.save_state()
number.target.highlight(MULTIPLIER_COLOR)
number.target.eyes.restore()
self.play(*[
MoveToTarget(
number,
rate_func = squish_rate_func(
smooth, alpha, alpha+0.5
),
run_time = 2,
)
for number, alpha in zip(numbers, np.linspace(0, 0.5, len(numbers)))
])
self.dither()
self.blink_numbers(numbers)
self.dither()
def blink_numbers(self, numbers):
self.play(*[
num.eyes.blink_anim(
rate_func = squish_rate_func(
there_and_back, alpha, alpha+0.2
)
)
for num, alpha in zip(
numbers[1:], 0.8*np.random.random(len(numbers))
)
])
class MultiplicativeGroupOfReals(AdditiveGroupOfReals):
CONFIG = {
"number_line_center" : 0.5*UP,
"shadow_line_center" : 1.5*DOWN,
"x_min" : -3*SPACE_WIDTH,
"x_max" : 3*SPACE_WIDTH,
"positive_reals_color" : MAROON_B,
}
def setup(self):
self.foreground_mobjects = VGroup()
def construct(self):
self.add_title()
self.add_number_line()
self.introduce_stretch_and_squish()
self.show_zero_fixed_in_place()
self.follow_one()
self.every_positive_number_association()
self.compose_actions(3, 2)
self.compose_actions(4, 0.5)
self.write_group_name()
self.compose_actions(1.5, 1.5)
def add_title(self):
self.title = TextMobject("Group of stretching/squishing actions")
self.title.to_edge(UP)
self.add(self.title)
def add_number_line(self):
AdditiveGroupOfReals.add_number_line(self)
self.zero_point = self.number_line.number_to_point(0)
self.one = filter(
lambda m : m.get_tex_string() is "1",
self.number_line.numbers
)[0]
self.one.add_background_rectangle()
self.one.background_rectangle.scale_in_place(1.3)
self.number_line.save_state()
def introduce_stretch_and_squish(self):
for num in [3, 0.25]:
self.stretch(num)
self.dither()
self.play(self.number_line.restore)
self.dither()
def show_zero_fixed_in_place(self):
arrow = Arrow(self.zero_point + UP, self.zero_point, buff = 0)
arrow.highlight(ADDER_COLOR)
words = TextMobject("Fix zero")
words.highlight(ADDER_COLOR)
words.next_to(arrow, UP)
self.play(
ShowCreation(arrow),
Write(words)
)
self.foreground_mobjects.add(arrow)
self.stretch(4)
self.stretch(0.1)
self.dither()
self.play(self.number_line.restore)
self.play(FadeOut(words))
self.dither()
self.zero_arrow = arrow
def follow_one(self):
dot = Dot(self.number_line.number_to_point(1))
arrow = Arrow(dot.get_center()+UP+RIGHT, dot)
words = TextMobject("Follow one")
words.next_to(arrow.get_start(), UP)
for mob in dot, arrow, words:
mob.highlight(MULTIPLIER_COLOR)
three_line, half_line = [
DashedLine(
self.number_line.number_to_point(num),
self.shadow_line.number_to_point(num)
)
for num in 3, 0.5
]
three_mob = filter(
lambda m : m.get_tex_string() == "3",
self.shadow_line.numbers
)[0]
half_point = self.shadow_line.number_to_point(0.5)
half_arrow = Arrow(
half_point+UP+LEFT, half_point, buff = SMALL_BUFF,
tip_length = 0.15,
)
half_label = TexMobject("1/2")
half_label.scale(0.7)
half_label.highlight(MULTIPLIER_COLOR)
half_label.next_to(half_arrow.get_start(), LEFT, buff = SMALL_BUFF)
self.play(
ShowCreation(arrow),
DrawBorderThenFill(dot),
Write(words)
)
self.number_line.add(dot)
self.number_line.numbers.add(dot)
self.number_line.save_state()
self.dither()
self.play(*map(FadeOut, [arrow, words]))
self.stretch(3)
self.play(
ShowCreation(three_line),
Animation(self.one)
)
dot_copy = dot.copy()
self.play(
dot_copy.move_to, three_line.get_bottom()
)
self.play(Indicate(three_mob, run_time = 2))
self.dither()
self.play(
self.number_line.restore,
*map(FadeOut, [three_line, dot_copy])
)
self.dither()
self.stretch(0.5)
self.play(
ShowCreation(half_line),
Animation(self.one)
)
dot_copy = dot.copy()
self.play(
dot_copy.move_to, half_line.get_bottom()
)
self.play(
Write(half_label),
ShowCreation(half_arrow)
)
self.dither()
self.play(
self.number_line.restore,
*map(FadeOut, [
half_label, half_arrow,
half_line, dot_copy
])
)
self.dither()
self.one_dot = dot
def every_positive_number_association(self):
positive_reals_line = Line(
self.shadow_line.number_to_point(0),
self.shadow_line.number_to_point(SPACE_WIDTH),
color = self.positive_reals_color
)
positive_reals_words = TextMobject("All positive reals")
positive_reals_words.highlight(self.positive_reals_color)
positive_reals_words.next_to(positive_reals_line, UP)
positive_reals_words.add_background_rectangle()
2017-03-02 11:53:04 -08:00
third_line, one_line = [
DashedLine(
self.number_line.number_to_point(num),
self.shadow_line.number_to_point(num)
)
2017-03-02 11:53:04 -08:00
for num in 0.33, 1
]
self.play(
self.zero_arrow.shift, 0.5*UP,
rate_func = there_and_back
)
self.dither()
self.play(
self.one_dot.shift, 0.25*UP,
rate_func = wiggle
)
self.stretch(3)
self.stretch(0.33/3, run_time = 3)
self.dither()
2017-03-02 11:53:04 -08:00
self.play(ShowCreation(third_line), Animation(self.one))
self.play(
ShowCreation(positive_reals_line),
Write(positive_reals_words),
)
self.dither()
self.play(
2017-03-02 11:53:04 -08:00
ReplacementTransform(third_line, one_line),
self.number_line.restore,
Animation(positive_reals_words),
run_time = 2
)
self.number_line.add_to_back(one_line)
self.number_line.save_state()
self.stretch(
7, run_time = 10, rate_func = there_and_back,
added_anims = [Animation(positive_reals_words)]
)
self.dither()
def compose_actions(self, num1, num2):
words = VGroup(*[
TextMobject("(%s by %s)"%(word, str(num)))
for num in num1, num2, num1*num2
for word in ["Stretch" if num > 1 else "Squish"]
])
words.submobjects.insert(2, TexMobject("="))
words.arrange_submobjects(RIGHT)
top_words = VGroup(*words[:2])
top_words.highlight(MULTIPLIER_COLOR)
bottom_words = VGroup(*words[2:])
bottom_words.next_to(top_words, DOWN)
words.scale(0.8)
words.next_to(self.number_line, UP)
words.to_edge(RIGHT)
for num, word in zip([num1, num2], top_words):
self.stretch(
num,
added_anims = [FadeIn(word)],
run_time = 3
)
self.dither()
self.play(Write(bottom_words, run_time = 2))
self.dither(2)
self.play(
ApplyMethod(self.number_line.restore, run_time = 2),
FadeOut(words),
)
self.dither()
def write_group_name(self):
new_title = TextMobject(
"Multiplicative group of positive real numbers"
)
new_title.to_edge(UP)
VGroup(
*new_title[:len("Multiplicative")]
).highlight(MULTIPLIER_COLOR)
VGroup(
*new_title[-len("positiverealnumbers"):]
).highlight(self.positive_reals_color)
self.play(Transform(self.title, new_title))
self.dither()
###
def stretch(self, factor, run_time = 2, **kwargs):
kwargs["run_time"] = run_time
target = self.number_line.copy()
target.stretch_about_point(factor, 0, self.zero_point)
total_factor = (target.number_to_point(1)-self.zero_point)[0]
for number in target.numbers:
number.stretch_in_place(1./factor, dim = 0)
if total_factor < 0.7:
number.stretch_in_place(total_factor, dim = 0)
self.play(
Transform(self.number_line, target, **kwargs),
*kwargs.get("added_anims", [])
)
def play(self, *anims, **kwargs):
anims = list(anims) + [Animation(self.foreground_mobjects)]
Scene.play(self, *anims, **kwargs)
class MultiplicativeGroupOfComplexNumbers(AdditiveGroupOfComplexNumbers):
CONFIG = {
"dot_radius" : Dot.CONFIG["radius"],
"y_min" : -3*SPACE_HEIGHT,
"y_max" : 3*SPACE_HEIGHT,
}
def construct(self):
self.add_plane()
self.add_title()
self.fix_zero_and_move_one()
self.show_example_actions()
self.show_action_at_i()
self.show_action_at_i_again()
self.show_i_squared_is_negative_one()
self.talk_through_specific_example()
self.show_break_down()
self.example_actions_broken_down()
def add_plane(self):
AdditiveGroupOfComplexNumbers.add_plane(self)
one_dot = Dot(
self.z_to_point(1),
color = MULTIPLIER_COLOR,
radius = self.dot_radius,
)
self.plane.add(one_dot)
self.plane.one_dot = one_dot
self.plane.save_state()
self.add(self.plane)
def add_title(self):
title = TextMobject(
"Multiplicative", "group of",
"complex numbers"
)
title.to_edge(UP)
title[0].highlight(MULTIPLIER_COLOR)
title[2].highlight(BLUE)
title.add_background_rectangle()
self.play(Write(title, run_time = 2))
self.dither()
self.add_foreground_mobjects(title)
def fix_zero_and_move_one(self):
zero_arrow = Arrow(
UP+1.25*LEFT, ORIGIN,
buff = 2*self.dot_radius
)
zero_arrow.highlight(ADDER_COLOR)
zero_words = TextMobject("Fix zero")
zero_words.highlight(ADDER_COLOR)
zero_words.add_background_rectangle()
zero_words.next_to(zero_arrow.get_start(), UP)
one_point = self.z_to_point(1)
one_arrow = Arrow(
one_point+UP+1.25*RIGHT, one_point,
buff = 2*self.dot_radius,
color = MULTIPLIER_COLOR,
)
one_words = TextMobject("Drag one")
one_words.highlight(MULTIPLIER_COLOR)
one_words.add_background_rectangle()
one_words.next_to(one_arrow.get_start(), UP)
self.play(
Write(zero_words, run_time = 2),
ShowCreation(zero_arrow),
Indicate(self.plane.zero_dot, color = RED),
)
self.play(
Write(one_words, run_time = 2),
ShowCreation(one_arrow),
Indicate(self.plane.one_dot, color = RED),
)
self.dither(2)
self.play(*map(FadeOut, [
zero_words, zero_arrow,
one_words, one_arrow,
]))
def show_example_actions(self):
z_list = [
complex(2),
complex(0.5),
complex(2, 1),
complex(-2, 2),
]
for last_z, z in zip([1] + z_list, z_list):
self.multiply_by_z(z/last_z)
self.dither()
self.reset_plane()
self.dither()
def show_action_at_i(self):
i_point = self.z_to_point(complex(0, 1))
i_dot = Dot(i_point)
i_dot.highlight(RED)
i_arrow = Arrow(i_point+UP+LEFT, i_point)
i_arrow.highlight(i_dot.get_color())
arc = Arc(
start_angle = np.pi/24,
angle = 10*np.pi/24,
radius = self.z_to_point(1)[0],
num_anchors = 20,
)
arc.add_tip(tip_length = 0.15)
arc.highlight(YELLOW)
self.play(
ShowCreation(i_arrow),
DrawBorderThenFill(i_dot)
)
self.dither()
self.play(
FadeOut(i_arrow),
ShowCreation(arc)
)
self.add_foreground_mobjects(arc)
self.dither(2)
self.multiply_by_z(complex(0, 1), run_time = 3)
self.remove(i_dot)
self.dither()
self.turn_arrow = arc
def show_action_at_i_again(self):
neg_one_label = filter(
lambda m : m.get_tex_string() == "-1",
self.real_labels
)[0]
half_turn_arc = Arc(
start_angle = np.pi/12,
angle = 10*np.pi/12,
color = self.turn_arrow.get_color()
)
half_turn_arc.add_tip(tip_length = 0.15)
self.multiply_by_z(complex(0, 1), run_time = 3)
self.dither()
self.play(Transform(
self.turn_arrow, half_turn_arc,
path_arc = np.pi/2
))
self.dither()
self.play(Indicate(neg_one_label, run_time = 2))
self.dither()
self.foreground_mobjects.remove(self.turn_arrow)
self.reset_plane(FadeOut(self.turn_arrow))
def show_i_squared_is_negative_one(self):
equation = TexMobject("i", "\\cdot", "i", "=", "-1")
terms = equation[::2]
equation.add_background_rectangle()
equation.next_to(ORIGIN, RIGHT)
equation.shift(1.5*UP)
equation.highlight(MULTIPLIER_COLOR)
self.play(Write(equation, run_time = 2))
self.dither()
for term in terms[:2]:
self.multiply_by_z(
complex(0, 1),
added_anims = [
Animation(equation),
Indicate(term, color = RED, run_time = 2)
]
)
self.dither()
self.play(Indicate(terms[-1], color = RED, run_time = 2))
self.dither()
self.reset_plane(FadeOut(equation))
def talk_through_specific_example(self):
z = complex(2, 1)
angle = np.angle(z)
point = self.z_to_point(z)
dot = Dot(point, color = WHITE)
label = TexMobject("%d + %di"%(z.real, z.imag))
label.add_background_rectangle()
label.next_to(dot, UP+RIGHT, buff = 0)
brace = Brace(
Line(ORIGIN, self.z_to_point(np.sqrt(5))),
UP
)
brace_text = brace.get_text("$\\sqrt{5}$")
brace_text.add_background_rectangle()
brace_text.scale(0.7, about_point = brace.get_top())
brace.rotate(angle)
brace_text.rotate(angle).rotate_in_place(-angle)
VGroup(brace, brace_text).highlight(MAROON_B)
arc = Arc(angle, color = WHITE, radius = 0.5)
angle_label = TexMobject("30^\\circ")
angle_label.scale(0.7)
angle_label.next_to(
arc, RIGHT,
buff = SMALL_BUFF, aligned_edge = DOWN
)
angle_label.highlight(MULTIPLIER_COLOR)
self.play(
Write(label),
DrawBorderThenFill(dot)
)
self.add_foreground_mobjects(label, dot)
self.dither()
self.multiply_by_z(z, run_time = 3)
self.dither()
self.reset_plane()
self.multiply_by_z(
np.exp(complex(0, 1)*angle),
added_anims = [
ShowCreation(arc, run_time = 2),
Write(angle_label)
]
)
self.add_foreground_mobjects(arc, angle_label)
self.dither()
self.play(
GrowFromCenter(brace),
Write(brace_text)
)
self.add_foreground_mobjects(brace, brace_text)
self.multiply_by_z(np.sqrt(5), run_time = 3)
self.dither(2)
to_remove = [
label, dot,
brace, brace_text,
arc, angle_label,
]
for mob in to_remove:
self.foreground_mobjects.remove(mob)
self.reset_plane(*map(FadeOut, to_remove))
self.dither()
def show_break_down(self):
positive_reals = Line(ORIGIN, SPACE_WIDTH*RIGHT)
positive_reals.highlight(MAROON_B)
circle = Circle(
radius = self.z_to_point(1)[0],
color = MULTIPLIER_COLOR
)
real_actions = [3, 0.5, 1]
rotation_actions = [
np.exp(complex(0, angle))
for angle in np.linspace(0, 2*np.pi, 4)[1:]
]
self.play(ShowCreation(positive_reals))
self.add_foreground_mobjects(positive_reals)
for last_z, z in zip([1]+real_actions, real_actions):
self.multiply_by_z(z/last_z)
self.dither()
self.play(ShowCreation(circle))
self.add_foreground_mobjects(circle)
for last_z, z in zip([1]+rotation_actions, rotation_actions):
self.multiply_by_z(z/last_z, run_time = 3)
self.dither()
def example_actions_broken_down(self):
z_list = [
complex(2, -1),
complex(-2, -3),
complex(0.5, 0.5),
]
for z in z_list:
dot = Dot(self.z_to_point(z))
dot.highlight(WHITE)
dot.save_state()
dot.move_to(self.plane.one_dot)
dot.set_fill(opacity = 1)
norm = np.abs(z)
angle = np.angle(z)
rot_z = np.exp(complex(0, angle))
self.play(dot.restore)
self.multiply_by_z(norm)
self.dither()
self.multiply_by_z(rot_z)
self.dither()
self.reset_plane(FadeOut(dot))
##
def multiply_by_z(self, z, run_time = 2, **kwargs):
target = self.plane.copy()
target.apply_complex_function(lambda w : z*w)
for dot in target.zero_dot, target.one_dot:
dot.scale_to_fit_width(2*self.dot_radius)
angle = np.angle(z)
kwargs["path_arc"] = kwargs.get("path_arc", angle)
self.play(
Transform(self.plane, target, run_time = run_time, **kwargs),
*kwargs.get("added_anims", [])
)
def reset_plane(self, *added_anims):
self.play(FadeOut(self.plane), *added_anims)
self.plane.restore()
self.play(FadeIn(self.plane))
class ExponentsAsRepeatedMultiplication(TeacherStudentsScene):
def construct(self):
self.show_repeated_multiplication()
self.show_non_counting_exponents()
def show_repeated_multiplication(self):
three_twos = TexMobject("2 \\cdot 2 \\cdot 2")
five_twos = TexMobject("2 \\cdot "*4 + "2")
exponents = []
teacher_corner = self.get_teacher().get_corner(UP+LEFT)
for twos in three_twos, five_twos:
twos.next_to(teacher_corner, UP)
twos.generate_target()
d = sum(np.array(list(twos.get_tex_string())) == "2")
exponents.append(d)
twos.brace = Brace(twos, UP)
twos.exp = twos.brace.get_text("$2^%d$"%d)
twos.generate_target()
twos.brace_anim = MaintainPositionRelativeTo(
VGroup(twos.brace, twos.exp), twos
)
self.play(
GrowFromCenter(three_twos.brace),
Write(three_twos.exp),
self.get_teacher().change_mode, "raise_right_hand",
)
for mob in three_twos:
self.play(Write(mob, run_time = 1))
self.change_student_modes(*["pondering"]*3)
self.dither(2)
self.play(
FadeIn(five_twos.brace),
FadeIn(five_twos.exp),
three_twos.center,
three_twos.to_edge, UP, 2*LARGE_BUFF,
three_twos.brace_anim,
)
self.play(FadeIn(
five_twos,
run_time = 3,
submobject_mode = "lagged_start"
))
self.dither(2)
cdot = TexMobject("\\cdot")
lhs = TexMobject("2^{%d + %d} = "%tuple(exponents))
rule = VGroup(
lhs, three_twos.target, cdot, five_twos.target
)
rule.arrange_submobjects()
lhs.next_to(three_twos.target, LEFT, aligned_edge = DOWN)
rule.next_to(self.get_pi_creatures(), UP)
self.play(
MoveToTarget(three_twos),
three_twos.brace_anim,
MoveToTarget(five_twos),
five_twos.brace_anim,
Write(cdot),
self.get_teacher().change_mode, "happy",
)
self.dither()
self.play(Write(lhs))
self.dither()
self.change_student_modes(*["happy"]*3)
self.dither()
general_equation = TexMobject("2^{x+y}=", "2^x", "2^y")
general_equation.to_edge(UP, buff = MED_LARGE_BUFF)
general_equation[0].highlight(GREEN_B)
VGroup(*general_equation[1:]).highlight(MULTIPLIER_COLOR)
self.play(*[
ReplacementTransform(
mob.copy(), term, run_time = 2
)
for term, mob in zip(general_equation, [
lhs, three_twos.exp, five_twos.exp
])
])
self.dither(2)
self.exponential_rule = general_equation
self.expanded_exponential_rule = VGroup(
lhs, three_twos, three_twos.brace, three_twos.exp,
cdot, five_twos, five_twos.brace, five_twos.exp,
)
def show_non_counting_exponents(self):
self.play(
self.expanded_exponential_rule.scale, 0.5,
self.expanded_exponential_rule.to_corner, UP+LEFT
)
half_power, neg_power, imag_power = alt_powers = VGroup(
TexMobject("2^{1/2}"),
TexMobject("2^{-1}"),
TexMobject("2^{i}"),
)
alt_powers.arrange_submobjects(RIGHT, buff = LARGE_BUFF)
alt_powers.next_to(self.get_students(), UP, buff = LARGE_BUFF)
self.play(
Write(half_power, run_time = 2),
*[
ApplyMethod(pi.change_mode, "pondering")
for pi in self.get_pi_creatures()
]
)
for mob in alt_powers[1:]:
self.play(Write(mob, run_time = 1))
self.dither()
self.dither()
self.play(*it.chain(*[
[pi.change_mode, "confused", pi.look_at, half_power]
for pi in self.get_students()
]))
for power in alt_powers[:2]:
self.play(Indicate(power))
self.dither()
self.dither()
self.teacher_says("Extend the \\\\ definition")
self.change_student_modes("pondering", "confused", "erm")
self.dither()
half_expression = TexMobject(
"\\big(", "2^{1/2}", "\\big)",
"\\big(2^{1/2}\\big) = 2^{1}"
)
neg_one_expression = TexMobject(
"\\big(", "2^{-1}", "\\big)",
"\\big( 2^{1} \\big) = 2^{0}"
)
expressions = VGroup(half_expression, neg_one_expression)
expressions.arrange_submobjects(
DOWN, aligned_edge = LEFT, buff = MED_LARGE_BUFF
)
expressions.next_to(self.get_students(), UP, buff = LARGE_BUFF)
expressions.to_edge(LEFT)
self.play(
Transform(half_power, half_expression[1]),
Write(half_expression),
RemovePiCreatureBubble(self.get_teacher()),
)
self.dither()
self.play(
Transform(neg_power, neg_one_expression[1]),
Write(neg_one_expression)
)
2017-03-02 11:53:04 -08:00
self.dither(2)
self.play(
self.exponential_rule.next_to,
self.get_teacher().get_corner(UP+LEFT), UP, MED_LARGE_BUFF,
self.get_teacher().change_mode, "raise_right_hand",
)
self.dither(2)
self.play(
imag_power.move_to, UP,
imag_power.scale_in_place, 1.5,
imag_power.highlight, BLUE,
2017-03-02 11:53:04 -08:00
self.exponential_rule.to_edge, RIGHT,
self.get_teacher().change_mode, "speaking"
)
self.play(*it.chain(*[
[pi.change_mode, "pondering", pi.look_at, imag_power]
for pi in self.get_students()
]))
self.dither()
group_theory_words = TextMobject("Group theory?")
group_theory_words.next_to(
2017-03-02 11:53:04 -08:00
self.exponential_rule, UP, buff = LARGE_BUFF
)
arrow = Arrow(
2017-03-02 11:53:04 -08:00
group_theory_words,
self.exponential_rule,
color = WHITE,
2017-03-02 11:53:04 -08:00
buff = SMALL_BUFF
)
2017-03-02 11:53:04 -08:00
group_theory_words.shift_onto_screen()
self.play(
Write(group_theory_words),
ShowCreation(arrow)
)
self.dither(2)
class ExponentsAsHomomorphism(Scene):
CONFIG = {
"top_line_center" : 2.5*UP,
"top_line_config" : {
"x_min" : -16,
"x_max" : 16,
},
"bottom_line_center" : 2.5*DOWN,
"bottom_line_config" : {
"x_min" : -2*SPACE_WIDTH,
"x_max" : 2*SPACE_WIDTH,
}
}
def construct(self):
self.comment_on_equation()
self.show_adders()
self.show_multipliers()
self.confused_at_mapping()
self.talk_through_composition()
self.add_quote()
def comment_on_equation(self):
equation = TexMobject(
"2", "^{x", "+", "y}", "=", "2^x", "2^y"
)
lhs = VGroup(*equation[:4])
rhs = VGroup(*equation[5:])
lhs_brace = Brace(lhs, UP)
lhs_text = lhs_brace.get_text("Add inputs")
lhs_text.highlight(GREEN_B)
rhs_brace = Brace(rhs, DOWN)
rhs_text = rhs_brace.get_text("Multiply outputs")
rhs_text.highlight(MULTIPLIER_COLOR)
self.add(equation)
for brace, text in (lhs_brace, lhs_text), (rhs_brace, rhs_text):
self.play(
GrowFromCenter(brace),
Write(text)
)
self.dither()
self.dither()
self.equation = equation
self.lhs_brace_group = VGroup(lhs_brace, lhs_text)
self.rhs_brace_group = VGroup(rhs_brace, rhs_text)
def show_adders(self):
equation = self.equation
adders = VGroup(equation[1], equation[3]).copy()
top_line = NumberLine(**self.top_line_config)
top_line.add_numbers()
top_line.shift(self.top_line_center)
self.play(
adders.scale, 1.5,
adders.center,
adders.space_out_submobjects, 2,
adders.to_edge, UP,
adders.highlight, GREEN_B,
FadeOut(self.lhs_brace_group),
Write(top_line)
)
self.dither()
for x in 3, 5, -8:
self.play(top_line.shift, x*RIGHT, run_time = 2)
self.dither()
self.top_line = top_line
self.adders = adders
def show_multipliers(self):
equation = self.equation
multipliers = VGroup(*self.equation[-2:]).copy()
bottom_line = NumberLine(**self.bottom_line_config)
bottom_line.add_numbers()
bottom_line.shift(self.bottom_line_center)
self.play(
multipliers.space_out_submobjects, 4,
multipliers.next_to, self.bottom_line_center,
UP, MED_LARGE_BUFF,
multipliers.highlight, YELLOW,
FadeOut(self.rhs_brace_group),
Write(bottom_line),
)
stretch_kwargs = {
}
for x in 3, 1./5, 5./3:
self.play(
self.get_stretch_anim(bottom_line, x),
run_time = 3
)
self.dither()
self.bottom_line = bottom_line
self.multipliers = multipliers
def confused_at_mapping(self):
arrow = Arrow(
self.top_line.get_bottom()[1]*UP,
self.bottom_line.get_top()[1]*UP,
color = WHITE
)
randy = Randolph(mode = "confused")
randy.scale(0.75)
randy.flip()
randy.next_to(arrow, RIGHT, LARGE_BUFF)
randy.look_at(arrow.get_top())
self.play(self.equation.to_edge, LEFT)
self.play(
ShowCreation(arrow),
FadeIn(randy)
)
self.play(randy.look_at, arrow.get_bottom())
self.play(Blink(randy))
self.dither()
for x in 1, -2, 3, 1, -3:
self.play(
self.get_stretch_anim(self.bottom_line, 2**x),
self.top_line.shift, x*RIGHT,
randy.look_at, self.top_line,
run_time = 2
)
if random.random() < 0.3:
self.play(Blink(randy))
else:
self.dither()
self.randy = randy
def talk_through_composition(self):
randy = self.randy
terms = list(self.adders) + list(self.multipliers)
inputs = [-1, 2]
target_texs = map(str, inputs)
target_texs += ["2^{%d}"%x for x in inputs]
for mob, target_tex in zip(terms, target_texs):
target = TexMobject(target_tex)
target.highlight(mob[0].get_color())
target.move_to(mob, DOWN)
if mob in self.adders:
target.to_edge(UP)
mob.target = target
self.play(
self.equation.next_to, ORIGIN, LEFT, MED_LARGE_BUFF,
randy.change_mode, "pondering",
randy.look_at, self.equation
)
self.dither()
self.play(randy.look_at, self.top_line)
self.show_composition(
*inputs,
parallel_anims = map(MoveToTarget, self.adders)
)
self.play(
FocusOn(self.bottom_line_center),
randy.look_at, self.bottom_line_center,
)
self.show_composition(
*inputs,
parallel_anims = map(MoveToTarget, self.multipliers)
)
self.dither()
def add_quote(self):
brace = Brace(self.equation, UP)
quote = TextMobject("``Preserves the group structure''")
quote.add_background_rectangle()
quote.next_to(brace, UP)
self.play(
GrowFromCenter(brace),
Write(quote),
self.randy.look_at, quote,
)
self.play(self.randy.change_mode, "thinking")
self.play(Blink(self.randy))
self.dither()
self.show_composition(-1, 2)
self.dither()
####
def show_composition(self, *inputs, **kwargs):
parallel_anims = kwargs.get("parallel_anims", [])
for x in range(len(inputs) - len(parallel_anims)):
parallel_anims.append(Animation(Mobject()))
for line in self.top_line, self.bottom_line:
line.save_state()
for x, parallel_anim in zip(inputs, parallel_anims):
anims = [
ApplyMethod(self.top_line.shift, x*RIGHT),
self.get_stretch_anim(self.bottom_line, 2**x),
]
for anim in anims:
anim.set_run_time(2)
self.play(parallel_anim)
self.play(*anims)
self.dither()
self.play(*[
line.restore
for line in self.top_line, self.bottom_line
])
def get_stretch_anim(self, bottom_line, x):
target = bottom_line.copy()
target.stretch_about_point(
x, 0, self.bottom_line_center,
)
for number in target.numbers:
number.stretch_in_place(1./x, dim = 0)
return Transform(bottom_line, target)
2017-02-28 22:32:43 -08:00
class DihedralCubeHomomorphism(GroupOfCubeSymmetries, SymmetriesOfSquare):
def construct(self):
angle_axis_pairs = [
(np.pi/2, OUT),
(np.pi, RIGHT),
(np.pi, OUT),
(np.pi, UP+RIGHT),
(-np.pi/2, OUT),
(np.pi, UP+LEFT),
]
angle_axis_pairs *= 3
2017-03-02 00:43:13 -08:00
title = TextMobject(
"``", "Homo", "morph", "ism", "''",
arg_separator = ""
)
homo_brace = Brace(title[1], UP, buff = SMALL_BUFF)
homo_def = homo_brace.get_text("same")
morph_brace = Brace(title[2], UP, buff = SMALL_BUFF)
morph_def = morph_brace.get_text("shape", buff = SMALL_BUFF)
def_group = VGroup(
homo_brace, homo_def,
morph_brace, morph_def
)
VGroup(title, def_group).to_edge(UP)
homo_group = VGroup(title[1], homo_brace, homo_def)
morph_group = VGroup(title[2], morph_brace, morph_def)
2017-02-28 22:32:43 -08:00
equation = TexMobject("f(X \\circ Y) = f(X) \\circ f(Y)")
equation.next_to(title, DOWN)
self.add(title, equation)
arrow = Arrow(LEFT, RIGHT)
cube = self.get_cube()
cube.next_to(arrow, RIGHT)
pose_matrix = self.get_pose_matrix()
square = self.square = Square(**self.square_config)
self.add_randy_to_square(square)
square.next_to(arrow, LEFT)
2017-03-02 00:43:13 -08:00
VGroup(square, arrow, cube).next_to(
equation, DOWN, buff = MED_LARGE_BUFF
)
2017-02-28 22:32:43 -08:00
self.add(square, cube)
self.play(ShowCreation(arrow))
2017-03-02 00:43:13 -08:00
for i, (angle, raw_axis) in enumerate(angle_axis_pairs):
2017-02-28 22:32:43 -08:00
posed_axis = np.dot(raw_axis, pose_matrix.T)
self.play(*[
Rotate(
mob, angle = angle, axis = axis,
in_place = True,
run_time = abs(angle/(np.pi/2))
)
for mob, axis in (square, raw_axis), (cube, posed_axis)
])
self.dither()
2017-03-02 00:43:13 -08:00
if i == 2:
for group, color in (homo_group, YELLOW), (morph_group, BLUE):
part, remainder = group[0], VGroup(*group[1:])
remainder.highlight(color)
self.play(
part.highlight, color,
FadeIn(remainder)
)
2017-02-28 22:32:43 -08:00
class ComplexExponentiationAbstract():
CONFIG = {
"start_base" : 2,
"new_base" : 5,
"group_type" : None,
"color" : None,
"vect" : None,
}
def construct(self):
self.base = self.start_base
example_inputs = [2, -3, 1]
2017-03-02 00:43:13 -08:00
self.add_vertical_line()
2017-02-28 22:32:43 -08:00
self.add_plane_unanimated()
self.add_title()
self.add_arrow()
self.show_example(complex(1, 1))
self.draw_real_line()
self.show_real_actions(*example_inputs)
self.show_pure_imaginary_actions(*example_inputs)
self.highlight_vertical_line()
self.highlight_unit_circle()
2017-03-02 00:43:13 -08:00
self.show_pure_imaginary_actions(*example_inputs)
2017-02-28 22:32:43 -08:00
self.walk_input_up_vertical()
self.change_base(self.new_base, str(self.new_base))
self.walk_input_up_vertical()
2017-03-02 00:43:13 -08:00
self.change_base(np.exp(1), "e")
self.take_steps_for_e()
self.write_eulers_formula()
self.show_pure_imaginary_actions(-np.pi, np.pi)
self.dither()
2017-02-28 22:32:43 -08:00
2017-03-02 00:43:13 -08:00
def add_vertical_line(self):
2017-02-28 22:32:43 -08:00
line = Line(SPACE_HEIGHT*UP, SPACE_HEIGHT*DOWN)
line.set_stroke(color = self.color, width = 10)
line.shift(-SPACE_WIDTH*self.vect/2)
self.add(line)
self.add_foreground_mobjects(line)
def add_plane_unanimated(self):
should_skip_animations = self.skip_animations
self.skip_animations = True
self.add_plane()
self.skip_animations = should_skip_animations
def add_title(self):
title = TextMobject(self.group_type, "group")
2017-03-02 00:43:13 -08:00
title.scale(0.8)
2017-02-28 22:32:43 -08:00
title[0].highlight(self.color)
title.add_background_rectangle()
2017-03-02 00:43:13 -08:00
title.to_edge(UP, buff = MED_SMALL_BUFF)
2017-02-28 22:32:43 -08:00
self.add_foreground_mobjects(title)
def add_arrow(self):
arrow = Arrow(LEFT, RIGHT, color = WHITE)
arrow.move_to(-SPACE_WIDTH*self.vect/2 + 2*UP)
arrow.set_stroke(width = 6),
2017-03-02 00:43:13 -08:00
func_mob = TexMobject("2^x")
func_mob.next_to(arrow, UP, aligned_edge = LEFT)
func_mob.add_background_rectangle()
2017-02-28 22:32:43 -08:00
2017-03-02 00:43:13 -08:00
self.add_foreground_mobjects(arrow, func_mob)
2017-02-28 22:32:43 -08:00
self.dither()
2017-03-02 00:43:13 -08:00
self.func_mob = func_mob
2017-02-28 22:32:43 -08:00
def show_example(self, z):
self.apply_action(
z,
run_time = 5,
rate_func = there_and_back
)
def draw_real_line(self):
line = VGroup(Line(ORIGIN, SPACE_WIDTH*RIGHT))
if self.vect[0] < 0:
line.add(Line(ORIGIN, SPACE_WIDTH*LEFT))
line.highlight(RED)
self.play(*map(ShowCreation, line), run_time = 3)
self.add_foreground_mobjects(line)
2017-03-02 00:43:13 -08:00
self.real_line = line
2017-02-28 22:32:43 -08:00
def show_real_actions(self, *example_inputs):
for x in example_inputs:
self.apply_action(x)
self.dither()
def show_pure_imaginary_actions(self, *example_input_imag_parts):
for y in example_input_imag_parts:
self.apply_action(complex(0, y), run_time = 3)
self.dither()
def change_base(self, new_base, new_base_tex):
2017-03-02 00:43:13 -08:00
new_func_mob = TexMobject(new_base_tex + "^x")
new_func_mob.add_background_rectangle()
new_func_mob.move_to(self.func_mob)
self.play(FocusOn(self.func_mob))
self.play(Transform(self.func_mob, new_func_mob))
self.dither()
self.base = new_base
def write_eulers_formula(self):
formula = TexMobject("e^", "{\\pi", "i}", "=", "-1")
VGroup(*formula[1:3]).highlight(ADDER_COLOR)
formula[-1].highlight(MULTIPLIER_COLOR)
formula.scale(1.5)
formula.next_to(ORIGIN, UP)
formula.shift(-SPACE_WIDTH*self.vect/2)
for part in formula:
part.add_to_back(BackgroundRectangle(part))
Scene.play(self, Write(formula))
self.add_foreground_mobjects(formula)
self.dither(2)
2017-02-28 22:32:43 -08:00
class ComplexExponentiationAdderHalf(
ComplexExponentiationAbstract,
AdditiveGroupOfComplexNumbers
):
CONFIG = {
"group_type" : "Additive",
"color" : GREEN_B,
"vect" : LEFT,
}
def construct(self):
ComplexExponentiationAbstract.construct(self)
def apply_action(self, z, run_time = 2, **kwargs):
kwargs["run_time"] = run_time
self.play(
ApplyMethod(
self.plane.shift, self.z_to_point(z),
**kwargs
),
*kwargs.get("added_anims", [])
)
def highlight_vertical_line(self):
line = VGroup(
Line(ORIGIN, SPACE_HEIGHT*UP),
Line(ORIGIN, SPACE_HEIGHT*DOWN),
)
line.highlight(YELLOW)
2017-03-02 00:43:13 -08:00
self.play(
FadeOut(self.real_line),
*map(ShowCreation, line)
)
self.foreground_mobjects.remove(self.real_line)
2017-02-28 22:32:43 -08:00
self.play(
line.rotate, np.pi/24,
rate_func = wiggle,
)
self.dither()
self.foreground_mobjects = [line] + self.foreground_mobjects
self.vertical_line = line
def highlight_unit_circle(self):
line = VGroup(
Line(ORIGIN, SPACE_HEIGHT*UP),
Line(ORIGIN, SPACE_HEIGHT*DOWN),
)
line.highlight(YELLOW)
for submob in line:
submob.insert_n_anchor_points(10)
submob.make_smooth()
circle = VGroup(
Circle(),
Circle().flip(RIGHT),
)
circle.highlight(YELLOW)
circle.shift(SPACE_WIDTH*RIGHT)
self.play(ReplacementTransform(
line, circle, run_time = 3
))
self.remove(circle)
self.dither()
def walk_input_up_vertical(self):
2017-03-02 00:43:13 -08:00
arrow = Arrow(ORIGIN, UP, buff = 0, tip_length = 0.15)
arrow.highlight(GREEN)
brace = Brace(arrow, RIGHT, buff = SMALL_BUFF)
brace_text = brace.get_text("1 unit")
brace_text.add_background_rectangle()
2017-02-28 22:32:43 -08:00
2017-03-02 00:43:13 -08:00
Scene.play(self, ShowCreation(arrow))
self.add_foreground_mobjects(arrow)
self.play(
GrowFromCenter(brace),
Write(brace_text, run_time = 1)
)
self.add_foreground_mobjects(brace, brace_text)
self.dither()
self.apply_action(complex(0, 1))
self.dither(7)##Line up with MultiplierHalf
to_remove = arrow, brace, brace_text
for mob in to_remove:
self.foreground_mobjects.remove(mob)
self.play(*map(FadeOut, to_remove))
self.apply_action(complex(0, -1))
2017-02-28 22:32:43 -08:00
2017-03-02 00:43:13 -08:00
def take_steps_for_e(self):
slide_values = [1, 1, 1, np.pi-3]
braces = [
Brace(Line(ORIGIN, x*UP), RIGHT, buff = SMALL_BUFF)
for x in np.cumsum(slide_values)
]
labels = map(TextMobject, [
"1 unit",
"2 units",
"3 units",
"$\\pi$ units",
])
for label, brace in zip(labels, braces):
label.add_background_rectangle()
label.next_to(brace, RIGHT, buff = SMALL_BUFF)
curr_brace = None
curr_label = None
for slide_value, label, brace in zip(slide_values, labels, braces):
self.apply_action(complex(0, slide_value))
if curr_brace is None:
curr_brace = brace
curr_label = label
self.play(
GrowFromCenter(curr_brace),
Write(curr_label)
)
self.add_foreground_mobjects(brace, label)
else:
self.play(
Transform(curr_brace, brace),
Transform(curr_label, label),
)
self.dither()
self.dither(4) ##Line up with multiplier half
2017-02-28 22:32:43 -08:00
class ComplexExponentiationMultiplierHalf(
ComplexExponentiationAbstract,
MultiplicativeGroupOfComplexNumbers
):
CONFIG = {
"group_type" : "Multiplicative",
"color" : MULTIPLIER_COLOR,
"vect" : RIGHT,
}
def construct(self):
2017-02-28 22:32:43 -08:00
ComplexExponentiationAbstract.construct(self)
def apply_action(self, z, run_time = 2, **kwargs):
kwargs["run_time"] = run_time
2017-03-02 00:43:13 -08:00
self.multiply_by_z(self.base**z, **kwargs)
2017-02-28 22:32:43 -08:00
def highlight_vertical_line(self):
2017-03-02 00:43:13 -08:00
self.play(FadeOut(self.real_line))
self.foreground_mobjects.remove(self.real_line)
self.dither(2)
2017-02-28 22:32:43 -08:00
def highlight_unit_circle(self):
line = VGroup(
Line(ORIGIN, SPACE_HEIGHT*UP),
Line(ORIGIN, SPACE_HEIGHT*DOWN),
)
line.highlight(YELLOW)
line.shift(SPACE_WIDTH*LEFT)
for submob in line:
submob.insert_n_anchor_points(10)
submob.make_smooth()
circle = VGroup(
Circle(),
Circle().flip(RIGHT),
)
circle.highlight(YELLOW)
self.play(ReplacementTransform(
line, circle, run_time = 3
))
self.add_foreground_mobjects(circle)
self.dither()
def walk_input_up_vertical(self):
2017-03-02 00:43:13 -08:00
output_z = self.base**complex(0, 1)
angle = np.angle(output_z)
2017-03-02 00:43:13 -08:00
arc, brace, curved_brace, radians_label = \
self.get_arc_braces_and_label(angle)
2017-03-02 00:43:13 -08:00
self.dither(3)
self.apply_action(complex(0, 1))
2017-03-02 00:43:13 -08:00
Scene.play(self, ShowCreation(arc))
self.add_foreground_mobjects(arc)
self.play(GrowFromCenter(brace))
self.play(Transform(brace, curved_brace))
self.play(Write(radians_label, run_time = 2))
self.dither(2)
2017-03-02 00:43:13 -08:00
self.foreground_mobjects.remove(arc)
self.play(*map(FadeOut, [arc, brace, radians_label]))
self.apply_action(complex(0, -1))
2017-03-02 00:43:13 -08:00
def get_arc_braces_and_label(self, angle):
arc = Arc(angle)
arc.set_stroke(GREEN, width = 6)
arc_line = Line(RIGHT, RIGHT+angle*UP)
brace = Brace(arc_line, RIGHT, buff = 0)
for submob in brace.family_members_with_points():
submob.insert_n_anchor_points(10)
curved_brace = brace.copy()
curved_brace.shift(LEFT)
curved_brace.apply_complex_function(
np.exp, maintain_smoothness = False
)
half_point = arc.point_from_proportion(0.5)
radians_label = TexMobject("%.3f"%angle)
radians_label.add_background_rectangle()
radians_label.next_to(
1.5*half_point, np.round(half_point), buff = 0
)
return arc, brace, curved_brace, radians_label
def take_steps_for_e(self):
angles = [1, 2, 3, np.pi]
curr_brace = None
curr_label = None
curr_arc = None
for last_angle, angle in zip([0]+angles, angles):
arc, brace, curved_brace, label = self.get_arc_braces_and_label(angle)
if angle == np.pi:
2017-03-02 11:53:04 -08:00
label = TexMobject("%.5f\\dots"%np.pi)
2017-03-02 00:43:13 -08:00
label.add_background_rectangle(opacity = 1)
label.next_to(curved_brace, UP, buff = SMALL_BUFF)
self.apply_action(complex(0, angle-last_angle))
self.dither(2)#Line up with Adder half
if curr_brace is None:
curr_brace = curved_brace
curr_label = label
curr_arc = arc
brace.set_fill(opacity = 0)
Scene.play(self, ShowCreation(curr_arc))
self.add_foreground_mobjects(curr_arc)
self.play(
ReplacementTransform(brace, curr_brace),
Write(curr_label)
)
self.add_foreground_mobjects(curr_brace, curr_label)
else:
Scene.play(self, ShowCreation(arc))
self.add_foreground_mobjects(arc)
self.foreground_mobjects.remove(curr_arc)
self.remove(curr_arc)
curr_arc = arc
self.play(
Transform(curr_brace, curved_brace),
Transform(curr_label, label),
)
self.dither()
self.dither()
class ExpComplexHomomorphismPreviewAbstract(ComplexExponentiationAbstract):
def construct(self):
self.base = self.start_base
self.add_vertical_line()
self.add_plane_unanimated()
self.add_title()
self.add_arrow()
self.change_base(np.exp(1), "e")
self.write_eulers_formula()
self.show_pure_imaginary_actions(np.pi, 0, -np.pi)
self.dither()
class ExpComplexHomomorphismPreviewAdderHalf(
ExpComplexHomomorphismPreviewAbstract,
ComplexExponentiationAdderHalf
):
def construct(self):
ExpComplexHomomorphismPreviewAbstract.construct(self)
class ExpComplexHomomorphismPreviewMultiplierHalf(
ExpComplexHomomorphismPreviewAbstract,
ComplexExponentiationMultiplierHalf
):
def construct(self):
ExpComplexHomomorphismPreviewAbstract.construct(self)
class WhyE(TeacherStudentsScene):
def construct(self):
self.student_says("Why e?")
self.play(self.get_teacher().change_mode, "pondering")
self.dither(3)
2017-03-02 11:53:04 -08:00
class ReadFormula(Scene):
def construct(self):
formula = TexMobject("e^", "{\\pi i}", "=", "-1")
formula[1].highlight(GREEN_B)
formula[3].highlight(MULTIPLIER_COLOR)
formula.scale(2)
randy = Randolph()
randy.shift(2*LEFT)
formula.next_to(randy, RIGHT, aligned_edge = UP)
2017-03-03 17:33:06 -08:00
randy.look_at(formula)
2017-03-02 11:53:04 -08:00
self.add(randy, formula)
2017-03-03 17:33:06 -08:00
self.dither()
2017-03-02 11:53:04 -08:00
self.play(randy.change_mode, "thinking")
self.dither()
self.play(Blink(randy))
2017-03-03 17:33:06 -08:00
self.dither(3)
2017-03-02 11:53:04 -08:00
2017-03-02 00:43:13 -08:00
class EfvgtPatreonThanks(PatreonThanks):
CONFIG = {
"specific_patrons" : [
2017-03-03 17:33:06 -08:00
"Ali Yahya",
2017-03-02 00:43:13 -08:00
"Meshal Alshammari",
"CrypticSwarm ",
"Justin Helps",
2017-03-03 17:33:06 -08:00
"Ankit Agarwal",
2017-03-02 00:43:13 -08:00
"Yu Jun",
"Shelby Doolittle",
"Dave Nicponski",
"Damion Kistler",
"Juan Benet",
"Othman Alikhan",
"Markus Persson",
"Dan Buchoff",
2017-03-03 17:33:06 -08:00
"Derek Dai",
2017-03-02 00:43:13 -08:00
"Joseph John Cox",
"Luc Ritchie",
"Nils Schneider",
"Mathew Bramson",
"Guido Gambardella",
"Jerry Ling",
"Mark Govea",
"Vecht",
"Shimin Kuang",
"Rish Kundalia",
"Achille Brighton",
"Kirk Werklund",
"Ripta Pasay",
"Felipe Diniz",
]
}
class EmeraldLogo(SVGMobject):
CONFIG = {
"file_name" : "emerald_logo",
"stroke_width" : 0,
"fill_opacity" : 1,
"propogate_style_to_family" : True,
# "helix_color" : "#439271",
"helix_color" : GREEN_E,
}
def __init__(self, **kwargs):
SVGMobject.__init__(self, **kwargs)
self.scale_to_fit_height(1)
for submob in self.split()[18:]:
submob.highlight(self.helix_color)
class ECLPromo(PiCreatureScene):
CONFIG = {
"seconds_to_blink" : 4,
}
def construct(self):
logo = EmeraldLogo()
2017-03-03 17:33:06 -08:00
logo.to_corner(UP+LEFT, buff = MED_SMALL_BUFF)
2017-03-02 00:43:13 -08:00
logo_part1 = VGroup(*logo[:15])
logo_part2 = VGroup(*logo[15:])
rect = Rectangle(height = 9, width = 16)
rect.scale_to_fit_height(5)
2017-03-03 17:33:06 -08:00
rect.next_to(logo, DOWN)
2017-03-02 00:43:13 -08:00
rect.to_edge(LEFT)
self.play(
2017-03-03 17:33:06 -08:00
self.pi_creature.change_mode, "hooray",
ShowCreation(rect)
2017-03-02 00:43:13 -08:00
)
2017-03-03 17:33:06 -08:00
self.dither(3)
self.play(FadeIn(
logo_part1, run_time = 3,
submobject_mode = "lagged_start"
))
logo_part2.save_state()
logo_part2.scale(2)
logo_part2.next_to(self.pi_creature.get_corner(UP+LEFT), UP)
logo_part2.shift(MED_SMALL_BUFF*RIGHT)
2017-03-02 00:43:13 -08:00
self.play(
self.pi_creature.change_mode, "raise_right_hand",
2017-03-03 17:33:06 -08:00
)
self.play(DrawBorderThenFill(logo_part2))
self.play(
logo_part2.scale_in_place, 0.5,
logo_part2.to_edge, UP
2017-03-02 00:43:13 -08:00
)
self.play(
2017-03-03 17:33:06 -08:00
logo_part2.restore,
2017-03-02 00:43:13 -08:00
self.pi_creature.change_mode, "happy"
)
2017-03-03 17:33:06 -08:00
self.play(self.pi_creature.look_at, rect)
2017-03-02 00:43:13 -08:00
self.dither(10)
self.play(
2017-03-03 17:33:06 -08:00
self.pi_creature.change_mode, "pondering",
self.pi_creature.look, DOWN
2017-03-02 00:43:13 -08:00
)
2017-03-03 17:33:06 -08:00
self.dither(10)
2017-03-02 11:53:04 -08:00
class ExpTransformation(ComplexTransformationScene):
CONFIG = {
"camera_class": CameraWithPerspective,
}
def construct(self):
self.camera.camera_distance = 10,
self.add_transformable_plane()
self.prepare_for_transformation(self.plane)
final_plane = self.plane.copy().apply_complex_function(np.exp)
cylinder = self.plane.copy().apply_function(
lambda (x, y, z) : np.array([x, np.sin(y), -np.cos(y)])
)
2017-03-03 17:33:06 -08:00
title = TexMobject("x \\to e^x")
2017-03-02 11:53:04 -08:00
title.add_background_rectangle()
title.scale(1.5)
title.next_to(ORIGIN, RIGHT)
title.to_edge(UP, buff = MED_SMALL_BUFF)
self.add_foreground_mobjects(title)
2017-03-02 11:53:04 -08:00
self.play(Transform(
self.plane, cylinder,
run_time = 3,
path_arc_axis = RIGHT,
path_arc = np.pi,
))
self.play(Rotate(
self.plane, -np.pi/3, UP,
run_time = 5
))
self.play(Transform(self.plane, final_plane, run_time = 3))
self.dither(3)
2017-03-03 17:33:06 -08:00
class Thumbnail(Scene):
def construct(self):
formula = TexMobject("e^", "{\\pi i}", "=", "-1")
formula[1].highlight(GREEN_B)
formula[3].highlight(YELLOW)
formula.scale(4)
formula.to_edge(UP, buff = LARGE_BUFF)
self.add(formula)
2017-03-03 17:33:06 -08:00
via = TextMobject("via")
via.scale(2)
groups = TextMobject("Group theory")
groups.scale(3)
groups.to_edge(DOWN)
via.move_to(VGroup(formula, groups))
self.add(via, groups)
2017-03-03 17:33:06 -08:00
2017-02-23 14:13:30 -08:00
2017-02-28 22:32:43 -08:00
2017-02-23 14:13:30 -08:00