Beispiel #1
0
        def call_power(x, n, call_stack):
            stack_frame = StackFrame(power_code,
                                     'power(%d, %d)' % (x, n),
                                     1, ['x', 'n', 't'],
                                     width=frame_width)
            call_stack.animate_call(stack_frame, self)

            self.play(*stack_frame.get_update_line_anims(2),
                      stack_frame.update_slot, 'x', x, stack_frame.update_slot,
                      'n', n)

            if n == 0:
                self.play(*stack_frame.get_update_line_anims(3))
                self.wait()
                call_stack.animate_return(self)
                return 1
            else:
                self.play(*stack_frame.get_update_line_anims(5))
                self.wait()
                t = call_power(x, n - 1, call_stack)

                self.play(
                    *stack_frame.get_update_line_anims(6),
                    stack_frame.update_slot,
                    't',
                    t,
                )
                self.wait()
                call_stack[-1].code = power_code
                call_stack.animate_return(self)
                return x * t
Beispiel #2
0
        def call_power2(x, n, call_stack, cc_num):
            new_cc_num = TextMobject(str(len(call_stack) -
                                         1)).move_to(cc_num).set_color(YELLOW)
            update_cc_anims = [ReplacementTransform(cc_num, new_cc_num)]

            call_ret_delay = 0.5
            stack_frame = StackFrame(power2_code,
                                     'power(%d, %d)' % (x, n),
                                     1, ['x', 'n', 't'],
                                     width=frame_width)
            call_stack.animate_call(stack_frame,
                                    self,
                                    extra_anims=update_cc_anims)

            self.play(
                *stack_frame.get_update_line_anims(2),
                stack_frame.update_slot,
                'x',
                x,
                stack_frame.update_slot,
                'n',
                n,
            )

            if n == 0:
                self.play(*stack_frame.get_update_line_anims(3))
                self.wait(duration=call_ret_delay)
                call_stack.animate_return(self)
                return 1
            else:
                self.play(*stack_frame.get_update_line_anims(5))
                self.wait(duration=call_ret_delay)

                t = call_power2(x, n // 2, call_stack, new_cc_num)
                self.play(
                    *stack_frame.get_update_line_anims(6),
                    stack_frame.update_slot,
                    't',
                    t,
                )

                if n % 2 == 0:
                    self.play(*stack_frame.get_update_line_anims(7))
                    self.wait(duration=call_ret_delay)
                    call_stack.animate_return(self)
                    return t * t

                self.play(*stack_frame.get_update_line_anims(9))
                self.wait(duration=call_ret_delay)
                call_stack.animate_return(self)
                return t * t * x
Beispiel #3
0
        def call_fib(run_ctx, call_stack, current_node, n):
            run_ctx['call_count'] += 1
            call_ret_delay = 0.5
            stack_frame = StackFrame(fib_code,
                                     'fib(%d)' % n,
                                     1, ['n', 'fn1', 'fn2'],
                                     width=call_stack[0].width,
                                     text_scale=call_stack[0].text_scale)
            sr = SurroundingRectangle(current_node)
            extra_anims = [current_node.set_color, YELLOW]
            if tree.current_rect:
                extra_anims.append(ReplacementTransform(tree.current_rect, sr))
            else:
                extra_anims.append(ShowCreation(sr))
            tree.current_rect = sr
            if current_node.parent:
                extra_anims.append(
                    ApplyMethod(current_node.parent.set_color, ORANGE))
            call_stack.animate_call(stack_frame, self, extra_anims=extra_anims)

            self.play(
                *stack_frame.get_update_line_anims(2),
                stack_frame.update_slot,
                'n',
                n,
            )
            if n == 0:
                self.play(*stack_frame.get_update_line_anims(3))
                self.wait(duration=call_ret_delay)

                extra_anims = []
                if run_ctx['call_count'] == 5:
                    s1 = TextMobject("and we know $F_0=0$")
                    s1.move_to(tree_area_frame).shift(DOWN)
                    self.play(FadeIn(s1))
                    extra_anims.append(FadeOut(s1))

                extra_anims.extend(update_for_return(current_node, 0, run_ctx))
                call_stack.animate_return(self, extra_anims=extra_anims)
                return 0

            self.play(*stack_frame.get_update_line_anims(5))
            if n == 1:
                self.play(*stack_frame.get_update_line_anims(6))
                self.wait(duration=call_ret_delay)

                extra_anims = []
                if run_ctx['call_count'] == 4:
                    s1 = TextMobject("we know $F_1=1$")
                    s1.move_to(tree_area_frame).shift(DOWN)
                    self.play(FadeIn(s1))
                    extra_anims.append(FadeOut(s1))

                extra_anims.extend(update_for_return(current_node, 1, run_ctx))
                call_stack.animate_return(self, extra_anims=extra_anims)
                return 1

            self.play(*stack_frame.get_update_line_anims(8))

            self.wait(duration=call_ret_delay)

            s1 = None
            if run_ctx['call_count'] == 1:
                s1 = TextMobject('we need $F_3$ and $F_2$')
                s1.move_to(tree_area_frame)
                self.play(FadeIn(s1))
                self.wait()
            elif run_ctx['call_count'] == 2:
                s1 = TextMobject('and now we need $F_2$ and $F_1$')
                s1.move_to(tree_area_frame).shift(DOWN)
                self.play(FadeIn(s1))
                self.wait()

            left_node, ll = tree.add_left_node(current_node,
                                               '$F_%d$' % (n - 1))
            right_node, rl = tree.add_right_node(current_node,
                                                 '$F_%d$' % (n - 2))
            left_node.set_color(BLUE)
            right_node.set_color(BLUE)
            self.add(ll, rl,
                     tree.current_rect)  # Keep the rect on top of lines
            self.play(*[FadeIn(o) for o in [left_node, ll, right_node, rl]])

            if s1:
                self.wait()
                self.play(FadeOut(s1))
                s1 = None

            fn1 = call_fib(run_ctx, call_stack, left_node, n - 1)

            if run_ctx['call_count'] == 4:
                s1 = TextMobject("now do the other half")
                s1.move_to(tree_area_frame).shift(DOWN)
                self.play(FadeIn(s1))
            elif run_ctx['call_count'] == 6:
                t1 = TextMobject("Using a ``tree'' for this is \\textit{much} "
                                 "more helpful!").scale(0.8)
                t2 = TextMobject("Shows where we've ", "been", ", where we ",
                                 "are", ",\\\\and where we're ", "going")
                t2.scale(0.8)
                t2.set_color_by_tex_to_color_map({
                    "been": GREEN_SCREEN,
                    "are": YELLOW,
                    "going": BLUE,
                })
                t1.move_to(tree_area_frame).shift(DOWN)
                t2.next_to(t1, DOWN, buff=MED_SMALL_BUFF)
                self.play(FadeIn(t1))
                self.wait()
                self.play(Write(t2))
                self.wait()
                run_ctx['final_desc'] = VGroup(t1, t2)

            self.play(
                *stack_frame.get_update_line_anims(9),
                stack_frame.update_slot,
                'fn1',
                fn1,
            )

            if s1:
                self.wait()
                self.play(FadeOut(s1))
                s1 = None

            self.wait(duration=call_ret_delay)
            fn2 = call_fib(run_ctx, call_stack, right_node, n - 2)

            extra_anims = []
            if run_ctx['call_count'] == 5:
                s1 = TextMobject("add the two halves")
                s1.move_to(tree_area_frame).shift(DOWN)
                self.play(FadeIn(s1))
                extra_anims.append(FadeOut(s1))
                run_ctx['update_node_delay'] = 0.1

            self.play(
                *stack_frame.get_update_line_anims(10),
                stack_frame.update_slot,
                'fn2',
                fn2,
            )

            self.wait(duration=call_ret_delay)
            extra_anims.extend(
                update_for_return(current_node, fn1 + fn2, run_ctx))
            call_stack.animate_return(self, extra_anims=extra_anims)
            return fn1 + fn2
Beispiel #4
0
    def construct(self):
        fib_code = self.get_fib_code(0.75)
        fib_code.to_edge(UP)
        self.add(fib_code)

        fc2 = self.get_fib_code(0.6)
        fc2.to_edge(UR)
        self.play(ReplacementTransform(fib_code, fc2))
        fib_code = fc2

        first_fib_arg = 4
        main_code = CodeBlock(
            'Java',
            r"""
            public static void main(String[] args) {
                int x = fib(%d);
            }
            """ % first_fib_arg,
            line_offset=11,
            code_scale=0.6,
        )

        main_frame = StackFrame(main_code,
                                'main()',
                                13, ['x'],
                                width=2.5,
                                text_scale=0.6)
        main_code.highlight_lines(13)
        VGroup(main_code,
               main_frame).arrange(RIGHT, buff=LARGE_BUFF * 2).to_edge(DOWN)
        tree_area_frame = Polygon(
            np.array((-FRAME_X_RADIUS, FRAME_Y_RADIUS, 0)),
            np.array((fib_code.get_corner(UL)[0], FRAME_Y_RADIUS, 0)),
            np.array((fib_code.get_corner(DL)[0], main_code.get_top()[1], 0)),
            np.array((-FRAME_X_RADIUS, main_code.get_top()[1], 0)),
            mark_paths_closed=True,
            close_new_points=True,
        )

        ready_desc = TextMobject(
            "We'll compute $F_%d$\\\\and track \\textit{all} "
            "our work as we go" % first_fib_arg)
        ready_desc.move_to(tree_area_frame)
        self.play(FadeIn(ready_desc))
        self.wait(duration=2)

        self.play(
            fib_code.to_edge,
            UP,
            FadeInFromDown(main_frame),
            FadeInFromDown(main_code),
        )

        tree_text_scale = 1.0
        tmp_leaf = TextMobject('$F_%d$' % 1).scale(tree_text_scale)
        leaf_width = tmp_leaf.get_width()
        level_spread_factors = [4, 1.9, 1.75]
        level_spreads = [f * leaf_width for f in level_spread_factors]

        tree = BinaryTree(
            max_depth=first_fib_arg,
            leaf_height=tmp_leaf.get_height(),
            level_buff=LARGE_BUFF * 1.5,
            level_spreads=level_spreads,
            text_scale=tree_text_scale,
        )

        def update_for_return(current_node, val, run_ctx):
            v = TextMobject(str(val))
            # v = TextMobject(current_node.label.tex_string, '$=%d$' % val)
            v.set_color(GREEN_SCREEN)
            v.scale(tree_text_scale)
            v.move_to(current_node.label)
            self.play(ReplacementTransform(current_node.label, v))
            self.wait(duration=run_ctx['update_node_delay'])
            extra_anims = []
            if current_node.parent:
                sr = SurroundingRectangle(current_node.parent)
                extra_anims.append(ReplacementTransform(tree.current_rect, sr))
                tree.current_rect = sr
                extra_anims.append(
                    ApplyMethod(current_node.parent.set_color, YELLOW))
            else:
                extra_anims.append(FadeOut(tree.current_rect))
            return extra_anims

        def call_fib(run_ctx, call_stack, current_node, n):
            run_ctx['call_count'] += 1
            call_ret_delay = 0.5
            stack_frame = StackFrame(fib_code,
                                     'fib(%d)' % n,
                                     1, ['n', 'fn1', 'fn2'],
                                     width=call_stack[0].width,
                                     text_scale=call_stack[0].text_scale)
            sr = SurroundingRectangle(current_node)
            extra_anims = [current_node.set_color, YELLOW]
            if tree.current_rect:
                extra_anims.append(ReplacementTransform(tree.current_rect, sr))
            else:
                extra_anims.append(ShowCreation(sr))
            tree.current_rect = sr
            if current_node.parent:
                extra_anims.append(
                    ApplyMethod(current_node.parent.set_color, ORANGE))
            call_stack.animate_call(stack_frame, self, extra_anims=extra_anims)

            self.play(
                *stack_frame.get_update_line_anims(2),
                stack_frame.update_slot,
                'n',
                n,
            )
            if n == 0:
                self.play(*stack_frame.get_update_line_anims(3))
                self.wait(duration=call_ret_delay)

                extra_anims = []
                if run_ctx['call_count'] == 5:
                    s1 = TextMobject("and we know $F_0=0$")
                    s1.move_to(tree_area_frame).shift(DOWN)
                    self.play(FadeIn(s1))
                    extra_anims.append(FadeOut(s1))

                extra_anims.extend(update_for_return(current_node, 0, run_ctx))
                call_stack.animate_return(self, extra_anims=extra_anims)
                return 0

            self.play(*stack_frame.get_update_line_anims(5))
            if n == 1:
                self.play(*stack_frame.get_update_line_anims(6))
                self.wait(duration=call_ret_delay)

                extra_anims = []
                if run_ctx['call_count'] == 4:
                    s1 = TextMobject("we know $F_1=1$")
                    s1.move_to(tree_area_frame).shift(DOWN)
                    self.play(FadeIn(s1))
                    extra_anims.append(FadeOut(s1))

                extra_anims.extend(update_for_return(current_node, 1, run_ctx))
                call_stack.animate_return(self, extra_anims=extra_anims)
                return 1

            self.play(*stack_frame.get_update_line_anims(8))

            self.wait(duration=call_ret_delay)

            s1 = None
            if run_ctx['call_count'] == 1:
                s1 = TextMobject('we need $F_3$ and $F_2$')
                s1.move_to(tree_area_frame)
                self.play(FadeIn(s1))
                self.wait()
            elif run_ctx['call_count'] == 2:
                s1 = TextMobject('and now we need $F_2$ and $F_1$')
                s1.move_to(tree_area_frame).shift(DOWN)
                self.play(FadeIn(s1))
                self.wait()

            left_node, ll = tree.add_left_node(current_node,
                                               '$F_%d$' % (n - 1))
            right_node, rl = tree.add_right_node(current_node,
                                                 '$F_%d$' % (n - 2))
            left_node.set_color(BLUE)
            right_node.set_color(BLUE)
            self.add(ll, rl,
                     tree.current_rect)  # Keep the rect on top of lines
            self.play(*[FadeIn(o) for o in [left_node, ll, right_node, rl]])

            if s1:
                self.wait()
                self.play(FadeOut(s1))
                s1 = None

            fn1 = call_fib(run_ctx, call_stack, left_node, n - 1)

            if run_ctx['call_count'] == 4:
                s1 = TextMobject("now do the other half")
                s1.move_to(tree_area_frame).shift(DOWN)
                self.play(FadeIn(s1))
            elif run_ctx['call_count'] == 6:
                t1 = TextMobject("Using a ``tree'' for this is \\textit{much} "
                                 "more helpful!").scale(0.8)
                t2 = TextMobject("Shows where we've ", "been", ", where we ",
                                 "are", ",\\\\and where we're ", "going")
                t2.scale(0.8)
                t2.set_color_by_tex_to_color_map({
                    "been": GREEN_SCREEN,
                    "are": YELLOW,
                    "going": BLUE,
                })
                t1.move_to(tree_area_frame).shift(DOWN)
                t2.next_to(t1, DOWN, buff=MED_SMALL_BUFF)
                self.play(FadeIn(t1))
                self.wait()
                self.play(Write(t2))
                self.wait()
                run_ctx['final_desc'] = VGroup(t1, t2)

            self.play(
                *stack_frame.get_update_line_anims(9),
                stack_frame.update_slot,
                'fn1',
                fn1,
            )

            if s1:
                self.wait()
                self.play(FadeOut(s1))
                s1 = None

            self.wait(duration=call_ret_delay)
            fn2 = call_fib(run_ctx, call_stack, right_node, n - 2)

            extra_anims = []
            if run_ctx['call_count'] == 5:
                s1 = TextMobject("add the two halves")
                s1.move_to(tree_area_frame).shift(DOWN)
                self.play(FadeIn(s1))
                extra_anims.append(FadeOut(s1))
                run_ctx['update_node_delay'] = 0.1

            self.play(
                *stack_frame.get_update_line_anims(10),
                stack_frame.update_slot,
                'fn2',
                fn2,
            )

            self.wait(duration=call_ret_delay)
            extra_anims.extend(
                update_for_return(current_node, fn1 + fn2, run_ctx))
            call_stack.animate_return(self, extra_anims=extra_anims)
            return fn1 + fn2

        root_node, _ = tree.add_left_node(None, '$F_%d$' % first_fib_arg)
        root_node.move_to(tree_area_frame)
        root_node.to_edge(UP)
        self.play(ShowCreation(root_node))
        self.wait()

        self.play(FadeOut(ready_desc))

        run_ctx = {
            'call_count': 0,
            'update_node_delay': 1.0,
        }

        result = call_fib(run_ctx, CallStack(main_frame, scroll_height=1),
                          root_node, first_fib_arg)
        self.play(
            *main_frame.get_update_line_anims(14),
            main_frame.update_slot,
            'x',
            result,
        )
        self.wait(duration=2)

        self.play(FadeOutAndShiftDown(main_code),
                  FadeOutAndShiftDown(main_frame))
        self.wait()

        t1 = TextMobject("It is common to see recursive algorithms "
                         "described with trees")
        t2 = TextMobject("\\textit{Try drawing them out as you go!}")
        t2.set_color(GREEN)
        t2.to_edge(DOWN)
        t1.next_to(t2, UP, buff=MED_LARGE_BUFF)
        self.play(FadeInFromDown(t1))
        self.wait(duration=1.5)
        self.play(Write(t2))
        self.wait(duration=5)

        x = self.camera.get_mobjects_to_display(self.mobjects)
        end_scale_group = VGroup(*x)
        end_fade_group = VGroup()
        self.animate_yt_end_screen(end_scale_group,
                                   end_fade_group,
                                   end_scale=0.6,
                                   show_elements=False)
Beispiel #5
0
        def call_fib(run_ctx, n, call_stack):
            run_ctx['call_count'] += 1
            call_ret_delay = 0.5
            stack_frame = StackFrame(fib_code,
                                     'fib(%d)' % n,
                                     1, ['n', 'fn1', 'fn2'],
                                     width=frame_width)
            call_stack.animate_call(stack_frame, self)

            self.play(
                *stack_frame.get_update_line_anims(2),
                stack_frame.update_slot,
                'n',
                n,
            )

            if n == 0:
                self.play(*stack_frame.get_update_line_anims(3))
                self.wait(duration=call_ret_delay)
                call_stack.animate_return(self)
                return 0

            self.play(*stack_frame.get_update_line_anims(5))
            if n == 1:
                self.play(*stack_frame.get_update_line_anims(6))
                self.wait(duration=call_ret_delay)
                call_stack.animate_return(self)
                return 1

            self.play(*stack_frame.get_update_line_anims(8))
            self.wait(duration=call_ret_delay)
            fn1 = call_fib(run_ctx, n - 1, call_stack)
            self.play(
                *stack_frame.get_update_line_anims(9),
                stack_frame.update_slot,
                'fn1',
                fn1,
            )

            if run_ctx['call_count'] == 4:
                t1 = TextMobject('\\textit{Whoa!!}')
                t1.set_color(YELLOW).scale(1.2)
                t1.next_to(fib_code, LEFT, buff=MED_LARGE_BUFF)
                self.play(GrowFromCenter(t1))
                t2 = TextMobject("\\textit{I'm lost...}")
                t2.next_to(t1, DOWN, buff=LARGE_BUFF)
                self.play(FadeInFromPoint(t2, t2.get_center()))
                run_ctx['whoa_desc'] = VGroup(t1, t2)

            self.wait(duration=call_ret_delay)
            fn2 = call_fib(run_ctx, n - 2, call_stack)
            self.play(
                *stack_frame.get_update_line_anims(10),
                stack_frame.update_slot,
                'fn2',
                fn2,
            )

            self.wait(duration=call_ret_delay)
            call_stack.animate_return(self)
            return fn1 + fn2
Beispiel #6
0
    def construct(self):
        fib_code = CodeBlock(
            'Java',
            r"""
            public static int fib(int n) {
                if (n == 0) {
                    return 0;
                }
                if (n == 1) {
                    return 1;
                }
                int fn1 = fib(n - 1);
                int fn2 = fib(n - 2);
                return fn1 + fn2;
            }
            """,
        )
        self.add(fib_code)

        main_code = CodeBlock(
            'Java',
            r"""
            public static void main(String[] args) {
                int x = fib(3);
            }
            """,
            line_offset=11,
            code_scale=0.6,
        )

        frame_width = 2.5
        main_frame = StackFrame(main_code,
                                'main()',
                                13, ['x'],
                                width=frame_width)
        main_code.highlight_lines(13)
        VGroup(main_code,
               main_frame).arrange(RIGHT, buff=LARGE_BUFF * 2).to_edge(DOWN)
        self.play(
            fib_code.to_edge,
            UP,
            FadeInFromDown(main_frame),
            FadeInFromDown(main_code),
        )
        self.wait()

        def call_fib(run_ctx, n, call_stack):
            run_ctx['call_count'] += 1
            call_ret_delay = 0.5
            stack_frame = StackFrame(fib_code,
                                     'fib(%d)' % n,
                                     1, ['n', 'fn1', 'fn2'],
                                     width=frame_width)
            call_stack.animate_call(stack_frame, self)

            self.play(
                *stack_frame.get_update_line_anims(2),
                stack_frame.update_slot,
                'n',
                n,
            )

            if n == 0:
                self.play(*stack_frame.get_update_line_anims(3))
                self.wait(duration=call_ret_delay)
                call_stack.animate_return(self)
                return 0

            self.play(*stack_frame.get_update_line_anims(5))
            if n == 1:
                self.play(*stack_frame.get_update_line_anims(6))
                self.wait(duration=call_ret_delay)
                call_stack.animate_return(self)
                return 1

            self.play(*stack_frame.get_update_line_anims(8))
            self.wait(duration=call_ret_delay)
            fn1 = call_fib(run_ctx, n - 1, call_stack)
            self.play(
                *stack_frame.get_update_line_anims(9),
                stack_frame.update_slot,
                'fn1',
                fn1,
            )

            if run_ctx['call_count'] == 4:
                t1 = TextMobject('\\textit{Whoa!!}')
                t1.set_color(YELLOW).scale(1.2)
                t1.next_to(fib_code, LEFT, buff=MED_LARGE_BUFF)
                self.play(GrowFromCenter(t1))
                t2 = TextMobject("\\textit{I'm lost...}")
                t2.next_to(t1, DOWN, buff=LARGE_BUFF)
                self.play(FadeInFromPoint(t2, t2.get_center()))
                run_ctx['whoa_desc'] = VGroup(t1, t2)

            self.wait(duration=call_ret_delay)
            fn2 = call_fib(run_ctx, n - 2, call_stack)
            self.play(
                *stack_frame.get_update_line_anims(10),
                stack_frame.update_slot,
                'fn2',
                fn2,
            )

            self.wait(duration=call_ret_delay)
            call_stack.animate_return(self)
            return fn1 + fn2

        run_ctx = {
            'call_count': 0,
        }

        result = call_fib(run_ctx, 3, CallStack(main_frame))
        self.play(
            *main_frame.get_update_line_anims(14),
            main_frame.update_slot,
            'x',
            result,
        )
        self.wait(duration=2)

        hrm_desc = TextMobject(
            "That worked, but it was really hard to follow!")
        hrm_desc.next_to(fib_code, DOWN, buff=MED_LARGE_BUFF)
        self.play(FadeOutAndShiftDown(main_frame),
                  FadeOutAndShiftDown(main_code),
                  FadeOut(run_ctx['whoa_desc']))
        self.play(FadeInFromDown(hrm_desc))
        self.wait(duration=2.5)

        t1 = TextMobject("The call stack shows where we are at any moment")
        t1.move_to(hrm_desc)
        t2 = TextMobject("but we don't know where we've been...")
        t2.next_to(t1, DOWN)
        t3 = TextMobject("or where we're going...")
        t3.next_to(t2, DOWN)

        self.play(ReplacementTransform(hrm_desc, t1))
        self.wait(duration=2)
        self.play(FadeInFromDown(t2))
        self.wait(duration=2)
        self.play(FadeInFromDown(t3))
        self.wait(duration=2)

        t4 = TextMobject(
            "Let's go again, but draw a new picture along the way")
        t4.move_to(t1)
        self.play(*[FadeOutAndShift(o, UP) for o in [t1, t2, t3]],
                  FadeInFromDown(t4))
        self.wait(duration=2.5)
        self.play(FadeOut(t4))
Beispiel #7
0
    def construct(self):
        t1 = TextMobject("Let's compute $x^n$").shift(UP)
        self.play(FadeIn(t1))
        self.wait()

        t2 = TextMobject("i.e., $2^4=16$, or $4^3=64$, etc.")
        t2.next_to(t1, DOWN, buff=LARGE_BUFF)
        self.play(FadeInFromDown(t2))
        self.wait(duration=2)

        t3 = TextMobject('Recall that')
        f1 = TexMobject('x^n=', 'x', '\\times', 'x \\times ... \\times x',
                        'x^{n-1}')
        f2 = TexMobject('x^n=', 'x', '\\times', 'x^{n-1}')
        f2.next_to(t3, RIGHT)
        dg = VGroup(t3, f2).center().shift(
            UP)  # Place t3 so the final result is centered
        f1.next_to(t3, RIGHT)
        b1 = BraceLabel(f1[1:-1],
                        '$n$ times',
                        brace_direction=UP,
                        label_constructor=TextMobject)
        g = VGroup(t3, f1[:-1], b1)  # For display
        self.play(
            FadeOut(t1),
            FadeOut(t2),
            FadeInFromDown(g),
        )
        self.wait(duration=3)

        b2 = BraceLabel(f1[3],
                        '$n-1$ times',
                        brace_direction=UP,
                        label_constructor=TextMobject)
        self.play(ReplacementTransform(b1, b2), )
        self.wait(duration=2)

        self.play(
            ReplacementTransform(f1[3], f2[3]),
            FadeOut(b2),
        )
        self.wait(duration=2)

        t4 = TextMobject("That's starting to feel a bit recursive!")
        t4.next_to(dg, DOWN, buff=MED_LARGE_BUFF)
        self.play(FadeIn(t4))
        self.wait()

        code_scale = 0.75
        power_code = CodeBlock(
            'Java',
            r"""
            public static int power(int x, int n) {
                if (n == 0) {
                    return 1;
                }
                int t = power(x, n - 1);
                return x * t;
            }
            """,
            code_scale=code_scale,
        )
        self.play(
            *[FadeOut(o) for o in [t3, t4, f1[:-1], f2[3]]],
            FadeInFromDown(power_code),
        )
        self.wait()

        b1 = BraceLabel(
            power_code.get_code().get_lines((2, 4)),
            'Remember $x^0=1$, because math!',
            brace_direction=RIGHT,
            label_constructor=TextMobject,
            label_scale=0.75,
        )
        self.play(ShowCreation(b1))
        self.wait(duration=2)

        t1 = TextMobject("Let's step through it to see how it goes...")
        t1.next_to(power_code, DOWN)
        self.play(FadeIn(t1), )
        self.wait()

        # Start stepping through this and see it go.
        main_code = CodeBlock(
            'Java',
            r"""
            public static void main(String[] args) {
                int y = power(4, 3);
            }
            """,
            line_offset=7,
            code_scale=code_scale - 0.1,
        )
        frame_width = 3.5
        main_frame = StackFrame(main_code,
                                'main()',
                                9, ['y'],
                                width=frame_width)
        main_code.highlight_lines(9)
        VGroup(main_code, main_frame).arrange(RIGHT,
                                              buff=LARGE_BUFF).to_edge(DOWN)
        self.play(
            FadeOut(t1),
            FadeOut(b1),
            power_code.to_edge,
            UP,
            FadeInFromDown(main_frame),
            FadeInFromDown(main_code),
        )
        self.wait()

        def call_power(x, n, call_stack):
            stack_frame = StackFrame(power_code,
                                     'power(%d, %d)' % (x, n),
                                     1, ['x', 'n', 't'],
                                     width=frame_width)
            call_stack.animate_call(stack_frame, self)

            self.play(*stack_frame.get_update_line_anims(2),
                      stack_frame.update_slot, 'x', x, stack_frame.update_slot,
                      'n', n)

            if n == 0:
                self.play(*stack_frame.get_update_line_anims(3))
                self.wait()
                call_stack.animate_return(self)
                return 1
            else:
                self.play(*stack_frame.get_update_line_anims(5))
                self.wait()
                t = call_power(x, n - 1, call_stack)

                self.play(
                    *stack_frame.get_update_line_anims(6),
                    stack_frame.update_slot,
                    't',
                    t,
                )
                self.wait()
                call_stack[-1].code = power_code
                call_stack.animate_return(self)
                return x * t

        result = call_power(4, 3, CallStack(main_frame))
        self.play(*main_frame.get_update_line_anims(10),
                  main_frame.update_slot, 'y', result)
        self.wait()

        final_eq = TexMobject('4^3=', '64')
        final_eq.next_to(power_code, DOWN, buff=LARGE_BUFF)
        lhs = final_eq[0].copy().move_to(
            main_code.get_code().get_lines(2)[12:15])
        rhs = final_eq[1].copy().move_to(main_frame.slots()[0])
        self.play(
            ReplacementTransform(lhs, final_eq[0]),
            ReplacementTransform(rhs, final_eq[1]),
        )
        self.wait(duration=2)

        self.play(*[FadeOut(o) for o in [final_eq, main_frame, main_code]])
        self.wait()
Beispiel #8
0
    def construct(self):
        code_scale = 0.7
        power2_code = CodeBlock(
            'Java',
            r"""
            public static int power2(int x, int n) {
                if (n == 0) {
                    return 1;
                }
                int t = power2(x, n / 2);
                if (n % 2 == 0) {
                    return t * t;
                }
                return t * t * x;
            }	
            """,
            code_scale=code_scale,
        )
        power2_code.to_edge(UP)
        self.add(power2_code)

        t1 = TextMobject(
            "This version should call itself fewer than $n$ times")
        t1.next_to(power2_code, DOWN, buff=LARGE_BUFF)
        self.play(FadeInFromDown(t1))
        self.wait(duration=2.5)

        t2 = TextMobject(
            'How many times do you think \\texttt{power2(2,30)} will call itself?',
            tex_to_color_map={'30': YELLOW})
        t2.next_to(t1, ORIGIN)
        self.play(FadeOutAndShift(t1, UP), FadeInFromDown(t2))
        self.wait(duration=2)

        t3 = TextMobject("We know it'll be less than 30!  Maybe 15?")
        t3.next_to(t2, DOWN, buff=MED_LARGE_BUFF)
        self.play(FadeInFromDown(t3))
        self.wait(duration=2)

        t4 = TextMobject("How about a lot less?  Let's see...")
        t4.next_to(t3, ORIGIN)
        self.play(ReplacementTransform(t3, t4))
        self.wait(duration=2)

        self.play(*[FadeOut(o) for o in self.mobjects if o != power2_code])

        # Start stepping through this and see it go.
        main_code = CodeBlock(
            'Java',
            r"""
            public static void main(String[] args) {
                int y = power2(2, 30);
            }
            """,
            line_offset=10,
            code_scale=code_scale - 0.1,
        )
        frame_width = 3.5
        main_frame = StackFrame(main_code,
                                'main()',
                                12, ['y'],
                                width=frame_width,
                                slot_char_width=8)
        main_code.highlight_lines(12)
        VGroup(main_code, main_frame).arrange(RIGHT,
                                              buff=LARGE_BUFF).to_edge(DOWN)
        self.play(
            FadeInFromDown(main_frame),
            FadeInFromDown(main_code),
        )
        self.wait()

        def call_power2(x, n, call_stack, cc_num):
            new_cc_num = TextMobject(str(len(call_stack) -
                                         1)).move_to(cc_num).set_color(YELLOW)
            update_cc_anims = [ReplacementTransform(cc_num, new_cc_num)]

            call_ret_delay = 0.5
            stack_frame = StackFrame(power2_code,
                                     'power(%d, %d)' % (x, n),
                                     1, ['x', 'n', 't'],
                                     width=frame_width)
            call_stack.animate_call(stack_frame,
                                    self,
                                    extra_anims=update_cc_anims)

            self.play(
                *stack_frame.get_update_line_anims(2),
                stack_frame.update_slot,
                'x',
                x,
                stack_frame.update_slot,
                'n',
                n,
            )

            if n == 0:
                self.play(*stack_frame.get_update_line_anims(3))
                self.wait(duration=call_ret_delay)
                call_stack.animate_return(self)
                return 1
            else:
                self.play(*stack_frame.get_update_line_anims(5))
                self.wait(duration=call_ret_delay)

                t = call_power2(x, n // 2, call_stack, new_cc_num)
                self.play(
                    *stack_frame.get_update_line_anims(6),
                    stack_frame.update_slot,
                    't',
                    t,
                )

                if n % 2 == 0:
                    self.play(*stack_frame.get_update_line_anims(7))
                    self.wait(duration=call_ret_delay)
                    call_stack.animate_return(self)
                    return t * t

                self.play(*stack_frame.get_update_line_anims(9))
                self.wait(duration=call_ret_delay)
                call_stack.animate_return(self)
                return t * t * x

        cc_label = TextMobject('Recursive Calls').scale(0.75)
        cc_label.to_edge(UL).shift(DOWN)
        call_counter = TextMobject('0').set_color(YELLOW).next_to(
            cc_label, DOWN)
        self.play(FadeIn(call_counter), FadeIn(cc_label))

        result = call_power2(2, 30, CallStack(main_frame), call_counter)
        self.play(
            *main_frame.get_update_line_anims(13),
            main_frame.update_slot,
            'y',
            result,
        )
        self.wait()

        t1 = TextMobject(
            'We got our answer in just 5 recursive calls!').set_color(YELLOW)
        t1.next_to(power2_code, DOWN, buff=MED_LARGE_BUFF)
        self.play(ShowCreation(t1))
        self.wait(duration=2)

        t1.generate_target()
        t1.target.center().to_edge(TOP)
        t2 = TextMobject('But why?').next_to(t1.target, DOWN, buff=LARGE_BUFF)
        self.play(
            MoveToTarget(t1),
            FadeInFromDown(t2),
            *[FadeOut(o) for o in self.mobjects if o != t1],
        )