def construct(self):
        mod = ModularMultiplier(
            Star(outer_radius=3, color=mn.BLUE),
            modulus=300,
            factor=1,
            line_config={
                "stroke_width": 1,
            },
        )

        mod_var = mn.Tex("Modulus", "$=$", f"${mod.modulus}$")
        factor_var = mn.Variable(mod.factor.get_value(), mn.Tex("Factor"))

        # Arrange mod_var so it lines up well with factor_var's elements
        mod_var[2].align_to(factor_var, mn.UR)
        mod_var[1].next_to(factor_var.label[0], mn.RIGHT)
        mod_var[0].next_to(mod_var[1], mn.LEFT)
        mod_var.shift((factor_var.height + 0.25) * mn.UP)

        factor_var.add_updater(
            lambda v: v.tracker.set_value(mod.factor.get_value()))

        info = mn.VGroup(mod_var, factor_var)
        info.to_corner(mn.UR)

        self.add(info, mod)

        self.animate_factors(mod, [2, 1])
    def init_lines(self):
        self.lines = mn.VGroup()
        self.add_to_back(self.lines)

        factor = self.factor.get_value()
        for n in range(self.modulus):
            n_point = self.n2p(n)
            mult_point = self.n2p(n * factor)

            line = mn.Line(n_point, mult_point, **self.line_config)
            self.lines.add(line)
Ejemplo n.º 3
0
    def construct_call(self, val: int) -> None:
        """Show how a call to the function with the given argument is evaluated"""
        call = m.VDict([
            ("name", m.Tex("\\verb|fact|").shift(m.LEFT * 5 + m.DOWN * 0.7)),
            ("val", m.Tex(f"\\verb|{val}|")),
        ])
        call["val"].next_to(call["name"], m.RIGHT, aligned_edge=m.UP)
        self.play(m.FadeIn(call))

        # Show the first call
        def_instance = deepcopy(self.def_box["function"]).remove("fn")
        def_instance.generate_target().scale(1 / self.def_scale_ratio).next_to(
            call, m.RIGHT * 5)
        lines = m.VGroup(
            ThinLine(
                call.get_corner(m.RIGHT) + m.RIGHT * 0.2,
                def_instance.target.get_corner(m.LEFT) + m.LEFT * 0.2,
                color=m.BLUE,
            ),
            ThinLine(
                def_instance.target.get_corner(m.DL) + m.LEFT * 0.2,
                def_instance.target.get_corner(m.UL) + m.LEFT * 0.2,
                color=m.BLUE,
            ),
        )
        self.wait()
        self.play(m.Indicate(self.def_box))
        self.play(
            m.MoveToTarget(def_instance),
            m.ShowCreation(lines),
        )
        self.wait()

        _, res_mobject = self.eval_call(def_instance, val, call["val"])

        self.play(m.FadeOut(call), m.FadeOut(lines),
                  m.ApplyMethod(res_mobject.center))
Ejemplo n.º 4
0
    def construct_call(self, val: int) -> None:
        """Show how a call to the OCaml function is evaluated

        val: the argument given to square_of_pred
        """
        call = m.VDict([
            ("name", m.Tex("\\verb|square_of_pred|").shift(m.LEFT * 2)),
            ("val", m.Tex(f"\\verb|{val}|")),
        ])
        call["val"].next_to(call["name"], m.RIGHT, aligned_edge=m.UP)
        self.play(m.FadeIn(call))

        # Shift the call and show instanciated definition of the function
        def_instance = deepcopy(self.def_box["function"]).remove("fn")
        def_instance.generate_target().scale(1 / self.def_scale_ratio).next_to(
            call, m.RIGHT * 5)
        lines = m.VGroup(
            ThinLine(
                call.get_corner(m.RIGHT) + m.RIGHT * 0.2,
                def_instance.target.get_corner(m.LEFT) + m.LEFT * 0.2,
                color=m.BLUE,
            ),
            ThinLine(
                def_instance.target.get_corner(m.DL) + m.LEFT * 0.2,
                def_instance.target.get_corner(m.UL) + m.LEFT * 0.2,
                color=m.BLUE,
            ),
        )
        self.wait()
        self.play(m.Indicate(self.def_box))
        self.play(
            m.MoveToTarget(def_instance),
            m.ShowCreation(lines),
        )
        self.wait()

        # Show context
        context = CallContext(def_instance, self)
        # add x=val to context
        context.add("x", call["val"])

        # Replace x by its value
        self.wait()
        context.replace_occurrence(-1, def_instance["pred"]["def"]["val"]["x"])
        self.wait()

        # Evaluate pred_x
        replace_expr(self, def_instance["pred"]["def"]["val"],
                     f"\\verb|{val-1}|")
        self.wait()
        # add pred_x=val-1 to context
        context.add(
            "pred\\_x",
            def_instance["pred"]["def"]["val"],
            highlight=def_instance["pred"],
            extra_animations=[
                m.FadeOutAndShift(def_instance["pred"], direction=m.UP),
                m.ApplyMethod(def_instance["res"].next_to, lines[1], m.RIGHT),
            ],
        )
        self.wait()

        # Replace pred_x by its value
        context.replace_occurrence(-1, def_instance["res"]["op2"])
        context.replace_occurrence(-1, def_instance["res"]["op1"])

        # Evaluate the result
        self.wait()
        replace_expr(
            self,
            def_instance["res"],
            f"\\verb|{(val-1) * (val-1)}|",
            aligned_edge=m.LEFT,
        )

        # Wrap up
        self.wait()
        self.play(
            m.FadeOut(context.entries),
            m.FadeOut(call),
            m.ApplyMethod(def_instance["res"].center),
            m.Uncreate(lines),
        )
Ejemplo n.º 5
0
    def eval_call(self, call: m.Mobject, val: int,
                  val_mobject: m.Mobject) -> Tuple[int, m.Mobject]:
        """Show the evaluation of one function call, recursively

        call: the manim object representing the call, expected to be oneline
        val: the value of `n` for that call

        Returns the value and the corresponding Mobject of the result of the call
        """
        context = CallContext(call, self)
        context.add("n", val_mobject)
        self.wait()

        # Evaluate the if's condition
        context.replace_occurrence(-1, call["if"]["cond"]["n"])
        self.wait()
        replace_expr(self, call["if"]["cond"],
                     f"\\verb|{str(val == 0).lower()}|")

        # Replace the expression with the correct if branch
        self.wait()
        self.play(m.Indicate(call["if"]["cond"]))
        if val == 0:
            bad = "rec"
            good = "base"
        else:
            good = "rec"
            bad = "base"
        strike_through = ThinLine(
            call[bad].get_corner(m.DL) + m.DL * 0.1,
            call[bad].get_corner(m.UR) + m.UR * 0.1,
        )
        rect = ThinRectangle().surround(call[good], stretch=True)
        self.play(m.ShowCreation(strike_through), m.ShowCreation(rect))
        self.wait()
        self.play(
            *map(m.FadeOut,
                 [strike_through, rect, call["if"], call[bad], call["else"]]))
        self.play(
            m.ApplyMethod(call[good].next_to, call.get_corner(m.LEFT),
                          m.RIGHT * 0.1))

        if val == 0:  # end of recursion
            self.play(*map(m.FadeOut, context.entries))
            return 1, call["base"]

        # Evaluate the expression containing the recursive call up to the call, starting
        # by the right-hand operand of the multiplication
        self.wait()
        self.play(m.Indicate(call["rec"]["call"]))
        context.replace_occurrence(-1, call["rec"]["call"]["arg"]["n"])
        self.wait(m.DEFAULT_WAIT_TIME / 2)
        replace_expr(self,
                     call["rec"]["call"]["arg"],
                     f"\\verb|{val - 1}|",
                     aligned_edge=m.LEFT)
        # Evaluate the recursive call
        rect = ThinRectangle(color=m.BLUE).surround(call["rec"]["call"],
                                                    stretch=True)
        def_instance = deepcopy(self.def_box["function"]).remove("fn")
        def_instance.generate_target().scale(1 / self.def_scale_ratio).next_to(
            rect, m.RIGHT * 5)
        lines = m.VGroup(
            ThinLine(
                rect.get_corner(m.RIGHT),
                def_instance.target.get_corner(m.LEFT) + m.LEFT * 0.2,
                color=m.BLUE,
            ),
            ThinLine(
                def_instance.target.get_corner(m.DL) + m.LEFT * 0.2,
                def_instance.target.get_corner(m.UL) + m.LEFT * 0.2,
                color=m.BLUE,
            ),
        )
        self.play(m.ShowCreation(rect))
        self.wait(m.DEFAULT_WAIT_TIME / 2)
        self.play(m.Indicate(self.def_box))
        self.play(m.MoveToTarget(def_instance), m.ShowCreation(lines))
        self.wait()
        shift_vector = (call["rec"]["call"]["arg"].get_center() -
                        val_mobject.get_center())
        self.play(
            m.ApplyMethod(self.camera.frame.shift, shift_vector),
            m.ApplyMethod(self.def_box.shift, shift_vector),
        )
        recursive_call_res, recursive_call_res_mobject = self.eval_call(
            def_instance, val - 1, call["rec"]["call"]["arg"])
        self.play(
            m.ApplyMethod(self.camera.frame.shift, -shift_vector),
            m.ApplyMethod(self.def_box.shift, -shift_vector),
        )
        self.play(
            m.FadeOut(lines),
            m.FadeOut(rect),
            m.FadeOut(call["rec"]["call"]),
            m.ApplyMethod(recursive_call_res_mobject.next_to, call["rec"]["*"],
                          m.RIGHT),
        )
        self.wait()
        call["rec"]["call"] = recursive_call_res_mobject
        # Evaluate the left-hand operand of the multiplication
        context.replace_occurrence(-1, call["rec"]["n"])
        res = val * recursive_call_res
        replace_expr(self, call["rec"], f"\\verb|{res}|", aligned_edge=m.LEFT)
        self.play(*map(m.FadeOut, context.entries))
        return res, call["rec"]