From 381950277958ea7757a9fbf8b1f62c4cd74dc96a Mon Sep 17 00:00:00 2001 From: Grant Sanderson Date: Tue, 12 May 2015 14:51:21 -0700 Subject: [PATCH] MoserSolutionInPascal --- Images/logo.png | Bin 0 -> 72651 bytes constants.py | 2 +- image_mobject.py | 5 +- moser/main.py | 145 ++++++++++++ moser/main.py~ | 518 +++++++++++++++++++++++++++++++++++++++++ moser/moser_helpers.py | 67 +++--- script_wrapper.py | 2 +- 7 files changed, 705 insertions(+), 34 deletions(-) create mode 100644 Images/logo.png create mode 100644 moser/main.py~ diff --git a/Images/logo.png b/Images/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..58d941a61a57cecb409f11547ba55964f60dd513 GIT binary patch literal 72651 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 literal 0 HcmV?d00001 diff --git a/constants.py b/constants.py index 87da6960..0820efa3 100644 --- a/constants.py +++ b/constants.py @@ -32,7 +32,7 @@ DEFAULT_DITHER_TIME = 1.0 DEFAULT_NUM_STARS = 1000 SPACE_HEIGHT = 4.0 -SPACE_WIDTH = DEFAULT_WIDTH * DEFAULT_HEIGHT / DEFAULT_WIDTH +SPACE_WIDTH = SPACE_HEIGHT * DEFAULT_WIDTH / DEFAULT_HEIGHT THIS_DIR = os.path.dirname(os.path.realpath(__file__)) IMAGE_DIR = os.path.join(THIS_DIR, "images") diff --git a/image_mobject.py b/image_mobject.py index dc9eacbd..21fa70c3 100644 --- a/image_mobject.py +++ b/image_mobject.py @@ -96,16 +96,17 @@ def tex_mobject(expression, size = r"\HUGE"): return tex_mobjects(expression, size) def tex_mobjects(expression, size = r"\HUGE"): + scale_value = 2 images = tex_to_image(expression, size) if isinstance(images, list): #TODO, is checking listiness really the best here? - result = [ImageMobject(im).scale(2) for im in images] + result = [ImageMobject(im).scale(scale_value) for im in images] center = CompoundMobject(*result).get_center() for mob in result: mob.shift(-center) return result else: - return ImageMobject(images).center().scale(2) + return ImageMobject(images).center().scale(scale_value) diff --git a/moser/main.py b/moser/main.py index 2483240c..66d80501 100644 --- a/moser/main.py +++ b/moser/main.py @@ -629,6 +629,66 @@ class PascalsTriangleWithNChooseK(PascalsTriangleScene): self.remove(*self.mobjects) self.add(*[mob_dicts[1-i][n][k] for n, k in self.coords]) +class PascalsTriangleNChooseKExample(PascalsTriangleScene): + args_list = [ + (N_PASCAL_ROWS, 5, 3), + ] + @staticmethod + def args_to_string(nrows, n, k): + return "%d_n=%d_k=%d"%(nrows, n, k) + + def __init__(self, nrows, n, k, *args, **kwargs): + PascalsTriangleScene.__init__(self, nrows, *args, **kwargs) + dither_time = 0.5 + triangle_terms = [self.coords_to_mobs[a][b] for a, b in self.coords] + formula_terms = left, n_mob, k_mob, right = tex_mobject([ + r"\left(", str(n), r"\atop %d"%k, r"\right)" + ]) + formula_center = (SPACE_WIDTH - 1, SPACE_HEIGHT - 1, 0) + self.remove(*triangle_terms) + self.add(*formula_terms) + self.dither() + self.animate(* + [ + ShowCreation(mob) for mob in triangle_terms + ]+[ + ApplyMethod((Mobject.shift, formula_center), mob) + for mob in formula_terms + ], + run_time = 1.0 + ) + self.remove(n_mob, k_mob) + for a in range(n+1): + row = [self.coords_to_mobs[a][b] for b in range(a+1)] + a_mob = tex_mobject(str(a)) + a_mob.shift(n_mob.get_center()) + a_mob.highlight("green") + self.add(a_mob) + for mob in row: + mob.highlight("green") + self.dither(dither_time) + if a < n: + for mob in row: + mob.highlight("white") + self.remove(a_mob) + self.dither() + for b in range(k+1): + b_mob = tex_mobject(str(b)) + b_mob.shift(k_mob.get_center()) + b_mob.highlight("yellow") + self.add(b_mob) + self.coords_to_mobs[n][b].highlight("yellow") + self.dither(dither_time) + if b < k: + self.coords_to_mobs[n][b].highlight("green") + self.remove(b_mob) + self.animate(*[ + ApplyMethod((Mobject.fade, 0.2), mob) + for mob in triangle_terms + if mob != self.coords_to_mobs[n][k] + ]) + self.dither() + class PascalsTriangleSumRows(PascalsTriangleScene): def __init__(self, *args, **kwargs): PascalsTriangleScene.__init__(self, *args, **kwargs) @@ -690,6 +750,91 @@ class PascalsTriangleSumRows(PascalsTriangleScene): self.add(powers_of_two_symbols[n]) +class MoserSolutionInPascal(PascalsTriangleScene): + args_list = [ + (N_PASCAL_ROWS, n) + for n in range(3, 8) + ] + [ + (BIG_N_PASCAL_ROWS, 10) + ] + @staticmethod + def args_to_string(nrows, n): + return "%d_n=%d"%(nrows,n) + + def __init__(self, nrows, n, *args, **kwargs): + PascalsTriangleScene.__init__(self, nrows, *args, **kwargs) + term_color = "green" + self.generate_n_choose_k_mobs() + self.remove(*[self.coords_to_mobs[n0][k0] for n0, k0 in self.coords]) + terms = one, plus0, n_choose_2, plus1, n_choose_4 = tex_mobjects([ + "1", "+", r"{%d \choose 2}"%n, "+", r"{%d \choose 4}"%n + ]) + target_terms = [] + for k in range(len(terms)): + if k%2 == 0 and k <= n: + new_term = deepcopy(self.coords_to_n_choose_k[n][k]) + new_term.highlight(term_color) + else: + new_term = Point( + self.coords_to_center(n, k) + ) + target_terms.append(new_term) + self.add(*terms) + self.dither() + self.animate(* + [ + FadeIn(self.coords_to_n_choose_k[n0][k0]) + for n0, k0 in self.coords + if (n0, k0) not in [(n, 0), (n, 2), (n, 4)] + ]+[ + Transform(term, target_term) + for term, target_term in zip(terms, target_terms) + ] + ) + self.dither() + term_range = range(0, min(4, n)+1, 2) + target_terms = dict([ + (k, deepcopy(self.coords_to_mobs[n][k]).highlight(term_color)) + for k in term_range + ]) + self.animate(* + [ + SemiCircleTransform( + self.coords_to_n_choose_k[n0][k0], + self.coords_to_mobs[n0][k0] + ) + for n0, k0 in self.coords + if (n0, k0) not in [(n, k) for k in term_range] + ]+[ + SemiCircleTransform(terms[k], target_terms[k]) + for k in term_range + ] + ) + self.dither() + for k in term_range: + if k == 0: + above_terms = [self.coords_to_n_choose_k[n-1][k]] + elif k == n: + above_terms = [self.coords_to_n_choose_k[n-1][k-1]] + else: + above_terms = [ + self.coords_to_n_choose_k[n-1][k-1], + self.coords_to_n_choose_k[n-1][k], + ] + self.add(self.coords_to_mobs[n][k]) + self.animate(Transform( + terms[k], + CompoundMobject(*above_terms).highlight(term_color) + )) + self.remove(*above_terms) + self.dither() + terms_sum = tex_mobject(str(moser_function(n))) + terms_sum.shift((SPACE_WIDTH-1, terms[0].get_center()[1], 0)) + terms_sum.highlight(term_color) + self.animate(Transform(CompoundMobject(*terms), terms_sum)) + + + ################################################## if __name__ == "__main__": diff --git a/moser/main.py~ b/moser/main.py~ new file mode 100644 index 00000000..e3b90107 --- /dev/null +++ b/moser/main.py~ @@ -0,0 +1,518 @@ +#!/usr/bin/env python + +import numpy as np +import itertools as it +import operator as op +from copy import deepcopy +from random import random + + +from animation import * +from mobject import * +from image_mobject import * +from constants import * +from region import * +from scene import Scene + +from moser_helpers import * +from graphs import * + +RADIUS = SPACE_HEIGHT - 0.1 +CIRCLE_DENSITY = DEFAULT_POINT_DENSITY_1D*RADIUS + +movie_prefix = "moser/" + +############################################ + +class CircleScene(Scene): + def __init__(self, radians, *args, **kwargs): + Scene.__init__(self, *args, **kwargs) + self.radius = RADIUS + self.circle = Circle(density = CIRCLE_DENSITY).scale(self.radius) + self.points = [ + (self.radius * np.cos(angle), self.radius * np.sin(angle), 0) + for angle in radians + ] + self.dots = [Dot(point) for point in self.points] + self.lines = [Line(p1, p2) for p1, p2 in it.combinations(self.points, 2)] + self.add(self.circle, *self.dots + self.lines) + +class GraphScene(Scene): + #Note, the placement of vertices in this is pretty hard coded, be + #warned if you want to change it. + def __init__(self, graph, *args, **kwargs): + Scene.__init__(self, *args, **kwargs) + #See CUBE_GRAPH above for format of graph + self.graph = graph + self.points = map(np.array, graph["vertices"]) + self.vertices = self.dots = [Dot(p) for p in self.points] + self.edges = [ + Line(self.points[i], self.points[j]) + for i, j in graph["edges"] + ] + self.add(*self.dots + self.edges) + + def generate_regions(self): + regions = [ + region_from_line_boundary(*[ + [ + self.points[rc[i]], + self.points[rc[(i+1)%len(rc)]] + ] + for i in range(len(rc)) + ]) + for rc in self.graph["region_cycles"] + ] + regions[-1].complement()#Outer region painted outwardly... + self.regions = regions + +################################################## + +def count_lines(*radians): + #TODO, Count things explicitly? + sc = CircleScene(radians) + text_center = (sc.radius + 1, sc.radius -1, 0) + scale_factor = 0.4 + text = tex_mobject(r"\text{How Many Lines?}", size = r"\large") + n = len(radians) + formula, answer = tex_mobject([ + r"{%d \choose 2} = \frac{%d(%d - 1)}{2} = "%(n, n, n), + str(choose(n, 2)) + ]) + text.scale(scale_factor).shift(text_center) + x = text_center[0] + new_lines = [ + Line((x-1, y, 0), (x+1, y, 0)) + for y in np.arange( + -(sc.radius - 1), + sc.radius - 1, + (2*sc.radius - 2)/len(sc.lines) + ) + ] + sc.add(text) + sc.dither() + sc.animate(*[ + Transform(line1, line2, run_time = 2) + for line1, line2 in zip(sc.lines, new_lines) + ]) + sc.dither() + sc.remove(text) + sc.count(new_lines) + anims = [FadeIn(formula)] + for mob in sc.mobjects: + if mob == sc.number: #put in during animate_count + anims.append(Transform(mob, answer)) + else: + anims.append(FadeOut(mob)) + sc.animate(*anims, run_time = 1) + sc.write_to_movie(movie_prefix + "CountLines%dPoints"%len(radians)) + + +def count_intersection_points(*radians): + radians = [r % (2*np.pi) for r in radians] + radians.sort() + sc = CircleScene(radians) + intersection_points = [ + intersection((p[0], p[2]), (p[1], p[3])) + for p in it.combinations(sc.points, 4) + ] + intersection_dots = [Dot(point) for point in intersection_points] + text_center = (sc.radius + 0.5, sc.radius -0.5, 0) + size = r"\large" + scale_factor = 0.4 + text = tex_mobject(r"\text{How Many Intersection Points?}", size = size) + n = len(radians) + formula, answer = tex_mobjects([ + r"{%d \choose 4} = \frac{%d(%d - 1)(%d - 2)(%d-3)}{1\cdot 2\cdot 3 \cdot 4}="%(n, n, n, n, n), + str(choose(n, 4)) + ]) + text.scale(scale_factor).shift(text_center) + # new_points = [ + # (text_center[0], y, 0) + # for y in np.arange( + # -(sc.radius - 1), + # sc.radius - 1, + # (2*sc.radius - 2)/choose(len(sc.points), 4) + # ) + # ] + # new_dots = CompoundMobject(*[ + # Dot(point) for point in new_points + # ]) + + sc.add(text) + sc.count(intersection_dots, "show", num_offset = (0, 0, 0)) + sc.dither() + # sc.animate(Transform(intersection_dots, new_dots)) + anims = [] + for mob in sc.mobjects: + if mob == sc.number: #put in during animate_count + anims.append(Transform(mob, answer)) + else: + anims.append(FadeOut(mob)) + anims.append(Animation(formula)) + sc.animate(*anims, run_time = 1) + + name = "CountIntersectionPoints%dPoints"%len(radians) + sc.write_to_movie(movie_prefix + name) + +def non_general_position(): + radians = np.arange(1, 7) + new_radians = (np.pi/3)*radians + sc1 = CircleScene(radians) + sc2 = CircleScene(new_radians) + center_region = reduce( + Region.intersect, + [ + HalfPlane((sc1.points[x], sc1.points[(x+3)%6])) + for x in [0, 4, 2]#Ya know, trust it + ] + ) + center_region + text = tex_mobject(r"\text{This region disappears}", size = r"\large") + text.center().scale(0.5).shift((-sc1.radius, sc1.radius-0.3, 0)) + arrow = Arrow( + point = (-0.35, -0.1, 0), + direction = (1, -1, 0), + length = sc1.radius + 1, + color = "white", + ) + + sc1.highlight_region(center_region, "green") + sc1.add(text, arrow) + sc1.dither(2) + sc1.remove(text, arrow) + sc1.reset_background() + sc1.animate(*[ + Transform(mob1, mob2, run_time = DEFAULT_ANIMATION_RUN_TIME) + for mob1, mob2 in zip(sc1.mobjects, sc2.mobjects) + ]) + sc1.write_to_movie(movie_prefix + "NonGeneralPosition") + +def line_corresponds_with_pair(radians, r1, r2): + sc = CircleScene(radians) + #Remove from sc.lines list, so they won't be faded out + assert r1 in radians and r2 in radians + line_index = list(it.combinations(radians, 2)).index((r1, r2)) + radians = list(radians) + dot0_index, dot1_index = radians.index(r1), radians.index(r2) + line, dot0, dot1 = sc.lines[line_index], sc.dots[dot0_index], sc.dots[dot1_index] + sc.lines.remove(line) + sc.dots.remove(dot0) + sc.dots.remove(dot1) + sc.dither() + sc.animate(*[ + FadeOut(mob, alpha_func = not_quite_there) + for mob in sc.lines + sc.dots + ]) + sc.add(sc.circle) + sc.animate(*[ + ScaleInPlace(mob, 3, alpha_func = there_and_back) + for mob in (dot0, dot1) + ]) + sc.animate(Transform(line, dot0)) + name = "LineCorrspondsWithPair%d%d"%(dot0_index, dot1_index) + sc.write_to_movie(movie_prefix + name) + +def illustrate_n_choose_k(n, k): + sc = Scene() + nrange = range(1, n+1) + tuples = list(it.combinations(nrange, k)) + nrange_mobs = tex_mobjects([str(n) + r'\;' for n in nrange]) + tuple_mobs = tex_mobjects( + [ + (r'\\&' if c%(20//k) == 0 else r'\;\;') + str(p) + for p, c in zip(tuples, it.count()) + ], + size = r"\small" + ) + tuple_terms = { + 2 : "pairs", + 3 : "triplets", + 4 : "quadruplets", + } + tuple_term = tuple_terms[k] if k in tuple_terms else "tuples" + form1, count, form2 = tex_mobject([ + r"{%d \choose %d} = "%(n, k), + "%d"%choose(n, k), + r" \text{ total %s}"%tuple_term + ]) + for mob in nrange_mobs: + mob.shift((0, 2, 0)) + for mob in form1, count, form2: + mob.shift((0, -SPACE_HEIGHT + 1, 0)) + count_center = count.get_center() + for mob in tuple_mobs: + mob.scale(0.6) + + sc.add(*nrange_mobs) + sc.dither() + run_time = 6.0 + frame_time = run_time / len(tuples) + for tup, count in zip(tuples, it.count()): + count_mob = tex_mobject(str(count+1)) + count_mob.center().shift(count_center) + sc.add(count_mob) + tuple_copy = CompoundMobject(*[nrange_mobs[index-1] for index in tup]) + tuple_copy.highlight() + sc.add(tuple_copy) + sc.add(tuple_mobs[count]) + sc.dither(frame_time) + sc.remove(count_mob) + sc.remove(tuple_copy) + sc.add(count_mob) + sc.animate(FadeIn(CompoundMobject(form1, form2))) + sc.write_to_movie(movie_prefix + "Illustrate%dChoose%d"%(n, k)) + +def intersection_point_correspondances(radians, indices): + assert(len(indices) == 4) + indices.sort() + sc = CircleScene(radians) + intersection_point = intersection( + (sc.points[indices[0]], sc.points[indices[2]]), + (sc.points[indices[1]], sc.points[indices[3]]) + ) + intersection_point = tuple(list(intersection_point) + [0]) + intersection_dot = Dot(intersection_point) + intersection_dot_arrow = Arrow(intersection_point).nudge() + sc.add(intersection_dot) + pairs = list(it.combinations(range(len(radians)), 2)) + lines_to_save = [ + sc.lines[pairs.index((indices[p0], indices[p1]))] + for p0, p1 in [(0, 2), (1, 3)] + ] + dots_to_save = [ + sc.dots[p] + for p in indices + ] + line_statement = tex_mobject(r"\text{Pair of Lines}") + dots_statement = tex_mobject(r"&\text{Quadruplet of} \\ &\text{outer dots}") + for mob in line_statement, dots_statement: + mob.center() + mob.scale(0.7) + mob.shift((SPACE_WIDTH-2, SPACE_HEIGHT - 1, 0)) + fade_outs = [] + line_highlights = [] + dot_highlights = [] + dot_pointers = [] + for mob in sc.mobjects: + if mob in lines_to_save: + line_highlights.append(Highlight(mob)) + elif mob in dots_to_save: + dot_highlights.append(Highlight(mob)) + dot_pointers.append(Arrow(mob.get_center()).nudge()) + elif mob != intersection_dot: + fade_outs.append(FadeOut(mob, alpha_func = not_quite_there)) + + sc.add(intersection_dot_arrow) + sc.animate(Highlight(intersection_dot)) + sc.remove(intersection_dot_arrow) + sc.animate(*fade_outs) + sc.dither() + sc.add(line_statement) + sc.animate(*line_highlights) + sc.remove(line_statement) + sc.dither() + sc.add(dots_statement, *dot_pointers) + sc.animate(*dot_highlights) + sc.remove(dots_statement, *dot_pointers) + + name = "IntersectionPointCorrespondances" + for ind in indices: + name += str(ind) + sc.write_to_movie(movie_prefix + name) + +def lines_intersect_outside(radians, indices): + assert(len(indices) == 4) + indices.sort() + sc = CircleScene(radians) + intersection_point = intersection( + (sc.points[indices[0]], sc.points[indices[1]]), + (sc.points[indices[2]], sc.points[indices[3]]) + ) + intersection_point = tuple(list(intersection_point) + [0]) + intersection_dot = Dot(intersection_point) + pairs = list(it.combinations(range(len(radians)), 2)) + lines_to_save = [ + sc.lines[pairs.index((indices[p0], indices[p1]))] + for p0, p1 in [(0, 1), (2, 3)] + ] + sc.animate(*[ + FadeOut(mob, alpha_func = not_quite_there) + for mob in sc.mobjects if mob not in lines_to_save + ]) + sc.animate(*[ + Transform( + Line(sc.points[indices[p0]], sc.points[indices[p1]]), + Line(sc.points[indices[p0]], intersection_point)) + for p0, p1 in [(0, 1), (3, 2)] + ] + [ShowCreation(intersection_dot)]) + + name = "LinesIntersectOutside" + for ind in indices: + name += str(ind) + sc.write_to_movie(movie_prefix + name) + +def quadruplets_to_intersections(*radians): + sc = CircleScene(radians) + quadruplets = it.combinations(range(len(radians)), 4) + frame_time = 1.0 + for quad in quadruplets: + intersection_dot = Dot(intersection( + (sc.points[quad[0]], sc.points[quad[2]]), + (sc.points[quad[1]], sc.points[quad[3]]) + )).repeat(3) + dot_quad = [deepcopy(sc.dots[i]) for i in quad] + for dot in dot_quad: + dot.scale_in_place(2) + # arrows = [Arrow(d.get_center()) for d in dot_quad] + dot_quad = CompoundMobject(*dot_quad) + # arrows = CompoundMobject(*arrows) + dot_quad.highlight() + # sc.add(arrows) + sc.add(dot_quad) + sc.dither(frame_time / 3) + sc.animate(Transform( + dot_quad, + intersection_dot, + run_time = 3*frame_time/2 + )) + # sc.remove(arrows) + + name = "QuadrupletsToIntersections" + str(len(radians)) + sc.write_to_movie(movie_prefix + name) + +def defining_graph(graph): + gs = GraphScene(graph) + dots, lines = gs.vertices, gs.edges + gs.remove(*dots + lines) + all_dots = CompoundMobject(*dots) + gs.animate(ShowCreation(all_dots)) + gs.remove(all_dots) + gs.add(*dots) + gs.dither() + gs.animate(*[ + ShowCreation(line) for line in lines + ]) + + #Move to new graph + new_graph = deepcopy(graph) + new_graph["vertices"] = [ + (v[0] + 3*random(), v[1] + 3*random(), 0) + for v in new_graph["vertices"] + ] + ngs = GraphScene(new_graph) + gs.animate(*[ + Transform(m[0], m[1]) + for m in zip(gs.mobjects, ngs.mobjects) + ], run_time = 7.0) + + name = "DefiningGraph" + graph["name"] + gs.write_to_movie(movie_prefix + name) + +def doubled_edges(graph): + gs = GraphScene(graph) + lines_to_double = gs.edges[:9:3] + crazy_lines = [ + ( + line, + Line(line.end, line.start), + CurvedLine(line.start, line.end) , + CurvedLine(line.end, line.start) + ) + for line in lines_to_double + ] + anims = [] + outward_curved_lines = [] + kwargs = {"run_time" : 3.0} + for straight, backwards, inward, outward in crazy_lines: + anims += [ + Transform(straight, inward, **kwargs), + Transform(backwards, outward, **kwargs), + ] + outward_curved_lines.append(outward) + gs.animate(*anims) + gs.dither() + gs.remove(*outward_curved_lines) + + name = "DoubledEdges" + graph["name"] + gs.write_to_movie(movie_prefix + name) + + +def eulers_formula(graph): + gs = GraphScene(graph) + terms = "V - E + F =2".split(" ") + form = dict([ + (key, mob) + for key, mob in zip(terms, tex_mobjects(terms)) + ]) + for mob in form.values(): + mob.shift((0, SPACE_HEIGHT-1.5, 0)) + formula = CompoundMobject(*form.values()) + new_form = dict([ + (key, deepcopy(mob).shift((0, -0.7, 0))) + for key, mob in zip(form.keys(), form.values()) + ]) + gs.add(formula) + colored_dots = [ + deepcopy(d).scale_in_place(1.5).highlight("red") + for d in gs.dots + ] + colored_edges = [ + deepcopy(e).highlight("red") + for e in gs.edges + ] + frame_time = 0.3 + + gs.generate_regions() + parameters = [ + (colored_dots, "V", "mobject", "-", "show_creation"), + (colored_edges, "E", "mobject", "+", "show_creation"), + (gs.regions, "F", "region", "=2", "show_all") + ] + for items, letter, item_type, symbol, mode in parameters: + gs.count( + items, + item_type = item_type, + mode = mode, + num_offset = new_form[letter].get_center(), + run_time = frame_time*len(items) + ) + gs.dither() + if item_type == "mobject": + gs.remove(*items) + gs.add(new_form[symbol]) + gs.reset_background() + + name = "EulersFormula" + graph["name"] + gs.write_to_movie(movie_prefix + name) + + +################################################## + +if __name__ == '__main__': + radians = np.arange(0, 6, 6.0/7) + # count_lines(*radians) + # count_lines(*radians[:4]) + # count_intersection_points(*radians[:4]) + # count_intersection_points(*radians[:6]) + # count_intersection_points(*radians) + # non_general_position() + # line_corresponds_with_pair(radians, radians[3], radians[4]) + # line_corresponds_with_pair(radians, radians[2], radians[5]) + # illustrate_n_choose_k(7, 2) + # illustrate_n_choose_k(6, 4) + # intersection_point_correspondances(radians, range(0, 7, 2)) + # lines_intersect_outside(radians, [2, 4, 5, 6]) + quadruplets_to_intersections(*radians[:6]) + # defining_graph(SAMPLE_GRAPH) + # doubled_edges(CUBE_GRAPH) + # eulers_formula(CUBE_GRAPH) + # eulers_formula(SAMPLE_GRAPH) + # eulers_formula(OCTOHEDRON_GRAPH) + + + + + + + diff --git a/moser/moser_helpers.py b/moser/moser_helpers.py index 0e63e20c..606e796b 100644 --- a/moser/moser_helpers.py +++ b/moser/moser_helpers.py @@ -156,46 +156,41 @@ class PascalsTriangleScene(Scene): def __init__(self, nrows, *args, **kwargs): Scene.__init__(self, *args, **kwargs) - diagram_height = 2*SPACE_HEIGHT - 1 - diagram_width = 1.5*SPACE_WIDTH - cell_height = diagram_height / nrows - cell_width = diagram_width / nrows - portion_to_fill = 0.7 - bottom_left = np.array( - (-cell_width * nrows / 2.0, -cell_height * nrows / 2.0, 0) + self.nrows = nrows + self.diagram_height = 2*SPACE_HEIGHT - 1 + self.diagram_width = 1.5*SPACE_WIDTH + self.cell_height = self.diagram_height / nrows + self.cell_width = self.diagram_width / nrows + self.portion_to_fill = 0.7 + self.bottom_left = np.array( + (-self.cell_width * nrows / 2.0, -self.cell_height * nrows / 2.0, 0) ) num_to_num_mob = {} - coords_to_mobs = {} - coords = [(n, k) for n in range(nrows) for k in range(n+1)] - for n, k in coords: + self.coords_to_mobs = {} + self.coords = [(n, k) for n in range(nrows) for k in range(n+1)] + for n, k in self.coords: num = choose(n, k) - center = bottom_left + ( - cell_width * (k+nrows/2.0 - n/2.0), - cell_height * (nrows - n), - 0 - ) + center = self.coords_to_center(n, k) if num not in num_to_num_mob: num_to_num_mob[num] = tex_mobject(str(num)) num_mob = deepcopy(num_to_num_mob[num]) scale_factor = min( 1, - portion_to_fill * cell_height / num_mob.get_height(), - portion_to_fill * cell_width / num_mob.get_width(), + self.portion_to_fill * self.cell_height / num_mob.get_height(), + self.portion_to_fill * self.cell_width / num_mob.get_width(), ) num_mob.center().scale(scale_factor).shift(center) - if n not in coords_to_mobs: - coords_to_mobs[n] = {} - coords_to_mobs[n][k] = num_mob - self.add(*[coords_to_mobs[n][k] for n, k in coords]) - #Add attributes - self.nrows = nrows - self.coords = coords - self.diagram_height = diagram_height - self.diagram_width = diagram_width - self.cell_height = cell_height - self.cell_width = cell_width - self.portion_to_fill= portion_to_fill - self.coords_to_mobs = coords_to_mobs + if n not in self.coords_to_mobs: + self.coords_to_mobs[n] = {} + self.coords_to_mobs[n][k] = num_mob + self.add(*[self.coords_to_mobs[n][k] for n, k in self.coords]) + + def coords_to_center(self, n, k): + return self.bottom_left + ( + self.cell_width * (k+self.nrows/2.0 - n/2.0), + self.cell_height * (self.nrows - n), + 0 + ) def generate_n_choose_k_mobs(self): self.coords_to_n_choose_k = {} @@ -212,6 +207,18 @@ class PascalsTriangleScene(Scene): self.coords_to_n_choose_k[n] = {} self.coords_to_n_choose_k[n][k] = nck_mob + def generate_sea_of_zeros(self): + zero = tex_mobject("0") + self.sea_of_zeros = [] + for n in range(self.nrows): + for a in range((self.nrows - n)/2 + 1): + for k in (n + a + 1, -a -1): + self.coords.append((n, k)) + mob = deepcopy(zero) + mob.shift(self.coords_to_center(n, k)) + self.coords_to_mobs[n][k] = mob + self.add(mob) + ################################################## diff --git a/script_wrapper.py b/script_wrapper.py index bab2be70..e9e18462 100644 --- a/script_wrapper.py +++ b/script_wrapper.py @@ -86,7 +86,7 @@ def command_line_create_scene(sys_argv, scene_classes, movie_prefix = ""): scene_classes ) name = SceneClass.__name__ + SceneClass.args_to_string(*args) - print "Writing %s..."%name + print "Constructing %s..."%name scene = SceneClass(*args, display_config = display_config) scene.write_to_movie(movie_prefix + name)