mirror of
https://github.com/3b1b/manim.git
synced 2025-04-13 09:47:07 +00:00
3635 lines
115 KiB
Python
3635 lines
115 KiB
Python
from big_ol_pile_of_manim_imports import *
|
|
|
|
#revert_to_original_skipping_status
|
|
|
|
def get_stack(
|
|
obj1, obj2, n, k,
|
|
fixed_start = None,
|
|
fixed_end = None,
|
|
obj_to_obj_buff = SMALL_BUFF,
|
|
vertical_buff = MED_SMALL_BUFF,
|
|
):
|
|
stack = VGroup()
|
|
for indices in it.combinations(list(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())
|
|
term.arrange(RIGHT, buff = obj_to_obj_buff)
|
|
stack.add(term)
|
|
stack.arrange(DOWN, buff = vertical_buff)
|
|
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(
|
|
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.set_height(self.height)
|
|
self.set_color(self.color)
|
|
|
|
class Female(Male):
|
|
CONFIG = {
|
|
"tex" : "\\female",
|
|
"color" : MAROON_B,
|
|
}
|
|
|
|
class PascalsTriangle(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()
|
|
|
|
######################
|
|
|
|
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.wait()
|
|
|
|
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.wait()
|
|
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.wait()
|
|
self.play(*list(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(OldLaggedStart(ShowCreation, lightbulb))
|
|
self.play(
|
|
ShowCreation(cross),
|
|
jenny.change, "sassy", cross,
|
|
randy.change, "happy"
|
|
)
|
|
self.wait(2)
|
|
|
|
self.to_fade = VGroup(lightbulb, cross)
|
|
|
|
def think_about_patterns(self):
|
|
randy, jenny = self.randy, self.jenny
|
|
rows = PascalsTriangle(
|
|
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.set_color(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.wait(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):
|
|
CONFIG = {
|
|
"n" : 5,
|
|
"zero_color" : BLUE,
|
|
"one_color" : PINK,
|
|
}
|
|
def construct(self):
|
|
self.show_all_stacks()
|
|
self.add_title()
|
|
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 show_all_stacks(self):
|
|
stacks = get_stacks(
|
|
self.get_obj1(), self.get_obj2(), self.n,
|
|
vertical_buff = SMALL_BUFF
|
|
)
|
|
stacks.to_edge(DOWN, buff = MED_LARGE_BUFF)
|
|
|
|
for stack in stacks:
|
|
self.play(FadeIn(
|
|
stack,
|
|
run_time = 0.2*len(stack),
|
|
lag_ratio = 0.5
|
|
))
|
|
self.wait()
|
|
|
|
self.set_variables_as_attrs(stacks)
|
|
|
|
def add_title(self):
|
|
n = self.n
|
|
stacks = self.stacks
|
|
|
|
n_choose_k = TexMobject("n \\choose k")
|
|
n_choose_k_words = TextMobject("``n choose k''")
|
|
nCk_group = VGroup(n_choose_k, n_choose_k_words)
|
|
nCk_group.arrange(RIGHT)
|
|
nCk_group.to_edge(UP)
|
|
|
|
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(RIGHT, buff = SMALL_BUFF)
|
|
equation.set_color(YELLOW)
|
|
equation[1].set_color(WHITE)
|
|
binomial_equations.add(equation)
|
|
|
|
for stack, eq in zip(stacks, binomial_equations):
|
|
eq.set_width(0.9*stack.get_width())
|
|
eq.next_to(stack, UP)
|
|
|
|
mover = VGroup()
|
|
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(nCk_group))
|
|
self.play(OldLaggedStart(
|
|
MoveToTarget, mover,
|
|
run_time = 3,
|
|
))
|
|
self.remove(mover)
|
|
self.add(binomial_equations)
|
|
self.wait()
|
|
|
|
self.set_variables_as_attrs(
|
|
n_choose_k, n_choose_k_words,
|
|
binomial_equations
|
|
)
|
|
|
|
def show_binomial_name(self):
|
|
new_words = TextMobject("``Binomial coefficients''")
|
|
new_words.move_to(self.n_choose_k_words, LEFT)
|
|
|
|
self.play(Transform(self.n_choose_k_words, new_words))
|
|
self.wait(2)
|
|
|
|
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)
|
|
|
|
self.play(
|
|
FadeOut(to_fade),
|
|
equation.scale, 1.5, equation.get_bottom(),
|
|
)
|
|
self.wait()
|
|
for line in stack:
|
|
ones = VGroup(*[mob for mob in line if "1" in mob.get_tex_string()])
|
|
line.ones = ones
|
|
self.play(OldLaggedStart(
|
|
ApplyMethod, ones,
|
|
lambda mob : (mob.set_color, 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.set_color(YELLOW)
|
|
self.add(number, brace)
|
|
self.wait(0.25)
|
|
self.remove(number, brace)
|
|
line.restore()
|
|
self.add(number, brace)
|
|
self.wait()
|
|
|
|
self.set_variables_as_attrs(
|
|
stack_brace = brace,
|
|
stack_count = number
|
|
)
|
|
|
|
def count_ways_to_fill_slots(self):
|
|
lines = VGroup(*[Line(ORIGIN, 0.25*RIGHT) for x in range(5)])
|
|
lines.arrange(RIGHT)
|
|
lines.next_to(self.stacks[3], LEFT, LARGE_BUFF, UP)
|
|
|
|
self.play(ShowCreation(lines))
|
|
count = 1
|
|
for indices in it.combinations(list(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.wait(0.35)
|
|
self.remove(ones, num)
|
|
count += 1
|
|
self.add(num, ones)
|
|
self.wait()
|
|
self.play(*list(map(FadeOut, [lines, num, ones])))
|
|
|
|
def walk_though_notation(self):
|
|
equation = self.binomial_equations[3]
|
|
rect = SurroundingRectangle(equation[0])
|
|
rect.set_color(WHITE)
|
|
words = TextMobject("``5 choose 3''")
|
|
words.next_to(rect, UP)
|
|
|
|
self.play(Write(words))
|
|
self.play(ShowCreation(rect))
|
|
self.play(FadeOut(rect))
|
|
self.wait(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.set_color, YELLOW,
|
|
last_ones.restore,
|
|
morty.look_at, ones,
|
|
run_time = 0.25
|
|
)
|
|
last_ones = ones
|
|
self.wait()
|
|
|
|
####
|
|
|
|
def get_obj1(self):
|
|
return TexMobject("1").set_color(self.one_color)
|
|
|
|
def get_obj2(self):
|
|
return TexMobject("0").set_color(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.set_height(self.stack_height)
|
|
stack.to_edge(DOWN)
|
|
for line in stack:
|
|
line.ones = VGroup(*[mob for mob in line if "1" in mob.get_tex_string()])
|
|
|
|
equation = TexMobject(
|
|
"{%d \\choose %d}"%(self.n, self.k),
|
|
"=", str(choose(self.n, self.k))
|
|
)
|
|
equation.set_color(YELLOW)
|
|
equation.set_color_by_tex("=", WHITE)
|
|
equation.next_to(stack, RIGHT, LARGE_BUFF)
|
|
|
|
self.add(equation)
|
|
self.play(OldLaggedStart(
|
|
FadeIn, stack,
|
|
lag_ratio = 0.1,
|
|
run_time = 10,
|
|
))
|
|
self.wait()
|
|
|
|
self.set_variables_as_attrs(stack)
|
|
|
|
def talk_through_one_line(self):
|
|
line = self.stack[8]
|
|
line.save_state()
|
|
distance = FRAME_X_RADIUS/2
|
|
|
|
self.play(line.shift, distance*LEFT)
|
|
|
|
brace = Brace(line, UP)
|
|
n_options = TextMobject(str(self.n), "options")
|
|
n_options.set_color_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.set_color(self.one_color)
|
|
choose_k = TextMobject("Choose", str(self.k), "of them")
|
|
choose_k.set_color_by_tex(str(self.k), YELLOW)
|
|
choose_k.next_to(arrows, DOWN)
|
|
|
|
self.play(
|
|
GrowFromCenter(brace),
|
|
Write(n_options),
|
|
run_time = 1
|
|
)
|
|
self.play(
|
|
OldLaggedStart(GrowArrow, arrows),
|
|
Write(choose_k, run_time = 1)
|
|
)
|
|
self.wait(2)
|
|
self.play(
|
|
line.restore,
|
|
*list(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.set_color(YELLOW)
|
|
line.ones.set_stroke(RED, 1)
|
|
self.add(brace, num)
|
|
self.wait(0.15)
|
|
self.remove(brace, num)
|
|
line.ones.restore()
|
|
self.add(brace, num)
|
|
self.wait()
|
|
|
|
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.set_color(MAROON_B)
|
|
|
|
self.play(*list(map(FadeIn, [lhs, coming_soon])))
|
|
self.wait()
|
|
self.play(
|
|
ApplyMethod(
|
|
lhs.shift, 0.65*FRAME_X_RADIUS*(LEFT+UP),
|
|
path_arc = np.pi/2,
|
|
rate_func = running_start,
|
|
remover = True,
|
|
),
|
|
*list(map(FadeOut, [brace, num, coming_soon]))
|
|
)
|
|
self.wait()
|
|
|
|
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.set_color, YELLOW,
|
|
ones.set_stroke, RED, 1,
|
|
last_ones.restore,
|
|
run_time = 0.2
|
|
)
|
|
last_ones = ones
|
|
self.wait()
|
|
|
|
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_in_grid(n, n, buff = LARGE_BUFF)
|
|
dots.next_to(ORIGIN, LEFT)
|
|
self.add(dots)
|
|
|
|
self.dots = dots
|
|
self.dot_to_dot_distance = get_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(list(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(RIGHT, buff = 0.5*SMALL_BUFF)
|
|
if last_line is None:
|
|
line.shift(FRAME_X_RADIUS*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.wait()
|
|
|
|
# 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(RIGHT)
|
|
|
|
# self.play(
|
|
# FadeIn(symbol),
|
|
# Write(words)
|
|
# )
|
|
# self.wait()
|
|
|
|
# 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(RIGHT, buff = SMALL_BUFF)
|
|
# equation.set_color(YELLOW)
|
|
# equation[1].set_color(WHITE)
|
|
# binomial_equations.add(equation)
|
|
# new_words = TextMobject("``Binomial coefficients''")
|
|
|
|
# stacks = get_stacks(
|
|
# TexMobject("x").set_color(BLUE),
|
|
# TexMobject("y").set_color(RED),
|
|
# n
|
|
# )
|
|
# stacks.to_edge(DOWN, buff = LARGE_BUFF)
|
|
# for stack, eq in zip(stacks, binomial_equations):
|
|
# eq.set_width(0.9*stack.get_width())
|
|
# eq.next_to(stack, UP)
|
|
|
|
# self.play(
|
|
# FadeIn(stacks, run_time = 2, lag_ratio = 0.5),
|
|
# 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.wait()
|
|
|
|
# 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(FRAME_X_RADIUS)
|
|
# line.next_to(top_stacks, DOWN)
|
|
|
|
# x = TexMobject("x").set_color(BLUE)
|
|
# y = TexMobject("y").set_color(RED)
|
|
# add_x, add_y = [
|
|
# TextMobject("Prepend", "$%s$"%s).set_color_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(OldLaggedStart(
|
|
# Indicate, new_top_stacks.start_terms,
|
|
# rate_func = there_and_back,
|
|
# run_time = 1,
|
|
# remover = True
|
|
# ))
|
|
# self.wait()
|
|
# self.play(Write(add_y, run_time = 1))
|
|
# self.play(Transform(stacks, new_stacks))
|
|
# self.play(OldLaggedStart(
|
|
# Indicate, new_stacks.start_terms,
|
|
# rate_func = there_and_back,
|
|
# run_time = 1,
|
|
# remover = True
|
|
# ))
|
|
# self.wait()
|
|
|
|
# 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].set_color(YELLOW)
|
|
# term[2].set_color(YELLOW)
|
|
# term.scale(0.85)
|
|
# term.next_to(top_stack.target, UP)
|
|
|
|
# self.play(MoveToTarget(top_stack))
|
|
# self.play(Write(term))
|
|
# self.wait()
|
|
|
|
# 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, lag_ratio = 0.5))
|
|
# self.wait()
|
|
|
|
# self.n_choose_k_term = term
|
|
|
|
# def add_stack(self):
|
|
# n, k = self.n, self.k
|
|
# x = TexMobject("x").set_color(BLUE)
|
|
# y = TexMobject("y").set_color(RED)
|
|
# stack = get_stack(x, y, n, k)
|
|
# stack.set_height(self.stack_height)
|
|
# stack.shift(FRAME_X_RADIUS*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.wait(0.25)
|
|
# last_number = number
|
|
# self.wait()
|
|
|
|
# self.stack = stack
|
|
# self.stack_count = last_number
|
|
# self.numbers = numbers
|
|
|
|
# def choose_k(self):
|
|
# n, k = self.n, self.k
|
|
|
|
# letter_set = TexMobject(
|
|
# "(",
|
|
# "A", ",",
|
|
# "B", ",",
|
|
# "C", ",",
|
|
# "D", ",",
|
|
# "E", ")"
|
|
# )
|
|
# letters = VGroup(*letter_set[1::2])
|
|
# letter_set.shift(FRAME_X_RADIUS*RIGHT/2)
|
|
# letter_set.to_edge(UP)
|
|
|
|
# letter_subsets = list(it.combinations(letters, k))
|
|
# subset_mobs = VGroup(*[
|
|
# VGroup(*letter_subset).copy().arrange(
|
|
# RIGHT, buff = SMALL_BUFF
|
|
# )
|
|
# for letter_subset in letter_subsets
|
|
# ]).arrange(DOWN, buff = MED_SMALL_BUFF)
|
|
# subset_mobs.set_height(self.stack_height)
|
|
# subset_mobs.shift(FRAME_X_RADIUS*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.set_color(YELLOW)
|
|
|
|
# self.revert_to_original_skipping_status()
|
|
# self.play(Write(letter_set, run_time = 1))
|
|
# self.play(
|
|
# Write(choose_words, run_time = 1),
|
|
# OldLaggedStart(FadeIn, subset_mobs)
|
|
# )
|
|
# self.wait()
|
|
# for subset, subset_mob in zip(letter_subsets, subset_mobs):
|
|
# VGroup(subset_mob, *subset).set_color(BLUE)
|
|
# self.wait(0.5)
|
|
# VGroup(*subset).set_color(WHITE)
|
|
# self.wait()
|
|
|
|
# self.set_variables_as_attrs(
|
|
# subset_mobs, letter_set, choose_words,
|
|
# )
|
|
|
|
# def split_stack_by_start(self):
|
|
# n, k = self.n, self.k
|
|
# stack = self.stack
|
|
# stack_count = self.stack_count
|
|
|
|
# top_num = choose(n-1, k-1)
|
|
# top_stack = VGroup(*stack[:top_num])
|
|
# bottom_stack = VGroup(*stack[top_num:])
|
|
|
|
# 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.wait()
|
|
|
|
# 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"
|
|
# )
|
|
|
|
# self.play(
|
|
# MoveToTarget(subset_mobs),
|
|
# GrowFromCenter(brace)
|
|
# )
|
|
# self.play(Write(expression))
|
|
# self.wait()
|
|
|
|
# class FormulaVsPattern(TeacherStudentsScene):
|
|
# def construct(self):
|
|
# self.show_formula()
|
|
# self.show_pattern()
|
|
|
|
# def show_formula(self):
|
|
# formula = TexMobject(
|
|
# "{n \\choose k} = {n! \\over (n-k)!k!}",
|
|
# )
|
|
# for i in 1, 5, 9:
|
|
# formula[i].set_color(BLUE)
|
|
# for i in 2, 11, 14:
|
|
# formula[i].set_color(YELLOW)
|
|
|
|
# self.student_thinks(formula, student_index = 1)
|
|
# self.play(self.teacher.change, "sassy")
|
|
# self.wait(2)
|
|
# self.play(
|
|
# FadeOut(self.students[1].bubble),
|
|
# FadeOut(formula),
|
|
# self.teacher.change, "raise_right_hand",
|
|
# self.get_student_changes(*["pondering"]*3)
|
|
# )
|
|
|
|
# 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(RIGHT)
|
|
# cards.to_corner(UP+RIGHT)
|
|
# words.next_to(cards, LEFT)
|
|
# words.shift_onto_screen()
|
|
|
|
# self.play(OldLaggedStart(DrawBorderThenFill, cards))
|
|
# self.play(Write(words))
|
|
# self.wait(3)
|
|
|
|
class ProbabilityOfKWomenInGroupOfFive(Scene):
|
|
CONFIG = {
|
|
"random_seed" : 0,
|
|
"n_people_per_lineup" : 5,
|
|
"n_examples" : 18,
|
|
"item_line_width" : 0.4,
|
|
}
|
|
def construct(self):
|
|
self.ask_question()
|
|
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):
|
|
title = TextMobject("5 randomly chosen people")
|
|
title.to_edge(UP)
|
|
self.add(title)
|
|
|
|
lineup_point = 1.5*UP
|
|
prob_words = VGroup(*[
|
|
TextMobject(
|
|
"Probability of", str(n), "women?"
|
|
).set_color_by_tex(str(n), YELLOW)
|
|
for n in range(self.n_people_per_lineup+1)
|
|
])
|
|
prob_words.arrange(DOWN)
|
|
prob_words.next_to(lineup_point, DOWN, MED_LARGE_BUFF)
|
|
|
|
def get_lineup():
|
|
lineup = self.get_random_lineup_of_men_and_women()
|
|
lineup.scale(1.5)
|
|
lineup.move_to(lineup_point, DOWN)
|
|
return lineup
|
|
|
|
last_lineup = get_lineup()
|
|
self.play(OldLaggedStart(FadeIn, last_lineup, run_time = 1))
|
|
|
|
for x in range(self.n_examples):
|
|
lineup = get_lineup()
|
|
anims = [last_lineup.items.fade, 1]
|
|
anims += list(map(GrowFromCenter, lineup.items))
|
|
if x >= 12 and x-12 < len(prob_words):
|
|
anims.append(FadeIn(prob_words[x-12]))
|
|
self.play(*anims, run_time = 0.75)
|
|
self.remove(last_lineup)
|
|
self.add(lineup)
|
|
self.wait(0.25)
|
|
last_lineup = lineup
|
|
|
|
self.title = title
|
|
self.prob_words = prob_words
|
|
self.lineup = last_lineup
|
|
|
|
def show_all_possibilities(self):
|
|
man, woman = Male(), Female()
|
|
|
|
vects = [
|
|
1.5*UP,
|
|
0.65*UP,
|
|
0.25*UP,
|
|
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):
|
|
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.set_color(YELLOW)
|
|
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)
|
|
)
|
|
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(OldLaggedStart(
|
|
ApplyMethod, group,
|
|
lambda m : (m.shift, MED_SMALL_BUFF*RIGHT),
|
|
rate_func = there_and_back,
|
|
lag_ratio = 0.9**i,
|
|
run_time = 1,
|
|
))
|
|
self.wait()
|
|
curr_lineup_group = lineup_group
|
|
self.lineups = curr_lineup_group
|
|
|
|
eq_32 = TexMobject("=", "32")
|
|
eq_32.move_to(twos.get_right())
|
|
eq_32.set_color_by_tex("32", YELLOW)
|
|
self.play(
|
|
n_possibilities[-1].next_to, eq_32, RIGHT,
|
|
twos.next_to, eq_32, LEFT,
|
|
FadeIn(eq_32),
|
|
)
|
|
self.wait()
|
|
|
|
n_possibilities.add(*eq_32)
|
|
self.set_variables_as_attrs(n_possibilities)
|
|
|
|
def stack_all_choices_by_number_of_women(self):
|
|
lineups = self.lineups
|
|
stacks = VGroup(*[VGroup() for x in range(6)])
|
|
for lineup in lineups:
|
|
lineup.women = VGroup(*[m for m in lineup.items if "female" in m.get_tex_string()])
|
|
stacks[len(lineup.women)].add(lineup)
|
|
stacks.generate_target()
|
|
stacks.target.scale(0.75)
|
|
for stack in stacks.target:
|
|
stack.arrange(DOWN, buff = 1.5*SMALL_BUFF)
|
|
stacks.target.arrange(
|
|
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.wait()
|
|
|
|
self.stacks = stacks
|
|
|
|
def go_through_stacks(self):
|
|
stacks = self.stacks
|
|
n = len(stacks) - 1
|
|
equations = VGroup()
|
|
for k, stack in enumerate(stacks):
|
|
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(RIGHT, SMALL_BUFF)
|
|
equation.set_color(YELLOW)
|
|
equation.set_color_by_tex("=", WHITE)
|
|
equation.next_to(stack, UP)
|
|
equations.add(equation)
|
|
|
|
self.play(
|
|
items.set_fill, None, 1,
|
|
lines.set_stroke, WHITE, 3,
|
|
Write(equation, run_time = 1)
|
|
)
|
|
self.play(OldLaggedStart(Indicate, women, rate_func = there_and_back))
|
|
self.wait()
|
|
|
|
self.equations = equations
|
|
self.numbers = VGroup(*[eq[-1] for eq in equations])
|
|
|
|
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(OldLaggedStart(
|
|
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.wait()
|
|
|
|
def show_answer_to_question(self):
|
|
stacks = self.stacks
|
|
numbers = self.numbers
|
|
n_possibilities = VGroup(
|
|
self.n_possibilities[-1],
|
|
self.n_possibilities[-3]
|
|
)
|
|
n_possibilities_part_to_fade = VGroup(
|
|
self.n_possibilities[-2],
|
|
*self.n_possibilities[:-3]
|
|
)
|
|
total = n_possibilities[-1]
|
|
title = self.title
|
|
n = self.n_people_per_lineup
|
|
|
|
self.play(
|
|
FadeOut(title),
|
|
FadeOut(n_possibilities_part_to_fade),
|
|
n_possibilities.to_corner, UP+RIGHT
|
|
)
|
|
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.set_color_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.wait(2)
|
|
self.play(
|
|
num.restore,
|
|
FadeOut(rect),
|
|
FadeOut(prob_words)
|
|
)
|
|
|
|
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.set_color(WHITE)
|
|
|
|
self.play(OldLaggedStart(FadeIn, question))
|
|
self.play(OldLaggedStart(ShowCreationThenDestruction, circles))
|
|
self.wait(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
|
|
|
|
def get_lineup(self, *mobjects, **kwargs):
|
|
buff = kwargs.get("buff", MED_SMALL_BUFF)
|
|
lines = VGroup(*[
|
|
Line(ORIGIN, self.item_line_width*RIGHT)
|
|
for mob in mobjects
|
|
])
|
|
lines.arrange(RIGHT, buff = buff)
|
|
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 AskAboutAllPossibilities(ProbabilityOfKWomenInGroupOfFive):
|
|
def construct(self):
|
|
man, woman = Male(), Female()
|
|
all_lineups = VGroup()
|
|
for bits in it.product(*[[False, True]]*5):
|
|
mobs = [
|
|
woman.copy() if bit else man.copy()
|
|
for bit in bits
|
|
]
|
|
all_lineups.add(self.get_lineup(*mobs))
|
|
brace = Brace(all_lineups, UP)
|
|
question = brace.get_text("What are all possibilities?")
|
|
|
|
self.add(brace, question)
|
|
for lineup in all_lineups:
|
|
self.add(lineup)
|
|
self.wait(0.25)
|
|
self.remove(lineup)
|
|
|
|
class RememberThisSensation(TeacherStudentsScene):
|
|
def construct(self):
|
|
self.teacher_says("Remember this \\\\ sensation")
|
|
self.change_student_modes("confused", "pondering", "erm")
|
|
self.wait(2)
|
|
|
|
class TeacherHoldingSomething(TeacherStudentsScene):
|
|
def construct(self):
|
|
self.play(
|
|
self.teacher.change, "raise_right_hand",
|
|
)
|
|
self.change_student_modes(
|
|
*["pondering"]*3,
|
|
look_at_arg = 2*UP+2*RIGHT
|
|
)
|
|
self.wait(6)
|
|
|
|
# class GroupsOf6(Scene):
|
|
# def construct(self):
|
|
# title = TexMobject("2^6 =", "64", "\\text{ Possibilities}")
|
|
# title.to_edge(UP, buff = MED_SMALL_BUFF)
|
|
# title.set_color_by_tex("64", YELLOW)
|
|
# man, woman = Male(), Female()
|
|
# stacks = get_stacks(man, woman, 6, vertical_buff = SMALL_BUFF)
|
|
# stacks.set_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(OldLaggedStart(
|
|
# OldLaggedStart, stacks,
|
|
# lambda s : (FadeIn, s),
|
|
# run_time = 3,
|
|
# ))
|
|
# self.play(Write(numbers, run_time = 3))
|
|
# self.wait()
|
|
# self.play(OldLaggedStart(
|
|
# ApplyMethod, women_groups,
|
|
# lambda m : (m.set_color, PINK),
|
|
# lag_ratio = 0.1,
|
|
# rate_func = wiggle,
|
|
# run_time = 6,
|
|
# ))
|
|
|
|
# class GroupsOf7(Scene):
|
|
# def construct(self):
|
|
# stack = get_stack(Male(), Female(), 7, 3)
|
|
# question = TextMobject(
|
|
# "How many groups \\\\ of 7 with 3 ", "$\\female$", "?"
|
|
# )
|
|
# question.set_color_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.wait(0.2)
|
|
# self.remove(item, number)
|
|
# self.add(item, number)
|
|
# self.wait(2)
|
|
|
|
class BuildFiveFromFour(ProbabilityOfKWomenInGroupOfFive):
|
|
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.wait()
|
|
curr_lineup_group = lineup_group
|
|
self.lineups = curr_lineup_group
|
|
|
|
eq_16 = TexMobject("=", "16")
|
|
eq_16.move_to(twos.get_right())
|
|
eq_16.set_color_by_tex("16", YELLOW)
|
|
self.play(
|
|
n_possibilities[-1].next_to, eq_16, RIGHT,
|
|
twos.next_to, eq_16, LEFT,
|
|
FadeIn(eq_16),
|
|
)
|
|
self.wait()
|
|
|
|
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 = [m for m in lineup.items if "female" in m.get_tex_string()]
|
|
stacks[len(women)].add(lineup)
|
|
stacks.generate_target()
|
|
stacks.target.scale(0.75)
|
|
for stack in stacks.target:
|
|
stack.arrange(DOWN, buff = SMALL_BUFF)
|
|
stacks.target.arrange(
|
|
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.wait()
|
|
|
|
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.set_color(YELLOW)
|
|
number = TexMobject(str(n+1))
|
|
number.next_to(stack, UP)
|
|
self.add(lineup_copy, number)
|
|
self.wait(0.25)
|
|
self.remove(lineup_copy, number)
|
|
self.add(number)
|
|
numbers.add(number)
|
|
self.play(FadeOut(rect))
|
|
self.wait()
|
|
|
|
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(FRAME_X_RADIUS*LEFT, FRAME_X_RADIUS*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(
|
|
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.wait()
|
|
|
|
#Fill extra slot
|
|
add_man = TextMobject("Add", "$\\male$")
|
|
add_man.set_color_by_tex("male", BLUE)
|
|
add_woman = TextMobject("Add", "$\\female$")
|
|
add_woman.set_color_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.wait()
|
|
|
|
#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.wait()
|
|
self.play(*list(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(OldLaggedStart(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(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),
|
|
*list(map(MoveToTarget, movers))
|
|
)
|
|
self.play(
|
|
VGroup(top_stacks[-1], top_stacks.numbers[-1]).align_to,
|
|
bottom_stacks, DOWN
|
|
)
|
|
self.wait()
|
|
|
|
new_numbers.add_to_back(bottom_stacks.numbers[0].copy())
|
|
new_numbers.add(top_stacks.numbers[-1].copy())
|
|
new_numbers.set_color(PINK)
|
|
self.play(Write(new_numbers, run_time = 3))
|
|
self.wait()
|
|
|
|
class BuildUpFromStart(Scene):
|
|
CONFIG = {
|
|
"n_iterations" : 7,
|
|
}
|
|
def construct(self):
|
|
stacks = VGroup(VGroup(Male()), VGroup(Female()))
|
|
stacks.arrange(RIGHT, buff = LARGE_BUFF)
|
|
stacks.numbers = self.get_numbers(stacks)
|
|
|
|
max_width = FRAME_WIDTH - 3
|
|
max_height = FRAME_Y_RADIUS - 1
|
|
|
|
self.add(stacks, stacks.numbers)
|
|
for x in range(self.n_iterations):
|
|
if x < 2:
|
|
wait_time = 1
|
|
else:
|
|
wait_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(*list(map(MoveToTarget, [top_group, low_group])))
|
|
self.wait(wait_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(
|
|
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(*list(map(MoveToTarget, [
|
|
top_stacks, low_stacks,
|
|
top_stacks.numbers, low_stacks.numbers,
|
|
])))
|
|
self.wait(wait_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.wait(wait_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(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(
|
|
list(map(MoveToTarget, all_movers)),
|
|
list(map(Write, plusses)),
|
|
))
|
|
|
|
#Add
|
|
new_numbers = self.get_numbers(stacks)
|
|
self.play(ReplacementTransform(
|
|
expressions, VGroup(*list(map(VGroup, new_numbers)))
|
|
))
|
|
self.wait(wait_time)
|
|
stacks.numbers = new_numbers
|
|
|
|
|
|
####
|
|
|
|
def get_numbers(self, stacks):
|
|
return VGroup(*[
|
|
TexMobject(str(len(stack))).next_to(stack, UP)
|
|
for stack in stacks
|
|
])
|
|
|
|
class IntroducePascalsTriangle(Scene):
|
|
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):
|
|
rows = PascalsTriangle(n_rows = self.max_n+1)
|
|
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.wait()
|
|
|
|
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.wait(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.wait(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.wait()
|
|
|
|
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),
|
|
OldLaggedStart(
|
|
Indicate, numbers,
|
|
rate_func = wiggle,
|
|
color = PINK,
|
|
)
|
|
)
|
|
self.play(*list(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.set_color_num(num)
|
|
self.add(line)
|
|
if n < self.max_n:
|
|
self.wait(0.25)
|
|
else:
|
|
self.wait(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.set_color_num(num)
|
|
self.add(line)
|
|
self.wait(0.5)
|
|
self.dehighlight_num(num)
|
|
self.remove(line)
|
|
num.set_color(YELLOW)
|
|
num.scale_in_place(1.2)
|
|
self.add(line)
|
|
self.wait()
|
|
|
|
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.wait(0.1)
|
|
self.remove(line, num)
|
|
self.add(line, num)
|
|
self.wait()
|
|
self.curr_line = line
|
|
|
|
#Probability
|
|
expr = TexMobject(
|
|
"P(4", "\\female", "\\text{ out of }", "9", ")", "="
|
|
)
|
|
expr.move_to(num.get_left())
|
|
expr.set_color_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(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, wait_time = 1):
|
|
for x in range(n):
|
|
if x == n-1:
|
|
wait_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.wait(wait_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.set_color, WHITE,
|
|
*list(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(RIGHT, SMALL_BUFF)
|
|
line.shift(FRAME_X_RADIUS*RIGHT/2 + FRAME_Y_RADIUS*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)
|
|
|
|
self.play(ShowCreation(circle))
|
|
self.play(Write(top_row))
|
|
self.wait()
|
|
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.wait()
|
|
|
|
###
|
|
|
|
def set_color_num(self, num):
|
|
num.set_color(YELLOW)
|
|
num.scale_in_place(1.2)
|
|
|
|
def dehighlight_num(self, num):
|
|
num.set_color(WHITE)
|
|
num.scale_in_place(1.0/1.2)
|
|
|
|
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 = FRAME_WIDTH - 2
|
|
max_height = FRAME_Y_RADIUS - 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]
|
|
|
|
bars_copy = bars.copy()
|
|
|
|
#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.set_width(bar.get_width())
|
|
number.next_to(bar, UP, SMALL_BUFF)
|
|
|
|
self.play(*list(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.set_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, lag_ratio = 0.5)
|
|
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.wait()
|
|
|
|
# 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.wait()
|
|
# self.play(self.teacher.change_mode, "happy")
|
|
# self.wait()
|
|
# self.teacher_says(
|
|
# "There is! But first...",
|
|
# target_mode = "hooray"
|
|
# )
|
|
# self.wait(2)
|
|
|
|
class ChooseThreeFromFive(InitialFiveChooseThreeExample, PiCreatureScene):
|
|
CONFIG = {
|
|
"n" : 5,
|
|
"k" : 3,
|
|
"pi_creature_scale_val" : 0.3,
|
|
"people_colors" : [
|
|
PURPLE, BLUE, GREEN, GOLD_E, GREY,
|
|
],
|
|
}
|
|
def construct(self):
|
|
self.remove(self.people)
|
|
self.show_binary_strings()
|
|
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.wait(0.25)
|
|
self.remove(num)
|
|
self.play(
|
|
Write(VGroup(*equation[:-1])),
|
|
ReplacementTransform(num, equation[-1])
|
|
)
|
|
self.wait()
|
|
|
|
self.set_variables_as_attrs(stack, equation)
|
|
|
|
def add_people(self):
|
|
people = self.people
|
|
|
|
names = self.get_names(people)
|
|
braces = self.get_people_braces(people)
|
|
|
|
self.play(
|
|
Write(braces),
|
|
OldLaggedStart(FadeIn, people),
|
|
VGroup(self.stack, self.equation).to_edge, RIGHT, LARGE_BUFF
|
|
)
|
|
self.play(OldLaggedStart(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.set_height(self.stack[0].get_height())
|
|
for name in mover.target[:2]:
|
|
name[-1].set_fill(opacity = 1)
|
|
mover.target.arrange(RIGHT, MED_SMALL_BUFF)
|
|
movers.add(mover)
|
|
movers.target.add(mover.target)
|
|
movers.target.arrange(
|
|
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(OldLaggedStart(
|
|
MoveToTarget, movers,
|
|
lag_ratio = 0.2,
|
|
run_time = 4,
|
|
))
|
|
self.wait()
|
|
|
|
self.name_triplets = movers
|
|
|
|
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(
|
|
OldLaggedStart(ShowCreation, people_rects),
|
|
MoveToTarget(people),
|
|
MoveToTarget(names),
|
|
)
|
|
self.wait()
|
|
self.play(
|
|
ReplacementTransform(line_rect, full_line_rect),
|
|
triplet.set_color, YELLOW
|
|
)
|
|
self.wait(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.set_color(YELLOW)
|
|
updownarrow.next_to(triplet, DOWN, SMALL_BUFF)
|
|
permutations = VGroup()
|
|
for indices in it.permutations(list(range(len(triplet)))):
|
|
perm = triplet.copy()
|
|
resorter = VGroup(*[
|
|
perm[i] for i in indices
|
|
])
|
|
resorter.arrange(RIGHT, MED_SMALL_BUFF)
|
|
resorter.next_to(updownarrow, DOWN)
|
|
permutations.add(perm)
|
|
|
|
words = TextMobject("``Order doesn't matter''")
|
|
words.scale(0.75)
|
|
words.set_color(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.wait()
|
|
if i == 4:
|
|
anims.append(Write(words, run_time = 1))
|
|
self.play(*anims)
|
|
self.play(*list(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.set_color(YELLOW)
|
|
|
|
self.play(
|
|
OldLaggedStart(
|
|
ShowCreationThenDestruction, odm_words_outline,
|
|
lag_ratio = 0.2,
|
|
run_time = 1,
|
|
),
|
|
OldLaggedStart(
|
|
ApplyMethod, self.people,
|
|
lambda pi : (pi.change, "confused", odm_words,)
|
|
),
|
|
OldLaggedStart(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(lambda p : random.random())
|
|
resorter.arrange(RIGHT, buff = SMALL_BUFF)
|
|
resorter.move_to(line)
|
|
self.play(MoveToTarget(line, path_arc = np.pi))
|
|
self.play(FadeOut(q_marks))
|
|
|
|
line.sort(lambda p : p[0])
|
|
words = VGroup(*list(map(TextMobject, ["First", "Second", "Fifth"])))
|
|
words.set_color(YELLOW)
|
|
words.scale(0.75)
|
|
word_arrow_groups = VGroup()
|
|
for i, word in zip([0, 1, 4], words):
|
|
arrow = Vector(0.5*DOWN)
|
|
arrow.set_color(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.wait()
|
|
word_arrow_groups.submobjects = [
|
|
word_arrow_groups[j]
|
|
for j in (1, 2, 0)
|
|
]
|
|
self.play(*list(map(FadeOut, [line, odm_words])))
|
|
|
|
def pattern_is_unambiguous(self):
|
|
all_ones = VGroup()
|
|
for line in self.stack:
|
|
ones = VGroup(*[m for m in line if "1" in m.get_tex_string()]).copy()
|
|
ones.set_color(YELLOW)
|
|
all_ones.add(ones)
|
|
|
|
self.play(
|
|
OldLaggedStart(
|
|
FadeIn, all_ones,
|
|
lag_ratio = 0.2,
|
|
run_time = 3,
|
|
rate_func = there_and_back
|
|
),
|
|
OldLaggedStart(
|
|
ApplyMethod, self.people,
|
|
lambda pi : (pi.change, "happy", ones),
|
|
)
|
|
)
|
|
self.wait()
|
|
for trip in it.combinations(self.people, 3):
|
|
rects = VGroup(*list(map(SurroundingRectangle, trip)))
|
|
self.add(rects)
|
|
self.wait(0.3)
|
|
self.remove(rects)
|
|
self.wait()
|
|
|
|
###
|
|
|
|
def create_pi_creatures(self):
|
|
people = VGroup(*[
|
|
PiCreature(color = color).scale(self.pi_creature_scale_val)
|
|
for color in self.people_colors
|
|
])
|
|
people.arrange(RIGHT)
|
|
people.shift(3*LEFT)
|
|
people.to_edge(UP, buff = 1.25)
|
|
self.people = people
|
|
return people
|
|
|
|
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.wait()
|
|
|
|
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.set_color_by_tex("Ali", self.people[0].get_color())
|
|
words.next_to(pi_name_groups, DOWN, 2*LARGE_BUFF)
|
|
|
|
checkmark = TexMobject("\\checkmark").set_color(GREEN)
|
|
cross = TexMobject("\\times").set_color(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.wait(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)
|
|
|
|
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.set_color(BLUE)
|
|
self.play(
|
|
GrowFromCenter(brace),
|
|
Write(total_count),
|
|
)
|
|
self.wait()
|
|
|
|
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.set_color, 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.wait(0.5)
|
|
self.remove(arrows)
|
|
self.add(arrows)
|
|
self.wait()
|
|
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.wait()
|
|
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.set_color(BLUE)
|
|
name_rect.set_fill(BLUE, opacity = 0.25)
|
|
self.play(Animation(name_rect, run_time = 0))
|
|
self.wait(0.25)
|
|
self.remove(name_rect)
|
|
|
|
class StudentsGetConfused(PiCreatureScene):
|
|
def construct(self):
|
|
pi1, pi2 = self.pi_creatures
|
|
line = VGroup(
|
|
Male(), Female(), Female(), Male(), Female()
|
|
)
|
|
width = line.get_width()
|
|
for i, mob in enumerate(line):
|
|
mob.shift((i*width+SMALL_BUFF)*RIGHT)
|
|
line.scale(1.5)
|
|
line.arrange(RIGHT, SMALL_BUFF)
|
|
line.move_to(self.pi_creatures, UP)
|
|
|
|
self.add(line)
|
|
self.play(
|
|
self.get_shuffle_anim(line),
|
|
PiCreatureSays(
|
|
pi1, "Wait \\dots order matters now?",
|
|
target_mode = "confused",
|
|
look_at_arg = line
|
|
)
|
|
)
|
|
self.play(
|
|
self.get_shuffle_anim(line),
|
|
*[
|
|
ApplyMethod(pi.change, "confused", line)
|
|
for pi in self.pi_creatures
|
|
]
|
|
)
|
|
for x in range(4):
|
|
self.play(self.get_shuffle_anim(line))
|
|
self.wait()
|
|
|
|
def create_pi_creatures(self):
|
|
pis = VGroup(*[
|
|
Randolph(color = color)
|
|
for color in (BLUE_D, BLUE_B)
|
|
])
|
|
pis[1].flip()
|
|
pis.arrange(RIGHT, buff = 5)
|
|
pis.to_edge(DOWN)
|
|
return pis
|
|
|
|
def get_shuffle_anim(self, line):
|
|
indices = list(range(len(line)))
|
|
random.shuffle(indices)
|
|
line.generate_target()
|
|
for i, m in zip(indices, line.target):
|
|
m.move_to(line[i])
|
|
return MoveToTarget(line, path_arc = np.pi)
|
|
|
|
class HowToComputeNChooseK(ChooseThreeFromFive):
|
|
CONFIG = {
|
|
"n" : 5,
|
|
"k" : 3,
|
|
"line_colors" : [GREEN, YELLOW],
|
|
"n_permutaitons_to_show" : 5,
|
|
}
|
|
def construct(self):
|
|
self.force_skipping()
|
|
|
|
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()
|
|
|
|
self.revert_to_original_skipping_status()
|
|
self.indicate_final_answer()
|
|
|
|
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)
|
|
|
|
self.add(people_group)
|
|
self.set_variables_as_attrs(
|
|
names, people_group,
|
|
people_braces = braces
|
|
)
|
|
|
|
def choose_example_ordered_triplets(self):
|
|
n, k = self.n, self.k
|
|
names = self.names
|
|
|
|
lines, place_words = self.get_lines_and_place_words()
|
|
|
|
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.wait()
|
|
self.play(chosen_names.restore)
|
|
self.wait()
|
|
|
|
self.set_variables_as_attrs(lines, place_words)
|
|
|
|
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),
|
|
OldLaggedStart(
|
|
FadeIn, name_rects,
|
|
rate_func = there_and_back,
|
|
remover = True,
|
|
)
|
|
)
|
|
self.play(
|
|
name.next_to, line, UP, SMALL_BUFF,
|
|
GrowArrow(arrow)
|
|
)
|
|
self.wait()
|
|
|
|
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(*list(zip(choice_numbers.target, dots))))
|
|
product.add(choice_numbers.target[-1])
|
|
product.arrange(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.wait()
|
|
|
|
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
|
|
|
|
n_perms = self.n_permutaitons_to_show + 1
|
|
for indices in list(it.permutations(list(range(3))))[1:n_perms]:
|
|
self.play(*[
|
|
ApplyMethod(
|
|
name.next_to, lines[i], UP, SMALL_BUFF,
|
|
path_arc = np.pi
|
|
)
|
|
for i, name in zip(indices, chosen_names)
|
|
])
|
|
self.wait(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.wait()
|
|
|
|
#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(*list(zip(choice_numbers.target, dots))))
|
|
product.add(choice_numbers.target[-1])
|
|
product.arrange(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.wait()
|
|
|
|
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(RIGHT, buff = SMALL_BUFF)
|
|
line.add(group)
|
|
all_groups.add(group)
|
|
line.arrange(RIGHT, buff = LARGE_BUFF)
|
|
lines.add(line)
|
|
lines.arrange(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])),
|
|
OldLaggedStart(
|
|
ApplyMethod, all_groups,
|
|
lambda g : (g.restore,),
|
|
rate_func = lambda t : smooth(1-t),
|
|
run_time = 4,
|
|
lag_ratio = 0.2,
|
|
),
|
|
)
|
|
self.wait()
|
|
self.play(
|
|
OldLaggedStart(FadeIn, rects),
|
|
Write(rhs[-1])
|
|
)
|
|
self.wait()
|
|
|
|
self.ordered_triplets = lines
|
|
self.triplet_group_rects = rects
|
|
self.rhs = rhs
|
|
|
|
def indicate_final_answer(self):
|
|
ordered_triplets = self.ordered_triplets
|
|
rects = self.triplet_group_rects
|
|
fraction = VGroup(*self.rhs[1:])
|
|
frac_rect = SurroundingRectangle(fraction)
|
|
|
|
brace = Brace(rects, LEFT)
|
|
brace_tex = brace.get_tex("10")
|
|
|
|
self.play(FocusOn(fraction))
|
|
self.play(ShowCreation(frac_rect))
|
|
self.play(FadeOut(frac_rect))
|
|
self.wait()
|
|
self.play(
|
|
GrowFromCenter(brace),
|
|
Write(brace_tex),
|
|
)
|
|
self.wait()
|
|
|
|
|
|
####
|
|
|
|
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(RIGHT, buff = SMALL_BUFF)
|
|
choice_counts.set_color_by_gradient(*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)
|
|
])
|
|
|
|
def get_lines_and_place_words(self):
|
|
n, k = self.n, self.k
|
|
width = max([n.get_width() for n in self.names]) + MED_SMALL_BUFF
|
|
lines = VGroup(*[
|
|
Line(ORIGIN, width*RIGHT)
|
|
for x in range(k)
|
|
])
|
|
lines.arrange(RIGHT)
|
|
lines.next_to(ORIGIN, DOWN, buff = LARGE_BUFF)
|
|
place_words = VGroup(*[
|
|
TexMobject("%d^\\text{%s}"%(i+1, s))
|
|
for i, s in zip(
|
|
list(range(k)),
|
|
it.chain(["st", "nd", "rd"], it.repeat("th"))
|
|
)
|
|
])
|
|
for mob in place_words, lines:
|
|
mob.set_color_by_gradient(*self.line_colors)
|
|
for word, line in zip(place_words, lines):
|
|
word.next_to(line, DOWN, SMALL_BUFF)
|
|
|
|
self.set_variables_as_attrs(lines, place_words)
|
|
return lines, place_words
|
|
|
|
class NineChooseFourExample(HowToComputeNChooseK):
|
|
CONFIG = {
|
|
"random_seed" : 2,
|
|
"n" : 9,
|
|
"k" : 4,
|
|
"line_colors" : [RED, MAROON_B],
|
|
"n_permutaitons_to_show" : 3,
|
|
}
|
|
def construct(self):
|
|
self.setup_people()
|
|
self.show_n_choose_k()
|
|
self.show_n_choose_k_pattern()
|
|
self.choose_k_people()
|
|
self.count_how_to_choose_k()
|
|
self.show_permutations()
|
|
self.finish_computation()
|
|
|
|
def setup_people(self):
|
|
self.remove(self.people)
|
|
self.people = TextMobject(" ".join([
|
|
chr(ord('A') + i )
|
|
for i in range(self.n)
|
|
]))
|
|
self.people.set_color_by_gradient(BLUE, YELLOW)
|
|
self.names = self.people
|
|
self.people.to_edge(UP, buff = LARGE_BUFF + MED_SMALL_BUFF)
|
|
lb, rb = braces = TextMobject("\\{\\}")
|
|
braces.scale(1.5)
|
|
lb.next_to(self.people, LEFT, SMALL_BUFF)
|
|
rb.next_to(self.people, RIGHT, SMALL_BUFF)
|
|
|
|
self.people_group = VGroup(braces, self.people)
|
|
self.people_braces = braces
|
|
|
|
def show_n_choose_k(self):
|
|
n, k = self.n, self.k
|
|
n_choose_k = TexMobject("{%d \\choose %d}"%(n, k))
|
|
n_choose_k.to_corner(UP + LEFT)
|
|
self.play(FadeIn(n_choose_k))
|
|
self.set_variables_as_attrs(n_choose_k)
|
|
|
|
def show_n_choose_k_pattern(self):
|
|
n, k = self.n, self.k
|
|
stack = get_stack(
|
|
TexMobject("1").set_color(PINK),
|
|
TexMobject("0").set_color(BLUE),
|
|
n, k
|
|
)
|
|
l = len(stack)
|
|
n_stacks = 6
|
|
columns = VGroup(*[
|
|
VGroup(*stack[(i*l)/n_stacks:((i+1)*l)/n_stacks])
|
|
for i in range(n_stacks)
|
|
])
|
|
columns.arrange(
|
|
RIGHT,
|
|
aligned_edge = UP,
|
|
buff = MED_LARGE_BUFF
|
|
)
|
|
columns.set_height(7)
|
|
columns.to_corner(DOWN + RIGHT)
|
|
|
|
for line in stack:
|
|
self.play(FadeIn(line, run_time = 0.1))
|
|
self.wait(2)
|
|
self.play(FadeOut(
|
|
stack, lag_ratio = 0.5, run_time = 2
|
|
))
|
|
|
|
def choose_k_people(self):
|
|
n, k = self.n, self.k
|
|
people = self.people
|
|
braces = self.people_braces
|
|
|
|
n_items = TextMobject("%d items"%n)
|
|
choose_k = TextMobject("choose %d"%k)
|
|
n_items.next_to(people, UP, buff = MED_LARGE_BUFF)
|
|
choose_k.next_to(people, DOWN, buff = LARGE_BUFF)
|
|
|
|
chosen_subset = VGroup(*random.sample(people, k))
|
|
|
|
self.play(
|
|
Write(braces),
|
|
OldLaggedStart(FadeIn, people, run_time = 1),
|
|
FadeIn(n_items),
|
|
)
|
|
self.wait()
|
|
self.play(
|
|
FadeIn(choose_k),
|
|
OldLaggedStart(
|
|
ApplyMethod, chosen_subset,
|
|
lambda m : (m.shift, MED_LARGE_BUFF*DOWN)
|
|
)
|
|
)
|
|
self.wait()
|
|
self.play(
|
|
chosen_subset.shift, MED_LARGE_BUFF*UP,
|
|
n_items.next_to, n_items.get_center(), LEFT,
|
|
choose_k.next_to, n_items.get_center(), RIGHT,
|
|
)
|
|
|
|
def count_how_to_choose_k(self):
|
|
lines, place_words = self.get_lines_and_place_words()
|
|
self.play(
|
|
OldLaggedStart(FadeIn, lines),
|
|
OldLaggedStart(FadeIn, place_words),
|
|
run_time = 1
|
|
)
|
|
self.count_possibilities()
|
|
|
|
def show_permutations(self):
|
|
self.show_permutations_of_ABC()
|
|
self.count_permutations_of_ABC()
|
|
|
|
def finish_computation(self):
|
|
equals = TexMobject("=")
|
|
equals.shift(2*LEFT)
|
|
fraction = self.fraction
|
|
six = fraction[0][0][3]
|
|
eight = fraction[0][0][1]
|
|
two_three = VGroup(*fraction[2][0][1:3])
|
|
four = fraction[2][0][0]
|
|
|
|
rhs = TexMobject("= 9 \\cdot 2 \\cdot 7 = 126")
|
|
|
|
self.play(
|
|
self.names.restore,
|
|
FadeOut(self.lines),
|
|
FadeOut(self.place_words),
|
|
self.n_choose_k.next_to, equals, LEFT,
|
|
self.fraction.next_to, equals, RIGHT,
|
|
FadeIn(equals),
|
|
)
|
|
self.wait()
|
|
|
|
for mob in six, eight, two_three, four:
|
|
mob.cross = Cross(mob)
|
|
mob.cross.set_stroke("red", 5)
|
|
two = TexMobject("2")
|
|
two.set_color(eight.get_fill_color())
|
|
two.next_to(eight, UP)
|
|
rhs.next_to(fraction, RIGHT)
|
|
|
|
self.play(
|
|
ShowCreation(six.cross),
|
|
ShowCreation(two_three.cross),
|
|
)
|
|
self.wait()
|
|
self.play(
|
|
ShowCreation(eight.cross),
|
|
ShowCreation(four.cross),
|
|
FadeIn(two)
|
|
)
|
|
self.wait()
|
|
self.play(Write(rhs))
|
|
self.wait()
|
|
|
|
class WeirdKindOfCancelation(TeacherStudentsScene):
|
|
def construct(self):
|
|
fraction = TexMobject(
|
|
"{5 \\cdot 4 \\cdot 3",
|
|
"\\text{ ordered}", "\\text{ triplets}",
|
|
"\\over",
|
|
"1 \\cdot 2 \\cdot 3", "\\text{ orderings \\;\\qquad}}"
|
|
)
|
|
top_numbers, ordered, triplets, frac_line, bottom_numbers, orderings = fraction
|
|
for mob in top_numbers, bottom_numbers:
|
|
mob.set_color_by_gradient(GREEN, YELLOW)
|
|
fraction.next_to(self.teacher, UP+LEFT)
|
|
|
|
names = VGroup(*list(map(TextMobject, [
|
|
"Ali", "Ben", "Cam", "Denis", "Evan"
|
|
])))
|
|
names.arrange(RIGHT)
|
|
names.to_edge(UP, buff = LARGE_BUFF)
|
|
names.save_state()
|
|
lb, rb = braces = TexMobject("\\{\\}")
|
|
braces.scale(2)
|
|
lb.next_to(names, LEFT, SMALL_BUFF)
|
|
rb.next_to(names, RIGHT, SMALL_BUFF)
|
|
|
|
chosen_names = VGroup(*random.sample(names, 3))
|
|
chosen_names.generate_target()
|
|
chosen_names.target.arrange(RIGHT)
|
|
chosen_names.target.next_to(top_numbers, UP, MED_LARGE_BUFF)
|
|
for name, name_target in zip(chosen_names, chosen_names.target):
|
|
name.target = name_target
|
|
|
|
self.teacher_says("It's like unit cancellation.")
|
|
self.change_student_modes(*["confused"]*3)
|
|
self.play(
|
|
RemovePiCreatureBubble(
|
|
self.teacher, target_mode = "raise_right_hand"
|
|
),
|
|
OldLaggedStart(FadeIn, fraction, run_time = 1),
|
|
FadeIn(braces),
|
|
OldLaggedStart(FadeIn, names)
|
|
)
|
|
self.change_student_modes(
|
|
*["pondering"]*3,
|
|
look_at_arg = fraction
|
|
)
|
|
|
|
#Go through numerators
|
|
for num, name in zip(top_numbers[::2], chosen_names):
|
|
rect = SurroundingRectangle(num)
|
|
name.target.set_color(num.get_color())
|
|
self.play(
|
|
ShowCreationThenDestruction(rect),
|
|
MoveToTarget(name),
|
|
)
|
|
self.wait(2)
|
|
|
|
#Go through denominators
|
|
permutations = list(it.permutations(list(range(3))))[1:]
|
|
|
|
self.shuffle(chosen_names, permutations[:2])
|
|
self.play(OldLaggedStart(
|
|
ShowCreationThenDestruction,
|
|
VGroup(*list(map(SurroundingRectangle, bottom_numbers[::2])))
|
|
))
|
|
self.shuffle(chosen_names, permutations[2:])
|
|
self.wait()
|
|
|
|
#Show cancelation
|
|
top_cross = Cross(ordered)
|
|
bottom_cross = Cross(orderings)
|
|
|
|
self.play(
|
|
ShowCreation(top_cross),
|
|
self.teacher.change, "maybe",
|
|
)
|
|
self.play(ShowCreation(bottom_cross))
|
|
self.change_student_modes(*["happy"]*3)
|
|
self.wait(3)
|
|
|
|
###
|
|
|
|
def shuffle(self, mobject, permutations):
|
|
for permutation in permutations:
|
|
self.play(*[
|
|
ApplyMethod(
|
|
m.move_to, mobject[i].get_center(),
|
|
path_arc = np.pi,
|
|
)
|
|
for i, m in zip(permutation, mobject)
|
|
])
|
|
|
|
class ABCNotBCA(Scene):
|
|
def construct(self):
|
|
words = TextMobject("If order mattered:")
|
|
equation = TextMobject("(A, B, C) $\\ne$ (B, C, A)")
|
|
equation.set_color(YELLOW)
|
|
equation.next_to(words, DOWN)
|
|
group = VGroup(words, equation)
|
|
group.set_width(FRAME_WIDTH - 1)
|
|
group.to_edge(DOWN)
|
|
self.add(words, equation)
|
|
|
|
class ShowFormula(Scene):
|
|
def construct(self):
|
|
specific_formula = TexMobject(
|
|
"{9 \\choose 4}", "=",
|
|
"{9 \\cdot 8 \\cdot 7 \\cdot 6", "\\over",
|
|
"4 \\cdot 3 \\cdot 2 \\cdot 1}"
|
|
)
|
|
general_formula = TexMobject(
|
|
"{n \\choose k}", "=",
|
|
"{n \\cdot (n-1) \\cdots (n-k+1)", "\\over",
|
|
"k \\cdot (k-1) \\cdots 2 \\cdot 1}"
|
|
)
|
|
for i, j in (0, 1), (2, 0), (2, 3), (2, 11):
|
|
general_formula[i][j].set_color(BLUE)
|
|
for i, j in (0, 2), (2, 13), (4, 0), (4, 3):
|
|
general_formula[i][j].set_color(YELLOW)
|
|
formulas = VGroup(specific_formula, general_formula)
|
|
formulas.arrange(DOWN, buff = 2)
|
|
formulas.to_edge(UP)
|
|
|
|
self.play(FadeIn(specific_formula))
|
|
self.play(FadeIn(general_formula))
|
|
self.wait(3)
|
|
|
|
class ConfusedPi(Scene):
|
|
def construct(self):
|
|
morty = Mortimer()
|
|
morty.scale(2.5)
|
|
morty.to_corner(UP+LEFT)
|
|
morty.look(UP+LEFT)
|
|
|
|
self.add(morty)
|
|
self.play(Blink(morty))
|
|
self.play(morty.change, "confused")
|
|
self.wait()
|
|
self.play(Blink(morty))
|
|
self.wait(2)
|
|
|
|
class SumsToPowerOf2(Scene):
|
|
CONFIG = {
|
|
"n" : 5,
|
|
"alt_n" : 7,
|
|
}
|
|
def construct(self):
|
|
self.setup_stacks()
|
|
self.count_32()
|
|
self.show_sum_as_n_choose_k()
|
|
self.show_alternate_sum()
|
|
|
|
def setup_stacks(self):
|
|
stacks = get_stacks(
|
|
TexMobject("1").set_color(PINK),
|
|
TexMobject("0").set_color(BLUE),
|
|
n = self.n,
|
|
vertical_buff = SMALL_BUFF,
|
|
)
|
|
stacks.to_corner(DOWN+LEFT)
|
|
numbers = VGroup(*[
|
|
TexMobject(str(choose(self.n, k)))
|
|
for k in range(self.n + 1)
|
|
])
|
|
for number, stack in zip(numbers, stacks):
|
|
number.next_to(stack, UP)
|
|
|
|
self.play(
|
|
OldLaggedStart(FadeIn, stacks),
|
|
OldLaggedStart(FadeIn, numbers),
|
|
)
|
|
self.wait()
|
|
|
|
self.set_variables_as_attrs(stacks, numbers)
|
|
|
|
def count_32(self):
|
|
lines = VGroup(*it.chain(*self.stacks))
|
|
rhs = TexMobject("= 2^{%d}"%self.n)
|
|
rhs.to_edge(UP, buff = LARGE_BUFF)
|
|
rhs.to_edge(RIGHT, buff = 2)
|
|
|
|
numbers = self.numbers.copy()
|
|
numbers.target = VGroup(*[
|
|
TexMobject("{%d \\choose %d}"%(self.n, k))
|
|
for k in range(self.n + 1)
|
|
])
|
|
plusses = VGroup(*[TexMobject("+") for n in numbers])
|
|
plusses.remove(plusses[-1])
|
|
plusses.add(TexMobject("="))
|
|
sum_group = VGroup(*it.chain(*list(zip(
|
|
numbers.target, plusses
|
|
))))
|
|
sum_group.arrange(RIGHT, SMALL_BUFF)
|
|
sum_group.next_to(numbers, UP, LARGE_BUFF)
|
|
sum_group.shift(MED_LARGE_BUFF*RIGHT)
|
|
|
|
for i, line in zip(it.count(1), lines):
|
|
line_copy = line.copy().set_color(YELLOW)
|
|
number = Integer(i)
|
|
number.scale(1.5)
|
|
number.to_edge(UP)
|
|
VGroup(number, line_copy).set_color(YELLOW)
|
|
self.add(line_copy, number)
|
|
self.wait(0.15)
|
|
self.remove(line_copy, number)
|
|
sum_result = number
|
|
self.add(sum_result)
|
|
self.wait()
|
|
|
|
sum_result.target = TexMobject(str(2**self.n))
|
|
sum_result.target.set_color(sum_result.get_color())
|
|
sum_result.target.next_to(sum_group, RIGHT)
|
|
rhs.next_to(sum_result.target, RIGHT, aligned_edge = DOWN)
|
|
self.play(
|
|
MoveToTarget(sum_result),
|
|
MoveToTarget(numbers),
|
|
Write(plusses),
|
|
Write(rhs),
|
|
)
|
|
self.wait()
|
|
|
|
self.set_variables_as_attrs(
|
|
plusses, sum_result, rhs,
|
|
n_choose_k_terms = numbers
|
|
)
|
|
|
|
def show_sum_as_n_choose_k(self):
|
|
numbers = self.numbers
|
|
plusses = self.plusses
|
|
n_choose_k_terms = self.n_choose_k_terms
|
|
rhs = VGroup(self.sum_result, self.rhs)
|
|
n = self.n
|
|
|
|
|
|
fractions = self.get_fractions(n)
|
|
plusses.generate_target()
|
|
sum_group = VGroup(*it.chain(*list(zip(
|
|
fractions, plusses.target
|
|
))))
|
|
sum_group.arrange(RIGHT, buff = 2*SMALL_BUFF)
|
|
sum_group.next_to(rhs, LEFT)
|
|
sum_group.shift(0.5*SMALL_BUFF*DOWN)
|
|
|
|
self.play(
|
|
Transform(n_choose_k_terms, fractions),
|
|
MoveToTarget(plusses),
|
|
lag_ratio = 0.5,
|
|
run_time = 2
|
|
)
|
|
self.wait()
|
|
|
|
def show_alternate_sum(self):
|
|
fractions = self.get_fractions(self.alt_n)
|
|
fractions.remove(*fractions[4:-1])
|
|
fractions.submobjects.insert(4, TexMobject("\\cdots"))
|
|
plusses = VGroup(*[
|
|
TexMobject("+") for f in fractions[:-1]
|
|
] + [TexMobject("=")])
|
|
sum_group = VGroup(*it.chain(*list(zip(
|
|
fractions, plusses
|
|
))))
|
|
sum_group.arrange(RIGHT)
|
|
sum_group.next_to(
|
|
self.n_choose_k_terms, DOWN,
|
|
aligned_edge = LEFT, buff = LARGE_BUFF
|
|
)
|
|
sum_group.shift(SMALL_BUFF*DOWN)
|
|
rhs = TexMobject(
|
|
str(2**self.alt_n),
|
|
"=", "2^{%d}"%(self.alt_n)
|
|
)
|
|
rhs[0].set_color(YELLOW)
|
|
rhs.next_to(sum_group, RIGHT)
|
|
|
|
self.play(
|
|
OldLaggedStart(FadeOut, self.stacks),
|
|
OldLaggedStart(FadeOut, self.numbers),
|
|
OldLaggedStart(FadeIn, sum_group),
|
|
)
|
|
self.play(OldLaggedStart(FadeIn, rhs))
|
|
self.wait(2)
|
|
|
|
####
|
|
|
|
def get_fractions(self, n):
|
|
fractions = VGroup(TexMobject("1"))
|
|
dot_str = " \\!\\cdot\\! "
|
|
for k in range(1, n+1):
|
|
ts = str(n)
|
|
bs = "1"
|
|
for i in range(1, k):
|
|
ts += dot_str + str(n-i)
|
|
bs += dot_str + str(i+1)
|
|
fraction = TexMobject("{%s \\over %s}"%(ts, bs))
|
|
fractions.add(fraction)
|
|
return fractions
|
|
|
|
class AskWhyTheyAreCalledBinomial(TeacherStudentsScene):
|
|
def construct(self):
|
|
example_binomials = VGroup(*[
|
|
TexMobject("(x+y)^%d"%d)
|
|
for d in range(2, 7)
|
|
])
|
|
example_binomials.arrange(UP)
|
|
example_binomials.next_to(
|
|
self.teacher.get_corner(UP+LEFT), UP
|
|
)
|
|
|
|
pascals = PascalsTriangle(n_rows = 6)
|
|
pascals.set_height(3)
|
|
pascals.to_corner(UP+LEFT, buff = MED_SMALL_BUFF)
|
|
pascals.set_color_by_gradient(BLUE, YELLOW)
|
|
|
|
binomial_word = TextMobject(
|
|
"Bi", "nomials",
|
|
arg_separator = "",
|
|
)
|
|
binomial_word.set_color_by_tex("Bi", YELLOW)
|
|
binomial_word.set_color_by_tex("nomials", WHITE)
|
|
binomial_word.next_to(example_binomials, LEFT, buff = 1.5)
|
|
arrows = VGroup(*[
|
|
Arrow(binomial_word.get_right(), binom.get_left())
|
|
for binom in example_binomials
|
|
])
|
|
arrows.set_color(BLUE)
|
|
|
|
two_variables = TextMobject("Two", "variables")
|
|
two_variables.next_to(binomial_word, DOWN)
|
|
two_variables.shift(SMALL_BUFF*LEFT)
|
|
for tv, bw in zip(two_variables, binomial_word):
|
|
tv.set_color(bw.get_color())
|
|
|
|
self.student_says(
|
|
"Why are they called \\\\ ``binomial coefficients''?"
|
|
)
|
|
self.play(OldLaggedStart(FadeIn, pascals))
|
|
self.wait()
|
|
self.play(
|
|
FadeIn(example_binomials[0]),
|
|
RemovePiCreatureBubble(self.students[1]),
|
|
self.teacher.change, "raise_right_hand",
|
|
)
|
|
moving_binom = example_binomials[0].copy()
|
|
for binom in example_binomials[1:]:
|
|
self.play(Transform(moving_binom, binom))
|
|
self.add(binom)
|
|
self.wait()
|
|
|
|
#Name themn
|
|
self.play(
|
|
Write(binomial_word),
|
|
OldLaggedStart(GrowArrow, arrows)
|
|
)
|
|
self.change_student_modes(*["pondering"]*3)
|
|
self.play(Write(two_variables))
|
|
self.wait(2)
|
|
|
|
class NextVideo(Scene):
|
|
def construct(self):
|
|
title = TextMobject("Next video: Binomial distribution")
|
|
title.to_edge(UP)
|
|
screen = ScreenRectangle(height = 6)
|
|
screen.next_to(title, DOWN)
|
|
|
|
self.play(
|
|
Write(title),
|
|
ShowCreation(screen)
|
|
)
|
|
self.wait()
|
|
|
|
class CombinationsPatreonEndScreen(PatreonEndScreen):
|
|
CONFIG = {
|
|
"specific_patrons" : [
|
|
"Randall Hunt",
|
|
"Desmos",
|
|
"Burt Humburg",
|
|
"CrypticSwarm",
|
|
"Juan Benet",
|
|
"David Kedmey",
|
|
"Ali Yahya",
|
|
"Mayank M. Mehrotra",
|
|
"Lukas Biewald",
|
|
"Yana Chernobilsky",
|
|
"Kaustuv DeBiswas",
|
|
"Kathryn Schmiedicke",
|
|
"Yu Jun",
|
|
"Dave Nicponski",
|
|
"Damion Kistler",
|
|
"Jordan Scales",
|
|
"Markus Persson",
|
|
"Egor Gumenuk",
|
|
"Yoni Nazarathy",
|
|
"Ryan Atallah",
|
|
"Joseph John Cox",
|
|
"Luc Ritchie",
|
|
"Supershabam",
|
|
"James Park",
|
|
"Samantha D. Suplee",
|
|
"Delton Ding",
|
|
"Thomas Tarler",
|
|
"Jonathan Eppele",
|
|
"Isak Hietala",
|
|
"1stViewMaths",
|
|
"Jacob Magnuson",
|
|
"Mark Govea",
|
|
"Dagan Harrington",
|
|
"Clark Gaebel",
|
|
"Eric Chow",
|
|
"Mathias Jansson",
|
|
"David Clark",
|
|
"Michael Gardner",
|
|
"Mads Elvheim",
|
|
"Erik Sundell",
|
|
"Awoo",
|
|
"Dr. David G. Stork",
|
|
"Tianyu Ge",
|
|
"Ted Suzman",
|
|
"Linh Tran",
|
|
"Andrew Busey",
|
|
"John Haley",
|
|
"Ankalagon",
|
|
"Eric Lavault",
|
|
"Boris Veselinovich",
|
|
"Julian Pulgarin",
|
|
"Jeff Linse",
|
|
"Cooper Jones",
|
|
"Ryan Dahl",
|
|
"Robert Teed",
|
|
"Jason Hise",
|
|
"Meshal Alshammari",
|
|
"Bernd Sing",
|
|
"James Thornton",
|
|
"Mustafa Mahdi",
|
|
"Mathew Bramson",
|
|
"Jerry Ling",
|
|
"Shimin Kuang",
|
|
"Rish Kundalia",
|
|
"Achille Brighton",
|
|
"Ripta Pasay",
|
|
]
|
|
}
|
|
|
|
class Thumbnail(Scene):
|
|
def construct(self):
|
|
n_choose_k = TexMobject("n \\choose k")
|
|
n_choose_k[1].set_color(YELLOW)
|
|
n_choose_k[2].set_color(YELLOW)
|
|
n_choose_k.scale(2)
|
|
n_choose_k.to_edge(UP)
|
|
stacks = get_stacks(
|
|
TexMobject("1").set_color(PINK),
|
|
TexMobject("0").set_color(BLUE),
|
|
n = 5, vertical_buff = SMALL_BUFF,
|
|
)
|
|
stacks.to_edge(DOWN)
|
|
stacks.shift(MED_SMALL_BUFF*LEFT)
|
|
|
|
self.add(n_choose_k, stacks)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|