数学分析基础可视化

单调有界原理证闭区间套定理

围绕单调有界原理证闭区间套定理,观察单调有界原理、闭区间套定理、数列收敛之间的关系与推理路径。

打开原视频

nested_interval_theorem.py
1from manim import *2import numpy as np3 4class NestedIntervalTheorem(Scene):5    def construct(self):6        # 配置参数7        x_range = [-1, 8, 1]8        y_range = [-0.5, 3.5, 0.5]9        10        # 创建坐标系11        axes = Axes(12            x_range=x_range,13            y_range=y_range,14            x_length=10,15            y_length=6,16            axis_config={17                "include_tip": True,18                "include_numbers": False  # 不显示坐标轴数值19            }20        )21        22        self.play(Create(axes, run_time=3))23        24        # 第一步:展示区间套的构造25        intervals = []26        interval_labels = []27        y_positions = [0.5, 1.5, 2.5]28        interval_data = [29            (1, 7, BLUE),    # [a₁, b₁]30            (2, 5, RED),     # [a₂, b₂]31            (3, 4, GREEN)    # [a₃, b₃]32        ]33        34        # 逐个显示区间及其标签35        for i, (a, b, color) in enumerate(interval_data):36            interval = Line(37                axes.c2p(a, y_positions[i]),38                axes.c2p(b, y_positions[i]),39                color=color,40                stroke_width=341            )42            # 添加端点标签43            left_point = Dot(axes.c2p(a, y_positions[i]), color=color, radius=0.05)44            right_point = Dot(axes.c2p(b, y_positions[i]), color=color, radius=0.05)45            left_label = MathTex(f"a_{i+1}", color=color).scale(0.6)46            right_label = MathTex(f"b_{i+1}", color=color).scale(0.6)47            left_label.next_to(left_point, DL, buff=0.1)48            right_label.next_to(right_point, DR, buff=0.1)49            50            # 区间标签51            interval_label = MathTex(f"[a_{i+1}, b_{i+1}]", color=color).scale(0.8)52            interval_label.next_to(interval, UP, buff=0.2)53            54            intervals.append(interval)55            interval_labels.append(interval_label)56            57            self.play(58                Create(interval),59                Create(left_point),60                Create(right_point),61                Write(left_label),62                Write(right_label),63                Write(interval_label),64                run_time=265            )66            67            # 显示包含关系68            if i > 0:69                subset_symbol = MathTex(r"\subset", color=YELLOW).scale(0.6)70                subset_symbol.next_to(interval, LEFT, buff=0.2)71                72                left_proj = DashedLine(73                    axes.c2p(interval_data[i-1][0], y_positions[i-1]),74                    axes.c2p(interval_data[i-1][0], y_positions[i]),75                    color=YELLOW,76                    dash_length=0.177                )78                right_proj = DashedLine(79                    axes.c2p(interval_data[i-1][1], y_positions[i-1]),80                    axes.c2p(interval_data[i-1][1], y_positions[i]),81                    color=YELLOW,82                    dash_length=0.183                )84                self.play(85                    Create(left_proj),86                    Create(right_proj),87                    Write(subset_symbol),88                    run_time=189                )90 91        # 第二步:先展示单调性92        monotone_arrows = VGroup()93        for i in range(len(interval_data)-1):94            # an的单调递增箭头95            a_monotone = Arrow(96                axes.c2p(interval_data[i][0], y_positions[i]),97                axes.c2p(interval_data[i+1][0], y_positions[i+1]),98                color=BLUE,99                buff=0.1,100                max_tip_length_to_length_ratio=0.15101            )102            # bn的单调递减箭头103            b_monotone = Arrow(104                axes.c2p(interval_data[i][1], y_positions[i]),105                axes.c2p(interval_data[i+1][1], y_positions[i+1]),106                color=RED,107                buff=0.1,108                max_tip_length_to_length_ratio=0.15109            )110            monotone_arrows.add(a_monotone, b_monotone)111        112        # 显示单调性标签(缩小并上移)113        monotone_labels = VGroup(114            VGroup(115                MathTex(r"\{a_n\}", color=BLUE),116                Text("单调递增有上界", font="SimSun")117            ).arrange(RIGHT, buff=0.1),118            VGroup(119                MathTex(r"\{b_n\}", color=RED),120                Text("单调递减有下界", font="SimSun")121            ).arrange(RIGHT, buff=0.1)122        ).arrange(DOWN, buff=0.2).scale(0.6)  # 缩小字体123        monotone_labels.to_edge(LEFT, buff=0.5).shift(UP * 1.5)  # 上移124        125        self.play(126            Write(monotone_labels),127            Create(monotone_arrows),128            run_time=3129        )130        131        # 定义极限点位置132        xi = 3.5  # 在这里定义xi133        134        # 然后展示收敛性135        # 显示an和bn的极限136        limit_arrows = VGroup()137        # an的极限箭头(向上)138        a_limit_arrow = Arrow(139            axes.c2p(interval_data[-1][0], y_positions[-1]),140            axes.c2p(xi, 3.2),141            color=BLUE,142            buff=0.1,143            max_tip_length_to_length_ratio=0.15144        )145        # bn的极限箭头(向上)146        b_limit_arrow = Arrow(147            axes.c2p(interval_data[-1][1], y_positions[-1]),148            axes.c2p(xi, 3.2),149            color=RED,150            buff=0.1,151            max_tip_length_to_length_ratio=0.15152        )153        limit_arrows.add(a_limit_arrow, b_limit_arrow)154 155        # # 显示极限值标签156        # limit_labels = VGroup(157        #     MathTex(r"\lim_{n \to \infty} a_n = a", color=BLUE),158        #     MathTex(r"\lim_{n \to \infty} b_n = b", color=RED)159        # ).arrange(DOWN, buff=0.3).scale(0.8)160        # limit_labels.next_to(monotone_labels, DOWN, buff=0.5)161 162        # self.play(163        #     Create(limit_arrows),164        #     Write(limit_labels),165        #     run_time=2166        # )167 168        # # 显示收敛性标签(放在极限值标签下面)169        # convergence_label = MathTex(170        #     r"\lim_{n \to \infty}(b_n - a_n) = 0", 171        #     color=YELLOW172        # ).scale(0.8)173        # convergence_label.next_to(limit_labels, DOWN, buff=0.3)174        175        # self.play(176        #     Write(convergence_label),177        #     run_time=2178        # )179 180        # # 显示极限值相等(放在收敛性标签下面)181        # equals_label = MathTex(r"a = b = \xi", color=YELLOW).scale(0.8)182        # equals_label.next_to(convergence_label, DOWN, buff=0.3)183 184        # self.play(185        #     Write(equals_label),186        #     run_time=1.5187       # )188 189        # 1. 显示第n个区间190        final_interval = Line(191            axes.c2p(3.3, 3.2),192            axes.c2p(3.7, 3.2),193            color=GREEN,194            stroke_width=4195        )196        final_left_point = Dot(axes.c2p(3.3, 3.2), color=GREEN, radius=0.05)197        final_right_point = Dot(axes.c2p(3.7, 3.2), color=GREEN, radius=0.05)198        final_left_label = MathTex("a_n", color=GREEN).scale(0.7)199        final_right_label = MathTex("b_n", color=GREEN).scale(0.7)200        final_left_label.next_to(final_left_point, LEFT, buff=0.1)201        final_right_label.next_to(final_right_point, RIGHT, buff=0.1)202        203        self.play(204            Create(final_interval),205            Create(final_left_point),206            Create(final_right_point),207            Write(final_left_label),208            Write(final_right_label),209            run_time=2210        )211 212        # 显示a3到aN和b3到bN的箭头213        a3_to_aN = Arrow(214            axes.c2p(interval_data[-1][0], y_positions[-1]),  # 从a3215            axes.c2p(3.3, 3.2),  # 到aN216            color=BLUE,217            buff=0.1,218            max_tip_length_to_length_ratio=0.15219        )220        b3_to_bN = Arrow(221            axes.c2p(interval_data[-1][1], y_positions[-1]),  # 从b3222            axes.c2p(3.7, 3.2),  # 到bN223            color=RED,224            buff=0.1,225            max_tip_length_to_length_ratio=0.15226        )227        228        self.play(229            Create(a3_to_aN),230            Create(b3_to_bN),231            run_time=2232        )233 234        # 2. 显示极限值标签235        limit_labels = VGroup(236            MathTex(r"\lim_{n \to \infty} a_n = a", color=BLUE),237            MathTex(r"\lim_{n \to \infty} b_n = b", color=RED)238        ).arrange(DOWN, buff=0.3).scale(0.8)239        limit_labels.next_to(monotone_labels, DOWN, buff=0.5)240 241        self.play(Write(limit_labels), run_time=3)242 243        # 3. 显示极限点244        limit_point = Dot(axes.c2p(xi, 3.5), color=YELLOW, radius=0.08)245        limit_label = MathTex(r"\xi", color=YELLOW).scale(0.8)246        limit_label.next_to(limit_point, UP)247        248        vertical_line = DashedLine(249            axes.c2p(xi, y_positions[0]),250            axes.c2p(xi, 3.5),251            color=YELLOW,252            dash_length=0.1253        )254        255        self.play(256            Create(vertical_line),257            Create(limit_point),258            Write(limit_label),259            run_time=2260        )261 262        # 显示从aN,bN到极限点的箭头263        aN_to_xi = Arrow(264            axes.c2p(3.3, 3.2),  # 从aN265            axes.c2p(xi, 3.5),  # 到ξ266            color=BLUE_A,267            buff=0.1,268            max_tip_length_to_length_ratio=0.15269        )270        bN_to_xi = Arrow(271            axes.c2p(3.7, 3.2),  # 从bN272            axes.c2p(xi, 3.5),  # 到ξ273            color=RED_A,274            buff=0.1,275            max_tip_length_to_length_ratio=0.15276        )277        278        self.play(279            Create(aN_to_xi),280            Create(bN_to_xi),281            run_time=2282        )283 284        # 4. 显示收敛性和极限值相等285        convergence_label = MathTex(286            r"\lim_{n \to \infty}(b_n - a_n) = 0", 287            color=YELLOW288        ).scale(0.8)289        convergence_label.next_to(limit_labels, DOWN, buff=0.3)290        291        equals_label = MathTex(r"a = b = \xi", color=YELLOW).scale(0.8)292        equals_label.next_to(convergence_label, DOWN, buff=0.3)293 294        self.play(295            Write(convergence_label),296            run_time=3297        )298        self.play(299            Write(equals_label),300            run_time=2301        )302 303        # 5. 反证法演示304        eta = 4.2305        other_point = Dot(axes.c2p(eta, 3.5), color=RED, radius=0.08)306        other_label = MathTex(r"\eta", color=RED).scale(0.8)307        other_label.next_to(other_point, UP)308        309        self.play(310            Create(other_point),311            Write(other_label),312            run_time=2.5313        )314 315        # 显示η不等于极限点,加上"任意"的表述316        neq_label = MathTex(r"\forall \eta \neq \xi", color=RED).scale(0.8)  # 添加任意符号317        neq_label.next_to(other_point, RIGHT, buff=0.3)318        319        self.play(Write(neq_label), run_time=1.5)320 321        # 显示存在区间使得η不属于该区间322        notin_label = MathTex(r"\exists n: \eta \notin [a_n, b_n]", color=RED).scale(0.8)  # 添加存在符号323        notin_label.next_to(neq_label, RIGHT, buff=0.2)324        325        self.play(Write(notin_label), run_time=1.5)326 327        # 用垂直向下的箭头表示η不在区间内(加粗)328        down_arrow = Arrow(329            axes.c2p(eta, 3.5),330            axes.c2p(eta, 3.2),331            color=RED,332            buff=0.1,333            max_tip_length_to_length_ratio=0.2,334            stroke_width=6335        )336        337        self.play(Create(down_arrow), run_time=2)338 339        # 添加an, bn的向上虚线和延长线340        left_proj = DashedLine(341            axes.c2p(3.3, 3.2),  # 从an开始342            axes.c2p(3.3, 3.5),  # 向上延伸343            color=YELLOW,344            dash_length=0.1345        )346        right_proj = DashedLine(347            axes.c2p(3.7, 3.2),  # 从bn开始348            axes.c2p(3.7, 3.5),  # 向上延伸349            color=YELLOW,350            dash_length=0.1351        )352        right_extension = DashedLine(353            axes.c2p(3.7, 3.2),  # 从bn开始354            axes.c2p(4.5, 3.2),  # 向右延伸超过η355            color=GREEN_A,356            dash_length=0.1357        )358        359        self.play(360            Create(left_proj),361            Create(right_proj),362            Create(right_extension),363            run_time=2364        )365 366        # 显示矛盾(只显示叉号)367        x = Cross(scale_factor=0.25, stroke_width=6).move_to(other_point)  # 叉号保持在η点368        369        self.play(Create(x), run_time=1.5)370        371        self.wait(2)372 373        # 最后强调唯一性374        xi_label = MathTex(r"\xi", color=YELLOW).scale(0.8)375        unique_text = Text("唯一", font="SimSun", color=YELLOW).scale(0.7)376        377        # 将ξ和"唯一"水平排列378        unique_group = VGroup(xi_label, unique_text).arrange(RIGHT, buff=0.2)379        unique_group.next_to(notin_label, DOWN, buff=0.3)  # 放在不等式下方380        381        self.play(382            limit_point.animate.scale(1.5).set_color(YELLOW),383            limit_label.animate.scale(1.5).set_color(YELLOW),384            Write(unique_group),385            run_time=2.5386        )387        388        self.wait(5)  # 最后的等待时间389 390def main():391    import os392    os.system("manim -pql nested_interval_theorem.py NestedIntervalTheorem")393 394if __name__ == "__main__":395    main()

讲解

这个视频围绕「单调有界原理证闭区间套定理」展开。画面把问题、图像和公式放在同一条理解路径中,让抽象关系先被看见。

开头先建立问题背景和主要对象,让观察从标题、坐标或第一组关系进入。

画面中出现的文字「单调递增有上界」给出视觉入口。随后画面通过对象创建、移动、淡入淡出和高亮,把抽象命题拆成可以跟随的步骤。

随后出现更具体的图像或公式提示,动画会把局部对象和整体结论联系起来。这里可以重点观察变量、曲线、区域或向量如何随镜头推进而变化。

核心公式可以写成:

\subset

这类公式可以和画面中的符号一一对应。

观察路径

观察路径可以分三步:先锁定「单调有界原理证闭区间套定理」中的核心对象,尤其留意单调有界原理、闭区间套定理、数列收敛之间的联系;再跟随画面中变量、图像或向量的变化;最后回到公式或结论,判断局部变化如何支撑整体关系。

本页可以从单调有界原理、闭区间套定理、数列收敛、确界原理这些概念进入,继续沿相邻问题观察同一类数学结构。