mirror of
https://github.com/3b1b/manim.git
synced 2025-08-05 16:49:03 +00:00
Finished definition of continuity
This commit is contained in:
parent
31b7732163
commit
c16abfd6c8
2 changed files with 353 additions and 12 deletions
|
@ -12,17 +12,18 @@ from animation.transform import \
|
||||||
GrowFromCenter, ClockwiseTransform, ApplyPointwiseFunction, \
|
GrowFromCenter, ClockwiseTransform, ApplyPointwiseFunction, \
|
||||||
ShrinkToCenter
|
ShrinkToCenter
|
||||||
from animation.simple_animations import \
|
from animation.simple_animations import \
|
||||||
ShowCreation, ShimmerIn, FadeOut, FadeIn
|
ShowCreation, ShimmerIn, FadeOut, FadeIn, Homotopy
|
||||||
from animation.meta_animations import \
|
from animation.meta_animations import \
|
||||||
DelayByOrder, TransformAnimations
|
DelayByOrder, TransformAnimations
|
||||||
from animation.playground import Vibrate
|
from animation.playground import Vibrate
|
||||||
|
|
||||||
from topics.geometry import \
|
from topics.geometry import \
|
||||||
Line, Dot, Arrow, Grid, Square, Point
|
Line, Dot, Arrow, Grid, Square, Point, Circle
|
||||||
from topics.characters import \
|
from topics.characters import \
|
||||||
ThoughtBubble, SpeechBubble, Mathematician
|
ThoughtBubble, SpeechBubble, Mathematician
|
||||||
from topics.number_line import UnitInterval, NumberLine
|
from topics.number_line import UnitInterval, NumberLine
|
||||||
from topics.three_dimensions import Stars
|
from topics.three_dimensions import Stars
|
||||||
|
from topics.functions import ParametricFunction
|
||||||
|
|
||||||
from region import region_from_polygon_vertices, Region
|
from region import region_from_polygon_vertices, Region
|
||||||
|
|
||||||
|
@ -494,18 +495,348 @@ class ContinuityRequired(Scene):
|
||||||
|
|
||||||
class FormalDefinitionOfContinuity(Scene):
|
class FormalDefinitionOfContinuity(Scene):
|
||||||
def construct(self):
|
def construct(self):
|
||||||
self.play(ShimmerIn(TextMobject(" ".join([
|
self.setup()
|
||||||
"$f : A \\to B$ is continuous if: \\\\ \n\n",
|
self.label_spaces()
|
||||||
"$\\forall x \\in A$,",
|
self.move_dot()
|
||||||
"$\\forall \\epsilon > 0$,",
|
self.label_jump()
|
||||||
"$\\exists \\delta > 0$ such that",
|
self.draw_circles()
|
||||||
"$|f(y) - f(x)| < \\epsilon$",
|
self.vary_circle_sizes()
|
||||||
"for all $y \\in A$ satisfying $|x-y|<\\delta$.",
|
self.discontinuous_point()
|
||||||
]))))
|
|
||||||
|
|
||||||
|
def setup(self):
|
||||||
|
self.input_color = YELLOW_C
|
||||||
|
self.output_color = RED
|
||||||
|
def spiril(t):
|
||||||
|
theta = 2*np.pi*t
|
||||||
|
return t*np.cos(theta)*RIGHT+t*np.sin(theta)*UP
|
||||||
|
|
||||||
|
self.spiril1 = ParametricFunction(
|
||||||
|
lambda t : 1.5*RIGHT + DOWN + 2*spiril(t),
|
||||||
|
density = 5*DEFAULT_POINT_DENSITY_1D,
|
||||||
|
)
|
||||||
|
self.spiril2 = ParametricFunction(
|
||||||
|
lambda t : 5.5*RIGHT + UP - 2*spiril(1-t),
|
||||||
|
density = 5*DEFAULT_POINT_DENSITY_1D,
|
||||||
|
)
|
||||||
|
Mobject.align_data(self.spiril1, self.spiril2)
|
||||||
|
self.output = Mobject(self.spiril1, self.spiril2)
|
||||||
|
self.output.ingest_sub_mobjects()
|
||||||
|
self.output.highlight(GREEN_A)
|
||||||
|
|
||||||
|
self.interval = UnitInterval()
|
||||||
|
self.interval.scale_to_fit_width(SPACE_WIDTH-1)
|
||||||
|
self.interval.to_edge(LEFT)
|
||||||
|
|
||||||
|
self.input_dot = Dot(color = self.input_color)
|
||||||
|
self.output_dot = self.input_dot.copy().highlight(self.output_color)
|
||||||
|
left, right = self.interval.get_left(), self.interval.get_right()
|
||||||
|
self.input_homotopy = lambda (x, y, z, t) : (x, y, t) + interpolate(left, right, t)
|
||||||
|
output_size = self.output.get_num_points()-1
|
||||||
|
output_points = self.output.points
|
||||||
|
self.output_homotopy = lambda (x, y, z, t) : (x, y, z) + output_points[int(t*output_size)]
|
||||||
|
|
||||||
|
def get_circles_and_points(self, min_input, max_input):
|
||||||
|
input_left, input_right = [
|
||||||
|
self.interval.number_to_point(num)
|
||||||
|
for num in min_input, max_input
|
||||||
|
]
|
||||||
|
input_circle = Circle(
|
||||||
|
radius = np.linalg.norm(input_left-input_right)/2,
|
||||||
|
color = WHITE
|
||||||
|
)
|
||||||
|
input_circle.shift((input_left+input_right)/2)
|
||||||
|
|
||||||
|
input_points = Line(
|
||||||
|
input_left, input_right,
|
||||||
|
color = self.input_color
|
||||||
|
)
|
||||||
|
output_points = Mobject(color = self.output_color)
|
||||||
|
n = self.output.get_num_points()
|
||||||
|
output_points.add_points(
|
||||||
|
self.output.points[int(min_input*n):int(max_input*n)]
|
||||||
|
)
|
||||||
|
output_center = output_points.points[int(0.5*output_points.get_num_points())]
|
||||||
|
max_distance = np.linalg.norm(output_center-output_points.points[-1])
|
||||||
|
output_circle = Circle(
|
||||||
|
radius = max_distance,
|
||||||
|
color = WHITE
|
||||||
|
)
|
||||||
|
output_circle.shift(output_center)
|
||||||
|
return (
|
||||||
|
input_circle,
|
||||||
|
input_points,
|
||||||
|
output_circle,
|
||||||
|
output_points
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def label_spaces(self):
|
||||||
|
input_space = TextMobject("Input Space")
|
||||||
|
input_space.to_edge(UP)
|
||||||
|
input_space.shift(LEFT*SPACE_WIDTH/2)
|
||||||
|
output_space = TextMobject("Output Space")
|
||||||
|
output_space.to_edge(UP)
|
||||||
|
output_space.shift(RIGHT*SPACE_WIDTH/2)
|
||||||
|
line = Line(
|
||||||
|
UP*SPACE_HEIGHT, DOWN*SPACE_HEIGHT,
|
||||||
|
color = WHITE
|
||||||
|
)
|
||||||
|
self.play(
|
||||||
|
ShimmerIn(input_space),
|
||||||
|
ShimmerIn(output_space),
|
||||||
|
ShowCreation(line),
|
||||||
|
ShowCreation(self.interval),
|
||||||
|
)
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
def move_dot(self):
|
||||||
|
kwargs = {
|
||||||
|
"rate_func" : None,
|
||||||
|
"run_time" : 3
|
||||||
|
}
|
||||||
|
self.play(
|
||||||
|
Homotopy(self.input_homotopy, self.input_dot, **kwargs),
|
||||||
|
Homotopy(self.output_homotopy, self.output_dot, **kwargs),
|
||||||
|
ShowCreation(self.output, **kwargs)
|
||||||
|
)
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
def label_jump(self):
|
||||||
|
jump_points = Mobject(
|
||||||
|
Point(self.spiril1.points[-1]),
|
||||||
|
Point(self.spiril2.points[0])
|
||||||
|
)
|
||||||
|
self.brace = Brace(jump_points, RIGHT)
|
||||||
|
self.jump = TextMobject("Jump")
|
||||||
|
self.jump.next_to(self.brace, RIGHT)
|
||||||
|
self.play(
|
||||||
|
GrowFromCenter(self.brace),
|
||||||
|
ShimmerIn(self.jump)
|
||||||
|
)
|
||||||
|
self.dither()
|
||||||
|
self.remove(self.brace, self.jump)
|
||||||
|
|
||||||
|
|
||||||
|
def draw_circles(self):
|
||||||
|
input_value = 0.45
|
||||||
|
input_radius = 0.04
|
||||||
|
for dot in self.input_dot, self.output_dot:
|
||||||
|
dot.center()
|
||||||
|
kwargs = {
|
||||||
|
"rate_func" : lambda t : interpolate(1, input_value, smooth(t))
|
||||||
|
}
|
||||||
|
self.play(
|
||||||
|
Homotopy(self.input_homotopy, self.input_dot, **kwargs),
|
||||||
|
Homotopy(self.output_homotopy, self.output_dot, **kwargs)
|
||||||
|
)
|
||||||
|
|
||||||
|
A, B = map(Mobject.get_center, [self.input_dot, self.output_dot])
|
||||||
|
A_text = TextMobject("A")
|
||||||
|
A_text.shift(A+2*(LEFT+UP))
|
||||||
|
A_arrow = Arrow(
|
||||||
|
A_text, self.input_dot,
|
||||||
|
color = self.input_color
|
||||||
|
)
|
||||||
|
B_text = TextMobject("B")
|
||||||
|
B_text.shift(B+2*RIGHT+DOWN)
|
||||||
|
B_arrow = Arrow(
|
||||||
|
B_text, self.output_dot,
|
||||||
|
color = self.output_color
|
||||||
|
)
|
||||||
|
tup = self.get_circles_and_points(
|
||||||
|
input_value-input_radius,
|
||||||
|
input_value+input_radius
|
||||||
|
)
|
||||||
|
input_circle, input_points, output_circle, output_points = tup
|
||||||
|
|
||||||
|
for text, arrow in [(A_text, A_arrow), (B_text, B_arrow)]:
|
||||||
|
self.play(
|
||||||
|
ShimmerIn(text),
|
||||||
|
ShowCreation(arrow)
|
||||||
|
)
|
||||||
|
self.dither()
|
||||||
|
self.remove(A_text, A_arrow, B_text, B_arrow)
|
||||||
|
self.play(ShowCreation(input_circle))
|
||||||
|
self.dither()
|
||||||
|
self.play(ShowCreation(input_points))
|
||||||
|
self.dither()
|
||||||
|
input_points_copy = input_points.copy()
|
||||||
|
self.play(
|
||||||
|
Transform(input_points_copy, output_points),
|
||||||
|
run_time = 2
|
||||||
|
)
|
||||||
|
self.dither()
|
||||||
|
self.play(ShowCreation(output_circle))
|
||||||
|
self.dither()
|
||||||
|
self.dither()
|
||||||
|
self.remove(*[
|
||||||
|
input_circle, input_points,
|
||||||
|
output_circle, input_points_copy
|
||||||
|
])
|
||||||
|
|
||||||
|
|
||||||
|
def vary_circle_sizes(self):
|
||||||
|
input_value = 0.45
|
||||||
|
radius = 0.04
|
||||||
|
vary_circles = VaryCircles(
|
||||||
|
self, input_value, radius,
|
||||||
|
run_time = 5,
|
||||||
|
)
|
||||||
|
self.play(vary_circles)
|
||||||
|
self.dither()
|
||||||
|
text = TextMobject("Function is ``Continuous at A''")
|
||||||
|
text.shift(2*UP).to_edge(LEFT)
|
||||||
|
arrow = Arrow(text, self.input_dot)
|
||||||
|
self.play(
|
||||||
|
ShimmerIn(text),
|
||||||
|
ShowCreation(arrow)
|
||||||
|
)
|
||||||
|
self.dither()
|
||||||
|
self.remove(vary_circles.mobject, text, arrow)
|
||||||
|
|
||||||
|
def discontinuous_point(self):
|
||||||
|
point_description = TextMobject(
|
||||||
|
"Point where the function jumps"
|
||||||
|
)
|
||||||
|
point_description.shift(3*RIGHT)
|
||||||
|
text = TextMobject("""
|
||||||
|
Circle around ouput \\\\
|
||||||
|
points can never \\\\
|
||||||
|
be smaller than \\\\
|
||||||
|
the jump
|
||||||
|
""")
|
||||||
|
text.scale(0.75)
|
||||||
|
text.shift(3.5*RIGHT)
|
||||||
|
|
||||||
|
input_value = 0.5
|
||||||
|
input_radius = 0.04
|
||||||
|
vary_circles = VaryCircles(
|
||||||
|
self, input_value, input_radius,
|
||||||
|
run_time = 5,
|
||||||
|
)
|
||||||
|
for dot in self.input_dot, self.output_dot:
|
||||||
|
dot.center()
|
||||||
|
kwargs = {
|
||||||
|
"rate_func" : lambda t : interpolate(0.45, input_value, smooth(t))
|
||||||
|
}
|
||||||
|
self.play(
|
||||||
|
Homotopy(self.input_homotopy, self.input_dot, **kwargs),
|
||||||
|
Homotopy(self.output_homotopy, self.output_dot, **kwargs)
|
||||||
|
)
|
||||||
|
arrow = Arrow(
|
||||||
|
point_description, self.output_dot,
|
||||||
|
buff = 0.05,
|
||||||
|
color = self.output_color
|
||||||
|
)
|
||||||
|
self.play(
|
||||||
|
ShimmerIn(point_description),
|
||||||
|
ShowCreation(arrow)
|
||||||
|
)
|
||||||
|
self.dither()
|
||||||
|
self.remove(point_description, arrow)
|
||||||
|
|
||||||
|
tup = self.get_circles_and_points(
|
||||||
|
input_value-input_radius,
|
||||||
|
input_value+input_radius
|
||||||
|
)
|
||||||
|
input_circle, input_points, output_circle, output_points = tup
|
||||||
|
input_points_copy = input_points.copy()
|
||||||
|
self.play(ShowCreation(input_circle))
|
||||||
|
self.play(ShowCreation(input_points))
|
||||||
|
self.play(
|
||||||
|
Transform(input_points_copy, output_points),
|
||||||
|
run_time = 2
|
||||||
|
)
|
||||||
|
self.play(ShowCreation(output_circle))
|
||||||
|
self.dither()
|
||||||
|
self.play(ShimmerIn(text))
|
||||||
|
self.remove(input_circle, input_points, output_circle, input_points_copy)
|
||||||
|
self.play(vary_circles)
|
||||||
|
self.dither()
|
||||||
|
self.remove(vary_circles.mobject)
|
||||||
|
|
||||||
|
def continuous_point(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class VaryCircles(Animation):
|
||||||
|
def __init__(self, scene, input_value, radius, **kwargs):
|
||||||
|
digest_locals(self)
|
||||||
|
Animation.__init__(self, Mobject(), **kwargs)
|
||||||
|
|
||||||
|
def update_mobject(self, alpha):
|
||||||
|
radius = self.radius + 0.9*self.radius*np.sin(1.5*np.pi*alpha)
|
||||||
|
self.mobject = Mobject(*self.scene.get_circles_and_points(
|
||||||
|
self.input_value-radius,
|
||||||
|
self.input_value+radius
|
||||||
|
)).ingest_sub_mobjects()
|
||||||
|
|
||||||
|
|
||||||
|
class FunctionIsContinuousText(Scene):
|
||||||
|
def construct(self):
|
||||||
|
all_points = TextMobject("$f$ is continuous at every input point")
|
||||||
|
continuous = TextMobject("$f$ is continuous")
|
||||||
|
all_points.shift(UP)
|
||||||
|
continuous.shift(DOWN)
|
||||||
|
arrow = Arrow(all_points, continuous)
|
||||||
|
|
||||||
|
self.play(ShimmerIn(all_points))
|
||||||
|
self.play(ShowCreation(arrow))
|
||||||
|
self.play(ShimmerIn(continuous))
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
|
||||||
|
class DefineActualHilbertCurveText(Scene):
|
||||||
|
def construct(self):
|
||||||
|
self.add(TextMobject("""
|
||||||
|
Finally define a Hilbert Curve\\dots
|
||||||
|
"""))
|
||||||
self.dither()
|
self.dither()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class WonderfulPropertyOfPseudoHilbertCurves(Scene):
|
||||||
|
def construct(self):
|
||||||
|
val = 0.3
|
||||||
|
text = TextMobject([
|
||||||
|
"PHC", "$_n", "(", "%3.1f"%val, ")$",
|
||||||
|
" has a limit point $n \\to \\infty$"
|
||||||
|
])
|
||||||
|
func_parts = text.split()[:5]
|
||||||
|
Mobject(*func_parts).center().to_edge(UP)
|
||||||
|
num_str, val_str = func_parts[1], func_parts[3]
|
||||||
|
curve = UnitInterval()
|
||||||
|
curve.sort_points(lambda p : p[0])
|
||||||
|
dot = Dot().shift(curve.number_to_point(val))
|
||||||
|
arrow = Arrow(val_str, dot, buff = 0.1)
|
||||||
|
|
||||||
|
self.play(ShowCreation(curve))
|
||||||
|
self.play(
|
||||||
|
ShimmerIn(val_str),
|
||||||
|
ShowCreation(arrow),
|
||||||
|
ShowCreation(dot)
|
||||||
|
)
|
||||||
|
self.dither()
|
||||||
|
self.play(
|
||||||
|
FadeOut(arrow),
|
||||||
|
*[
|
||||||
|
FadeIn(func_parts[i])
|
||||||
|
for i in 0, 1, 2, 4
|
||||||
|
]
|
||||||
|
)
|
||||||
|
for num in range(2,7):
|
||||||
|
new_curve = HilbertCurve(order = num)
|
||||||
|
new_curve.scale(0.8)
|
||||||
|
new_dot = Dot(new_curve.points[int(val*new_curve.get_num_points())])
|
||||||
|
new_num_str = TexMobject(str(num)).replace(num_str)
|
||||||
|
self.play(
|
||||||
|
Transform(curve, new_curve),
|
||||||
|
Transform(dot, new_dot),
|
||||||
|
Transform(num_str, new_num_str)
|
||||||
|
)
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -216,6 +216,14 @@ class Mobject(object):
|
||||||
mob.apply_over_attr_arrays(lambda arr : arr[indices])
|
mob.apply_over_attr_arrays(lambda arr : arr[indices])
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
def reverse_points(self):
|
||||||
|
for mob in self.nonempty_family_members():
|
||||||
|
mob.apply_over_attr_arrays(
|
||||||
|
lambda arr : np.array(list(reversed(arr)))
|
||||||
|
)
|
||||||
|
return self
|
||||||
|
|
||||||
|
|
||||||
def repeat(self, count):
|
def repeat(self, count):
|
||||||
"""
|
"""
|
||||||
This can make transition animations nicer
|
This can make transition animations nicer
|
||||||
|
@ -261,7 +269,9 @@ class Mobject(object):
|
||||||
"""
|
"""
|
||||||
target_point = np.sign(direction) * (SPACE_WIDTH, SPACE_HEIGHT, 0)
|
target_point = np.sign(direction) * (SPACE_WIDTH, SPACE_HEIGHT, 0)
|
||||||
anchor_point = self.get_critical_point(direction)
|
anchor_point = self.get_critical_point(direction)
|
||||||
self.shift(target_point - anchor_point - buff * np.array(direction))
|
shift_val = target_point - anchor_point - buff * np.array(direction)
|
||||||
|
shift_val = shift_val * abs(np.sign(direction))
|
||||||
|
self.shift(shift_val)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def to_corner(self, corner = LEFT+DOWN, buff = DEFAULT_MOBJECT_TO_EDGE_BUFFER):
|
def to_corner(self, corner = LEFT+DOWN, buff = DEFAULT_MOBJECT_TO_EDGE_BUFFER):
|
||||||
|
@ -517,7 +527,7 @@ class Point(Mobject):
|
||||||
#TODO, Make the two implementations bellow non-redundant
|
#TODO, Make the two implementations bellow non-redundant
|
||||||
class Mobject1D(Mobject):
|
class Mobject1D(Mobject):
|
||||||
DEFAULT_CONFIG = {
|
DEFAULT_CONFIG = {
|
||||||
"density" : DEFAULT_POINT_DENSITY_1D,
|
"density" : DEFAULT_POINT_DENSITY_1D,
|
||||||
}
|
}
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
digest_config(self, kwargs)
|
digest_config(self, kwargs)
|
||||||
|
|
Loading…
Add table
Reference in a new issue