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])
Exemple #2
0
    def get_def() -> m.VDict:
        """Generate a renderable `square_of_pred` OCaml function

        The function:
        ```ocaml
        let square_of_pred x =
            let pred_x = x-1 in
            pred_x * pred_x
        ```
        """
        # first line: `let square_of_pred x =`
        fn_def = m.Tex("\\verb|let square_of_pred x =|")

        # second line: `let pred_x = x - 1 in`
        # -> let
        pred_let = (m.Tex("\\verb|let|").next_to(
            fn_def, m.DOWN, aligned_edge=m.LEFT).shift(INDENT))
        # -> pred_x = x - 1
        # ---> pred_x =
        pred_def = m.VDict([(
            "name",
            m.Tex("\\verb|pred_x =|").next_to(pred_let,
                                              m.RIGHT,
                                              aligned_edge=m.UP),
        )])
        # ---> x - 1
        # -----> x
        pred_def_val = m.VDict([(
            "x",
            m.Tex("\\verb|x|").next_to(pred_def["name"], m.RIGHT),
        )])
        # -----> - 1
        pred_def_val.add([(
            "min",
            m.Tex("\\verb|- 1|").next_to(pred_def_val["x"],
                                         m.RIGHT,
                                         aligned_edge=m.DOWN),
        )])
        pred_def.add([("val", pred_def_val)])
        ## in
        pred_end = m.Tex("\\verb|in|").next_to(pred_def,
                                               m.RIGHT,
                                               aligned_edge=m.UP)
        pred = m.VDict([
            ("let", pred_let),
            ("def", pred_def),
            ("end", pred_end),
        ])

        ### Last line: `pred_x * pred_x`
        res = m.VDict([(
            "op1",
            m.Tex("\\verb|pred_x|").next_to(pred, m.DOWN, aligned_edge=m.LEFT),
        )])
        res.add([("mul", m.Tex("\\verb|*|").next_to(res["op1"], m.RIGHT))])
        res.add([("op2", res["op1"].copy().next_to(res["mul"], m.RIGHT))])

        return m.VDict([("fn", fn_def), ("pred", pred), ("res", res)])
Exemple #3
0
    def __init__(self, origin: m.Mobject, scene: m.Scene):
        self.entries = m.Group(
            m.Tex("Contexte~:", color=m.GRAY).next_to(origin,
                                                      m.UP * 2,
                                                      aligned_edge=m.LEFT))
        scene.play(m.FadeInFrom(self.entries, direction=m.DOWN))

        self.scene = scene
Exemple #4
0
    def add(
        self,
        name: str,
        val_orig: m.Mobject,
        highlight: m.Mobject = None,
        extra_animations: List[m.Animation] = None,
    ) -> None:
        """Add an name-value association to the context and return animations

        name -- the name part of the association
        val_orig -- a Mobject that is the value part of the association
        highlight -- a Mobject that should be highlighted before other animations are
            played, defaults to val_orig
        extra_animations -- animations to be played along the others during the last
            step

        This creates a copy of `val_orig` and sets its target to the position of
        the value in the context, the returned animations will make the copy
        move to this position.
        """
        self.scene.play(m.Indicate(highlight if highlight else val_orig))

        association = m.VDict([
            ("name", m.Tex(name, color=m.GRAY)),
            ("eq", m.Tex("=", color=m.GRAY)),
            ("val", val_orig.copy()),
        ])
        association["name"].move_to(self.entries[-1], aligned_edge=m.LEFT)
        association["eq"].next_to(association["name"], m.RIGHT)
        association["val"].generate_target().next_to(association["eq"],
                                                     m.RIGHT).set_color(m.GRAY)

        self.scene.play(
            m.ApplyMethod(self.entries.shift, m.UP * 0.5),
            m.FadeInFrom(association["name"], direction=m.DOWN),
            m.FadeInFrom(association["eq"], direction=m.DOWN),
            m.MoveToTarget(association["val"]),
            *(extra_animations if extra_animations else []),
        )
        self.entries.add(association)
        self.scene.remove(association)  # The previous line created a copy
Exemple #5
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))
Exemple #6
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),
        )
Exemple #7
0
def replace_expr(scene: m.Scene, expr: m.Mobject, text: str, **kwargs) -> None:
    """Play an animation that transforms an expression in an other

    kwargs are given to a call to the new Mobject's `move_to` method
    """
    scene.play(m.Transform(expr, m.Tex(text).move_to(expr, **kwargs)))
Exemple #8
0
    def get_def() -> m.Mobject:
        """Generate a renderable OCaml fact function

        The function:
        ```ocaml
        let rec fact n =
          if n = 0 then
            1
          else
            n * fact (n - 1)
        ```
        """
        # First line: `let rec fact n =`
        fn_line = m.Tex("\\verb|let rec fact n =|")

        # Second line: `if n = 0 then`
        # -> `if`
        if_if = (m.Tex("\\verb|if|").next_to(
            fn_line, m.DOWN, aligned_edge=m.LEFT).shift(INDENT))
        # -> `n = 0`
        if_cond_n = m.Tex("\\verb|n|").next_to(  # `n`
            if_if, m.RIGHT, aligned_edge=m.DOWN)
        if_cond_eq = m.Tex("\\verb|=|").next_to(if_cond_n, m.RIGHT)  # `=`
        if_cond_zero = m.Tex("\\verb|0|").next_to(if_cond_eq, m.RIGHT)  # `0`
        if_cond = m.VDict([  # assembling
            ("n", if_cond_n), ("=", if_cond_eq), ("0", if_cond_zero)
        ])
        # -> `then`
        if_then = m.Tex("\\verb|then|").next_to(if_cond,
                                                m.RIGHT,
                                                aligned_edge=m.UP)
        # <- assembling
        if_line = m.VDict([("if", if_if), ("cond", if_cond),
                           ("then", if_then)])

        # Third line: `1`
        base_line = (m.Tex("\\verb|1|").next_to(
            if_line, m.DOWN, aligned_edge=m.LEFT).shift(INDENT))

        # Fourth line: `else`
        else_line = (m.Tex("\\verb|else|").next_to(
            base_line, m.DOWN, aligned_edge=m.LEFT).shift(-INDENT))

        # Fifth line: `n * fact (n - 1)`
        # -> n
        rec_n = (m.Tex("\\verb|n|").next_to(else_line,
                                            m.DOWN,
                                            aligned_edge=m.LEFT).shift(INDENT))
        # -> *
        rec_times = m.Tex("\\verb|*|").next_to(rec_n,
                                               m.RIGHT,
                                               aligned_edge=m.UP)
        # -> `fact (n - 1)`
        # ---> `fact`
        rec_call_name = m.Tex("\\verb|fact|").next_to(rec_times,
                                                      m.RIGHT,
                                                      aligned_edge=m.DOWN)
        # ---> `(n - 1)`
        rec_call_arg_ob = m.Tex("\\verb|(|").next_to(  # `(`
            rec_call_name, m.RIGHT, aligned_edge=m.UP)
        rec_call_arg_n = m.Tex("\\verb|n|").next_to(  # `n`
            rec_call_arg_ob, m.RIGHT * 0.3)
        rec_call_arg_min = m.Tex("\\verb|-|").next_to(  # `-`
            rec_call_arg_n, m.RIGHT)
        rec_call_arg_one = m.Tex("\\verb|1|").next_to(  # `1`
            rec_call_arg_min, m.RIGHT)
        rec_call_arg_cb = m.Tex("\\verb|)|").next_to(  # `)`
            rec_call_arg_one, m.RIGHT * 0.3)
        rec_call_arg = m.VDict([  # assembling
            ("(", rec_call_arg_ob),
            ("n", rec_call_arg_n),
            ("-", rec_call_arg_min),
            ("1", rec_call_arg_one),
            (")", rec_call_arg_cb),
        ])
        # <--- assembling
        rec_call = m.VDict([("name", rec_call_name), ("arg", rec_call_arg)])
        # <- assembling
        rec = m.VDict([("n", rec_n), ("*", rec_times), ("call", rec_call)])

        return m.VDict([
            ("fn", fn_line),
            ("if", if_line),
            ("base", base_line),
            ("else", else_line),
            ("rec", rec),
        ]).move_to(m.ORIGIN)