More inventing math progress

This commit is contained in:
Grant Sanderson
2015-08-03 22:23:00 -07:00
parent 6af2e9c6c2
commit 9cf8e7b75e
9 changed files with 290 additions and 15 deletions

View File

@ -5,7 +5,7 @@ import copy
import warnings import warnings
from animation import Animation from animation import Animation
from mobject import Mobject from mobject import Mobject, Point
from constants import * from constants import *
from helpers import * from helpers import *

View File

@ -121,6 +121,9 @@ def rush_into(t):
def rush_from(t): def rush_from(t):
return 2*high_inflection_0_to_1(t/2.0+0.5) - 1 return 2*high_inflection_0_to_1(t/2.0+0.5) - 1
def slow_into(t):
return np.sqrt(1-(1-t)*(1-t))
def there_and_back(t, inflection = 10.0): def there_and_back(t, inflection = 10.0):
new_t = 2*t if t < 0.5 else 2*(1 - t) new_t = 2*t if t < 0.5 else 2*(1 - t)
return high_inflection_0_to_1(new_t, inflection) return high_inflection_0_to_1(new_t, inflection)

View File

@ -65,6 +65,7 @@ class PiCreature(Mobject):
part.points = self.points[curr:curr+n_points,:] part.points = self.points[curr:curr+n_points,:]
part.rgbs = self.rgbs[curr:curr+n_points,:] part.rgbs = self.rgbs[curr:curr+n_points,:]
curr += n_points curr += n_points
return self
def reload_from_parts(self): def reload_from_parts(self):
self.rewire_part_attributes(self_from_parts = True) self.rewire_part_attributes(self_from_parts = True)

View File

@ -177,9 +177,13 @@ class Mobject(object):
self.rotate(np.pi / 7, [1, 0, 0]) self.rotate(np.pi / 7, [1, 0, 0])
return self return self
def replace(self, other_mobject): def replace(self, mobject, stretch = False):
self.scale(other_mobject.get_width()/self.get_width()) if stretch:
self.center().shift(other_mobject.get_center()) self.stretch_to_fit_width(mobject.get_width())
self.stretch_to_fit_height(mobject.get_height())
else:
self.scale(mobject.get_width()/self.get_width())
self.center().shift(mobject.get_center())
return self return self
def apply_function(self, function): def apply_function(self, function):

View File

@ -93,7 +93,7 @@ class Line(Mobject1D):
def __init__(self, start, end, density = DEFAULT_POINT_DENSITY_1D, *args, **kwargs): def __init__(self, start, end, density = DEFAULT_POINT_DENSITY_1D, *args, **kwargs):
self.start = np.array(start) self.start = np.array(start)
self.end = np.array(end) self.end = np.array(end)
density *= self.get_length() density *= max(self.get_length(), 0.1)
Mobject1D.__init__(self, density = density, *args, **kwargs) Mobject1D.__init__(self, density = density, *args, **kwargs)
def generate_points(self): def generate_points(self):

View File

@ -21,6 +21,7 @@ DEFAULT_COUNT_RUN_TIME = 5.0
class Scene(object): class Scene(object):
def __init__(self, def __init__(self,
display_config = PRODUCTION_QUALITY_DISPLAY_CONFIG, display_config = PRODUCTION_QUALITY_DISPLAY_CONFIG,
construct_args = [],
background = None, background = None,
start_dither_time = DEFAULT_DITHER_TIME): start_dither_time = DEFAULT_DITHER_TIME):
self.display_config = display_config self.display_config = display_config
@ -38,7 +39,7 @@ class Scene(object):
self.background = self.original_background self.background = self.original_background
self.shape = self.background.shape[:2] self.shape = self.background.shape[:2]
#TODO, space shape #TODO, space shape
self.construct() self.construct(*construct_args)
def construct(self): def construct(self):
pass #To be implemented in subclasses pass #To be implemented in subclasses

View File

@ -106,7 +106,10 @@ def command_line_create_scene(movie_prefix = ""):
) )
name = SceneClass.__name__ + SceneClass.args_to_string(*args) name = SceneClass.__name__ + SceneClass.args_to_string(*args)
print "Constructing %s..."%name print "Constructing %s..."%name
scene = SceneClass(*args, display_config = display_config) scene = SceneClass(
display_config = display_config,
construct_args = args
)
if action == "write": if action == "write":
scene.write_to_movie(os.path.join(movie_prefix, name)) scene.write_to_movie(os.path.join(movie_prefix, name))
elif action == "preview": elif action == "preview":

View File

@ -4,6 +4,7 @@ import numpy as np
import itertools as it import itertools as it
from copy import deepcopy from copy import deepcopy
import sys import sys
import operator as op
from animation import * from animation import *
@ -18,7 +19,8 @@ DIVERGENT_SUM_TEXT = [
"1", "1",
"+2", "+2",
"+4", "+4",
"+8", "+\\cdots", "+8",
"+\\cdots",
"+2^n", "+2^n",
"+\\cdots", "+\\cdots",
"= -1", "= -1",
@ -29,15 +31,47 @@ CONVERGENT_SUM_TEXT = [
"+\\frac{1}{4}", "+\\frac{1}{4}",
"+\\frac{1}{8}", "+\\frac{1}{8}",
"+\\frac{1}{16}", "+\\frac{1}{16}",
"+\\cdots+", "+\\cdots",
"\\frac{1}{2^n}", "+\\frac{1}{2^n}",
"+\\cdots", "+\\cdots",
"=1", "=1",
] ]
CONVERGENT_SUM_TERMS = [
"\\frac{1}{2}",
"\\frac{1}{4}",
"\\frac{1}{8}",
"\\frac{1}{16}",
]
PARTIAL_CONVERGENT_SUMS_TEXT = [
"\\frac{1}{2}",
"", "", ",\\quad",
"\\frac{1}{2} + \\frac{1}{4}",
"=", "\\frac{3}{4}", ",\\quad",
"\\frac{1}{2} + \\frac{1}{4} + \\frac{1}{8}",
"=", "\\frac{7}{8}", ",\\quad",
"\\frac{1}{2} + \\frac{1}{4} + \\frac{1}{8} + \\frac{1}{16}",
"=", "\\frac{15}{16}", ",\\dots"
]
def partial_sum(n):
return sum([1.0/2**(k+1) for k in range(n)])
ALT_PARTIAL_SUM_TEXT = reduce(op.add, [
[str(partial_sum(n)), "&=", "+".join(CONVERGENT_SUM_TERMS[:n])+"\\\\"]
for n in range(1, len(CONVERGENT_SUM_TERMS)+1)
])+ [
"\\vdots", "&", "\\\\",
"1.0", "&=", "+".join(CONVERGENT_SUM_TERMS)+"+\\cdots+\\frac{1}{2^n}+\\cdots"
]
NUM_WRITTEN_TERMS = 4 NUM_WRITTEN_TERMS = 4
INTERVAL_RADIUS = 5 INTERVAL_RADIUS = 5
NUM_INTERVAL_TICKS = 16 NUM_INTERVAL_TICKS = 16
def divergent_sum(): def divergent_sum():
return tex_mobject(DIVERGENT_SUM_TEXT, size = "\\large").scale(2) return tex_mobject(DIVERGENT_SUM_TEXT, size = "\\large").scale(2)
@ -216,6 +250,26 @@ class ReasonsForMakingVideo(Scene):
self.add(line_two) self.add(line_two)
self.dither() self.dither()
class DiscoverAndDefine(Scene):
def construct(self):
sum_mob = tex_mobject("\\sum_{n = 1}^\\infty a_n")
discover = text_mobject("What does it feel like to discover these?")
define = text_mobject([
"What does it feel like to",
"\\emph{define} ",
"them?"
])
sum_mob.shift(2*UP)
define.shift(2*DOWN)
define_parts = define.split()
define_parts[1].highlight("skyblue")
self.add(sum_mob)
self.animate(FadeIn(discover))
self.dither()
self.animate(FadeIn(CompoundMobject(*define_parts)))
self.dither()
class YouAsMathematician(Scene): class YouAsMathematician(Scene):
def construct(self): def construct(self):
you = draw_you() you = draw_you()
@ -323,13 +377,17 @@ class ZoomInOnInterval(Scene):
class DanceDotOnInterval(Scene): class DanceDotOnInterval(Scene):
def construct(self): def construct(self):
num_height = 1.3*DOWN
interval = zero_to_one_interval() interval = zero_to_one_interval()
dots = [ dots = [
Dot(radius = 3*Dot.DEFAULT_RADIUS).shift(INTERVAL_RADIUS*x+UP) Dot(radius = 3*Dot.DEFAULT_RADIUS).shift(INTERVAL_RADIUS*x+UP)
for x in LEFT, RIGHT for x in LEFT, RIGHT
] ]
color_range = Color("green").range_to("grey", NUM_WRITTEN_TERMS) color_range = Color("green").range_to("yellow", NUM_WRITTEN_TERMS)
conv_sum = convergent_sum().split() conv_sum = convergent_sum().split()
partial_sums = tex_mobject(PARTIAL_CONVERGENT_SUMS_TEXT, size = "\\small")
partial_sums.scale(1.5).to_edge(UP)
partial_sum_parts = partial_sums.split()
self.add(interval) self.add(interval)
self.animate(*[ self.animate(*[
@ -346,17 +404,219 @@ class DanceDotOnInterval(Scene):
ApplyMethod(dots[0].shift, shift_val), ApplyMethod(dots[0].shift, shift_val),
ShowCreation(line) ShowCreation(line)
) )
num = conv_sum[count] num = conv_sum[count].scale(0.75)
num.shift(RIGHT*(line.get_center()[0]-num.get_center()[0])) num.shift(RIGHT*(line.get_center()[0]-num.get_center()[0]))
if num.get_width() > line.get_length(): if num.get_width() > line.get_length():
num.stretch_to_fit_width(line.get_length()) num.stretch_to_fit_width(line.get_length())
num.shift(3*DOWN) num.shift(num_height)
self.animate( self.animate(
ApplyMethod(line.shift, 2*DOWN), ApplyMethod(line.shift, 2*DOWN),
FadeIn(num) FadeIn(num)
) )
self.dither() self.dither()
self.animate(FadeIn(conv_sum[NUM_WRITTEN_TERMS])) partial_sum_parts[0].highlight("yellow")
for x in range(0, len(partial_sum_parts), 4):
partial_sum_parts[x+2].highlight("yellow")
self.animate(*[
FadeIn(partial_sum_parts[y])
for y in range(x, x+4)
])
self.dither(2)
class OrganizePartialSums(Scene):
def construct(self):
partial_sums = tex_mobject(PARTIAL_CONVERGENT_SUMS_TEXT, size = "\\small")
partial_sums.scale(1.5).to_edge(UP)
partial_sum_parts = partial_sums.split()
for x in [0] + range(2, len(partial_sum_parts), 4):
partial_sum_parts[x].highlight("yellow")
pure_sums = [
partial_sum_parts[x]
for x in range(0, len(partial_sum_parts), 4)
]
new_pure_sums = deepcopy(pure_sums)
for pure_sum, count in zip(new_pure_sums, it.count(3, -1.2)):
pure_sum.center().scale(1/1.25).highlight("white")
pure_sum.to_edge(LEFT).shift(2*RIGHT+count*UP)
self.add(*partial_sum_parts)
self.dither()
self.animate(*[
SemiCircleTransform(*pair, counterclockwise=False)
for pair in zip(pure_sums, new_pure_sums)
]+[
FadeOut(mob)
for mob in partial_sum_parts
if mob not in pure_sums
])
self.dither()
down_arrow = tex_mobject("\\downarrow")
down_arrow.to_edge(LEFT).shift(2*RIGHT+2*DOWN)
infinite_sum = tex_mobject("".join(CONVERGENT_SUM_TEXT[:-1]), size = "\\samll")
infinite_sum.scale(1.5/1.25)
infinite_sum.to_corner(DOWN+LEFT).shift(2*RIGHT)
self.animate(FadeIn(CompoundMobject(down_arrow, infinite_sum)))
self.dither()
class SeeNumbersApproachOne(Scene):
def construct(self):
interval = zero_to_one_interval()
arrow = Arrow(INTERVAL_RADIUS*RIGHT, tail=ORIGIN).nudge()
arrow.shift(DOWN).highlight("yellow")
num_dots = 6
colors = Color("green").range_to("yellow", num_dots)
dots = CompoundMobject(*[
Dot(
density = 2*DEFAULT_POINT_DENSITY_1D
).scale(1+1.0/2.0**x).shift(
INTERVAL_RADIUS*RIGHT +\
(INTERVAL_RADIUS/2.0**x)*LEFT
).highlight(colors.next())
for x in range(num_dots)
])
self.add(interval)
self.animate(
ShowCreation(arrow),
ShowCreation(dots),
run_time = 2.0
)
self.dither()
class HowDoYouDefineInfiniteSums(Scene):
def construct(self):
you = draw_you().center().rewire_part_attributes()
text = text_mobject(
["How", " do", " you,\\\\", "\\emph{define}"],
size = "\\Huge"
).shift(UP).split()
text[-1].shift(3*DOWN).highlight("skyblue")
sum_mob = tex_mobject("\\sum_{n=0}^\\infty{a_n}")
text[-1].shift(LEFT)
sum_mob.shift(text[-1].get_center()+2*RIGHT)
self.add(you)
self.dither()
for mob in text[:-1]:
self.add(mob)
self.dither(0.1)
self.animate(BlinkPiCreature(you))
self.dither()
self.add(text[-1])
self.dither()
self.add(sum_mob)
self.dither()
class LessAboutNewThoughts(Scene):
def construct(self):
words = generating, new, thoughts, to, definitions = text_mobject([
"Generating", " new", " thoughts", "$\\rightarrow$",
"useful definitions"
], size = "\\large").split()
gen_cross = ImageMobject("cross").highlight("red")
new_cross = deepcopy(gen_cross)
for cross, mob in [(gen_cross, generating), (new_cross, new)]:
cross.replace(mob, stretch = True)
disecting = text_mobject("Disecting")
disecting.shift(generating.get_center() + 0.7*UP)
old = text_mobject("old")
old.shift(new.get_center()+0.7*DOWN)
kwargs = {"run_time" : 0.25}
self.add(*words)
self.dither()
self.animate(ShowCreation(gen_cross, **kwargs))
self.animate(ShowCreation(new_cross, **kwargs))
self.dither()
self.add(disecting)
self.dither(0.25)
self.add(old)
self.dither()
class ListOfPartialSums(Scene):
def construct(self):
all_terms = np.array(tex_mobject(
ALT_PARTIAL_SUM_TEXT,
size = "\\large"
).split())
numbers, equals, sums = [
all_terms[range(k, 12, 3)]
for k in 0, 1, 2
]
dots = all_terms[12]
one = all_terms[-3]
last_equal = all_terms[-2]
infinite_sum = all_terms[-1]
self.count(
numbers,
mode = "show",
display_numbers = False,
run_time = 1.0
)
self.animate(ShowCreation(dots))
self.dither()
self.animate(
FadeIn(CompoundMobject(*equals)),
*[
Transform(deepcopy(number), finite_sum)
for number, finite_sum in zip(numbers, sums)
]
)
self.animate(*[
ApplyMethod(s.highlight, "yellow", alpha_func = there_and_back)
for s in sums
])
self.dither()
self.add(one.highlight("green"))
self.dither()
class ShowDecreasingDistance(Scene):
args_list = [(1,), (2,)]
@staticmethod
def args_to_string(num):
return str(num)
def construct(self, num):
number_line = NumberLine(interval_size = 1).add_numbers()
vert_line0 = Line(0.5*UP, UP)
vert_line1 = Line(0.5*UP+num*RIGHT, UP+num*RIGHT)
horiz_line = Line(UP, UP+num*RIGHT)
lines = [vert_line0, vert_line1, horiz_line]
for line in lines:
line.highlight("green")
self.add(number_line, *lines)
self.dither()
self.animate(
ApplyMethod(vert_line0.shift, RIGHT),
Transform(
horiz_line,
Line(vert_line0.end+RIGHT, vert_line1.end).highlight("green")
),
run_time = 2.5
)
self.dither()

View File

@ -20,7 +20,10 @@ def tex_to_image(expression,
if os.path.exists(image_dir): if os.path.exists(image_dir):
result = [ result = [
Image.open(os.path.join(image_dir, png_file)).convert('RGB') Image.open(os.path.join(image_dir, png_file)).convert('RGB')
for png_file in os.listdir(image_dir) for png_file in sorted(
os.listdir(image_dir),
cmp_enumerated_files
)
] ]
else: else:
filestem = os.path.join(TEX_DIR, exp_hash) filestem = os.path.join(TEX_DIR, exp_hash)