mirror of
https://github.com/3b1b/manim.git
synced 2025-07-30 13:34:19 +08:00
223 lines
7.5 KiB
Python
223 lines
7.5 KiB
Python
from fractions import Fraction
|
|
|
|
from manimlib.imports import *
|
|
from functools import reduce
|
|
|
|
|
|
class FractionMobject(VGroup):
|
|
CONFIG = {
|
|
"max_height": 1,
|
|
}
|
|
|
|
def __init__(self, fraction, **kwargs):
|
|
VGroup.__init__(self, **kwargs)
|
|
numerator = self.numerator = Integer(fraction.numerator)
|
|
self.add(numerator)
|
|
if fraction.denominator != 1:
|
|
denominator = Integer(fraction.denominator)
|
|
line = TexMobject("/")
|
|
numerator.next_to(line, LEFT, SMALL_BUFF)
|
|
denominator.next_to(line, RIGHT, SMALL_BUFF)
|
|
self.add(numerator, line, denominator)
|
|
self.set_height(min(self.max_height, self.get_height()))
|
|
self.value = fraction
|
|
|
|
def add_plus_if_needed(self):
|
|
if self.value > 0:
|
|
plus = TexMobject("+")
|
|
plus.next_to(self, LEFT, SMALL_BUFF)
|
|
plus.match_color(self)
|
|
self.add_to_back(plus)
|
|
|
|
|
|
class ShowRowReduction(Scene):
|
|
CONFIG = {
|
|
"matrices": [
|
|
[
|
|
[2, -1, -1],
|
|
[0, 3, -4],
|
|
[-3, 2, 1],
|
|
],
|
|
[
|
|
[1, 0, 0],
|
|
[0, 1, 0],
|
|
[0, 0, 1],
|
|
],
|
|
# [[1], [2], [3]],
|
|
],
|
|
"h_spacing": 2,
|
|
"extra_h_spacing": 0.5,
|
|
"v_spacing": 1,
|
|
"include_separation_lines": True,
|
|
"changing_row_color": YELLOW,
|
|
"reference_row_color": BLUE,
|
|
}
|
|
|
|
def construct(self):
|
|
self.initialize_terms()
|
|
|
|
self.apply_row_rescaling(0, Fraction(1, 2))
|
|
self.add_row_multiple_to_row(2, 0, 3)
|
|
self.apply_row_rescaling(1, Fraction(1, 3))
|
|
self.add_row_multiple_to_row(2, 1, Fraction(-1, 2))
|
|
self.apply_row_rescaling(2, Fraction(6))
|
|
self.add_row_multiple_to_row(0, 1, Fraction(1, 2))
|
|
self.add_row_multiple_to_row(0, 2, Fraction(7, 6))
|
|
self.add_row_multiple_to_row(1, 2, Fraction(4, 3))
|
|
self.wait()
|
|
|
|
def initialize_terms(self):
|
|
full_matrix = reduce(
|
|
lambda m, v: np.append(m, v, axis=1),
|
|
self.matrices
|
|
)
|
|
mobject_matrix = np.vectorize(FractionMobject)(full_matrix)
|
|
rows = self.rows = VGroup(*it.starmap(VGroup, mobject_matrix))
|
|
for i, row in enumerate(rows):
|
|
for j, term in enumerate(row):
|
|
term.move_to(
|
|
i * self.v_spacing * DOWN +
|
|
j * self.h_spacing * RIGHT
|
|
)
|
|
|
|
# Visually seaprate distinct parts
|
|
separation_lines = self.separation_lines = VGroup()
|
|
lengths = [len(m[0]) for m in self.matrices]
|
|
for partial_sum in np.cumsum(lengths)[:-1]:
|
|
VGroup(*mobject_matrix[:, partial_sum:].flatten()).shift(
|
|
self.extra_h_spacing * RIGHT
|
|
)
|
|
c1 = VGroup(*mobject_matrix[:, partial_sum - 1])
|
|
c2 = VGroup(*mobject_matrix[:, partial_sum])
|
|
line = DashedLine(c1.get_top(), c1.get_bottom())
|
|
line.move_to(VGroup(c1, c2))
|
|
separation_lines.add(line)
|
|
|
|
if self.include_separation_lines:
|
|
group = VGroup(rows, separation_lines)
|
|
else:
|
|
group = rows
|
|
group.center().to_edge(DOWN, buff=2)
|
|
self.add(group)
|
|
|
|
def add_variables(self):
|
|
# If it is meant to represent a system of equations
|
|
pass
|
|
|
|
def apply_row_rescaling(self, row_index, scale_factor):
|
|
row = self.rows[row_index]
|
|
new_row = VGroup()
|
|
for element in row:
|
|
target = FractionMobject(element.value * scale_factor)
|
|
target.move_to(element)
|
|
new_row.add(target)
|
|
new_row.set_color(self.changing_row_color)
|
|
|
|
label = VGroup(
|
|
TexMobject("r_%d" % (row_index + 1)),
|
|
TexMobject("\\rightarrow"),
|
|
TexMobject("("),
|
|
FractionMobject(scale_factor),
|
|
TexMobject(")"),
|
|
TexMobject("r_%d" % (row_index + 1)),
|
|
)
|
|
label.arrange(RIGHT, buff=SMALL_BUFF)
|
|
label.to_edge(UP)
|
|
VGroup(label[0], label[-1]).set_color(self.changing_row_color)
|
|
|
|
scalar_mob = FractionMobject(scale_factor)
|
|
scalar_mob.add_to_back(
|
|
TexMobject("\\times").next_to(scalar_mob, LEFT, SMALL_BUFF)
|
|
)
|
|
scalar_mob.scale(0.5)
|
|
scalar_mob.next_to(row[0], DR, SMALL_BUFF)
|
|
|
|
# Do do, fancier illustrations here
|
|
self.play(
|
|
FadeIn(label),
|
|
row.set_color, self.changing_row_color,
|
|
)
|
|
self.play(FadeIn(scalar_mob))
|
|
for elem, new_elem in zip(row, new_row):
|
|
self.play(scalar_mob.next_to, elem, DR, SMALL_BUFF)
|
|
self.play(ReplacementTransform(elem, new_elem, path_arc=30 * DEGREES))
|
|
self.play(FadeOut(scalar_mob))
|
|
self.play(new_row.set_color, WHITE)
|
|
self.play(FadeOut(label))
|
|
self.rows.submobjects[row_index] = new_row
|
|
|
|
def add_row_multiple_to_row(self, row1_index, row2_index, scale_factor):
|
|
row1 = self.rows[row1_index]
|
|
row2 = self.rows[row2_index]
|
|
new_row1 = VGroup()
|
|
scaled_row2 = VGroup()
|
|
for elem1, elem2 in zip(row1, row2):
|
|
target = FractionMobject(elem1.value + scale_factor * elem2.value)
|
|
target.move_to(elem1)
|
|
new_row1.add(target)
|
|
|
|
scaled_term = FractionMobject(scale_factor * elem2.value)
|
|
scaled_term.move_to(elem2)
|
|
scaled_row2.add(scaled_term)
|
|
new_row1.set_color(self.changing_row_color)
|
|
scaled_row2.set_color(self.reference_row_color)
|
|
|
|
for elem1, elem2 in zip(row1, scaled_row2):
|
|
elem2.add_plus_if_needed()
|
|
elem2.scale(0.5)
|
|
elem2.next_to(elem1, UL, buff=SMALL_BUFF)
|
|
|
|
label = VGroup(
|
|
TexMobject("r_%d" % (row1_index + 1)),
|
|
TexMobject("\\rightarrow"),
|
|
TexMobject("r_%d" % (row1_index + 1)),
|
|
TexMobject("+"),
|
|
TexMobject("("),
|
|
FractionMobject(scale_factor),
|
|
TexMobject(")"),
|
|
TexMobject("r_%d" % (row2_index + 1)),
|
|
)
|
|
label.arrange(RIGHT, buff=SMALL_BUFF)
|
|
label.to_edge(UP)
|
|
VGroup(label[0], label[2]).set_color(self.changing_row_color)
|
|
label[-1].set_color(self.reference_row_color)
|
|
|
|
self.play(
|
|
FadeIn(label),
|
|
row1.set_color, self.changing_row_color,
|
|
row2.set_color, self.reference_row_color,
|
|
)
|
|
row1.target.next_to(self.rows, UP, buff=2)
|
|
row1.target.align_to(row1, LEFT)
|
|
|
|
row2.target.next_to(row1.target, DOWN, buff=MED_LARGE_BUFF)
|
|
lp, rp = row2_parens = TexMobject("()")
|
|
row2_parens.set_height(row2.get_height() + 2 * SMALL_BUFF)
|
|
lp.next_to(row2, LEFT, SMALL_BUFF)
|
|
rp.next_to(row2, RIGHT, SMALL_BUFF)
|
|
scalar = FractionMobject(scale_factor)
|
|
scalar.next_to(lp, LEFT, SMALL_BUFF)
|
|
scalar.add_plus_if_needed()
|
|
|
|
self.play(
|
|
FadeIn(row2_parens),
|
|
Write(scalar),
|
|
)
|
|
self.play(ReplacementTransform(row2.copy(), scaled_row2))
|
|
self.wait()
|
|
for elem, new_elem, s_elem in zip(row1, new_row1, scaled_row2):
|
|
self.play(
|
|
FadeOut(elem),
|
|
FadeIn(new_elem),
|
|
Transform(s_elem, new_elem.copy().fade(1), remover=True)
|
|
)
|
|
self.wait()
|
|
self.play(
|
|
FadeOut(label),
|
|
FadeOut(row2_parens),
|
|
FadeOut(scalar),
|
|
new_row1.set_color, WHITE,
|
|
row2.set_color, WHITE,
|
|
)
|
|
self.rows.submobjects[row1_index] = new_row1
|