diff --git a/eoc/exp_footnote.py b/eoc/exp_footnote.py index 7a721a55..66751ac5 100644 --- a/eoc/exp_footnote.py +++ b/eoc/exp_footnote.py @@ -224,6 +224,7 @@ class DoublingPopulation(PiCreatureScene): self.play( FadeOut(self.dM_dt_question), + FadeOut(self.population_size_descriptor), FadeIn(day_to_day) ) rect = self.let_day_pass_and_highlight_new_creatures(frac) @@ -238,11 +239,8 @@ class DoublingPopulation(PiCreatureScene): def let_day_pass_and_highlight_new_creatures(self, frac): num_new_creatures = 2**self.get_curr_day() - brace = self.population_size_descriptor self.let_one_day_pass() - new_brace = self.get_population_size_descriptor() - self.play(Transform(brace, new_brace)) new_creatures = VGroup( *self.get_on_screen_pi_creatures()[-num_new_creatures:] ) @@ -291,7 +289,7 @@ class DoublingPopulation(PiCreatureScene): expressions = [false_deriv, difference_eq, real_deriv] text_arg_list = [ ("Tempting", "...",), - ("Rate of change", "\\\\ per day"), + ("Rate of change", "\\\\ over one full day"), ("Rate of change", "\\\\ in a small time"), ] for expression, text_args in zip(expressions, text_arg_list): @@ -309,7 +307,6 @@ class DoublingPopulation(PiCreatureScene): fading_creatures = VGroup(*self.get_on_screen_pi_creatures()[8:]) - brace = self.population_size_descriptor self.play(*map(FadeIn, [ false_deriv, false_deriv.brace, false_deriv.brace_text @@ -319,13 +316,9 @@ class DoublingPopulation(PiCreatureScene): Transform(time, new_time), FadeOut(fading_creatures) ) - new_brace = self.get_population_size_descriptor() - self.play(Transform(brace, new_brace)) self.dither() for x in range(3): self.let_one_day_pass(run_time = 2) - new_brace = self.get_population_size_descriptor() - self.play(Transform(brace, new_brace)) self.dither(2) for expression in difference_eq, real_deriv: @@ -336,7 +329,6 @@ class DoublingPopulation(PiCreatureScene): Transform(false_deriv.brace_text, expression.brace_text), ) self.dither(3) - self.play(FadeOut(brace)) self.reset() for x in range(self.get_num_days()): self.let_one_day_pass() @@ -484,8 +476,304 @@ class DoublingPopulation(PiCreatureScene): return top_words, bottom_words - - +class AnalyzeExponentRatio(PiCreatureScene): + CONFIG = { + "base" : 2, + "base_str" : "2", + } + def construct(self): + base_str = self.base_str + + func_def = TexMobject("M(", "t", ")", "= ", "%s^"%base_str, "t") + func_def.to_corner(UP+LEFT) + self.add(func_def) + + ratio = TexMobject( + "{ {%s^"%base_str, "{t", "+", "dt}", "-", + "%s^"%base_str, "t}", + "\\over \\,", "dt}" + ) + ratio.shift(UP+LEFT) + + lhs = TexMobject("{dM", "\\over \\,", "dt}", "(", "t", ")", "=") + lhs.next_to(ratio, LEFT) + + + two_to_t_plus_dt = VGroup(*ratio[:4]) + two_to_t = VGroup(*ratio[5:7]) + two_to_t_two_to_dt = TexMobject( + "%s^"%base_str, "t", + "%s^"%base_str, "{dt}" + ) + two_to_t_two_to_dt.move_to(two_to_t_plus_dt, DOWN+LEFT) + exp_prop_brace = Brace(two_to_t_two_to_dt, UP) + + one = TexMobject("1") + one.move_to(ratio[5], DOWN) + lp, rp = parens = TexMobject("()") + parens.stretch(1.3, 1) + parens.scale_to_fit_height(ratio.get_height()) + lp.next_to(ratio, LEFT, buff = 0) + rp.next_to(ratio, RIGHT, buff = 0) + + extracted_two_to_t = TexMobject("%s^"%base_str, "t") + extracted_two_to_t.next_to(lp, LEFT, buff = SMALL_BUFF) + + expressions = [ + ratio, two_to_t_two_to_dt, + extracted_two_to_t, lhs, func_def + ] + for expression in expressions: + expression.highlight_by_tex("t", YELLOW) + expression.highlight_by_tex("dt", GREEN) + + #Apply exponential property + self.play( + Write(ratio), Write(lhs), + self.pi_creature.change_mode, "raise_right_hand" + ) + self.dither(2) + self.play( + two_to_t_plus_dt.next_to, exp_prop_brace, UP, + self.pi_creature.change_mode, "pondering" + ) + self.play( + ReplacementTransform( + two_to_t_plus_dt.copy(), two_to_t_two_to_dt, + run_time = 2, + path_arc = np.pi, + ), + FadeIn(exp_prop_brace) + ) + self.dither(2) + + #Talk about exponential property + add_exp_rect, mult_rect = rects = [ + Rectangle( + stroke_color = BLUE, + stroke_width = 2, + ).replace(mob).scale_in_place(1.1) + for mob in [ + VGroup(*two_to_t_plus_dt[1:]), + two_to_t_two_to_dt + ] + ] + words = VGroup(*[ + TextMobject(s, " ideas") + for s in "Additive", "Multiplicative" + ]) + words[0].move_to(words[1], LEFT) + words.highlight(BLUE) + words.next_to(two_to_t_plus_dt, RIGHT, buff = 1.5*LARGE_BUFF) + arrows = VGroup(*[ + Arrow(word.get_left(), rect, color = words.get_color()) + for word, rect in zip(words, rects) + ]) + + self.play(ShowCreation(add_exp_rect)) + self.dither() + self.play(ReplacementTransform( + add_exp_rect.copy(), mult_rect + )) + self.dither() + self.change_mode("happy") + self.play(Write(words[0], run_time = 2)) + self.play(ShowCreation(arrows[0])) + self.dither() + self.play( + Transform(*words), + Transform(*arrows), + ) + self.dither(2) + self.play(*map(FadeOut, [ + words[0], arrows[0], add_exp_rect, mult_rect, + two_to_t_plus_dt, exp_prop_brace, + ])) + + #Factor out 2^t + self.play(*[ + FadeIn( + mob, + run_time = 2, + rate_func = squish_rate_func(smooth, 0.5, 1) + ) + for mob in one, lp, rp + ] + [ + ReplacementTransform( + mob, extracted_two_to_t, + path_arc = np.pi/2, + run_time = 2, + ) + for mob in two_to_t, VGroup(*two_to_t_two_to_dt[:2]) + ] + [ + lhs.next_to, extracted_two_to_t, LEFT + ]) + self.change_mode("pondering") + shifter = VGroup(ratio[4], one, *two_to_t_two_to_dt[2:]) + stretcher = VGroup(lp, ratio[7], rp) + self.play( + shifter.next_to, ratio[7], UP, + stretcher.stretch_in_place, 0.9, 0 + ) + self.dither(2) + + #Ask about dt -> 0 + brace = Brace(VGroup(extracted_two_to_t, ratio), DOWN) + alt_brace = Brace(parens, DOWN) + dt_to_zero = TexMobject("dt", "\\to 0") + dt_to_zero.highlight_by_tex("dt", GREEN) + dt_to_zero.next_to(brace, DOWN) + + self.play(GrowFromCenter(brace)) + self.play(Write(dt_to_zero)) + self.dither(2) + + #Who cares + randy = Randolph() + randy.scale(0.7) + randy.to_edge(DOWN) + + self.play( + FadeIn(randy), + self.pi_creature.change_mode, "plain", + ) + self.play(PiCreatureSays( + randy, "Who cares?", + bubble_kwargs = {"direction" : LEFT}, + target_mode = "angry", + )) + self.dither(2) + self.play( + RemovePiCreatureBubble(randy), + FadeOut(randy), + self.pi_creature.change_mode, "hooray", + self.pi_creature.look_at, parens + ) + self.play( + Transform(brace, alt_brace), + dt_to_zero.next_to, alt_brace, DOWN + ) + self.dither() + + #Highlight separation + rects = [ + Rectangle( + stroke_color = color, + stroke_width = 2, + ).replace(mob, stretch = True).scale_in_place(1.1) + for mob, color in [ + (VGroup(parens, dt_to_zero), GREEN), + (extracted_two_to_t, YELLOW), + ] + ] + self.play(ShowCreation(rects[0])) + self.dither(2) + self.play(ReplacementTransform(rects[0].copy(), rects[1])) + self.change_mode("happy") + self.dither() + self.play(*map(FadeOut, rects)) + + #Plug in specific values + static_constant = self.try_specific_dt_values() + constant = static_constant.copy() + + #Replace with actual constant + limit_term = VGroup( + brace, dt_to_zero, ratio[4], one, rects[0], + *ratio[7:]+two_to_t_two_to_dt[2:] + ) + self.play(FadeIn(rects[0])) + self.play(limit_term.to_corner, DOWN+LEFT) + self.play( + lp.stretch, 0.5, 1, + lp.stretch, 0.8, 0, + lp.next_to, extracted_two_to_t[0], RIGHT, + rp.stretch, 0.5, 1, + rp.stretch, 0.8, 0, + rp.next_to, lp, RIGHT, SMALL_BUFF, + rp.shift, constant.get_width()*RIGHT, + constant.next_to, extracted_two_to_t[0], RIGHT, MED_LARGE_BUFF + ) + self.dither() + self.change_mode("confused") + self.dither() + + #hold_final_value + derivative = VGroup( + lhs, extracted_two_to_t, parens, constant + ) + func_def_rhs = VGroup(*func_def[-2:]).copy() + func_lp, func_rp = func_parens = TexMobject("()") + func_parens.set_fill(opacity = 0) + func_lp.next_to(func_def_rhs[0], LEFT, buff = 0) + func_rp.next_to(func_lp, RIGHT, buff = func_def_rhs.get_width()) + func_def_rhs.add(func_parens) + M = lhs[0][1] + + self.play( + FadeOut(M), + func_def_rhs.move_to, M, LEFT, + func_def_rhs.set_fill, None, 1, + ) + lhs[0].submobjects[1] = func_def_rhs + self.dither() + self.play( + derivative.next_to, self.pi_creature, UP, + derivative.to_edge, RIGHT, + self.pi_creature.change_mode, "raise_right_hand" + ) + self.dither(2) + for mob in extracted_two_to_t, constant: + self.play(Indicate(mob)) + self.dither() + self.dither(2) + + def try_specific_dt_values(self): + expressions = [] + for num_zeros in [1, 2, 4, 7]: + dt_str = "0." + num_zeros*"0" + "1" + dt_num = float(dt_str) + output_num = (self.base**dt_num - 1) / dt_num + output_str = "%.7f\\dots"%output_num + + expression = TexMobject( + "{%s^"%self.base_str, "{%s}"%dt_str, "-1", + "\\over \\,", "%s}"%dt_str, + "=", output_str + ) + expression.highlight_by_tex(dt_str, GREEN) + expression.highlight_by_tex(output_str, BLUE) + expression.to_corner(UP+RIGHT) + expressions.append(expression) + + curr_expression = expressions[0] + self.play( + Write(curr_expression), + self.pi_creature.change_mode, "pondering" + ) + self.dither(2) + for expression in expressions[1:]: + self.play(Transform(curr_expression, expression)) + self.dither(2) + return curr_expression[-1] + +class ExponentRatioWithThree(AnalyzeExponentRatio): + CONFIG = { + "base" : 3, + "base_str" : "3", + } + +class ExponentRatioWithSeven(AnalyzeExponentRatio): + CONFIG = { + "base" : 3, + "base_str" : "3", + } + +class ExponentRatioWithE(AnalyzeExponentRatio): + CONFIG = { + "base" : np.exp(1), + "base_str" : "e", + }