def construct(self): circle = manim.Circle() circle.set_fill(manim.PINK, opacity=0.5) square = manim.Square() square.flip(manim.RIGHT) square.rotate(-3 * manim.TAU / 8) self.play(manim.ShowCreation(square)) self.play(manim.Transform(square, circle)) self.play(manim.FadeOut(square))
def construct_def_box(self): """Construct the function's definition in a box""" fact = self.get_def() rect = ThinRectangle().surround(fact, stretch=True) self.play(m.Write(fact)) self.play(m.ShowCreation(rect)) self.def_box = m.VDict([("function", fact), ("box", rect)]) self.def_box.generate_target().scale(self.def_scale_ratio).to_corner( m.UL) self.play(m.MoveToTarget(self.def_box))
def construct_def_box(self) -> None: """Show the creation of the OCaml definiton, with a box""" # Create the function definition and its rectangular box self.def_box = m.VDict([("function", self.get_def())]) self.def_box.add([ ("box", ThinRectangle(height=1.5).surround(self.def_box["function"])) ]) # Animate the creations self.play(m.Write(self.def_box["function"])) self.play(m.ShowCreation(self.def_box["box"])) # Move and scale down to up-left corner of the scene self.def_box.generate_target() self.def_box.target.scale(self.def_scale_ratio).to_corner(m.UL) self.play(m.MoveToTarget(self.def_box))
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))
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), )
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"]