n_uniqueness_demo.py
1from manim import *2import numpy as np3 4class NUniquenessDemo(Scene):5 def construct(self):6 # Set default font7 Text.set_default(font="SimSun")8 9 # Title10 title = Text("极限定义中N的不唯一性", font="SimSun").scale(0.5) # 缩小标题11 title.to_edge(UP, buff=0.3)12 self.play(Write(title))13 self.wait(1)14 15 # Problem statement16 problem = MathTex(r"\lim_{n \to \infty} \frac{3n^2}{n^2 - 3} = 3").scale(0.8) # 缩小题目17 problem.next_to(title, DOWN, buff=0.3) # 上移一点18 19 self.play(Write(problem))20 self.wait(2)21 22 # Create axes for visualization23 axes = Axes(24 x_range=[0, 30, 5],25 y_range=[2, 4, 0.5],26 axis_config={"include_tip": True},27 x_length=8, # 缩小图像28 y_length=4 # 缩小图像29 )30 axes.next_to(problem, DOWN, buff=0.3).shift(RIGHT * 1.5) # 上移一点并右移一些31 32 # Labels for axes33 x_label = MathTex("n").next_to(axes.x_axis, RIGHT, buff=0.3)34 y_label = MathTex("f(n)").next_to(axes.y_axis, UP, buff=0.3)35 36 self.play(Create(axes), Write(x_label), Write(y_label))37 self.wait(1)38 39 # Function to plot40 def func(x):41 return 3 * x**2 / (x**2 - 3)42 43 # Plot points on the graph44 points = VGroup()45 x_values = range(2, 31) # 正整数n从2到3046 for x in x_values:47 y = func(x)48 point = Dot(axes.c2p(x, y), color=BLUE, radius=0.05)49 points.add(point)50 51 graph_label = MathTex(r"f(n) = \frac{3n^2}{n^2 - 3}").next_to(axes.c2p(25, func(25)), UP, buff=0.2).scale(0.7).shift(LEFT * 1.5) # 左移一些52 graph_label.set_color(BLUE)53 54 # Plot the limit line y = 355 limit_line = axes.plot(lambda x: 3, x_range=[0, 30], color=GREEN)56 limit_label = MathTex("y = 3").next_to(limit_line.get_end(), DOWN, buff=0.2).scale(0.7)57 limit_label.set_color(GREEN)58 59 self.play(Create(points), Write(graph_label))60 self.play(Create(limit_line), Write(limit_label))61 self.wait(2)62 63 # Show epsilon band64 epsilon = 0.265 upper_epsilon_line = axes.plot(lambda x: 3 + epsilon, x_range=[0, 30], color=RED)66 lower_epsilon_line = axes.plot(lambda x: 3 - epsilon, x_range=[0, 30], color=RED)67 68 upper_epsilon_label = MathTex(f"y = 3 + \\varepsilon = {3 + epsilon}").next_to(upper_epsilon_line.get_end(), UP, buff=0.1).scale(0.6)69 upper_epsilon_label.set_color(RED)70 lower_epsilon_label = MathTex(f"y = 3 - \\varepsilon = {3 - epsilon}").next_to(lower_epsilon_line.get_end(), DOWN, buff=0.1).scale(0.6)71 lower_epsilon_label.set_color(RED)72 73 # 显示epsilon值右移一个单位74 epsilon_label = MathTex(f"\\varepsilon = {epsilon}").next_to(axes, DOWN, buff=0.1).shift(UP*1.5 + LEFT*3)75 epsilon_label.set_color(RED)76 77 self.play(Create(upper_epsilon_line), Create(lower_epsilon_line))78 self.play(Write(upper_epsilon_label), Write(lower_epsilon_label), Write(epsilon_label))79 self.wait(2)80 81 # Calculate different N values 82 # Method 1: Standard calculation (N = ceil(sqrt(9/ε + 3)))83 N1_float = np.sqrt(9/epsilon + 3)84 N1 = int(np.ceil(N1_float))85 86 # Method 2: More conservative estimation87 N2_float = np.sqrt(18/epsilon)88 N2 = int(np.ceil(N2_float))89 # But we also need n ≥ 4 for our approximation, so take max(4, N2)90 N2 = max(4, N2)91 92 # Method 3: Even more conservative estimation93 N3_float = np.sqrt(13.5/epsilon)94 N3 = int(np.ceil(N3_float))95 # But we also need n ≥ 3 for our approximation, so take max(3, N3)96 N3 = max(3, N3)97 98 # Display derivation methods title99 derivation_title = Text("不同的N推导方法:", font="SimSun").scale(0.5)100 derivation_title.to_corner(UL, buff=0.5).shift(RIGHT*0.1) # 整体左移0.4个单位(从0.5到0.1)101 102 self.play(Write(derivation_title))103 self.wait(1)104 105 # Method 1106 method1_title = Text("方法1: 基本方法", font="SimSun").scale(0.4)107 method1_derivation = MathTex(108 r"|f(n)-3| = \left|\frac{9}{n^2-3}\right| < \varepsilon \Rightarrow n > \sqrt{\frac{9}{\varepsilon}+3}"109 ).scale(0.5)110 method1_result = MathTex("N_1 = \\left\\lceil \\sqrt{\\frac{9}{\\varepsilon}+3} \\right\\rceil = ").scale(0.6)111 112 method1_group = VGroup(method1_title, method1_derivation, method1_result).arrange(DOWN, aligned_edge=LEFT, buff=0.2)113 method1_group.next_to(derivation_title, DOWN, buff=0.3).scale(0.8).shift(RIGHT*0.1) # 整体左移0.4个单位114 115 self.play(Write(method1_title))116 self.play(Write(method1_derivation))117 self.wait(2)118 119 # Show N1 result120 method1_result_N = MathTex(str(N1)).scale(0.6).next_to(method1_result, RIGHT, buff=0.1)121 122 self.play(Write(method1_result))123 self.wait(1)124 self.play(Write(method1_result_N)) # N1结果晚1秒显示125 self.wait(1)126 127 # Show N1 on graph128 n1_line = axes.get_vertical_line(129 axes.c2p(N1, 0),130 line_config={"color": YELLOW, "stroke_width": 4}131 )132 133 n1_label = MathTex(f"N_1 = {N1}").next_to(n1_line, UP, buff=0.1).scale(0.6)134 n1_label.set_color(YELLOW)135 136 # Create a dotted vertical line spanning the entire y-range137 n1_dotted_line = DashedLine(138 start=axes.c2p(N1, axes.get_y_range()[0]),139 end=axes.c2p(N1, axes.get_y_range()[1]),140 color=YELLOW,141 stroke_width=2,142 dash_length=0.1143 )144 145 self.play(Create(n1_dotted_line), run_time=0.5)146 self.play(Create(n1_line), Write(n1_label), run_time=0.5)147 self.wait(1)148 149 # Highlight points for N1150 highlight_points1 = VGroup()151 for x in x_values:152 if x > N1:153 y = func(x)154 point = Dot(axes.c2p(x, y), color=YELLOW, radius=0.07)155 highlight_points1.add(point)156 157 self.play(Create(highlight_points1), run_time=1.5)158 self.wait(2)159 160 # Method 2: Different estimation technique161 method2_title = Text("方法2: 不同放大技巧(n>3时)", font="SimSun").scale(0.4)162 method2_derivation = MathTex(163 r"n^2-3 \geq \frac{n^2}{2} \Rightarrow |f(n)-3| \leq \frac{18}{n^2} < \varepsilon \Rightarrow n > \sqrt{\frac{18}{\varepsilon}}"164 ).scale(0.5)165 166 method2_group = VGroup(method2_title, method2_derivation).arrange(DOWN, aligned_edge=LEFT, buff=0.2)167 method2_group.next_to(method1_group, DOWN, buff=0.3).scale(0.8).shift(RIGHT*0.2) # 整体右移0.1个单位(从0.1到0.2)168 169 self.play(Write(method2_title))170 self.play(Write(method2_derivation))171 self.wait(2)172 173 # Show N2 result174 method2_result = MathTex("N_2 = \\max(3, \\left\\lceil \\sqrt{\\frac{18}{\\varepsilon}} \\right\\rceil) = ").scale(0.6)175 method2_result_N = MathTex(str(N2)).scale(0.6).next_to(method2_result, RIGHT, buff=0.1)176 method2_result.next_to(method2_group, DOWN, buff=0.2).shift(RIGHT*0.2) # 整体右移0.1个单位177 method2_result_N.next_to(method2_result, RIGHT, buff=0.1)178 179 self.play(Write(method2_result))180 self.wait(1)181 self.play(Write(method2_result_N)) # N2结果晚1秒显示182 self.wait(0.5)183 184 # Show N2 on graph185 n2_line = axes.get_vertical_line(186 axes.c2p(N2, 0),187 line_config={"color": ORANGE, "stroke_width": 4}188 )189 190 n2_label = MathTex(f"N_2 = {N2}").next_to(n2_line, UP, buff=0.1).scale(0.6).shift(DOWN*0.3) # N2标签下移191 n2_label.set_color(ORANGE)192 193 # Create a dotted vertical line spanning the entire y-range194 n2_dotted_line = DashedLine(195 start=axes.c2p(N2, axes.get_y_range()[0]),196 end=axes.c2p(N2, axes.get_y_range()[1]),197 color=ORANGE,198 stroke_width=2,199 dash_length=0.1200 )201 202 self.play(Create(n2_dotted_line), run_time=0.5)203 self.play(Create(n2_line), Write(n2_label), run_time=0.5)204 self.wait(0.5)205 206 # Highlight points for N2207 highlight_points2 = VGroup()208 for x in x_values:209 if x > N2:210 y = func(x)211 point = Dot(axes.c2p(x, y), color=ORANGE, radius=0.07)212 highlight_points2.add(point)213 214 self.play(Create(highlight_points2), run_time=1.5)215 self.wait(2)216 217 # Method 3: Another estimation technique218 method3_title = Text("方法3: 另一种放大技巧(n>3时)", font="SimSun").scale(0.4)219 method3_derivation = MathTex(220 r"n^2-3 \geq \frac{2n^2}{3} \Rightarrow |f(n)-3| \leq \frac{13.5}{n^2} < \varepsilon \Rightarrow n > \sqrt{\frac{13.5}{\varepsilon}}"221 ).scale(0.5)222 223 method3_group = VGroup(method3_title, method3_derivation).arrange(DOWN, aligned_edge=LEFT, buff=0.2)224 method3_group.next_to(method2_result, DOWN, buff=0.3).scale(0.8).shift(RIGHT*0.2) # 整体右移0.1个单位(从0.1到0.2)225 226 self.play(Write(method3_title))227 self.play(Write(method3_derivation))228 self.wait(2)229 230 # Show N3 result231 method3_result = MathTex("N_3 = \\max(3, \\left\\lceil \\sqrt{\\frac{13.5}{\\varepsilon}} \\right\\rceil) = ").scale(0.6)232 method3_result_N = MathTex(str(N3)).scale(0.6).next_to(method3_result, RIGHT, buff=0.1)233 method3_result.next_to(method3_group, DOWN, buff=0.2).shift(RIGHT*0.2) # 整体右移0.1个单位234 method3_result_N.next_to(method3_result, RIGHT, buff=0.1)235 236 self.play(Write(method3_result))237 self.wait(1)238 self.play(Write(method3_result_N)) # N3结果晚1秒显示239 self.wait(0.5)240 241 # Show N3 on graph242 n3_line = axes.get_vertical_line(243 axes.c2p(N3, 0),244 line_config={"color": PURPLE, "stroke_width": 4}245 )246 247 n3_label = MathTex(f"N_3 = {N3}").next_to(n3_line, UP, buff=0.1).scale(0.6).shift(DOWN*0.5) # N3标签进一步下移248 249 n3_label.set_color(PURPLE)250 251 # Create a dotted vertical line spanning the entire y-range252 n3_dotted_line = DashedLine(253 start=axes.c2p(N3, axes.get_y_range()[0]),254 end=axes.c2p(N3, axes.get_y_range()[1]),255 color=PURPLE,256 stroke_width=2,257 dash_length=0.1258 )259 260 self.play(Create(n3_dotted_line), run_time=0.5)261 self.play(Create(n3_line), Write(n3_label), run_time=0.5)262 self.wait(1)263 264 # Highlight points for N3265 highlight_points3 = VGroup()266 for x in x_values:267 if x > N3:268 y = func(x)269 point = Dot(axes.c2p(x, y), color=PURPLE, radius=0.07)270 highlight_points3.add(point)271 272 self.play(Create(highlight_points3), run_time=1.5)273 self.wait(2)274 275 # Conclusion text at the bottom center276 conclusion = Text(277 "通过不同的不等式放大技巧,可以得到不同的N值",278 font="SimSun"279 ).scale(0.6).to_edge(DOWN, buff=0.5).shift(RIGHT*2) # 结论右移两个单位280 281 self.play(Write(conclusion))282 self.wait(3)283 284def main():285 scene = NUniquenessDemo()286 scene.render()287 288if __name__ == "__main__":289 main() 讲解
这个视频围绕「极限定义中N的不唯一性」展开。画面把问题、图像和公式放在同一条理解路径中,让抽象关系先被看见。
开头先建立问题背景和主要对象,让观察从标题、坐标或第一组关系进入。
画面中出现的文字「极限定义中N的不唯一性」给出视觉入口。随后画面通过对象创建、移动、淡入淡出和高亮,把抽象命题拆成可以跟随的步骤。
随后出现更具体的图像或公式提示,动画会把局部对象和整体结论联系起来。这里可以重点观察变量、曲线、区域或向量如何随镜头推进而变化。
核心公式可以写成:
这类公式可以和画面中的符号一一对应。
观察路径
观察路径可以分三步:先锁定「极限定义中N的不唯一性」中的核心对象,尤其留意epsilon-N 定义、数列极限、证明中的 N 不唯一之间的联系;再跟随画面中变量、图像或向量的变化;最后回到公式或结论,判断局部变化如何支撑整体关系。
本页可以从epsilon-N 定义、数列极限、证明中的 N 不唯一这些概念进入,继续沿相邻问题观察同一类数学结构。