Files
2019-05-02 20:36:14 -07:00

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