gt22 icon

Untitled

gt22 | PRO | 06/12/19 02:03:01 PM UTC | 0 ⭐ | 1229 👁️ | Never ⏰ | []
Python |

5.4 KB

|

None

|

0 👍

/

0 👎

from big_ol_pile_of_manim_imports import *
 
 
def p(x=0, y=0):
    if type(x) == list or type(x) == tuple or type(x) == np.ndarray:
        return np.array(x)
    return np.array((x, y, 0))
 
 
def near(mobj, edge=ORIGIN):
    return mobj.get_critical_point(edge)
 
 
def comp(x=(0, 0, 0), y=(0, 0, 0)):
    return p(x[0], y[1])
 
 
class MMScene(Scene):
 
    m1 = np.array([[1, 2], [2, 9]])
    m2 = np.array([[2, 4, 3], [6, 8, 3]])
    res_a, res_b, num_steps = None, None, None
    res_data = None
    x, y, res = None, None, None
 
    def construct(self):
        if self.m1.shape[1] != self.m2.shape[0]:
            raise ValueError("Invalid matrices")
 
        self.res_a = self.m1.shape[0]
        self.res_b = self.m2.shape[1]
        self.num_steps = self.m1.shape[1]
 
        self.create_xy_matrices()
        self.wait(0.5)
        self.shift_y_matrix()
        self.create_res_matrix()
        self.wait(0.5)
        self.perform_multiplication()
        self.wait(1)
        self.clean_up()
        self.wait(3)
 
    def create_xy_matrices(self):
        self.x = IntegerMatrix(self.m1)
        self.x.move_to(p(-0.1), RIGHT)
        self.y = IntegerMatrix(self.m2)
        self.y.move_to(p(0.1), LEFT)
        self.play(FadeIn(self.x), FadeIn(self.y))
 
    def shift_y_matrix(self):
        yc = self.y.copy()
        yc.shift(p(y=self.x.get_height() + 0.1))
        self.play(Transform(self.y, yc, lag_ration=0))
        self.remove(self.y)
        self.add(yc)
        self.y = yc
 
    def create_res_matrix(self):
        self.res_data = np.zeros((self.res_a, self.res_b), dtype=int)
        self.res = IntegerMatrix(self.res_data)
        self.res.move_to(comp(near(self.y), near(self.x)))
        self.play(FadeIn(self.res))
 
    def perform_multiplication(self):
        for i in range(self.res_a):
            for j in range(self.res_b):
                self.calc_res_elem(i, j)
 
    def clean_up(self):
        rc = self.res.copy()
        rc.move_to(ORIGIN)
        self.play(FadeOut(self.x), FadeOut(self.y), Transform(self.res, rc))
        self.remove(self.x, self.y, self.res)
        self.add(rc)
        self.res = rc
 
    def circle_matrix(self, m: Matrix, elem: int, color='red'):
        e = m.get_entries()[elem]
        c = Circle(radius=max(e.get_width(), e.get_height()) / 2 + 0.2, color=color)
        c.move_to(e)
        return c
 
    def calc_res_elem(self, x, y):
        elem = self.res_data.shape[1] * x + y
        res_tex = TexMobject(str(self.res_data[x, y]))
        tex_pos = comp(y=near(self.x, DOWN) - 0.1)
        res_tex.set_color(GREEN)
        res_tex.move_to(tex_pos, UP)
        c = self.circle_matrix(self.res, elem, 'green')
        self.play(ShowCreation(c, run_time=0.5))
        self.play(Write(res_tex, run_time=0.5))
        xcp, ycp = None, None
        for step in range(self.num_steps):
            x_elem = self.m1.shape[1] * x + step
            y_elem = self.m2.shape[1] * step + y
 
            a, b = self.m1[x, step], self.m2[step, y]
            dr = a * b
            self.res_data[x, y] += dr
 
            xcp, ycp = self.calc_step(x_elem, y_elem, xcp, ycp)
 
            res_tex = self.display_multiplication_tex(res_tex, a, b, dr, self.res_data[x, y])
 
            self.res, c = self.update_res_matrix(c, elem)
 
        self.play(*[FadeOut(g) for g in [c, xcp, ycp, res_tex]])
        self.remove(c, xcp, ycp, res_tex)
 
    def update_res_matrix(self, c, elem):
        rm = IntegerMatrix(self.res_data)
        rm.move_to(self.res)
        cc = self.circle_matrix(rm, elem, 'green')
        self.play(Transform(self.res, rm), Transform(c, cc))
        self.remove(self.res, c)
        self.add(rm, cc)
        return rm, cc
 
    def display_multiplication_tex(self, res_tex, a, b, dr, res):
        cur_res = res_tex.get_tex_string()
        rtm = TexMobject(f"_{{}}{cur_res}+{a}_{{}}\\times{b}^{{}}", tex_to_color_map={
            f'{a}_{{}}': RED,
            f'{b}^{{}}': YELLOW,
            f'_{{}}{cur_res}': GREEN
        })
        rtm.move_to(res_tex, UP)
        rta = TexMobject(f"{cur_res}^{{}}+{dr}_{{}}", tex_to_color_map={
            f"{cur_res}^{{}}": GREEN,
            f"{dr}_{{}}": ORANGE
        })
        rta.move_to(res_tex, UP)
        rt = TexMobject(str(res))
        rt.set_color(GREEN)
        rt.move_to(res_tex, UP)
        self.chain_transorm([res_tex, rtm, rta, rt], 0.5, run_time=0.7)
        return rt
 
    def chain_transorm(self, mobjs, wait_time, **kwargs):
        for a, b in zip(mobjs, mobjs[1:]):
            self.play(Transform(a, b, **kwargs))
            self.remove(a)
            self.add(b)
            self.wait(wait_time)
 
    def calc_step(self, x_elem, y_elem, xcp, ycp):
 
        if xcp is None or ycp is None:
            xc = self.circle_matrix(self.x, x_elem)
            yc = self.circle_matrix(self.y, y_elem, 'yellow')
            self.play(*[ShowCreation(a, run_time=0.5) for a in (xc, yc)])
        else:
            xc = self.update_circle(xcp, self.x, x_elem)
            yc = self.update_circle(ycp, self.y, y_elem)
 
            self.play(*[Transform(a, b, run_time=0.7, lag_ratio=0) for a, b in ((xcp, xc), (ycp, yc))])
            self.remove(xcp, ycp)
            self.add(xc, yc)
        return xc, yc
 
    @staticmethod
    def update_circle(c, m, e):
        cc = c.copy()
        cc.move_to(m.get_entries()[e])
        return cc

Comments