mirror of
https://github.com/3b1b/manim.git
synced 2025-04-13 09:47:07 +00:00
Showed sphere/necklace-division association
This commit is contained in:
parent
44dc2f6968
commit
fd5dc23839
3 changed files with 453 additions and 9 deletions
457
borsuk.py
457
borsuk.py
|
@ -1079,13 +1079,14 @@ class WriteAntipodalCoordinates(WritePointCoordinates):
|
|||
class GeneralizeBorsukUlam(Scene):
|
||||
CONFIG = {
|
||||
"n_dims" : 3,
|
||||
"boundary_colors" : [GREEN, BLUE],
|
||||
"boundary_colors" : [GREEN_B, BLUE],
|
||||
"output_boundary_color" : [MAROON_B, YELLOW],
|
||||
"negative_color" : RED,
|
||||
}
|
||||
def construct(self):
|
||||
def setup(self):
|
||||
self.colors = color_gradient(self.boundary_colors, self.n_dims)
|
||||
|
||||
def construct(self):
|
||||
sphere_set = self.get_sphere_set()
|
||||
arrow = Arrow(LEFT, RIGHT)
|
||||
f = TexMobject("f")
|
||||
|
@ -1556,13 +1557,18 @@ class ThinkAboutTheChoices(TeacherStudentsScene):
|
|||
Think about the choices
|
||||
behind a division...
|
||||
""")
|
||||
self.change_student_modes(*["pondering"]*3)
|
||||
self.change_student_modes(
|
||||
*["pondering"]*3,
|
||||
look_at_arg = SPACE_WIDTH*RIGHT+SPACE_HEIGHT*DOWN
|
||||
)
|
||||
self.dither(3)
|
||||
|
||||
class ChoicesInNecklaceCutting(Scene):
|
||||
CONFIG = {
|
||||
"num_continuous_division_searches" : 4,
|
||||
"final_num_pair" : [1./6, 1./3],
|
||||
"final_num_pair" : [1./6, 1./2],
|
||||
"necklace_center" : DOWN,
|
||||
"thief_box_offset" : 1.2,
|
||||
}
|
||||
def construct(self):
|
||||
self.add_necklace()
|
||||
|
@ -1589,6 +1595,7 @@ class ChoicesInNecklaceCutting(Scene):
|
|||
numbers_with_elongated_ticks = [],
|
||||
)
|
||||
interval.stretch_to_fit_width(width)
|
||||
interval.shift(self.necklace_center)
|
||||
tick_marks = interval.tick_marks
|
||||
tick_marks.set_stroke(WHITE, width = 2)
|
||||
|
||||
|
@ -1602,11 +1609,12 @@ class ChoicesInNecklaceCutting(Scene):
|
|||
segments.add(segment)
|
||||
|
||||
self.necklace = VGroup(segments, tick_marks)
|
||||
self.interval = interval
|
||||
self.add(self.necklace)
|
||||
|
||||
self.interval = interval
|
||||
|
||||
def choose_places_to_cut(self):
|
||||
v_lines = [DashedLine(UP, DOWN), for x in range(2)]
|
||||
v_lines = VGroup(*[DashedLine(UP, DOWN) for x in range(2)])
|
||||
num_pairs = [
|
||||
sorted([random.random(), random.random()])
|
||||
for x in range(self.num_continuous_division_searches)
|
||||
|
@ -1614,23 +1622,443 @@ class ChoicesInNecklaceCutting(Scene):
|
|||
|
||||
point_pairs = [
|
||||
map(self.interval.number_to_point, num_pair)
|
||||
for num_pair in num_pair
|
||||
for num_pair in num_pairs
|
||||
]
|
||||
|
||||
for line, point in zip(v_lines, point_pairs[0]):
|
||||
line.move_to(point)
|
||||
self.play(ShowCreation(v_lines))
|
||||
for point_pair in point_pairs[1:]:
|
||||
self.dither()
|
||||
self.play(*[
|
||||
ApplyMethod(line.move_to, point)
|
||||
for line, point in zip(v_lines, point_pair)
|
||||
])
|
||||
self.dither()
|
||||
|
||||
self.division_points = list(it.chain(
|
||||
[self.interval.get_left()],
|
||||
point_pairs[-1],
|
||||
[self.interval.get_right()]
|
||||
))
|
||||
|
||||
self.v_lines = v_lines
|
||||
|
||||
def show_three_numbers_adding_to_one(self):
|
||||
pass
|
||||
points = self.division_points
|
||||
braces = [
|
||||
Brace(Line(p1+SMALL_BUFF*RIGHT/2, p2+SMALL_BUFF*LEFT/2))
|
||||
for p1, p2 in zip(points, points[1:])
|
||||
]
|
||||
for char, denom, brace in zip("abc", [6, 3, 2], braces):
|
||||
brace.label = brace.get_text("$%s$"%char)
|
||||
brace.concrete_label = brace.get_text("$\\frac{1}{%d}$"%denom)
|
||||
VGroup(
|
||||
brace.label,
|
||||
brace.concrete_label
|
||||
).highlight(YELLOW)
|
||||
|
||||
words = TextMobject(
|
||||
"1) Choose", "$a$, $b$, $c$", "so that", "$a+b+c = 1$"
|
||||
)
|
||||
words[1].highlight(YELLOW)
|
||||
words[3].highlight(YELLOW)
|
||||
words.to_corner(UP+LEFT)
|
||||
|
||||
self.play(*it.chain(*[
|
||||
[GrowFromCenter(brace), Write(brace.label)]
|
||||
for brace in braces
|
||||
]))
|
||||
self.play(Write(words))
|
||||
self.dither(2)
|
||||
self.play(*[
|
||||
ReplacementTransform(brace.label, brace.concrete_label)
|
||||
for brace in braces
|
||||
])
|
||||
self.dither()
|
||||
self.wiggle_v_lines()
|
||||
self.dither()
|
||||
self.play(*map(FadeOut, list(braces) + [
|
||||
brace.concrete_label for brace in braces
|
||||
]))
|
||||
|
||||
self.choice_one_words = words
|
||||
|
||||
def make_binary_choice(self):
|
||||
groups = self.get_groups()
|
||||
boxes, labels = self.get_boxes_and_labels()
|
||||
arrow_pairs, curr_arrows = self.get_choice_arrow_pairs(groups)
|
||||
words = TextMobject("2) Make a binary choice for each segment")
|
||||
words.next_to(
|
||||
self.choice_one_words, DOWN,
|
||||
buff = MED_LARGE_BUFF,
|
||||
aligned_edge = LEFT
|
||||
)
|
||||
|
||||
self.play(Write(words))
|
||||
self.play(*map(FadeIn, [boxes, labels]))
|
||||
for binary_choices in it.product(*[[0, 1]]*3):
|
||||
self.play(*[
|
||||
ApplyMethod(group.move_to, group.target_points[choice])
|
||||
for group, choice in zip(groups, binary_choices)
|
||||
] + [
|
||||
Transform(
|
||||
curr_arrow, arrow_pair[choice],
|
||||
path_arc = np.pi
|
||||
)
|
||||
for curr_arrow, arrow_pair, choice in zip(
|
||||
curr_arrows, arrow_pairs, binary_choices
|
||||
)
|
||||
])
|
||||
self.dither()
|
||||
|
||||
######
|
||||
|
||||
def get_groups(self):
|
||||
segments, tick_marks = self.necklace
|
||||
n_segments = len(segments)
|
||||
indices = [0, n_segments/6, n_segments/2, n_segments]
|
||||
|
||||
groups = [
|
||||
VGroup(
|
||||
VGroup(*segments[i1:i2]),
|
||||
VGroup(*tick_marks[i1:i2]),
|
||||
)
|
||||
for i1, i2 in zip(indices, indices[1:])
|
||||
]
|
||||
for group, index in zip(groups, indices[1:]):
|
||||
group.add(tick_marks[index].copy())
|
||||
groups[-1][-1].add(tick_marks[-1])
|
||||
|
||||
for group in groups:
|
||||
group.target_points = [
|
||||
group.get_center() + self.thief_box_offset*vect
|
||||
for vect in UP, DOWN
|
||||
]
|
||||
|
||||
return groups
|
||||
|
||||
def get_boxes_and_labels(self):
|
||||
box = Rectangle(
|
||||
height = self.necklace.get_height()+SMALL_BUFF,
|
||||
width = self.necklace.get_width()+2*SMALL_BUFF,
|
||||
stroke_width = 0,
|
||||
fill_color = WHITE,
|
||||
fill_opacity = 0.25
|
||||
)
|
||||
box.move_to(self.necklace)
|
||||
|
||||
boxes = VGroup(*[
|
||||
box.copy().shift(self.thief_box_offset*vect)
|
||||
for vect in UP, DOWN
|
||||
])
|
||||
labels = VGroup(*[
|
||||
TextMobject(
|
||||
"Thief %d"%(i+1)
|
||||
).next_to(box, UP, aligned_edge = RIGHT)
|
||||
for i, box in enumerate(boxes)
|
||||
])
|
||||
return boxes, labels
|
||||
|
||||
def get_choice_arrow_pairs(self, groups):
|
||||
arrow = TexMobject("\\uparrow")
|
||||
arrow_pairs = [
|
||||
[arrow.copy(), arrow.copy().rotate(np.pi)]
|
||||
for group in groups
|
||||
]
|
||||
pre_arrow_points = [
|
||||
VectorizedPoint(group.get_center())
|
||||
for group in groups
|
||||
]
|
||||
for point, arrow_pair in zip(pre_arrow_points, arrow_pairs):
|
||||
for arrow, color in zip(arrow_pair, [GREEN, RED]):
|
||||
arrow.highlight(color)
|
||||
arrow.move_to(point.get_center())
|
||||
return arrow_pairs, pre_arrow_points
|
||||
|
||||
def wiggle_v_lines(self):
|
||||
self.play(
|
||||
*it.chain(*[
|
||||
[
|
||||
line.rotate_in_place, np.pi/12, vect,
|
||||
line.highlight, RED
|
||||
]
|
||||
for line, vect in zip(self.v_lines, [OUT, IN])
|
||||
]),
|
||||
rate_func = wiggle
|
||||
)
|
||||
|
||||
class CompareThisToSphereChoice(TeacherStudentsScene):
|
||||
def construct(self):
|
||||
self.teacher_says("""
|
||||
Compare this to choosing
|
||||
a point on the sphere.
|
||||
""")
|
||||
self.change_student_modes(
|
||||
*["pondering"]*3,
|
||||
look_at_arg = SPACE_WIDTH*RIGHT+SPACE_HEIGHT*DOWN
|
||||
)
|
||||
self.dither(3)
|
||||
|
||||
class ChoicesForSpherePoint(GeneralizeBorsukUlam):
|
||||
def construct(self):
|
||||
self.add_sphere_set()
|
||||
self.initialize_words()
|
||||
self.play(Write(self.choice_one_words))
|
||||
self.dither()
|
||||
self.show_example_choices()
|
||||
self.show_binary_choices()
|
||||
|
||||
def get_tuple(self):
|
||||
tup = TexMobject("(x, y, z)")
|
||||
for i, color in zip([1, 3, 5], self.colors):
|
||||
tup[i].highlight(color)
|
||||
return tup
|
||||
|
||||
def get_condition(self):
|
||||
condition = TexMobject("x^2+y^2+z^2 = 1")
|
||||
for i, color in zip([0, 3, 6], self.colors):
|
||||
VGroup(*condition[i:i+2]).highlight(color)
|
||||
return condition
|
||||
|
||||
def add_sphere_set(self):
|
||||
sphere_set = self.get_sphere_set()
|
||||
sphere_set.scale(0.7)
|
||||
sphere_set.to_edge(RIGHT)
|
||||
sphere_set.shift(UP)
|
||||
|
||||
self.add(sphere_set)
|
||||
|
||||
def initialize_words(self):
|
||||
choice_one_words = TextMobject(
|
||||
"1) Choose", "$x^2$, $y^2$, $z^2$",
|
||||
"so that", "$x^2+y^2+z^2 = 1$"
|
||||
)
|
||||
for i in 1, 3:
|
||||
for j, color in zip([0, 3, 6], self.colors):
|
||||
VGroup(*choice_one_words[i][j:j+2]).highlight(color)
|
||||
choice_one_words.to_corner(UP+LEFT)
|
||||
|
||||
choice_two_words = TextMobject(
|
||||
"2) Make a binary choice for each one"
|
||||
)
|
||||
choice_two_words.next_to(
|
||||
choice_one_words, DOWN,
|
||||
buff = MED_LARGE_BUFF,
|
||||
aligned_edge = LEFT
|
||||
)
|
||||
|
||||
self.choice_one_words = choice_one_words
|
||||
self.choice_two_words = choice_two_words
|
||||
|
||||
def show_example_choices(self):
|
||||
choices = VGroup(*[
|
||||
TexMobject(*tex).highlight(color)
|
||||
for color, tex in zip(self.colors, [
|
||||
("x", "^2 = ", "1/6"),
|
||||
("y", "^2 = ", "1/3"),
|
||||
("z", "^2 = ", "1/2"),
|
||||
])
|
||||
])
|
||||
choices.arrange_submobjects(
|
||||
DOWN,
|
||||
buff = LARGE_BUFF,
|
||||
aligned_edge = LEFT
|
||||
)
|
||||
choices.scale_to_fit_height(SPACE_HEIGHT)
|
||||
choices.to_edge(LEFT)
|
||||
choices.shift(DOWN)
|
||||
|
||||
self.play(FadeIn(
|
||||
choices,
|
||||
run_time = 2,
|
||||
submobject_mode = "lagged_start"
|
||||
))
|
||||
self.dither()
|
||||
|
||||
self.choices = choices
|
||||
|
||||
def show_binary_choices(self):
|
||||
for choice in self.choices:
|
||||
var_tex = choice.expression_parts[0]
|
||||
frac_tex = choice.expression_parts[2]
|
||||
sqrts = VGroup(*[
|
||||
TexMobject(
|
||||
var_tex + "=" + sign + \
|
||||
"\\sqrt{%s}"%frac_tex)
|
||||
for sign in ["+", "-"]
|
||||
])
|
||||
for sqrt in sqrts:
|
||||
sqrt.scale(0.6)
|
||||
sqrts.arrange_submobjects(DOWN)
|
||||
sqrts.next_to(choice, RIGHT, buff = LARGE_BUFF)
|
||||
sqrts.highlight(choice.get_color())
|
||||
|
||||
arrows = VGroup(*[
|
||||
Arrow(
|
||||
choice.get_right(), sqrt.get_left(),
|
||||
color = WHITE,
|
||||
tip_length = 0.1,
|
||||
buff = SMALL_BUFF
|
||||
)
|
||||
for sqrt in sqrts
|
||||
])
|
||||
|
||||
self.play(ShowCreation(arrows))
|
||||
self.play(FadeIn(sqrts, submobject_mode = "lagged_start"))
|
||||
self.play(Write(self.choice_two_words))
|
||||
self.dither()
|
||||
|
||||
class NecklaceDivisionSphereAssociation(ChoicesInNecklaceCutting):
|
||||
CONFIG = {
|
||||
"xyz_colors" : color_gradient([GREEN_B, BLUE], 3),
|
||||
"necklace_center" : DOWN,
|
||||
"thief_box_offset" : 1.6,
|
||||
"denoms" : [6, 3, 2],
|
||||
}
|
||||
def construct(self):
|
||||
self.add_necklace()
|
||||
self.add_sphere_point_label()
|
||||
self.choose_places_to_cut()
|
||||
self.add_braces()
|
||||
self.add_boxes_and_labels()
|
||||
self.show_binary_choice_association()
|
||||
self.ask_about_antipodal_pairs()
|
||||
|
||||
def add_sphere_point_label(self):
|
||||
label = TextMobject(
|
||||
"$(x, y, z)$",
|
||||
"such that",
|
||||
"$x^2 + y^2 + z^2 = 1$"
|
||||
)
|
||||
for i, j_list in (0, [1, 3, 5]), (2, [0, 3, 6]):
|
||||
for j, color in zip(j_list, self.xyz_colors):
|
||||
label[i][j].highlight(color)
|
||||
label.to_corner(UP+RIGHT)
|
||||
|
||||
ghost_sphere_point = VectorizedPoint()
|
||||
ghost_sphere_point.to_corner(UP+LEFT, buff = LARGE_BUFF)
|
||||
ghost_sphere_point.shift(2*RIGHT)
|
||||
|
||||
arrow = Arrow(
|
||||
label.get_left(), ghost_sphere_point,
|
||||
color = WHITE
|
||||
)
|
||||
|
||||
self.add(label, arrow)
|
||||
|
||||
self.sphere_point_label = label
|
||||
|
||||
def add_braces(self):
|
||||
points = self.division_points
|
||||
braces = [
|
||||
Brace(
|
||||
Line(p1+SMALL_BUFF*RIGHT/2, p2+SMALL_BUFF*LEFT/2),
|
||||
UP
|
||||
)
|
||||
for p1, p2 in zip(points, points[1:])
|
||||
]
|
||||
for char, brace, color, denom in zip("xyz", braces, self.xyz_colors, self.denoms):
|
||||
brace.label = brace.get_text(
|
||||
"$%s^2$"%char, "$= 1/%d$"%denom,
|
||||
buff = SMALL_BUFF
|
||||
)
|
||||
brace.label.highlight(color)
|
||||
if brace.label.get_right()[0] > brace.get_right()[0]:
|
||||
brace.label.next_to(
|
||||
brace, UP, buff = SMALL_BUFF,
|
||||
aligned_edge = RIGHT
|
||||
)
|
||||
|
||||
self.play(*it.chain(
|
||||
map(GrowFromCenter, braces),
|
||||
[Write(brace.label) for brace in braces]
|
||||
))
|
||||
self.dither()
|
||||
|
||||
self.braces = braces
|
||||
|
||||
def add_boxes_and_labels(self):
|
||||
boxes, labels = self.get_boxes_and_labels()
|
||||
self.play(*map(FadeIn, [boxes, labels]))
|
||||
self.dither()
|
||||
|
||||
def show_binary_choice_association(self):
|
||||
groups = self.get_groups()
|
||||
self.swapping_anims = []
|
||||
final_choices = [1, 0, 1]
|
||||
quads = zip(self.braces, self.denoms, groups, final_choices)
|
||||
for brace, denom, group, final_choice in quads:
|
||||
char = brace.label.args[0][1]
|
||||
choices = [
|
||||
TexMobject(
|
||||
char, "=", sign, "\\sqrt{\\frac{1}{%d}}"%denom
|
||||
)
|
||||
for sign in "+", "-"
|
||||
]
|
||||
for choice, color in zip(choices, [GREEN, RED]):
|
||||
# choice[0].highlight(brace.label.get_color())
|
||||
choice[2].highlight(color)
|
||||
choice.scale(0.8)
|
||||
choice.move_to(group)
|
||||
if choice.get_width() > 0.8*group.get_width():
|
||||
choice.next_to(group.get_right(), LEFT, buff = MED_SMALL_BUFF)
|
||||
original_choices = [m.copy() for m in choices]
|
||||
|
||||
self.play(
|
||||
ReplacementTransform(
|
||||
VGroup(brace.label[0], brace, brace.label[1]),
|
||||
choices[0]
|
||||
),
|
||||
group.move_to, group.target_points[0]
|
||||
)
|
||||
self.dither()
|
||||
self.play(
|
||||
Transform(*choices),
|
||||
group.move_to, group.target_points[1]
|
||||
)
|
||||
self.dither()
|
||||
if final_choice == 0:
|
||||
self.play(
|
||||
Transform(choices[0], original_choices[0]),
|
||||
group.move_to, group.target_points[0]
|
||||
)
|
||||
self.swapping_anims += [
|
||||
Transform(choices[0], original_choices[1-final_choice]),
|
||||
group.move_to, group.target_points[1-final_choice]
|
||||
]
|
||||
|
||||
def ask_about_antipodal_pairs(self):
|
||||
question = TextMobject("What do antipodal points signify?")
|
||||
question.move_to(self.sphere_point_label, LEFT)
|
||||
question.highlight(MAROON_B)
|
||||
antipodal_tex = TexMobject(
|
||||
"(x, y, z) \\rightarrow (-x, -y, -z)"
|
||||
)
|
||||
antipodal_tex.next_to(question, DOWN, aligned_edge = LEFT)
|
||||
|
||||
self.play(FadeOut(self.sphere_point_label))
|
||||
self.play(FadeIn(question))
|
||||
self.dither()
|
||||
self.play(Write(antipodal_tex))
|
||||
self.dither()
|
||||
self.wiggle_v_lines()
|
||||
self.dither()
|
||||
self.play(*self.swapping_anims)
|
||||
self.dither()
|
||||
|
||||
class TotalLengthOfEachJewelEquals(NecklaceDivisionSphereAssociation):
|
||||
CONFIG = {
|
||||
"random_seed" : 2,
|
||||
"hard_coded_fair_division_indices" : [],
|
||||
}
|
||||
def construct(self):
|
||||
random.seed(self.random_seed)
|
||||
self.add_necklace()
|
||||
self.add_boxes_and_labels()
|
||||
self.find_fair_division()
|
||||
|
||||
def find_fair_division(self):
|
||||
pass
|
||||
|
||||
|
||||
|
@ -1645,6 +2073,19 @@ class ChoicesInNecklaceCutting(Scene):
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -470,6 +470,9 @@ class TeacherStudentsScene(Scene):
|
|||
pairs = [(s, m) for s, m in pairs if m is not None]
|
||||
start = VGroup(*[s for s, m in pairs])
|
||||
target = VGroup(*[s.copy().change_mode(m) for s, m in pairs])
|
||||
if "look_at_arg" in kwargs:
|
||||
for pi in target:
|
||||
pi.look_at(kwargs["look_at_arg"])
|
||||
self.play(
|
||||
Transform(
|
||||
start, target,
|
||||
|
|
|
@ -169,7 +169,7 @@ class Arrow(Line):
|
|||
"color" : YELLOW_C,
|
||||
"tip_length" : 0.25,
|
||||
"tip_angle" : np.pi/6,
|
||||
"buff" : 0.3,
|
||||
"buff" : MED_SMALL_BUFF,
|
||||
"propogate_style_to_family" : False,
|
||||
"preserve_tip_size_when_scaling" : True,
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue