mirror of
https://github.com/3b1b/manim.git
synced 2025-08-01 08:54:38 +08:00
middle of massive restructure, everything still broken
This commit is contained in:
171
topics/combinatorics.py
Normal file
171
topics/combinatorics.py
Normal file
@ -0,0 +1,171 @@
|
||||
from helpers import *
|
||||
|
||||
from scene import Scene
|
||||
|
||||
|
||||
DEFAULT_COUNT_NUM_OFFSET = (SPACE_WIDTH - 1, SPACE_HEIGHT - 1, 0)
|
||||
DEFAULT_COUNT_RUN_TIME = 5.0
|
||||
|
||||
class CountingScene(Scene):
|
||||
def count(self, items, item_type = "mobject", *args, **kwargs):
|
||||
if item_type == "mobject":
|
||||
self.count_mobjects(items, *args, **kwargs)
|
||||
elif item_type == "region":
|
||||
self.count_regions(items, *args, **kwargs)
|
||||
else:
|
||||
raise Exception("Unknown item_type, should be mobject or region")
|
||||
return self
|
||||
|
||||
def count_mobjects(
|
||||
self, mobjects, mode = "highlight",
|
||||
color = "red",
|
||||
display_numbers = True,
|
||||
num_offset = DEFAULT_COUNT_NUM_OFFSET,
|
||||
run_time = DEFAULT_COUNT_RUN_TIME):
|
||||
"""
|
||||
Note, leaves final number mobject as "number" attribute
|
||||
|
||||
mode can be "highlight", "show_creation" or "show", otherwise
|
||||
a warning is given and nothing is animating during the count
|
||||
"""
|
||||
if len(mobjects) > 50: #TODO
|
||||
raise Exception("I don't know if you should be counting \
|
||||
too many mobjects...")
|
||||
if len(mobjects) == 0:
|
||||
raise Exception("Counting mobject list of length 0")
|
||||
if mode not in ["highlight", "show_creation", "show"]:
|
||||
raise Warning("Unknown mode")
|
||||
frame_time = run_time / len(mobjects)
|
||||
if mode == "highlight":
|
||||
self.add(*mobjects)
|
||||
for mob, num in zip(mobjects, it.count(1)):
|
||||
if display_numbers:
|
||||
num_mob = tex_mobject(str(num))
|
||||
num_mob.center().shift(num_offset)
|
||||
self.add(num_mob)
|
||||
if mode == "highlight":
|
||||
original_color = mob.color
|
||||
mob.highlight(color)
|
||||
self.dither(frame_time)
|
||||
mob.highlight(original_color)
|
||||
if mode == "show_creation":
|
||||
self.play(ShowCreation(mob, run_time = frame_time))
|
||||
if mode == "show":
|
||||
self.add(mob)
|
||||
self.dither(frame_time)
|
||||
if display_numbers:
|
||||
self.remove(num_mob)
|
||||
if display_numbers:
|
||||
self.add(num_mob)
|
||||
self.number = num_mob
|
||||
return self
|
||||
|
||||
def count_regions(self, regions,
|
||||
mode = "one_at_a_time",
|
||||
num_offset = DEFAULT_COUNT_NUM_OFFSET,
|
||||
run_time = DEFAULT_COUNT_RUN_TIME,
|
||||
**unused_kwargsn):
|
||||
if mode not in ["one_at_a_time", "show_all"]:
|
||||
raise Warning("Unknown mode")
|
||||
frame_time = run_time / (len(regions))
|
||||
for region, count in zip(regions, it.count(1)):
|
||||
num_mob = tex_mobject(str(count))
|
||||
num_mob.center().shift(num_offset)
|
||||
self.add(num_mob)
|
||||
self.highlight_region(region)
|
||||
self.dither(frame_time)
|
||||
if mode == "one_at_a_time":
|
||||
self.reset_background()
|
||||
self.remove(num_mob)
|
||||
self.add(num_mob)
|
||||
self.number = num_mob
|
||||
return self
|
||||
|
||||
|
||||
BIG_N_PASCAL_ROWS = 11
|
||||
N_PASCAL_ROWS = 7
|
||||
|
||||
class PascalsTriangleScene(Scene):
|
||||
args_list = [
|
||||
(N_PASCAL_ROWS,),
|
||||
(BIG_N_PASCAL_ROWS,),
|
||||
]
|
||||
@staticmethod
|
||||
def args_to_string(*args):
|
||||
return str(args[0])
|
||||
|
||||
def __init__(self, nrows, *args, **kwargs):
|
||||
Scene.__init__(self, *args, **kwargs)
|
||||
self.nrows = nrows
|
||||
self.diagram_height = 2*SPACE_HEIGHT - 1
|
||||
self.diagram_width = 1.5*SPACE_WIDTH
|
||||
self.cell_height = self.diagram_height / nrows
|
||||
self.cell_width = self.diagram_width / nrows
|
||||
self.portion_to_fill = 0.7
|
||||
self.bottom_left = np.array(
|
||||
(-self.cell_width * nrows / 2.0, -self.cell_height * nrows / 2.0, 0)
|
||||
)
|
||||
num_to_num_mob = {}
|
||||
self.coords_to_mobs = {}
|
||||
self.coords = [(n, k) for n in range(nrows) for k in range(n+1)]
|
||||
for n, k in self.coords:
|
||||
num = choose(n, k)
|
||||
center = self.coords_to_center(n, k)
|
||||
if num not in num_to_num_mob:
|
||||
num_to_num_mob[num] = tex_mobject(str(num))
|
||||
num_mob = deepcopy(num_to_num_mob[num])
|
||||
scale_factor = min(
|
||||
1,
|
||||
self.portion_to_fill * self.cell_height / num_mob.get_height(),
|
||||
self.portion_to_fill * self.cell_width / num_mob.get_width(),
|
||||
)
|
||||
num_mob.center().scale(scale_factor).shift(center)
|
||||
if n not in self.coords_to_mobs:
|
||||
self.coords_to_mobs[n] = {}
|
||||
self.coords_to_mobs[n][k] = num_mob
|
||||
self.add(*[self.coords_to_mobs[n][k] for n, k in self.coords])
|
||||
|
||||
def coords_to_center(self, n, k):
|
||||
return self.bottom_left + (
|
||||
self.cell_width * (k+self.nrows/2.0 - n/2.0),
|
||||
self.cell_height * (self.nrows - n),
|
||||
0
|
||||
)
|
||||
|
||||
def generate_n_choose_k_mobs(self):
|
||||
self.coords_to_n_choose_k = {}
|
||||
for n, k in self.coords:
|
||||
nck_mob = tex_mobject(r"{%d \choose %d}"%(n, k))
|
||||
scale_factor = min(
|
||||
1,
|
||||
self.portion_to_fill * self.cell_height / nck_mob.get_height(),
|
||||
self.portion_to_fill * self.cell_width / nck_mob.get_width(),
|
||||
)
|
||||
center = self.coords_to_mobs[n][k].get_center()
|
||||
nck_mob.center().scale(scale_factor).shift(center)
|
||||
if n not in self.coords_to_n_choose_k:
|
||||
self.coords_to_n_choose_k[n] = {}
|
||||
self.coords_to_n_choose_k[n][k] = nck_mob
|
||||
|
||||
def generate_sea_of_zeros(self):
|
||||
zero = tex_mobject("0")
|
||||
self.sea_of_zeros = []
|
||||
for n in range(self.nrows):
|
||||
for a in range((self.nrows - n)/2 + 1):
|
||||
for k in (n + a + 1, -a -1):
|
||||
self.coords.append((n, k))
|
||||
mob = deepcopy(zero)
|
||||
mob.shift(self.coords_to_center(n, k))
|
||||
self.coords_to_mobs[n][k] = mob
|
||||
self.add(mob)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user