3b1b-manim/eop/combinations.py

2939 lines
94 KiB
Python
Raw Normal View History

2017-11-29 10:11:41 -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 animation.continual_animation import *
from topics.geometry import *
from topics.characters import *
from topics.functions import *
from topics.fractals import *
from topics.number_line import *
from topics.combinatorics import *
from topics.numerals import *
from topics.three_dimensions import *
from topics.objects import *
from topics.probability import *
from topics.complex_numbers import *
from scene import Scene
from scene.reconfigurable_scene import ReconfigurableScene
from scene.zoomed_scene import *
from camera import Camera
from mobject.svg_mobject import *
from mobject.tex_mobject import *
from topics.graph_scene import *
from topics.probability import *
#revert_to_original_skipping_status
def get_stack(
obj1, obj2, n, k,
fixed_start = None,
fixed_end = None,
2017-11-29 15:12:39 -08:00
obj_to_obj_buff = SMALL_BUFF,
vertical_buff = MED_SMALL_BUFF,
2017-11-29 10:11:41 -08:00
):
stack = VGroup()
for indices in it.combinations(range(n), k):
term = VGroup(*[
obj1.copy() if i in indices else obj2.copy()
for i in range(n)
])
if fixed_start:
term.add_to_back(fixed_start.copy())
if fixed_end:
term.add(fixed_end.copy())
2017-11-29 15:12:39 -08:00
term.arrange_submobjects(RIGHT, buff = obj_to_obj_buff)
2017-11-29 10:11:41 -08:00
stack.add(term)
2017-11-29 15:12:39 -08:00
stack.arrange_submobjects(DOWN, buff = vertical_buff)
2017-11-29 10:11:41 -08:00
return stack
def get_stacks(obj1, obj2, n, **kwargs):
stacks = VGroup()
for k in range(n+1):
stacks.add(get_stack(obj1, obj2, n, k, **kwargs))
stacks.arrange_submobjects(
RIGHT,
buff = MED_LARGE_BUFF,
aligned_edge = DOWN
)
return stacks
class Male(TexMobject):
CONFIG = {
"height" : 0.4,
"tex" : "\\male",
"color" : BLUE,
}
def __init__(self, **kwargs):
digest_config(self, kwargs)
TexMobject.__init__(self, self.tex, **kwargs)
self.scale_to_fit_height(self.height)
self.highlight(self.color)
class Female(Male):
CONFIG = {
"tex" : "\\female",
"color" : MAROON_B,
}
2017-12-03 16:22:24 -08:00
class PascalsTraingle(VGroup):
CONFIG = {
"n_rows" : 9,
"distance" : 0.8,
"max_width_to_distance_ratio" : 0.7,
"angle" : 0.2*np.pi,
}
def __init__(self, **kwargs):
VGroup.__init__(self, **kwargs)
distance = self.distance
angle = self.angle
max_width = self.max_width_to_distance_ratio * distance
t_down = rotate_vector(distance*DOWN, -angle)
t_right = 2*distance*np.sin(angle)*RIGHT
for n in range(self.n_rows):
row = VGroup()
for k in range(n+1):
num = TexMobject(str(choose(n, k)))
num.shift(n*t_down + k*t_right)
row.add(num)
self.add(row)
self.center()
2017-11-29 10:11:41 -08:00
######################
2017-12-03 16:22:24 -08:00
class ExperienceProblemSolver(PiCreatureScene):
def construct(self):
self.add_equation()
self.jenny_solves()
self.no_genius()
self.think_about_patterns()
def add_equation(self):
equation = TexMobject(
"\\frac{x^3 + y^3}{(x+y)^2} + \\frac{3xy}{x+y}"
)
equation.to_edge(UP)
self.play(Write(equation))
self.dither()
self.equation = equation
def jenny_solves(self):
randy, jenny = self.randy, self.jenny
jenny_words = TextMobject("It's just $x+y$")
randy_words = TextMobject("...wait...")
randy_words.next_to(randy.get_corner(UP+RIGHT), RIGHT)
self.pi_creature_says(
jenny, jenny_words,
target_mode = "hooray",
bubble_kwargs = {"height" : 2, "width" : 3}
)
self.dither()
self.play(
randy.change, "confused", self.equation,
Write(randy_words)
)
self.play(randy.look_at, self.equation.get_left())
self.play(randy.look_at, jenny.eyes)
self.play(jenny.change, "happy")
self.play(randy.change, "tired")
self.dither()
self.play(*map(FadeOut, [
jenny.bubble, jenny_words, randy_words
]))
def no_genius(self):
randy, jenny = self.randy, self.jenny
lightbulb = Lightbulb()
lightbulb.next_to(jenny, UP)
cross = Cross(lightbulb)
cross.set_stroke(RED, 8)
self.play(LaggedStart(ShowCreation, lightbulb))
self.play(
ShowCreation(cross),
jenny.change, "sassy", cross,
randy.change, "happy"
)
self.dither(2)
self.to_fade = VGroup(lightbulb, cross)
def think_about_patterns(self):
randy, jenny = self.randy, self.jenny
rows = PascalsTraingle(
n_rows = 6,
distance = 0.6,
)
rows.scale(0.8)
for row in rows:
for num in row:
n = float(num.get_tex_string())
num.highlight(interpolate_color(
BLUE, YELLOW, n/10.0
))
self.pi_creature_thinks(
jenny, "",
bubble_kwargs = {"width" : 5, "height" : 4.2},
added_anims = [
FadeOut(self.to_fade),
FadeOut(self.equation),
randy.change, "plain"
]
)
rows.move_to(
jenny.bubble.get_bubble_center() + \
MED_SMALL_BUFF*(UP+LEFT)
)
self.play(FadeIn(rows[0]))
for last_row, curr_row in zip(rows, rows[1:]):
self.play(*[
Transform(
last_row.copy(), VGroup(*mobs),
remover = True
)
for mobs in curr_row[1:], curr_row[:-1]
])
self.add(curr_row)
self.dither(3)
############
def create_pi_creatures(self):
randy = Randolph()
randy.to_edge(DOWN)
randy.shift(4*LEFT)
jenny = PiCreature(color = BLUE_C).flip()
jenny.to_edge(DOWN)
jenny.shift(4*RIGHT)
self.randy, self.jenny = randy, jenny
return randy, jenny
class InitialFiveChooseThreeExample(Scene):
2017-11-29 10:11:41 -08:00
CONFIG = {
"n" : 5,
"zero_color" : BLUE,
"one_color" : PINK,
2017-11-29 10:11:41 -08:00
}
def construct(self):
self.add_title()
self.show_all_stacks()
self.show_binomial_name()
self.issolate_single_stack()
self.count_chosen_stack()
self.count_ways_to_fill_slots()
self.walk_though_notation()
self.emphasize_pattern_over_number()
def add_title(self):
2017-11-29 10:11:41 -08:00
symbol = TexMobject("n \\choose k")
words = TextMobject("``n choose k''")
group = VGroup(symbol, words)
group.arrange_submobjects(RIGHT)
group.to_edge(UP)
2017-11-29 10:11:41 -08:00
self.add(group)
self.n_choose_k = symbol
self.n_choose_k_words = words
2017-11-29 10:11:41 -08:00
def show_all_stacks(self):
n = self.n
n_choose_k = self.n_choose_k
n_choose_k_words = self.n_choose_k_words
2017-11-29 10:11:41 -08:00
binomials = VGroup(*[
TexMobject("%d \\choose %d"%(n, k))
for k in range(n+1)
])
binomial_equations = VGroup()
for k, binomial in enumerate(binomials):
binomial.scale(0.75)
number = TexMobject(str(choose(n, k)))
equation = VGroup(binomial, TexMobject("="), number)
equation.arrange_submobjects(RIGHT, buff = SMALL_BUFF)
equation.highlight(YELLOW)
equation[1].highlight(WHITE)
binomial_equations.add(equation)
stacks = get_stacks(
self.get_obj1(), self.get_obj2(), n,
vertical_buff = SMALL_BUFF
2017-11-29 10:11:41 -08:00
)
stacks.to_edge(DOWN, buff = MED_LARGE_BUFF)
2017-11-29 10:11:41 -08:00
for stack, eq in zip(stacks, binomial_equations):
eq.scale_to_fit_width(0.9*stack.get_width())
eq.next_to(stack, UP)
mover = VGroup()
2017-11-29 10:11:41 -08:00
for eq in binomial_equations:
point = VectorizedPoint(n_choose_k.get_center())
group = VGroup(n_choose_k, point, point).copy()
group.target = eq
mover.add(group)
self.play(FadeIn(
stacks,
run_time = 2,
submobject_mode = "lagged_start"
))
self.play(LaggedStart(
MoveToTarget, mover,
run_time = 3,
))
self.remove(mover)
self.add(binomial_equations)
self.dither()
2017-11-29 10:11:41 -08:00
self.set_variables_as_attrs(stacks, binomial_equations)
def show_binomial_name(self):
new_words = TextMobject("``Binomial coefficients''")
new_words.move_to(self.n_choose_k_words, LEFT)
2017-11-29 10:11:41 -08:00
self.play(Transform(self.n_choose_k_words, new_words))
self.dither(2)
2017-11-29 10:11:41 -08:00
def issolate_single_stack(self):
stack = self.stacks[3]
equation = self.binomial_equations[3]
to_fade = VGroup(*self.stacks)
to_fade.add(*self.binomial_equations)
to_fade.add(self.n_choose_k, self.n_choose_k_words)
to_fade.remove(stack, equation)
2017-11-29 10:11:41 -08:00
self.play(
FadeOut(to_fade),
equation.scale, 1.5, equation.get_bottom(),
2017-11-29 10:11:41 -08:00
)
self.dither()
for line in stack:
ones = VGroup(*filter(
lambda mob : "1" in mob.get_tex_string(),
line
))
line.ones = ones
self.play(LaggedStart(
ApplyMethod, ones,
lambda mob : (mob.highlight, YELLOW),
rate_func = there_and_back,
lag_ratio = 0.7,
run_time = 1,
))
def count_chosen_stack(self):
stack = self.stacks[3]
for i, line in enumerate(stack):
number = TexMobject(str(i+1))
number.next_to(stack, LEFT)
brace = Brace(VGroup(*stack[:i+1]), LEFT)
number.next_to(brace, LEFT)
line.save_state()
line.highlight(YELLOW)
self.add(number, brace)
self.dither(0.25)
self.remove(number, brace)
line.restore()
self.add(number, brace)
2017-11-29 10:11:41 -08:00
self.dither()
self.set_variables_as_attrs(
stack_brace = brace,
stack_count = number
2017-11-29 10:11:41 -08:00
)
def count_ways_to_fill_slots(self):
lines = VGroup(*[Line(ORIGIN, 0.25*RIGHT) for x in range(5)])
lines.arrange_submobjects(RIGHT)
lines.next_to(self.stacks[3], LEFT, LARGE_BUFF, UP)
self.play(ShowCreation(lines))
count = 1
for indices in it.combinations(range(5), 3):
ones = VGroup(*[
self.get_obj1().next_to(lines[i], UP)
for i in indices
])
num = TexMobject(str(count))
num.next_to(lines, DOWN)
self.add(ones, num)
self.dither(0.35)
self.remove(ones, num)
count += 1
self.add(num, ones)
2017-11-29 10:11:41 -08:00
self.dither()
self.play(*map(FadeOut, [lines, num, ones]))
def walk_though_notation(self):
equation = self.binomial_equations[3]
rect = SurroundingRectangle(equation[0])
rect.highlight(WHITE)
words = TextMobject("``5 choose 3''")
words.next_to(rect, UP)
self.play(Write(words))
self.play(ShowCreation(rect))
self.play(FadeOut(rect))
self.dither(2)
def emphasize_pattern_over_number(self):
morty = Mortimer().flip()
morty.to_corner(DOWN+LEFT)
words = TextMobject("Remember the pattern \\\\ not the number")
words.next_to(morty, UP)
words.shift_onto_screen()
self.play(FadeIn(morty))
self.play(
morty.change, "speaking",
Write(words, run_time = 2)
)
self.play(
Blink(morty),
morty.change, "happy"
)
self.revert_to_original_skipping_status()
last_ones = VGroup()
last_ones.save_state()
for x in range(2):
for line in self.stacks[3]:
ones = line.ones
ones.save_state()
self.play(
ones.highlight, YELLOW,
last_ones.restore,
morty.look_at, ones,
run_time = 0.25
)
last_ones = ones
self.dither()
####
def get_obj1(self):
return TexMobject("1").highlight(self.one_color)
def get_obj2(self):
return TexMobject("0").highlight(self.zero_color)
class SixChooseThreeExample(InitialFiveChooseThreeExample):
CONFIG = {
"n" : 6,
"k" : 3,
"stack_height" : 7,
}
def construct(self):
self.show_stack()
self.talk_through_one_line()
self.count_stack()
self.think_about_pattern()
def show_stack(self):
stack = get_stack(
self.get_obj1(), self.get_obj2(),
self.n, self.k,
vertical_buff = SMALL_BUFF
)
stack.scale_to_fit_height(self.stack_height)
stack.to_edge(DOWN)
for line in stack:
line.ones = VGroup(*filter(
lambda mob : "1" in mob.get_tex_string(),
line
))
equation = TexMobject(
"{%d \\choose %d}"%(self.n, self.k),
"=", str(choose(self.n, self.k))
)
equation.highlight(YELLOW)
equation.highlight_by_tex("=", WHITE)
equation.next_to(stack, RIGHT, LARGE_BUFF)
self.play(
FadeIn(equation),
LaggedStart(FadeIn, stack)
)
self.dither()
self.set_variables_as_attrs(stack)
def talk_through_one_line(self):
line = self.stack[8]
line.save_state()
distance = SPACE_WIDTH/2
self.play(line.shift, distance*LEFT)
brace = Brace(line, UP)
n_options = TextMobject(str(self.n), "options")
n_options.highlight_by_tex(str(self.n), YELLOW)
n_options.next_to(brace, UP)
arrows = VGroup(*[
Vector(0.5*UP).next_to(one, DOWN, SMALL_BUFF)
for one in line.ones
])
arrows.highlight(self.one_color)
choose_k = TextMobject("Choose", str(self.k), "of them")
choose_k.highlight_by_tex(str(self.k), YELLOW)
choose_k.next_to(arrows, DOWN)
self.play(
GrowFromCenter(brace),
Write(n_options),
run_time = 1
)
self.play(
LaggedStart(GrowArrow, arrows),
Write(choose_k, run_time = 1)
)
self.dither(2)
self.play(
line.restore,
*map(FadeOut, [brace, n_options, arrows, choose_k])
)
def count_stack(self):
stack = self.stack
for i, line in enumerate(stack):
brace = Brace(VGroup(*stack[:i+1]), LEFT)
num = TexMobject(str(i+1))
num.next_to(brace, LEFT)
line.ones.save_state()
line.ones.highlight(YELLOW)
line.ones.set_stroke(RED, 1)
self.add(brace, num)
self.dither(0.15)
self.remove(brace, num)
line.ones.restore()
self.add(brace, num)
self.dither()
lhs = TexMobject(
"\\frac{6 \\cdot 5 \\cdot 3}{1 \\cdot 2 \\cdot 3} ="
)
lhs.next_to(num, LEFT)
coming_soon = TextMobject("Coming soon...")
coming_soon.next_to(lhs, UP)
coming_soon.highlight(MAROON_B)
self.play(*map(FadeIn, [lhs, coming_soon]))
self.dither()
self.play(
ApplyMethod(
lhs.shift, 0.65*SPACE_WIDTH*(LEFT+UP),
path_arc = np.pi/2,
rate_func = running_start,
remover = True,
),
*map(FadeOut, [brace, num, coming_soon])
)
self.dither()
def think_about_pattern(self):
self.revert_to_original_skipping_status()
last_ones = VGroup()
last_ones.save_state()
for x in range(2):
for line in self.stack:
ones = line.ones
ones.save_state()
self.play(
ones.highlight, YELLOW,
ones.set_stroke, RED, 1,
last_ones.restore,
run_time = 0.2
)
last_ones = ones
self.dither()
class SixChooseThreeInOtherContext(Scene):
def construct(self):
self.add_dots()
self.count_paths_to_three_three()
def add_dots(self):
n = 4
dots = VGroup(*[Dot() for x in range(n**2)])
dots.arrange_submobjects_in_grid(n, n, buff = LARGE_BUFF)
dots.next_to(ORIGIN, LEFT)
self.add(dots)
self.dots = dots
self.dot_to_dot_distance = np.linalg.norm(
dots[1].get_center() - dots[0].get_center()
)
def count_paths_to_three_three(self):
dots = self.dots
d = self.dot_to_dot_distance
lower_left = dots.get_corner(DOWN+LEFT)
lower_left += dots[0].radius*(UP+RIGHT)
right = Vector(d*RIGHT, color = PINK)
up = Vector(d*UP, color = BLUE)
last_rights = None
last_ups = None
last_line = None
for indices in it.combinations(range(6), 3):
bools = [i in indices for i in range(6)]
arrows = VGroup(*[
right.deepcopy() if b else up.deepcopy()
for b in bools
])
last_point = np.array(lower_left)
ups, rights = VGroup(), VGroup()
for arrow, b in zip(arrows, bools):
arrow.shift(last_point - arrow.get_start())
last_point = arrow.get_end()
group = rights if b else ups
group.add(arrow)
line = VGroup(*[arrow.tip.copy() for arrow in arrows])
line.arrange_submobjects(RIGHT, buff = 0.5*SMALL_BUFF)
if last_line is None:
line.shift(SPACE_WIDTH*RIGHT/2)
line.to_edge(UP)
self.play(
ShowCreation(arrows),
ShowCreation(line)
)
else:
line.next_to(last_line, DOWN, SMALL_BUFF)
self.play(
FadeIn(line),
ReplacementTransform(last_rights, rights),
ReplacementTransform(last_ups, ups),
)
last_rights = rights
last_ups = ups
last_line = line
self.dither()
# class Introduction(Scene):
# CONFIG = {
# "start_n" : 4,
# }
# def construct(self):
# self.write_n_choose_k()
# self.show_binomial_coefficients()
# self.perform_shift()
# def write_n_choose_k(self):
# symbol = TexMobject("n \\choose k")
# words = TextMobject("``n choose k''")
# group = VGroup(symbol, words)
# group.arrange_submobjects(RIGHT)
# self.play(
# FadeIn(symbol),
# Write(words)
# )
# self.dither()
# self.set_variables_as_attrs(n_choose_k_group = group)
# def show_binomial_coefficients(self):
# n = self.start_n
# n_choose_k, n_choose_k_words = self.n_choose_k_group
# binomials = VGroup(*[
# TexMobject("%d \\choose %d"%(n, k))
# for k in range(n+1)
# ])
# binomial_equations = VGroup()
# for k, binomial in enumerate(binomials):
# binomial.scale(0.75)
# number = TexMobject(str(choose(n, k)))
# equation = VGroup(binomial, TexMobject("="), number)
# equation.arrange_submobjects(RIGHT, buff = SMALL_BUFF)
# equation.highlight(YELLOW)
# equation[1].highlight(WHITE)
# binomial_equations.add(equation)
# new_words = TextMobject("``Binomial coefficients''")
# stacks = get_stacks(
# TexMobject("x").highlight(BLUE),
# TexMobject("y").highlight(RED),
# n
# )
# stacks.to_edge(DOWN, buff = LARGE_BUFF)
# for stack, eq in zip(stacks, binomial_equations):
# eq.scale_to_fit_width(0.9*stack.get_width())
# eq.next_to(stack, UP)
# self.play(
# FadeIn(stacks, run_time = 2, submobject_mode = "lagged_start"),
# self.n_choose_k_group.to_edge, UP
# )
# new_words.move_to(n_choose_k_words, LEFT)
# self.play(Transform(n_choose_k_words, new_words))
# for eq in binomial_equations:
# point = VectorizedPoint(n_choose_k.get_center())
# self.play(ReplacementTransform(
# VGroup(n_choose_k, point, point).copy(),
# eq
# ))
# self.dither()
# self.set_variables_as_attrs(stacks, binomial_equations)
# def perform_shift(self):
# n = self.start_n
# to_fade = VGroup(
# self.n_choose_k_group,
# self.binomial_equations
# )
# stacks = self.stacks
# top_stacks = stacks.copy()
# top_stacks.to_edge(UP, buff = MED_SMALL_BUFF)
# line = Line(LEFT, RIGHT, color = WHITE)
# line.scale(SPACE_WIDTH)
# line.next_to(top_stacks, DOWN)
# x = TexMobject("x").highlight(BLUE)
# y = TexMobject("y").highlight(RED)
# add_x, add_y = [
# TextMobject("Prepend", "$%s$"%s).highlight_by_tex(s, color)
# for s, color in ("x", BLUE), ("y", RED)
# ]
# add_x.to_corner(UP+LEFT)
# add_y.to_edge(LEFT).shift(MED_SMALL_BUFF*DOWN)
# new_stacks, new_top_stacks = [
# get_stacks(x, y, n, fixed_start = var)
# for var in y, x
# ]
# new_top_stacks.to_edge(UP, buff = MED_SMALL_BUFF)
# new_stacks.to_edge(DOWN)
# for s in new_stacks, new_top_stacks:
# s.start_terms = VGroup()
# for stack in s:
# for term in stack:
# s.start_terms.add(term[0])
# s_to_s_distance = \
# new_stacks[1].get_center()[0] - \
# new_stacks[0].get_center()[0]
# self.play(
# FadeOut(to_fade),
# stacks.to_edge, DOWN,
# ReplacementTransform(stacks.copy(), top_stacks),
# )
# self.play(ShowCreation(line))
# self.play(Write(add_x, run_time = 1))
# self.play(Transform(top_stacks, new_top_stacks))
# self.play(LaggedStart(
# Indicate, new_top_stacks.start_terms,
# rate_func = there_and_back,
# run_time = 1,
# remover = True
# ))
# self.dither()
# self.play(Write(add_y, run_time = 1))
# self.play(Transform(stacks, new_stacks))
# self.play(LaggedStart(
# Indicate, new_stacks.start_terms,
# rate_func = there_and_back,
# run_time = 1,
# remover = True
# ))
# self.dither()
# self.play(
# top_stacks.shift, s_to_s_distance*RIGHT/2,
# stacks.shift, s_to_s_distance*LEFT/2,
# )
# self.play(*map(FadeOut, [add_x, add_y, line]))
# point = VectorizedPoint()
# point.move_to(top_stacks[0].get_bottom())
# point.shift(s_to_s_distance*LEFT)
# top_stacks.add_to_back(point)
# point = VectorizedPoint()
# point.move_to(stacks[-1].get_bottom())
# point.shift(s_to_s_distance*RIGHT)
# point.shift(MED_SMALL_BUFF*DOWN)
# stacks.add(point)
# for k, stack, top_stack in zip(it.count(), stacks, top_stacks):
# top_stack.generate_target()
# top_stack.target.next_to(stack, UP, MED_SMALL_BUFF)
# # term = TexMobject(
# # str(choose(n+1, k)),
# # "x^%d"%(n+1-k),
# # "y^%d"%k
# # )
# term = TexMobject(
# "{%d \\choose %d}"%(n+1, k),
# "=",
# str(choose(n+1, k))
# )
# term[0].scale(0.85, about_point = term[0].get_right())
# term[0].highlight(YELLOW)
# term[2].highlight(YELLOW)
# term.scale(0.85)
# term.next_to(top_stack.target, UP)
# self.play(MoveToTarget(top_stack))
# self.play(Write(term))
# self.dither()
2017-11-29 10:11:41 -08:00
# class DifferentWaysToThinkAboutNChooseK(Scene):
# CONFIG = {
# "n" : 5,
# "k" : 3,
# "stack_height" : 5,
# }
# def construct(self):
# self.add_n_choose_k_term()
# self.add_stack()
# self.choose_k()
# self.split_stack_by_start()
# self.split_choices_by_start()
# def add_n_choose_k_term(self):
# term = TexMobject("{5 \\choose 3} = 10")
# term.to_edge(UP)
# self.play(FadeIn(term, submobject_mode = "lagged_start"))
# self.dither()
2017-11-29 10:11:41 -08:00
# self.n_choose_k_term = term
2017-11-29 10:11:41 -08:00
# def add_stack(self):
# n, k = self.n, self.k
# x = TexMobject("x").highlight(BLUE)
# y = TexMobject("y").highlight(RED)
# stack = get_stack(x, y, n, k)
# stack.scale_to_fit_height(self.stack_height)
# stack.shift(SPACE_WIDTH*LEFT/2)
# stack.to_edge(DOWN)
# numbers = VGroup(*[
# TexMobject("%d"%(d+1))
# for d in range(choose(n, k))
# ])
# numbers.next_to(stack, UP)
# last_number = None
# for term, number in zip(stack, numbers):
# self.add(term, number)
# if last_number:
# self.remove(last_number)
# self.dither(0.25)
# last_number = number
# self.dither()
2017-11-29 10:11:41 -08:00
# self.stack = stack
# self.stack_count = last_number
# self.numbers = numbers
2017-11-29 10:11:41 -08:00
# def choose_k(self):
# n, k = self.n, self.k
2017-11-29 10:11:41 -08:00
# letter_set = TexMobject(
# "(",
# "A", ",",
# "B", ",",
# "C", ",",
# "D", ",",
# "E", ")"
# )
# letters = VGroup(*letter_set[1::2])
# letter_set.shift(SPACE_WIDTH*RIGHT/2)
# letter_set.to_edge(UP)
# letter_subsets = list(it.combinations(letters, k))
# subset_mobs = VGroup(*[
# VGroup(*letter_subset).copy().arrange_submobjects(
# RIGHT, buff = SMALL_BUFF
# )
# for letter_subset in letter_subsets
# ]).arrange_submobjects(DOWN, buff = MED_SMALL_BUFF)
# subset_mobs.scale_to_fit_height(self.stack_height)
# subset_mobs.shift(SPACE_WIDTH*RIGHT/2)
# subset_mobs.to_edge(DOWN)
# choose_words = TextMobject("Choose %d"%k)
# choose_words.scale(0.9)
# choose_words.next_to(letter_set, DOWN)
# choose_words.highlight(YELLOW)
# self.revert_to_original_skipping_status()
# self.play(Write(letter_set, run_time = 1))
# self.play(
# Write(choose_words, run_time = 1),
# LaggedStart(FadeIn, subset_mobs)
# )
# self.dither()
# for subset, subset_mob in zip(letter_subsets, subset_mobs):
# VGroup(subset_mob, *subset).highlight(BLUE)
# self.dither(0.5)
# VGroup(*subset).highlight(WHITE)
# self.dither()
2017-11-29 10:11:41 -08:00
# self.set_variables_as_attrs(
# subset_mobs, letter_set, choose_words,
# )
2017-11-29 10:11:41 -08:00
# def split_stack_by_start(self):
# n, k = self.n, self.k
# stack = self.stack
# stack_count = self.stack_count
2017-11-29 10:11:41 -08:00
# top_num = choose(n-1, k-1)
# top_stack = VGroup(*stack[:top_num])
# bottom_stack = VGroup(*stack[top_num:])
2017-11-29 10:11:41 -08:00
# self.play(
# FadeOut(stack_count),
# top_stack.shift, UP
# )
# for stack, new_k in (top_stack, k-1), (bottom_stack, k):
# brace = Brace(stack, RIGHT)
# brace_tex = brace.get_tex(
# "{%d \\choose %d} = %d"%(n-1, new_k, choose(n-1, new_k))
# )
# rect = SurroundingRectangle(VGroup(*[
# VGroup(*term[1:])
# for term in stack
# ]), buff = 0.5*SMALL_BUFF)
# rect.set_stroke(WHITE, 2)
# self.play(
# GrowFromCenter(brace),
# Write(brace_tex),
# ShowCreation(rect)
# )
# self.dither()
2017-11-29 10:11:41 -08:00
# def split_choices_by_start(self):
# subset_mobs = self.subset_mobs
# subset_mobs.generate_target()
# subset_mobs.target.shift(LEFT)
# brace = Brace(subset_mobs.target, RIGHT)
# expression = brace.get_tex(
# "\\frac{5 \\cdot 4 \\cdot 3}{1 \\cdot 2 \\cdot 3}",
# "= 10"
# )
2017-11-29 10:11:41 -08:00
# self.play(
# MoveToTarget(subset_mobs),
# GrowFromCenter(brace)
# )
# self.play(Write(expression))
# self.dither()
2017-11-29 10:11:41 -08:00
# class FormulaVsPattern(TeacherStudentsScene):
# def construct(self):
# self.show_formula()
# self.show_pattern()
2017-11-29 10:11:41 -08:00
# def show_formula(self):
# formula = TexMobject(
# "{n \\choose k} = {n! \\over (n-k)!k!}",
# )
# for i in 1, 5, 9:
# formula[i].highlight(BLUE)
# for i in 2, 11, 14:
# formula[i].highlight(YELLOW)
# self.student_thinks(formula, student_index = 1)
# self.play(self.teacher.change, "sassy")
# self.dither(2)
# self.play(
# FadeOut(self.students[1].bubble),
# FadeOut(formula),
# self.teacher.change, "raise_right_hand",
# self.get_student_changes(*["pondering"]*3)
# )
2017-11-29 10:11:41 -08:00
# def show_pattern(self):
# words = TextMobject(
# "What is the \\\\ probability of a flush?"
# )
# values = random.sample(PlayingCard.CONFIG["possible_values"], 5)
# cards = VGroup(*[
# PlayingCard(value = value, suit = "hearts")
# for value in values
# ])
# cards.arrange_submobjects(RIGHT)
# cards.to_corner(UP+RIGHT)
# words.next_to(cards, LEFT)
# words.shift_onto_screen()
2017-11-29 10:11:41 -08:00
# self.play(LaggedStart(DrawBorderThenFill, cards))
# self.play(Write(words))
# self.dither(3)
2017-11-29 10:11:41 -08:00
class ProbabilityOfKWomenInGroupOfFive(Scene):
2017-11-29 10:11:41 -08:00
CONFIG = {
"random_seed" : 0,
2017-11-29 10:11:41 -08:00
"n_people_per_lineup" : 5,
"n_examples" : 16,
2017-11-29 10:11:41 -08:00
"item_line_width" : 0.4,
}
def construct(self):
random.seed(self.random_seed)
self.ask_question()
2017-11-29 10:11:41 -08:00
self.show_all_possibilities()
self.stack_all_choices_by_number_of_women()
self.go_through_stacks()
self.remember_this_sensation()
self.show_answer_to_question()
self.ask_about_pattern()
def ask_question(self):
2017-11-29 10:11:41 -08:00
title = TextMobject("5 randomly chosen people")
title.to_edge(UP)
2017-11-29 10:11:41 -08:00
self.add(title)
lineup_point = 1.5*UP
prob_words = VGroup(*[
TextMobject(
"Probability of", str(n), "women?"
).highlight_by_tex(str(n), YELLOW)
for n in range(self.n_people_per_lineup+1)
])
prob_words.arrange_submobjects(DOWN)
prob_words.next_to(lineup_point, DOWN, MED_LARGE_BUFF)
2017-11-29 10:11:41 -08:00
def get_lineup():
2017-11-29 10:11:41 -08:00
lineup = self.get_random_lineup_of_men_and_women()
lineup.scale(1.5)
lineup.move_to(lineup_point, DOWN)
return lineup
2017-11-29 10:11:41 -08:00
last_lineup = get_lineup()
self.play(
LaggedStart(FadeIn, last_lineup),
LaggedStart(FadeIn, prob_words),
)
2017-11-29 10:11:41 -08:00
for x in xrange(self.n_examples):
lineup = get_lineup()
self.play(
# last_lineup.items.shift, UP,
last_lineup.items.fade, 1,
*map(GrowFromCenter, lineup.items),
run_time = 0.75
)
self.remove(last_lineup)
2017-11-29 10:11:41 -08:00
self.add(lineup)
self.dither(0.25)
2017-11-29 10:11:41 -08:00
last_lineup = lineup
self.title = title
self.prob_words = prob_words
2017-11-29 10:11:41 -08:00
self.lineup = last_lineup
def show_all_possibilities(self):
man, woman = Male(), Female()
vects = [
1.5*UP,
0.65*UP,
0.25*UP,
2017-11-29 10:11:41 -08:00
3.5*RIGHT,
1.5*RIGHT,
]
lineup_groups = VGroup()
for k in range(6):
lineup_group = VGroup()
for tup in it.product(*[[woman, man]]*k):
2017-11-29 10:11:41 -08:00
lineup = self.get_lineup(*list(tup) + (5-k)*[None])
lineup.scale(1.4*(0.9)**k)
lineup.move_to(0.5*DOWN)
for mob, vect in zip(tup, vects):
if mob is woman:
lineup.shift(vect)
else:
lineup.shift(-vect)
lineup_group.add(lineup)
lineup_groups.add(lineup_group)
n_possibilities = TexMobject(
"2 \\cdot", "2 \\cdot", "2 \\cdot", "2 \\cdot", "2",
"\\text{ Possibilities}"
)
n_possibilities.next_to(self.title, DOWN)
twos = VGroup(*n_possibilities[-2::-1])
twos.highlight(YELLOW)
2017-11-29 10:11:41 -08:00
two_anims = [
ReplacementTransform(
VectorizedPoint(twos[0].get_center()),
twos[0]
)
] + [
ReplacementTransform(t1.copy(), t2)
for t1, t2 in zip(twos, twos[1:])
]
curr_lineup_group = lineup_groups[0]
self.play(
ReplacementTransform(self.lineup, curr_lineup_group[0]),
FadeOut(self.prob_words)
2017-11-29 10:11:41 -08:00
)
for i, lineup_group in enumerate(lineup_groups[1:]):
anims = [ReplacementTransform(curr_lineup_group, lineup_group)]
anims += two_anims[:i+1]
if i == 0:
anims.append(FadeIn(n_possibilities[-1]))
self.remove(twos)
self.play(*anims)
men, women = VGroup(), VGroup()
for lineup in lineup_group:
item = lineup.items[i]
if "female" in item.get_tex_string():
women.add(item)
else:
men.add(item)
for group in men, women:
self.play(LaggedStart(
ApplyMethod, group,
lambda m : (m.shift, MED_SMALL_BUFF*RIGHT),
rate_func = there_and_back,
lag_ratio = 0.9**i,
run_time = 1,
))
self.dither()
curr_lineup_group = lineup_group
self.lineups = curr_lineup_group
eq_32 = TexMobject("=", "32")
eq_32.move_to(twos.get_right())
eq_32.highlight_by_tex("32", YELLOW)
self.play(
n_possibilities[-1].next_to, eq_32, RIGHT,
twos.next_to, eq_32, LEFT,
FadeIn(eq_32),
)
self.dither()
n_possibilities.add(*eq_32)
self.set_variables_as_attrs(n_possibilities)
def stack_all_choices_by_number_of_women(self):
2017-11-29 10:11:41 -08:00
lineups = self.lineups
stacks = VGroup(*[VGroup() for x in range(6)])
2017-11-29 10:11:41 -08:00
for lineup in lineups:
lineup.women = VGroup(*filter(
lambda m : "female" in m.get_tex_string(),
2017-11-29 10:11:41 -08:00
lineup.items
))
stacks[len(lineup.women)].add(lineup)
stacks.generate_target()
stacks.target.scale(0.75)
for stack in stacks.target:
stack.arrange_submobjects(DOWN, buff = 1.5*SMALL_BUFF)
2017-11-29 10:11:41 -08:00
stacks.target.arrange_submobjects(
RIGHT, buff = MED_LARGE_BUFF, aligned_edge = DOWN
)
stacks.target.to_edge(DOWN)
self.play(MoveToTarget(
stacks,
run_time = 2,
path_arc = np.pi/2
))
self.dither()
self.stacks = stacks
def go_through_stacks(self):
stacks = self.stacks
n = len(stacks) - 1
equations = VGroup()
for k, stack in enumerate(stacks):
2017-11-29 10:11:41 -08:00
items = VGroup()
lines = VGroup()
women = VGroup()
for lineup in stack:
items.add(lineup.items)
lines.add(lineup.lines)
for item in lineup.items:
if "female" in item.get_tex_string():
women.add(item)
equation = TexMobject(
"{%d \\choose %d}"%(n, k),
"=",
str(len(stack))
)
equation[0].scale_in_place(0.6)
equation.arrange_submobjects(RIGHT, SMALL_BUFF)
equation.highlight(YELLOW)
equation.highlight_by_tex("=", WHITE)
equation.next_to(stack, UP)
equations.add(equation)
2017-11-29 10:11:41 -08:00
self.play(
items.set_fill, None, 1,
lines.set_stroke, WHITE, 3,
Write(equation, run_time = 1)
2017-11-29 10:11:41 -08:00
)
self.play(LaggedStart(Indicate, women, rate_func = there_and_back))
self.dither()
self.equations = equations
self.numbers = VGroup(*[eq[-1] for eq in equations])
2017-11-29 10:11:41 -08:00
def remember_this_sensation(self):
n_possibilities = self.n_possibilities
n_possibilities_rect = SurroundingRectangle(n_possibilities)
twos = VGroup(*n_possibilities[:5])
numbers = self.numbers
self.play(ShowCreation(n_possibilities_rect))
self.play(LaggedStart(
Indicate, twos,
rate_func = wiggle
))
self.play(FadeOut(n_possibilities_rect))
for number in numbers:
self.play(Indicate(number, color = PINK, run_time = 0.5))
self.dither()
def show_answer_to_question(self):
stacks = self.stacks
numbers = self.numbers
n_possibilities = VGroup(
self.n_possibilities[-1],
self.n_possibilities[-3]
2017-11-29 10:11:41 -08:00
)
n_possibilities_part_to_fade = VGroup(
self.n_possibilities[-2],
*self.n_possibilities[:-3]
2017-11-29 10:11:41 -08:00
)
total = n_possibilities[-1]
title = self.title
n = self.n_people_per_lineup
2017-11-29 10:11:41 -08:00
self.play(
FadeOut(title),
FadeOut(n_possibilities_part_to_fade),
n_possibilities.to_corner, UP+RIGHT
2017-11-29 10:11:41 -08:00
)
for k, stack, num in zip(it.count(), stacks, numbers):
rect = SurroundingRectangle(stack)
num.save_state()
prob_words = TexMobject(
"P(", "\\#", "\\female", "=", str(k), ")"
"=", "{\\quad \\over", "32}",
"\\approx", "%0.3f"%(choose(n, k)/32.0)
)
prob_words.highlight_by_tex_to_color_map({
"female" : MAROON_B,
"32" : YELLOW,
})
frac_line = prob_words.get_parts_by_tex("over")
prob_words.to_corner(UP+LEFT)
self.play(
num.next_to, frac_line, UP, SMALL_BUFF,
FadeIn(prob_words)
)
self.play(ShowCreation(rect))
self.dither(2)
self.play(
num.restore,
FadeOut(rect),
FadeOut(prob_words)
)
2017-11-29 10:11:41 -08:00
def ask_about_pattern(self):
question = TextMobject("Where do these \\\\ numbers come from?")
question.to_edge(UP)
numbers = self.numbers
circles = VGroup(*[
Circle().replace(num, dim_to_match = 1).scale_in_place(1.5)
for num in numbers
])
circles.highlight(WHITE)
self.play(LaggedStart(FadeIn, question))
self.play(LaggedStart(ShowCreationThenDestruction, circles))
self.dither(2)
######
def get_random_lineup_of_men_and_women(self):
man, woman = Male(), Female()
lineup = self.get_lineup(*[
woman if random.choice([True, False]) else man
for y in range(self.n_people_per_lineup)
])
return lineup
2017-11-29 15:12:39 -08:00
def get_lineup(self, *mobjects, **kwargs):
buff = kwargs.get("buff", MED_SMALL_BUFF)
2017-11-29 10:11:41 -08:00
lines = VGroup(*[
Line(ORIGIN, self.item_line_width*RIGHT)
for mob in mobjects
])
2017-11-29 15:12:39 -08:00
lines.arrange_submobjects(RIGHT, buff = buff)
2017-11-29 10:11:41 -08:00
items = VGroup()
for line, mob in zip(lines, mobjects):
item = VectorizedPoint() if mob is None else mob.copy()
item.next_to(line, UP, SMALL_BUFF)
items.add(item)
result = VGroup(lines, items)
result.lines = lines
result.items = items
return result
class RememberThisSensation(TeacherStudentsScene):
def construct(self):
self.teacher_says("Remember this \\\\ sensation")
self.change_student_modes("confused", "pondering", "erm")
self.dither(2)
# class GroupsOf6(Scene):
# def construct(self):
# title = TexMobject("2^6 =", "64", "\\text{ Possibilities}")
# title.to_edge(UP, buff = MED_SMALL_BUFF)
# title.highlight_by_tex("64", YELLOW)
# man, woman = Male(), Female()
# stacks = get_stacks(man, woman, 6, vertical_buff = SMALL_BUFF)
# stacks.scale_to_fit_height(6.25)
# stacks.to_edge(DOWN, buff = MED_SMALL_BUFF)
# women_groups = VGroup()
# for stack in stacks:
# for lineup in stack:
# group = VGroup()
# for item in lineup:
# if "female" in item.get_tex_string():
# group.add(item)
# women_groups.add(group)
# numbers = VGroup()
# for stack in stacks:
# number = TexMobject(str(len(stack)))
# number.next_to(stack, UP, SMALL_BUFF)
# numbers.add(number)
# self.add(title)
# self.play(LaggedStart(
# LaggedStart, stacks,
# lambda s : (FadeIn, s),
# run_time = 3,
# ))
# self.play(Write(numbers, run_time = 3))
# self.dither()
# self.play(LaggedStart(
# ApplyMethod, women_groups,
# lambda m : (m.highlight, PINK),
# lag_ratio = 0.1,
# rate_func = wiggle,
# run_time = 6,
# ))
2017-11-29 15:12:39 -08:00
# class GroupsOf7(Scene):
# def construct(self):
# stack = get_stack(Male(), Female(), 7, 3)
# question = TextMobject(
# "How many groups \\\\ of 7 with 3 ", "$\\female$", "?"
# )
# question.highlight_by_tex("female", MAROON_B)
# question.shift(1.5*UP)
# self.add(question)
# for n, item in enumerate(stack):
# item.center()
# number = TexMobject(str(n))
# number.next_to(ORIGIN, DOWN, LARGE_BUFF)
# self.add(item, number)
# self.dither(0.2)
# self.remove(item, number)
# self.add(item, number)
# self.dither(2)
class BuildFiveFromFour(ProbabilityOfKWomenInGroupOfFive):
2017-11-29 15:12:39 -08:00
def construct(self):
self.show_all_configurations_of_four()
self.organize_into_stacks()
self.walk_through_stacks()
self.split_into_two_possibilities()
self.combine_stacks()
def show_all_configurations_of_four(self):
man, woman = Male(), Female()
n = 4
vects = [
1.5*UP,
0.5*UP,
3.5*RIGHT,
1.5*RIGHT,
]
lineup_groups = VGroup()
for k in range(n+1):
lineup_group = VGroup()
for tup in it.product(*[[man, woman]]*k):
lineup = self.get_lineup(*list(tup) + (n-k)*[None])
lineup.scale(1.4*(0.9)**k)
lineup.move_to(0.5*DOWN)
for mob, vect in zip(tup, vects):
if mob is woman:
lineup.shift(vect)
else:
lineup.shift(-vect)
lineup_group.add(lineup)
lineup_groups.add(lineup_group)
n_possibilities = TexMobject(
"2 \\cdot", "2 \\cdot", "2 \\cdot", "2",
"\\text{ Possibilities}"
)
n_possibilities.to_edge(UP)
twos = VGroup(*n_possibilities[-2::-1])
two_anims = [
ReplacementTransform(
VectorizedPoint(twos[0].get_center()),
twos[0]
)
] + [
ReplacementTransform(t1.copy(), t2)
for t1, t2 in zip(twos, twos[1:])
]
curr_lineup_group = lineup_groups[0]
self.play(
ShowCreation(curr_lineup_group[0]),
)
for i, lineup_group in enumerate(lineup_groups[1:]):
anims = [ReplacementTransform(curr_lineup_group, lineup_group)]
anims += two_anims[:i+1]
if i == 0:
anims.append(FadeIn(n_possibilities[-1]))
self.remove(twos)
self.play(*anims)
self.dither()
curr_lineup_group = lineup_group
self.lineups = curr_lineup_group
eq_16 = TexMobject("=", "16")
eq_16.move_to(twos.get_right())
eq_16.highlight_by_tex("16", YELLOW)
self.play(
n_possibilities[-1].next_to, eq_16, RIGHT,
twos.next_to, eq_16, LEFT,
FadeIn(eq_16),
)
self.dither()
n_possibilities.add(eq_16)
self.n_possibilities = n_possibilities
def organize_into_stacks(self):
lineups = self.lineups
stacks = VGroup(*[VGroup() for x in range(5)])
for lineup in lineups:
women = filter(
lambda m : "female" in m.get_tex_string(),
lineup.items
)
stacks[len(women)].add(lineup)
stacks.generate_target()
stacks.target.scale(0.75)
for stack in stacks.target:
stack.arrange_submobjects(DOWN, buff = SMALL_BUFF)
stacks.target.arrange_submobjects(
RIGHT, buff = MED_LARGE_BUFF, aligned_edge = DOWN
)
stacks.target.to_edge(DOWN, buff = MED_SMALL_BUFF)
self.play(MoveToTarget(
stacks,
run_time = 2,
path_arc = np.pi/2
))
self.dither()
self.stacks = stacks
def walk_through_stacks(self):
stacks = self.stacks
numbers = VGroup()
for stack in stacks:
rect = SurroundingRectangle(stack)
rect.set_stroke(WHITE, 2)
self.play(ShowCreation(rect))
for n, lineup in enumerate(stack):
lineup_copy = lineup.copy()
lineup_copy.highlight(YELLOW)
number = TexMobject(str(n+1))
number.next_to(stack, UP)
self.add(lineup_copy, number)
self.dither(0.25)
self.remove(lineup_copy, number)
self.add(number)
numbers.add(number)
self.play(FadeOut(rect))
self.dither()
stacks.numbers = numbers
def split_into_two_possibilities(self):
bottom_stacks = self.stacks
top_stacks = bottom_stacks.deepcopy()
top_group = VGroup(top_stacks, top_stacks.numbers)
h_line = DashedLine(SPACE_WIDTH*LEFT, SPACE_WIDTH*RIGHT)
#Initial split
self.play(
FadeOut(self.n_possibilities),
top_group.to_edge, UP, MED_SMALL_BUFF,
)
self.play(ShowCreation(h_line))
#Add extra slot
for stacks, sym in (top_stacks, Female()), (bottom_stacks, Male()):
sym.set_fill(opacity = 0)
new_stacks = VGroup()
to_fade_in = VGroup()
for stack in stacks:
new_stack = VGroup()
for lineup in stack:
new_lineup = self.get_lineup(*[
Female() if "female" in item.get_tex_string() else Male()
for item in lineup.items
] + [sym], buff = SMALL_BUFF)
new_lineup.replace(lineup, dim_to_match = 1)
new_stack.add(new_lineup)
for group in lineup.items, lineup.lines:
point = VectorizedPoint(group[-1].get_center())
group.add(point)
to_fade_in.add(lineup.items[-1])
new_stacks.add(new_stack)
new_stacks.arrange_submobjects(
RIGHT, buff = MED_LARGE_BUFF, aligned_edge = DOWN
)
new_stacks.move_to(stacks, DOWN)
stacks.target = new_stacks
stacks.to_fade_in = to_fade_in
stacks.numbers.generate_target()
for number, stack in zip(stacks.numbers.target, new_stacks):
number.next_to(stack, UP)
for stacks in top_stacks, bottom_stacks:
self.play(
MoveToTarget(stacks),
MoveToTarget(stacks.numbers)
)
self.dither()
#Fill extra slot
add_man = TextMobject("Add", "$\\male$")
add_man.highlight_by_tex("male", BLUE)
add_woman = TextMobject("Add", "$\\female$")
add_woman.highlight_by_tex("female", MAROON_B)
add_man.next_to(ORIGIN, DOWN).to_edge(LEFT)
add_woman.to_corner(UP+LEFT)
for stacks, words in (bottom_stacks, add_man), (top_stacks, add_woman):
to_fade_in = stacks.to_fade_in
to_fade_in.set_fill(opacity = 1)
to_fade_in.save_state()
Transform(to_fade_in, VGroup(words[-1])).update(1)
self.play(Write(words, run_time = 1))
self.play(to_fade_in.restore)
self.dither()
#Perform shift
dist = top_stacks[1].get_center()[0] - top_stacks[0].get_center()[0]
self.play(
top_stacks.shift, dist*RIGHT/2,
top_stacks.numbers.shift, dist*RIGHT/2,
bottom_stacks.shift, dist*LEFT/2,
bottom_stacks.numbers.shift, dist*LEFT/2,
)
self.dither()
self.play(*map(FadeOut, [add_man, add_woman, h_line]))
self.set_variables_as_attrs(top_stacks, bottom_stacks)
def combine_stacks(self):
top_stacks = self.top_stacks
bottom_stacks = self.bottom_stacks
rects = VGroup()
for stacks, color in (top_stacks, MAROON_C), (bottom_stacks, BLUE_D):
for stack in stacks:
rect = SurroundingRectangle(stack)
rect.set_stroke(color, 2)
rects.add(rect)
stack.add(rect)
new_numbers = VGroup()
self.play(LaggedStart(ShowCreation, rects, run_time = 1))
for i, top_stack in enumerate(top_stacks[:-1]):
bottom_stack = bottom_stacks[i+1]
top_number = top_stacks.numbers[i]
bottom_number = bottom_stacks.numbers[i+1]
movers = top_stack, top_number, bottom_number
for mob in movers:
mob.generate_target()
top_stack.target.move_to(bottom_stack.get_top(), DOWN)
plus = TexMobject("+")
expr = VGroup(top_number.target, plus, bottom_number.target)
expr.arrange_submobjects(RIGHT, buff = SMALL_BUFF)
expr.next_to(top_stack.target.get_top(), UP)
new_number = TexMobject(str(
len(top_stack) + len(bottom_stack) - 2
))
new_number.next_to(expr, UP)
new_numbers.add(new_number)
self.play(
Write(plus),
*map(MoveToTarget, movers)
)
self.play(
VGroup(top_stacks[-1], top_stacks.numbers[-1]).align_to,
bottom_stacks, DOWN
)
self.dither()
new_numbers.add_to_back(bottom_stacks.numbers[0].copy())
new_numbers.add(top_stacks.numbers[-1].copy())
new_numbers.highlight(PINK)
self.play(Write(new_numbers, run_time = 3))
self.dither()
2017-11-30 12:02:55 -08:00
class BuildUpFromStart(Scene):
CONFIG = {
"n_iterations" : 7,
}
def construct(self):
stacks = VGroup(VGroup(Male()), VGroup(Female()))
stacks.arrange_submobjects(RIGHT, buff = LARGE_BUFF)
stacks.numbers = self.get_numbers(stacks)
max_width = 2*SPACE_WIDTH - 3
max_height = SPACE_HEIGHT - 1
self.add(stacks, stacks.numbers)
for x in range(self.n_iterations):
if x < 2:
dither_time = 1
else:
dither_time = 0.2
#Divide
low_stacks = stacks
low_group = VGroup(low_stacks, low_stacks.numbers)
top_stacks = stacks.deepcopy()
top_group = VGroup(top_stacks, top_stacks.numbers)
for group, vect in (top_group, UP), (low_group, DOWN):
group.generate_target()
if group[0].get_height() > max_height:
group.target[0].stretch_to_fit_height(max_height)
for stack, num in zip(*group.target):
num.next_to(stack, UP)
group.target.next_to(ORIGIN, vect)
self.play(*map(MoveToTarget, [top_group, low_group]))
self.dither(dither_time)
#Expand
for stacks, i in (low_stacks, 0), (top_stacks, -1):
sym = stacks[i][i][i]
new_stacks = VGroup()
for stack in stacks:
new_stack = VGroup()
for line in stack:
new_line = line.copy()
new_sym = sym.copy()
buff = 0.3*line.get_height()
new_sym.next_to(line, RIGHT, buff = buff)
new_line.add(new_sym)
line.add(VectorizedPoint(line[-1].get_center()))
new_stack.add(new_line)
new_stacks.add(new_stack)
new_stacks.arrange_submobjects(
RIGHT, buff = LARGE_BUFF, aligned_edge = DOWN
)
if new_stacks.get_width() > max_width:
new_stacks.stretch_to_fit_width(max_width)
if new_stacks.get_height() > max_height:
new_stacks.stretch_to_fit_height(max_height)
new_stacks.move_to(stacks, DOWN)
stacks.target = new_stacks
stacks.numbers.generate_target()
for num, stack in zip(stacks.numbers.target, new_stacks):
num.next_to(stack, UP)
self.play(*map(MoveToTarget, [
top_stacks, low_stacks,
top_stacks.numbers, low_stacks.numbers,
]))
self.dither(dither_time)
#Shift
dist = top_stacks[1].get_center()[0] - top_stacks[0].get_center()[0]
self.play(
top_group.shift, dist*RIGHT/2,
low_group.shift, dist*LEFT/2,
)
self.dither(dither_time)
#Stack
all_movers = VGroup()
plusses = VGroup()
expressions = VGroup(low_stacks.numbers[0])
stacks = VGroup(low_stacks[0])
v_buff = 0.25*stacks[0][0].get_height()
for i, top_stack in enumerate(top_stacks[:-1]):
low_stack = low_stacks[i+1]
top_num = top_stacks.numbers[i]
low_num = low_stacks.numbers[i+1]
movers = [top_stack, top_num, low_num]
for mover in movers:
mover.generate_target()
plus = TexMobject("+")
expr = VGroup(top_num.target, plus, low_num.target)
expr.arrange_submobjects(RIGHT, buff = SMALL_BUFF)
top_stack.target.next_to(low_stack, UP, buff = v_buff)
expr.next_to(top_stack.target, UP)
all_movers.add(*movers)
plusses.add(plus)
expressions.add(VGroup(top_num, plus, low_num))
stacks.add(VGroup(*it.chain(low_stack, top_stack)))
last_group = VGroup(top_stacks[-1], top_stacks.numbers[-1])
last_group.generate_target()
last_group.target.align_to(low_stacks, DOWN)
all_movers.add(last_group)
stacks.add(top_stacks[-1])
expressions.add(top_stacks.numbers[-1])
self.play(*it.chain(
map(MoveToTarget, all_movers),
map(Write, plusses),
))
#Add
new_numbers = self.get_numbers(stacks)
self.play(ReplacementTransform(
expressions, VGroup(*map(VGroup, new_numbers))
))
self.dither(dither_time)
stacks.numbers = new_numbers
####
def get_numbers(self, stacks):
return VGroup(*[
TexMobject(str(len(stack))).next_to(stack, UP)
for stack in stacks
])
2017-12-03 16:22:24 -08:00
class IntroducePascalsTriangle(Scene):
2017-11-30 12:02:55 -08:00
CONFIG = {
"max_n" : 9,
}
def construct(self):
self.show_triangle()
self.show_sum_of_two_over_rule()
self.keep_in_mind_what_these_mean()
self.issolate_9_choose_4_term()
self.show_9_choose_4_pattern()
self.cap_off_triangle()
def show_triangle(self):
2017-12-03 16:22:24 -08:00
rows = PascalsTraingle(n_rows = self.max_n+1)
2017-11-30 12:02:55 -08:00
self.play(FadeIn(rows[1]))
for last_row, curr_row in zip(rows[1:], rows[2:]):
self.play(*[
Transform(
last_row.copy(), VGroup(*mobs),
remover = True
)
for mobs in curr_row[1:], curr_row[:-1]
])
self.add(curr_row)
self.dither()
self.rows = rows
def show_sum_of_two_over_rule(self):
rows = self.rows
example = rows[5][3]
ex_top1 = rows[4][2]
ex_top2 = rows[4][3]
rects = VGroup()
for mob, color in (example, GREEN), (ex_top1, BLUE), (ex_top2, YELLOW):
mob.rect = SurroundingRectangle(mob, color = color)
rects.add(mob.rect)
rows_to_fade = VGroup(*rows[1:4] + rows[6:])
rows_to_fade.save_state()
top_row = rows[4]
low_row = rows[5]
top_row_copy = top_row.copy()
top_row.save_state()
top_row.add(ex_top2.rect)
top_row_copy.add(ex_top1.rect)
h_line = Line(LEFT, RIGHT)
h_line.stretch_to_fit_width(low_row.get_width() + 2)
h_line.next_to(low_row, UP, 1.5*SMALL_BUFF)
plus = TexMobject("+")
plus.next_to(h_line.get_left(), UP+RIGHT, buff = 1.5*SMALL_BUFF)
self.play(ShowCreation(example.rect))
self.play(
ReplacementTransform(example.rect.copy(), ex_top1.rect),
ReplacementTransform(example.rect.copy(), ex_top2.rect),
)
self.dither(2)
self.play(rows_to_fade.fade, 1)
self.play(
top_row.align_to, low_row, LEFT,
top_row_copy.next_to, top_row, UP,
top_row_copy.align_to, low_row, RIGHT,
)
self.play(
ShowCreation(h_line),
Write(plus)
)
self.dither(2)
for row in top_row, top_row_copy:
row.remove(row[-1])
self.play(
rows_to_fade.restore,
top_row.restore,
Transform(
top_row_copy, top_row.saved_state,
remover = True
),
FadeOut(VGroup(h_line, plus)),
FadeOut(rects),
)
self.dither()
def keep_in_mind_what_these_mean(self):
morty = Mortimer().flip()
morty.scale(0.7)
morty.to_edge(LEFT)
morty.shift(DOWN)
numbers = VGroup(*it.chain(*self.rows[1:]))
random.shuffle(numbers.submobjects)
self.play(FadeIn(morty))
self.play(PiCreatureSays(
morty, "Keep in mind \\\\ what these mean.",
bubble_kwargs = {
"width" : 3.5,
"height" : 2.5,
}
))
self.play(
Blink(morty),
LaggedStart(
Indicate, numbers,
rate_func = wiggle,
color = PINK,
)
)
self.play(*map(FadeOut, [
morty, morty.bubble, morty.bubble.content
]))
def issolate_9_choose_4_term(self):
rows = self.rows
for n in range(1, self.max_n+1):
num = rows[n][0]
line = get_stack(Female(), Male(), n, 0)[0]
if n < self.max_n:
line.next_to(num, LEFT)
else:
line.next_to(num, DOWN, MED_LARGE_BUFF)
self.highlight_num(num)
self.add(line)
if n < self.max_n:
self.dither(0.25)
else:
self.dither(1.25)
self.dehighlight_num(num)
self.remove(line)
for k in range(1, 5):
num = rows[self.max_n][k]
line = get_stack(Female(), Male(), self.max_n, k)[0]
line.next_to(num, DOWN, MED_LARGE_BUFF)
self.highlight_num(num)
self.add(line)
self.dither(0.5)
self.dehighlight_num(num)
self.remove(line)
num.highlight(YELLOW)
num.scale_in_place(1.2)
self.add(line)
self.dither()
self.nine_choose_four_term = num
self.nine_choose_four_line = line
def show_9_choose_4_pattern(self):
rows = VGroup(*self.rows[1:])
all_stacks = get_stacks(Female(), Male(), 9)
stack = all_stacks[4]
all_lines = VGroup(*it.chain(*all_stacks))
self.play(
rows.shift, 3*UP,
self.nine_choose_four_line.shift, 2.5*UP,
)
self.remove(self.nine_choose_four_line)
for n, line in enumerate(stack):
line.next_to(self.nine_choose_four_term, DOWN, LARGE_BUFF)
num = Integer(n+1)
num.next_to(line, DOWN, MED_LARGE_BUFF)
self.add(line, num)
self.dither(0.1)
self.remove(line, num)
self.add(line, num)
self.dither()
self.curr_line = line
#Probability
expr = TexMobject(
"P(4", "\\female", "\\text{ out of }", "9", ")", "="
)
expr.move_to(num.get_left())
expr.highlight_by_tex("female", MAROON_B)
nine_choose_four_term = self.nine_choose_four_term.copy()
nine_choose_four_term.generate_target()
nine_choose_four_term.target.scale(1./1.2)
over_512 = TexMobject("\\quad \\over 2^9")
frac = VGroup(nine_choose_four_term.target, over_512)
frac.arrange_submobjects(DOWN, buff = SMALL_BUFF)
frac.next_to(expr, RIGHT, SMALL_BUFF)
eq_result = TexMobject("\\approx 0.246")
eq_result.next_to(frac, RIGHT)
def show_random_lines(n, dither_time = 1):
for x in range(n):
if x == n-1:
dither_time = 0
new_line = random.choice(all_lines)
new_line.move_to(self.curr_line)
self.remove(self.curr_line)
self.curr_line = new_line
self.add(self.curr_line)
self.dither(dither_time)
self.play(FadeOut(num), FadeIn(expr))
show_random_lines(4)
self.play(
MoveToTarget(nine_choose_four_term),
Write(over_512)
)
show_random_lines(4)
self.play(Write(eq_result))
show_random_lines(6)
self.play(
self.nine_choose_four_term.scale_in_place, 1./1.2,
self.nine_choose_four_term.highlight, WHITE,
*map(FadeOut, [
expr, nine_choose_four_term,
over_512, eq_result, self.curr_line
])
)
self.play(rows.shift, 3*DOWN)
def cap_off_triangle(self):
top_row = self.rows[0]
circle = Circle(color = YELLOW)
circle.replace(top_row, dim_to_match = 1)
circle.scale_in_place(1.5)
line_groups = VGroup()
for n in range(4, -1, -1):
line = VGroup(*[
random.choice([Male, Female])()
for k in range(n)
])
if n == 0:
line.add(Line(LEFT, RIGHT).scale(0.1).set_stroke(BLACK, 0))
line.arrange_submobjects(RIGHT, SMALL_BUFF)
line.shift(SPACE_WIDTH*RIGHT/2 + SPACE_HEIGHT*UP/2)
brace = Brace(line, UP)
if n == 1:
label = "1 Person"
else:
label = "%d People"%n
brace_text = brace.get_text(label)
line_group = VGroup(line, brace, brace_text)
line_groups.add(line_group)
2017-11-29 15:12:39 -08:00
2017-11-30 12:02:55 -08:00
self.play(ShowCreation(circle))
self.play(Write(top_row))
self.dither()
curr_line_group = line_groups[0]
self.play(FadeIn(curr_line_group))
for line_group in line_groups[1:]:
self.play(ReplacementTransform(
curr_line_group, line_group
))
curr_line_group = line_group
self.dither()
2017-11-29 15:12:39 -08:00
2017-11-30 12:02:55 -08:00
###
2017-11-29 15:12:39 -08:00
2017-11-30 12:02:55 -08:00
def highlight_num(self, num):
num.highlight(YELLOW)
num.scale_in_place(1.2)
2017-11-29 15:12:39 -08:00
2017-11-30 12:02:55 -08:00
def dehighlight_num(self, num):
num.highlight(WHITE)
num.scale_in_place(1.0/1.2)
2017-11-29 15:12:39 -08:00
2017-12-01 16:42:57 -08:00
class StacksApproachBellCurve(Scene):
CONFIG = {
"n_iterations" : 30,
}
def construct(self):
bar = Square(side_length = 1)
bar.set_fill(BLUE)
bar.set_stroke(width = 0)
bars = VGroup(bar)
numbers = VGroup(Integer(1))
numbers.next_to(bars, UP, SMALL_BUFF)
max_width = 2*SPACE_WIDTH - 2
max_height = SPACE_HEIGHT - 1.5
for x in range(self.n_iterations):
if x == 0:
distance = 1.5
else:
distance = bars[1].get_center()[0] - bars[0].get_center()[0]
2017-11-29 15:12:39 -08:00
2017-12-01 16:42:57 -08:00
bars_copy = bars.copy()
2017-11-29 15:12:39 -08:00
2017-12-01 16:42:57 -08:00
#Copy and shift
for mob, vect in (bars, DOWN), (bars_copy, UP):
mob.generate_target()
if mob.target.get_height() > max_height:
mob.target.stretch_to_fit_height(max_height)
if mob.target.get_width() > max_width:
mob.target.stretch_to_fit_width(max_width)
mob.target.next_to(ORIGIN, vect, MED_LARGE_BUFF)
colors = color_gradient([BLUE, YELLOW], len(bars)+1)
for color, bar in zip(colors, bars.target):
bar.set_fill(color)
for color, bar in zip(colors[1:], bars_copy.target):
bar.set_fill(color)
bars_copy.set_fill(opacity = 0)
numbers_copy = numbers.copy()
for bs, ns in (bars, numbers), (bars_copy, numbers_copy):
ns.generate_target()
for bar, number in zip(bs.target, ns.target):
# if number.get_width() > bar.get_width():
# number.scale_to_fit_width(bar.get_width())
number.next_to(bar, UP, SMALL_BUFF)
self.play(*map(MoveToTarget, [
bars, bars_copy,
numbers, numbers_copy
]))
self.play(
bars.shift, distance*LEFT/2,
numbers.shift, distance*LEFT/2,
bars_copy.shift, distance*RIGHT/2,
numbers_copy.shift, distance*RIGHT/2,
)
#Stack
bars_copy.generate_target()
numbers.generate_target()
numbers_copy.generate_target()
new_numbers = VGroup()
min_scale_val = 1
for i in range(len(bars)-1):
top_bar = bars_copy.target[i]
low_bar = bars[i+1]
top_num = numbers_copy.target[i]
low_num = numbers.target[i+1]
new_num = Integer(top_num.number + low_num.number)
if new_num.get_width() > top_bar.get_width():
min_scale_val = min(
min_scale_val,
top_bar.get_width() / new_num.get_width()
)
new_numbers.add(new_num)
top_bar.move_to(low_bar.get_top(), DOWN)
new_num.next_to(top_bar, UP, SMALL_BUFF)
Transform(low_num, new_num).update(1)
Transform(top_num, new_num).update(1)
for group in new_numbers, numbers.target[1:], numbers_copy.target[:-1]:
for num in group:
num.scale(min_scale_val, about_point = num.get_bottom())
if x > 1:
height = numbers.target[1].get_height()
for mob in numbers.target[0], numbers_copy.target[-1]:
mob.scale_to_fit_height(height)
bars_copy.target[-1].align_to(bars, DOWN)
numbers_copy.target[-1].next_to(bars_copy.target[-1], UP, SMALL_BUFF)
self.play(*[
MoveToTarget(mob, submobject_mode = "lagged_start")
for mob in bars_copy, numbers, numbers_copy
])
self.remove(numbers, numbers_copy)
numbers = VGroup(numbers[0])
numbers.add(*new_numbers)
numbers.add(numbers_copy[-1])
#Resize lower bars
for top_bar, low_bar in zip(bars_copy[:-1], bars[1:]):
bottom = low_bar.get_bottom()
low_bar.replace(
VGroup(low_bar, top_bar),
stretch = True
)
low_bar.move_to(bottom, DOWN)
bars.add(bars_copy[-1])
self.remove(bars_copy)
self.add(bars)
self.add(numbers)
self.dither()
# class IsThereABetterWayToCompute(TeacherStudentsScene):
# def construct(self):
# self.student_says(
# "Is there a better \\\\ way to compute these?",
# target_mode = "raise_left_hand",
# )
# self.change_student_modes("confused", "raise_left_hand", "erm")
# self.dither()
# self.play(self.teacher.change_mode, "happy")
# self.dither()
# self.teacher_says(
# "There is! But first...",
# target_mode = "hooray"
# )
# self.dither(2)
2017-12-01 16:42:57 -08:00
class ChooseThreeFromFive(InitialFiveChooseThreeExample, PiCreatureScene):
CONFIG = {
"n" : 5,
"k" : 3,
"pi_creature_scale_val" : 0.3,
"people_colors" : [
PURPLE, BLUE, GREEN, GOLD_E, GREY,
],
}
2017-12-01 16:42:57 -08:00
def construct(self):
self.remove(self.people)
self.show_binary_strings()
2017-12-01 16:42:57 -08:00
self.add_people()
self.choose_triplets()
self.show_association_with_binary(3)
self.show_association_with_binary(5)
self.order_doesnt_matter()
self.that_phrase_is_confusing()
self.pattern_is_unambiguous()
def show_binary_strings(self):
n, k = self.n, self.k
stack = get_stack(
self.get_obj1(), self.get_obj2(), n, k,
vertical_buff = SMALL_BUFF,
)
stack.to_edge(DOWN, buff = LARGE_BUFF)
equation = TexMobject(
"{%d \\choose %d}"%(n, k),
"=", str(choose(n, k)),
)
equation[0].scale(0.75, about_point = equation[0].get_right())
equation.next_to(stack, UP)
for i, line in enumerate(stack):
num = TexMobject(str(i+1))
num.next_to(stack, UP)
self.add(line, num)
self.dither(0.25)
self.remove(num)
self.play(
Write(VGroup(*equation[:-1])),
ReplacementTransform(num, equation[-1])
)
self.dither()
self.set_variables_as_attrs(stack, equation)
2017-12-01 16:42:57 -08:00
def add_people(self):
people = self.people
names = self.get_names(people)
braces = self.get_people_braces(people)
self.play(
Write(braces),
LaggedStart(FadeIn, people),
VGroup(self.stack, self.equation).to_edge, RIGHT, LARGE_BUFF
)
self.play(LaggedStart(FadeIn, names))
self.set_variables_as_attrs(names, braces)
def choose_triplets(self):
movers = VGroup()
movers.generate_target()
max_name_width = max([n.get_width() for n in self.names])
for name_triplet in it.combinations(self.names, 3):
mover = VGroup(*name_triplet).copy()
mover.generate_target()
if hasattr(self, "stack"):
mover.target.scale_to_fit_height(self.stack[0].get_height())
for name in mover.target[:2]:
name[-1].set_fill(opacity = 1)
mover.target.arrange_submobjects(RIGHT, MED_SMALL_BUFF)
movers.add(mover)
movers.target.add(mover.target)
movers.target.arrange_submobjects(
DOWN, buff = SMALL_BUFF,
aligned_edge = LEFT,
)
movers.target.next_to(self.people, DOWN, MED_LARGE_BUFF)
if hasattr(self, "stack"):
movers.target.align_to(self.stack, UP)
self.play(LaggedStart(
MoveToTarget, movers,
lag_ratio = 0.2,
run_time = 4,
))
self.dither()
self.name_triplets = movers
2017-12-01 16:42:57 -08:00
def show_association_with_binary(self, index):
people = self.people
names = self.names
for mob in people, names:
mob.save_state()
mob.generate_target()
line = self.stack[index].copy()
triplet = self.name_triplets[index]
triplet.save_state()
line.generate_target()
for bit, name in zip(line.target, self.names):
bit.next_to(name, UP)
line_rect = SurroundingRectangle(line)
full_line_rect = SurroundingRectangle(VGroup(line, triplet))
people_rects = VGroup()
for pi, name, obj in zip(people.target, names.target, line):
if "1" in obj.get_tex_string():
rect = SurroundingRectangle(VGroup(pi, name))
people_rects.add(rect)
pi.change_mode("hooray")
else:
pi.fade(0.5)
name.fade(0.5)
self.play(ShowCreation(line_rect))
self.play(MoveToTarget(line))
self.play(
LaggedStart(ShowCreation, people_rects),
MoveToTarget(people),
MoveToTarget(names),
)
self.dither()
self.play(
ReplacementTransform(line_rect, full_line_rect),
triplet.highlight, YELLOW
)
self.dither(2)
self.play(
people.restore,
names.restore,
triplet.restore,
FadeOut(line),
FadeOut(full_line_rect),
FadeOut(people_rects),
)
def order_doesnt_matter(self):
triplet = self.name_triplets[0].copy()
triplet.set_fill(opacity = 1)
triplet.next_to(
self.name_triplets, RIGHT,
buff = LARGE_BUFF,
aligned_edge = UP,
)
updownarrow = TexMobject("\\Updownarrow")
updownarrow.highlight(YELLOW)
updownarrow.next_to(triplet, DOWN, SMALL_BUFF)
permutations = VGroup()
for indices in it.permutations(range(len(triplet))):
perm = triplet.copy()
resorter = VGroup(*[
perm[i] for i in indices
])
resorter.arrange_submobjects(RIGHT, MED_SMALL_BUFF)
resorter.next_to(updownarrow, DOWN)
permutations.add(perm)
words = TextMobject("``Order doesn't matter''")
words.scale(0.75)
words.highlight(BLUE)
words.next_to(permutations, DOWN)
self.play(ReplacementTransform(
self.name_triplets[0].copy(), triplet
))
curr_perm = permutations[0]
self.play(
ReplacementTransform(triplet.copy(), curr_perm),
Write(updownarrow)
)
for i in range(8):
new_perm = permutations[i%(len(permutations)-1)+1]
anims = [
Transform(
curr_perm, new_perm,
path_arc = np.pi,
)
]
if i == 1:
self.dither()
if i == 4:
anims.append(Write(words, run_time = 1))
self.play(*anims)
self.play(*map(FadeOut, [triplet, curr_perm, updownarrow]))
self.order_doesnt_matter_words = words
def that_phrase_is_confusing(self):
odm_words = self.order_doesnt_matter_words
odm_words_outline = VGroup()
for letter in odm_words:
mob = VMobject()
mob.points = letter.points
odm_words_outline.add(mob)
odm_words_outline.set_fill(opacity = 0)
odm_words_outline.set_stroke(YELLOW, 1)
line = self.stack[0].copy()
q_marks = TextMobject("???")
q_marks.next_to(odm_words, DOWN)
q_marks.highlight(YELLOW)
self.play(
LaggedStart(
ShowCreationThenDestruction, odm_words_outline,
lag_ratio = 0.2,
run_time = 1,
),
LaggedStart(
ApplyMethod, self.people,
lambda pi : (pi.change, "confused", odm_words,)
),
LaggedStart(FadeIn, q_marks),
)
self.play(line.next_to, odm_words, UP)
for x in range(6):
line.generate_target()
resorter = VGroup(*line.target)
resorter.sort_submobjects(lambda p : random.random())
resorter.arrange_submobjects(RIGHT, buff = SMALL_BUFF)
resorter.move_to(line)
self.play(MoveToTarget(line, path_arc = np.pi))
self.play(FadeOut(q_marks))
line.sort_submobjects(lambda p : p[0])
words = VGroup(*map(TextMobject, ["First", "Second", "Fifth"]))
words.highlight(YELLOW)
words.scale(0.75)
word_arrow_groups = VGroup()
for i, word in zip([0, 1, 4], words):
arrow = Vector(0.5*DOWN)
arrow.highlight(YELLOW)
arrow.next_to(line[i], UP, SMALL_BUFF)
word.next_to(arrow, UP, SMALL_BUFF)
word_arrow_groups.add(VGroup(word, arrow))
for x in range(2):
for i in range(len(word_arrow_groups)+1):
anims = []
if i > 0:
anims.append(FadeOut(word_arrow_groups[i-1]))
if i < len(word_arrow_groups):
anims.append(FadeIn(word_arrow_groups[i]))
self.play(*anims)
self.dither()
word_arrow_groups.submobjects = [
word_arrow_groups[j]
for j in 1, 2, 0
]
self.play(*map(FadeOut, [line, odm_words]))
def pattern_is_unambiguous(self):
all_ones = VGroup()
for line in self.stack:
ones = VGroup(*filter(
lambda m : "1" in m.get_tex_string(),
line
)).copy()
ones.highlight(YELLOW)
all_ones.add(ones)
self.play(
LaggedStart(
FadeIn, all_ones,
lag_ratio = 0.2,
run_time = 3,
rate_func = there_and_back
),
LaggedStart(
ApplyMethod, self.people,
lambda pi : (pi.change, "happy", ones),
)
)
self.dither()
for trip in it.combinations(self.people, 3):
rects = VGroup(*map(SurroundingRectangle, trip))
self.add(rects)
self.dither(0.3)
self.remove(rects)
self.dither()
2017-11-29 15:12:39 -08:00
###
def create_pi_creatures(self):
people = VGroup(*[
PiCreature(color = color).scale(self.pi_creature_scale_val)
for color in self.people_colors
])
people.arrange_submobjects(RIGHT)
people.shift(3*LEFT)
people.to_edge(UP, buff = 1.25)
self.people = people
return people
2017-11-29 15:12:39 -08:00
def get_names(self, people):
names = VGroup(*[
TextMobject(name + ",")
for name in "Ali", "Ben", "Cam", "Denis", "Evan"
])
for name, pi in zip(names, people):
name[-1].set_fill(opacity = 0)
name.scale(0.75)
name.next_to(pi, UP, 2*SMALL_BUFF)
pi.name = name
return names
def get_people_braces(self, people):
group = VGroup(people, *[pi.name for pi in people])
lb, rb = braces = TexMobject("\\{ \\}")
braces.scale(2)
braces.stretch_to_fit_height(1.3*group.get_height())
lb.next_to(group, LEFT, SMALL_BUFF)
rb.next_to(group, RIGHT, SMALL_BUFF)
return braces
class SubsetProbabilityExample(ChooseThreeFromFive):
CONFIG = {
"random_seed" : 1,
}
def construct(self):
self.setup_people()
self.ask_question()
self.show_all_triplets()
self.circle_those_with_ali()
def setup_people(self):
people = self.people
names = self.get_names(people)
braces = self.get_people_braces(people)
group = VGroup(people, names, braces)
self.play(group.shift, -group.get_center()[0]*RIGHT)
self.dither()
self.set_variables_as_attrs(names, braces)
def ask_question(self):
pi_name_groups = VGroup(*[
VGroup(pi, pi.name)
for pi in self.people
])
words = TextMobject(
"Choose 3 people randomly.\\\\",
"Probability", "Ali", "is one of them?"
)
words.highlight_by_tex("Ali", self.people[0].get_color())
words.next_to(pi_name_groups, DOWN, 2*LARGE_BUFF)
checkmark = TexMobject("\\checkmark").highlight(GREEN)
cross = TexMobject("\\times").highlight(RED)
for mob in checkmark, cross:
mob.scale(2)
mob.next_to(self.braces, DOWN, aligned_edge = LEFT)
mob.shift(MED_SMALL_BUFF*LEFT)
ali = pi_name_groups[0]
self.play(FadeIn(words))
for x in range(4):
group = VGroup(*random.sample(pi_name_groups, 3))
group.save_state()
group.generate_target()
group.target.shift(LARGE_BUFF*DOWN)
for pi, name in group.target:
pi.change("hooray", checkmark)
if ali in group:
symbol = checkmark
rect = SurroundingRectangle(
group.target[group.submobjects.index(ali)]
)
rect.set_stroke(GREEN)
else:
symbol = cross
rect = VGroup()
run_time = 1
self.play(
MoveToTarget(group),
FadeIn(symbol),
ShowCreation(rect),
run_time = run_time,
)
self.dither(0.5)
self.play(
group.restore,
FadeOut(symbol),
FadeOut(rect),
run_time = run_time,
)
self.question = words
self.set_variables_as_attrs(pi_name_groups)
2017-11-29 15:12:39 -08:00
def show_all_triplets(self):
self.play(
self.question.scale, 0.75,
self.question.to_corner, UP+RIGHT,
VGroup(self.people, self.names, self.braces).to_edge, LEFT,
)
self.choose_triplets()
brace = Brace(self.name_triplets, RIGHT)
total_count = brace.get_tex(
"{5 \\choose 3}", "=", "10",
buff = MED_LARGE_BUFF
)
total_count.highlight(BLUE)
self.play(
GrowFromCenter(brace),
Write(total_count),
)
self.dither()
self.set_variables_as_attrs(brace, total_count)
def circle_those_with_ali(self):
name_triplets = self.name_triplets
five_choose_three, equals, ten = self.total_count
names = self.names
with_ali = VGroup(*name_triplets[:6])
alis = VGroup(*[group[0] for group in with_ali])
rect = SurroundingRectangle(with_ali)
frac_lines = VGroup()
for vect in LEFT, RIGHT:
frac_line = TexMobject("\\quad \\over \\quad")
if vect is LEFT:
frac_line.stretch(1.5, 0)
frac_line.next_to(equals, vect)
frac_lines.add(frac_line)
four_choose_two = TexMobject("4 \\choose 2")
four_choose_two.next_to(frac_lines[0], UP, SMALL_BUFF)
six = TexMobject("6")
six.next_to(frac_lines[1], UP, SMALL_BUFF)
self.play(
ShowCreation(rect),
alis.highlight, YELLOW
)
for pair in it.combinations(names[1:], 2):
arrows = VGroup()
for pi in pair:
arrow = Vector(0.5*DOWN, color = YELLOW)
arrow.next_to(pi, UP)
arrows.add(arrow)
self.add(arrows)
self.dither(0.5)
self.remove(arrows)
self.add(arrows)
self.dither()
self.play(
FadeIn(frac_lines),
five_choose_three.next_to, frac_lines[0], DOWN, SMALL_BUFF,
ten.next_to, frac_lines[1], DOWN, SMALL_BUFF,
Write(four_choose_two)
)
self.dither()
self.play(ReplacementTransform(
four_choose_two.copy(), six
))
self.play(FadeOut(arrows))
for x in range(20):
name_rect = SurroundingRectangle(random.choice(name_triplets))
name_rect.highlight(BLUE)
name_rect.set_fill(BLUE, opacity = 0.25)
self.play(Animation(name_rect, run_time = 0))
self.dither(0.25)
self.remove(name_rect)
class HowToComputeNChooseK(ChooseThreeFromFive):
CONFIG = {
"n" : 5,
"k" : 3,
"line_colors" : [GREEN, YELLOW]
}
def construct(self):
self.setup_people()
self.choose_example_ordered_triplets()
self.count_possibilities()
self.show_permutations_of_ABC()
self.count_permutations_of_ABC()
self.reset_stage()
self.show_whats_being_counted()
2017-11-29 15:12:39 -08:00
def setup_people(self):
people = self.people
names = self.get_names(people)
braces = self.get_people_braces(people)
people_group = VGroup(people, names, braces)
people_group.center().to_edge(UP, buff = MED_LARGE_BUFF)
2017-11-29 15:12:39 -08:00
self.add(people_group)
self.set_variables_as_attrs(
names, people_group,
people_braces = braces
)
2017-11-29 10:11:41 -08:00
def choose_example_ordered_triplets(self):
n, k = self.n, self.k
names = self.names
2017-11-29 10:11:41 -08:00
width = max([n.get_width() for n in self.names]) + 2*SMALL_BUFF
lines = VGroup(*[
Line(ORIGIN, width*RIGHT)
for x in range(k)
])
lines.arrange_submobjects(RIGHT)
lines.next_to(ORIGIN, DOWN, buff = LARGE_BUFF)
place_words = VGroup(*[
TexMobject("%d^\\text{%s}"%(i+1, s))
for i, s in zip(
range(k),
it.chain(["st", "nd", "rd"], it.repeat("th"))
)
])
for mob in place_words, lines:
mob.gradient_highlight(*self.line_colors)
for word, line in zip(place_words, lines):
word.next_to(line, DOWN, SMALL_BUFF)
for x in range(3):
chosen_names = VGroup(*random.sample(names, k))
chosen_names.save_state()
for name, line, word in zip(chosen_names, lines, place_words):
name.generate_target()
name.target.next_to(line, UP, SMALL_BUFF)
anims = [MoveToTarget(name)]
if x == 0:
anims += [ShowCreation(line), FadeIn(word)]
self.play(*anims)
self.dither()
self.play(chosen_names.restore)
self.dither()
self.set_variables_as_attrs(lines, place_words)
2017-11-29 10:11:41 -08:00
def count_possibilities(self):
n, k = self.n, self.k
lines = self.lines
choice_counts = self.get_choice_counts(n, k)
arrows = self.get_choice_count_arrows(choice_counts)
name_rects = VGroup()
for name in self.names:
name.rect = SurroundingRectangle(name)
name_rects.add(name.rect)
chosen_names = VGroup(*random.sample(self.names, k))
self.names.save_state()
for name, line, count, arrow in zip(chosen_names, lines, choice_counts, arrows):
self.play(
FadeIn(count),
LaggedStart(
FadeIn, name_rects,
rate_func = there_and_back,
remover = True,
)
)
self.play(
name.next_to, line, UP, SMALL_BUFF,
GrowArrow(arrow)
)
self.dither()
name_rects.remove(name.rect)
name_rects.set_stroke(YELLOW, 3)
#Consolidate choice counts
choice_numbers = VGroup(*[
cc.submobjects.pop(1)
for cc in choice_counts
])
choice_numbers.generate_target()
dots = VGroup(*[TexMobject("\\cdot") for x in range(k-1)])
product = VGroup(*it.chain(*zip(choice_numbers.target, dots)))
product.add(choice_numbers.target[-1])
product.arrange_submobjects(RIGHT, buff = SMALL_BUFF)
chosen_names_brace = Brace(chosen_names, UP)
product.next_to(chosen_names_brace, UP)
self.play(
FadeOut(choice_counts),
FadeOut(arrows),
MoveToTarget(choice_numbers),
Write(dots),
GrowFromCenter(chosen_names_brace),
)
self.dither()
self.set_variables_as_attrs(
chosen_names, chosen_names_brace, choice_numbers,
choice_numbers_dots = dots,
)
def show_permutations_of_ABC(self):
chosen_names = self.chosen_names
lines = self.lines
for indices in list(it.permutations(range(3)))[1:]:
self.play(*[
ApplyMethod(
name.next_to, lines[i], UP, SMALL_BUFF,
path_arc = np.pi
)
for i, name in zip(indices, chosen_names)
])
self.dither(0.5)
def count_permutations_of_ABC(self):
n, k = self.n, self.k
lines = self.lines
chosen_names = self.chosen_names
brace = self.chosen_names_brace
numerator = VGroup(
self.choice_numbers, self.choice_numbers_dots,
)
frac_line = Line(LEFT, RIGHT)
frac_line.replace(numerator, dim_to_match = 0)
frac_line.to_edge(RIGHT)
choice_counts = self.get_choice_counts(k, k)
arrows = self.get_choice_count_arrows(choice_counts)
self.play(
chosen_names.shift, UP,
chosen_names.to_edge, LEFT,
numerator.next_to, frac_line, UP, SMALL_BUFF,
FadeOut(brace),
)
shuffled_names = random.sample(chosen_names, k)
for line, name, count, arrow in zip(lines, shuffled_names, choice_counts, arrows):
self.play(FadeIn(count), GrowArrow(arrow))
self.play(
name.next_to, line, UP, SMALL_BUFF,
path_arc = -np.pi/3,
)
self.dither()
#Consolidate choice counts
choice_numbers = VGroup(*[
cc.submobjects.pop(1)
for cc in choice_counts
])
choice_numbers.generate_target()
dots = VGroup(*[TexMobject("\\cdot") for x in range(k-1)])
product = VGroup(*it.chain(*zip(choice_numbers.target, dots)))
product.add(choice_numbers.target[-1])
product.arrange_submobjects(RIGHT, buff = SMALL_BUFF)
product.next_to(frac_line, DOWN, SMALL_BUFF)
self.play(
FadeOut(choice_counts),
FadeOut(arrows),
MoveToTarget(choice_numbers),
Write(dots),
ShowCreation(frac_line),
)
self.dither()
self.fraction = VGroup(
numerator, frac_line, VGroup(choice_numbers, dots)
)
def reset_stage(self):
n, k = self.n, self.k
n_choose_k_equals = TexMobject(
"{%d \\choose %d} ="%(n, k)
)
n_choose_k_equals.next_to(ORIGIN, RIGHT, LARGE_BUFF)
n_choose_k_equals.to_edge(UP, LARGE_BUFF)
self.play(
self.names.restore,
FadeOut(self.lines),
FadeOut(self.place_words),
)
self.play(
self.people_group.to_edge, LEFT,
FadeIn(n_choose_k_equals),
self.fraction.next_to, n_choose_k_equals, RIGHT, SMALL_BUFF
)
def show_whats_being_counted(self):
n, k = self.n, self.k
letters = VGroup(*[name[0] for name in self.names])
rhs = TexMobject("=", "{60", "\\over", "6}")
rhs.next_to(self.fraction, RIGHT)
all_groups = VGroup()
lines = VGroup()
for ordered_triplet in it.combinations(letters, k):
line = VGroup()
for triplet in it.permutations(ordered_triplet):
group = VGroup(*triplet).copy()
group.save_state()
group.arrange_submobjects(RIGHT, buff = SMALL_BUFF)
line.add(group)
all_groups.add(group)
line.arrange_submobjects(RIGHT, buff = LARGE_BUFF)
lines.add(line)
lines.arrange_submobjects(DOWN)
lines.scale(0.8)
lines.to_edge(DOWN)
rects = VGroup(*[
SurroundingRectangle(
line, buff = 0,
stroke_width = 0,
fill_color = BLUE,
fill_opacity = 0.5,
)
for line in lines
])
self.play(
Write(VGroup(*rhs[:-1])),
LaggedStart(
ApplyMethod, all_groups,
lambda g : (g.restore,),
rate_func = lambda t : smooth(1-t),
run_time = 4,
lag_ratio = 0.2,
),
)
self.dither()
self.play(
LaggedStart(FadeIn, rects),
Write(rhs[-1])
)
self.dither()
####
def get_choice_counts(self, n, k):
people_braces = self.people_braces
choice_counts = VGroup(*[
TextMobject(
"(", str(n0), " choices", ")",
arg_separator = ""
)
for n0 in range(n, n-k, -1)
])
choice_counts.arrange_submobjects(RIGHT, buff = SMALL_BUFF)
choice_counts.gradient_highlight(*self.line_colors)
choice_counts.next_to(people_braces, DOWN)
return choice_counts
def get_choice_count_arrows(self, choice_counts):
lines = self.lines
return VGroup(*[
Arrow(
count.get_bottom(),
line.get_center() + MED_LARGE_BUFF*UP,
color = line.get_color()
)
for count, line in zip(choice_counts, lines)
])
2017-11-29 10:11:41 -08:00