extra diagram file refactors
This commit is contained in:
parent
b28f7fd65f
commit
879cbc909f
@ -1,29 +1,20 @@
|
||||
from functools import partial
|
||||
import time
|
||||
from threading import Thread
|
||||
from typing import Callable, Literal
|
||||
|
||||
from matplotlib import animation, pyplot as plt
|
||||
import numpy as np
|
||||
from sympy.plotting import plot_implicit
|
||||
|
||||
from .carry import Carry
|
||||
|
||||
writer = animation.writers["ffmpeg"](fps=15, metadata={"artist": "Me"})
|
||||
|
||||
|
||||
def times(base: np.ndarray, carry: Carry, val):
|
||||
base *= val
|
||||
carry.apply(base)
|
||||
return base
|
||||
|
||||
|
||||
def add(base: np.ndarray, carry: Carry, val=1, center=(0, 0)):
|
||||
base[center] += val
|
||||
carry.apply(base)
|
||||
return base
|
||||
from .expansion import add, times, poly_from_array
|
||||
|
||||
|
||||
def animate(
|
||||
fig, frames: list[int] | None, **kwargs
|
||||
) -> Callable[..., animation.FuncAnimation]:
|
||||
"""Decorator-style wrapper for FuncAnimation."""
|
||||
# Why isn't this how the function is exposed by default?
|
||||
return lambda func: animation.FuncAnimation(fig, func, frames, **kwargs)
|
||||
|
||||
@ -38,6 +29,20 @@ def animate_carry_count(
|
||||
frames: list[int] | None = None,
|
||||
interval=200,
|
||||
) -> animation.FuncAnimation:
|
||||
"""
|
||||
Create a video of integer expansions using a `carry`.
|
||||
Expansions use a `dims` x `dims` numpy array.
|
||||
|
||||
The video starts from the expansion of one, and subsequent frames come from
|
||||
either adding `op_val` to the constant term or multiplying each term by `op_val`,
|
||||
both followed by carrying.
|
||||
`operation` decides which of these to use.
|
||||
|
||||
The constant term of the expansion is specified with `center`.
|
||||
print("Starting animation")
|
||||
By default, the constant term is at position (0, 0), in the upper left corner.
|
||||
If the carry expands leftward or upward, it is instead in the center of the array.
|
||||
"""
|
||||
if center is None:
|
||||
if carry.over_pos != (0, 0):
|
||||
center = (dims // 2, dims // 2)
|
||||
@ -81,3 +86,90 @@ def animate_carry_count(
|
||||
title[0] *= op_val
|
||||
|
||||
return ret
|
||||
|
||||
# writer = animation.writers["ffmpeg"](fps=15, metadata={"artist": "Me"})
|
||||
|
||||
def bindfig(fig):
|
||||
"""
|
||||
Create a function which is compatible with the signature of `pyplot.figure`,
|
||||
but alters the already-existing figure `fig` instead.
|
||||
"""
|
||||
def ret(**kwargs):
|
||||
for i, j in kwargs.items():
|
||||
if i == "figsize":
|
||||
if j is not None:
|
||||
fig.set_figwidth(j[0])
|
||||
fig.set_figheight(j[1])
|
||||
continue
|
||||
fig.__dict__["set_" + i](j)
|
||||
return fig
|
||||
return ret
|
||||
|
||||
|
||||
def animate_carry_curves(
|
||||
carry: Carry,
|
||||
dims: int = 100,
|
||||
operation: Literal["add", "multiply"] = "add",
|
||||
op_val=1,
|
||||
center: tuple[int, int] | None = None,
|
||||
# Animation parameters
|
||||
frames: list[int] | None = None,
|
||||
# interval=200,
|
||||
) -> animation.FuncAnimation:
|
||||
"""
|
||||
Create a video of implicit plots of "incremented curves" based on a `carry`.
|
||||
These are curves for which we re-interpret an expansion as a polynomial equal
|
||||
equal to the integer it represents.
|
||||
"""
|
||||
if center is None:
|
||||
if carry.over_pos != (0, 0):
|
||||
center = (dims // 2, dims // 2)
|
||||
else:
|
||||
center = (0, 0)
|
||||
|
||||
if operation == "add":
|
||||
next_func = partial(add, carry=carry, val=op_val, center=center)
|
||||
elif operation == "multiply":
|
||||
if op_val == 1:
|
||||
raise ValueError(f"too small value {op_val} for repeated multiplication")
|
||||
next_func = partial(times, carry=carry, val=op_val)
|
||||
else:
|
||||
raise ValueError(f"Cannot use {repr(operation)} for animation")
|
||||
|
||||
expansion = np.zeros((dims, dims), dtype=np.int32)
|
||||
expansion[center] = 0
|
||||
count = [0]
|
||||
|
||||
# I hate doing it, but there's no other way to control the figure uses
|
||||
fig = plt.gcf()
|
||||
plt.figure = bindfig(fig)
|
||||
plt.tight_layout()
|
||||
|
||||
# More sympy.plot_implicit nonsense
|
||||
t = Thread(target=lambda: time.sleep(1) or plt.close())
|
||||
t.run()
|
||||
plt.title(f"{count[0]}")
|
||||
plot_implicit(
|
||||
poly_from_array(carry._arr),
|
||||
backend="matplotlib",
|
||||
)
|
||||
|
||||
@animate(fig, frames)
|
||||
def ret(_):
|
||||
next_poly = poly_from_array(expansion) - count[0]
|
||||
|
||||
if next_poly != 0:
|
||||
fig.clf()
|
||||
plot_implicit(
|
||||
next_poly,
|
||||
backend="matplotlib",
|
||||
)
|
||||
plt.title(f"{count[0]}")
|
||||
|
||||
if operation == "add":
|
||||
count[0] += op_val
|
||||
else:
|
||||
count[0] *= op_val
|
||||
next_func(expansion)
|
||||
|
||||
return ret
|
||||
|
||||
@ -20,7 +20,7 @@ def _validate_carry(arr: np.ndarray) -> tuple[int, tuple[int, int]]:
|
||||
overflow = -val
|
||||
over_pos = (i, j)
|
||||
|
||||
if coeff_sum < 0:
|
||||
if coeff_sum > 0:
|
||||
raise ValueError("Sum of coefficients too small")
|
||||
|
||||
if overflow is None or over_pos is None:
|
||||
|
||||
@ -1,88 +0,0 @@
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
from sympy.abc import x, y
|
||||
from sympy.plotting import plot_implicit
|
||||
|
||||
from .anim import animate
|
||||
|
||||
def _first_nonzero(arr: np.ndarray, axis: int):
|
||||
mask = arr!=0
|
||||
return min(np.where(mask.any(axis=axis), mask.argmax(axis=axis), arr.shape[axis] + 1))
|
||||
|
||||
def latex_polynumber(
|
||||
arr: np.ndarray,
|
||||
center: tuple[int, int] | None = None,
|
||||
show_zero: bool = False
|
||||
):
|
||||
upper_left = _first_nonzero(arr, 0), _first_nonzero(arr, 1)
|
||||
lower_right = (
|
||||
len(arr) - _first_nonzero(np.flip(arr, 0), 0) - 1,
|
||||
len(arr[1]) - _first_nonzero(np.flip(arr, 1), 1) - 1
|
||||
)
|
||||
|
||||
center_left, center_top = center or (0, 0)
|
||||
if center is not None:
|
||||
# this does not need offset, since we iterate over this range
|
||||
center_top = center[0]
|
||||
# but this does for the array environment argument
|
||||
center_left = center[1] - upper_left[1]
|
||||
|
||||
num_columns = lower_right[1] - upper_left[1]
|
||||
column_layout = ("c" * center_left) + "|" + ("c" * (num_columns - center_left))
|
||||
|
||||
# build array output
|
||||
ret = "\\begin{array}{" + column_layout + "}"
|
||||
for i in range(upper_left[0], lower_right[0] + 1):
|
||||
if i == center_top:
|
||||
ret += " \\hline "
|
||||
ret += " & ".join([
|
||||
str(arr[i,j] if arr[i,j] != 0 or show_zero else "")
|
||||
for j in range(upper_left[1], lower_right[1] + 1)
|
||||
])
|
||||
# next row
|
||||
ret += " \\\\ "
|
||||
return ret + "\\end{array}"
|
||||
|
||||
|
||||
def poly_from_array(array):
|
||||
ret = 0
|
||||
for i, row in enumerate(array):
|
||||
for j, val in enumerate(row):
|
||||
ret += val*(x**i * y**j)
|
||||
return ret
|
||||
|
||||
def bindfig(fig):
|
||||
def ret(**kwargs):
|
||||
for i, j in kwargs.items():
|
||||
if i == "figsize":
|
||||
if j is not None:
|
||||
fig.set_figwidth(j[0])
|
||||
fig.set_figheight(j[1])
|
||||
continue
|
||||
fig.__dict__["set_" + i](j)
|
||||
return fig
|
||||
return ret
|
||||
|
||||
def anim_curves(next_func, dims=25, invalid=2, frames=None, interval=200):
|
||||
zero = np.zeros((dims, dims), dtype=np.int32)
|
||||
#zero[0,0] = 1
|
||||
fig = plt.gcf()
|
||||
#plt.colorbar()
|
||||
|
||||
#temp = plt.figure
|
||||
#I hate doing it, but there's no other way to get the figure before it's plotted
|
||||
plt.figure = bindfig(fig)
|
||||
|
||||
@animate(fig, frames, interval=interval)
|
||||
def ret(fr):
|
||||
next_func(zero, invalid)
|
||||
fig.clf()
|
||||
plot_implicit(
|
||||
poly_from_array(zero) - fr,
|
||||
backend='matplotlib',
|
||||
adaptive=False
|
||||
)
|
||||
plt.title(f"{fr+1}")
|
||||
print(fr)
|
||||
|
||||
return ret
|
||||
@ -2,41 +2,41 @@ import numpy as np
|
||||
|
||||
from .carry import Carry
|
||||
|
||||
xy_2 = Carry([[2,-1],[-1,0]])
|
||||
xy_3 = Carry([[3,-1],[-1,0]])
|
||||
x2y_3 = Carry([[3,-2],[-1,0]])
|
||||
x3y_4 = Carry([[4,-3],[-1,0]])
|
||||
xy_2 = Carry([[-2,1],[1,0]])
|
||||
xy_3 = Carry([[-3,1],[1,0]])
|
||||
x2y_3 = Carry([[-3,2],[1,0]])
|
||||
x3y_4 = Carry([[-4,3],[1,0]])
|
||||
|
||||
laplace = Carry([[0,-1,0],[-1,4,-1],[0,-1,0]])
|
||||
laplace3 = Carry([[0,0,0],[-1,3,-1],[0,-1,0]])
|
||||
laplace = Carry([[0,1,0],[1,-4,1],[0,1,0]])
|
||||
laplace3 = Carry([[0,0,0],[1,-3,1],[0,1,0]])
|
||||
|
||||
almost_folium = Carry([[0,0,-1], [0,2,0], [-1,0,0]])
|
||||
almost_folium = Carry([[0,0,1], [0,-2,0], [1,0,0]])
|
||||
folium = Carry([
|
||||
[ 0,0,0,-1],
|
||||
[ 0,2,0, 0],
|
||||
[ 0,0,0, 0],
|
||||
[-1,0,0, 0]
|
||||
[ 0, 0,0, 1],
|
||||
[ 0,-2,0, 0],
|
||||
[ 0, 0,0, 0],
|
||||
[ 1, 0,0, 0]
|
||||
])
|
||||
folium3 = Carry([
|
||||
[ 0,0,0,-1],
|
||||
[ 0,3,0, 0],
|
||||
[ 0,0,0, 0],
|
||||
[-1,0,0, 0]
|
||||
[ 0, 0,0, 1],
|
||||
[ 0,-3,0, 0],
|
||||
[ 0, 0,0, 0],
|
||||
[ 1, 0,0, 0]
|
||||
])
|
||||
folium4 = Carry([
|
||||
[ 0, 0, 0,-1, 0],
|
||||
[ 0, 0, 0, 0,-1],
|
||||
[ 0, 0, 4, 0, 0],
|
||||
[-1, 0, 0, 0, 0],
|
||||
[ 0,-1, 0, 0, 0]
|
||||
[ 0, 0, 0, 1, 0],
|
||||
[ 0, 0, 0, 0, 1],
|
||||
[ 0, 0,-4, 0, 0],
|
||||
[ 1, 0, 0, 0, 0],
|
||||
[ 0, 1, 0, 0, 0]
|
||||
])
|
||||
|
||||
def triangle_spread(n):
|
||||
ret = np.zeros((n + 1, n + 1), dtype=np.int32)
|
||||
ret[0, 0] = -1
|
||||
ret[1, 1] = 3
|
||||
ret[n, 0] = -1
|
||||
ret[0, n] = -1
|
||||
ret[0, 0] = 1
|
||||
ret[1, 1] = -3
|
||||
ret[n, 0] = 1
|
||||
ret[0, n] = 1
|
||||
return ret
|
||||
|
||||
triangle1 = Carry(triangle_spread(1))
|
||||
@ -45,34 +45,34 @@ triangle3 = Carry(triangle_spread(3)) #factorable!
|
||||
triangle4 = Carry(triangle_spread(4))
|
||||
|
||||
tri3_rot = Carry([
|
||||
[ 0, 0,-1, 0, 0],
|
||||
[ 0, 0, 3, 0, 0],
|
||||
[-1, 0, 0, 0,-1]
|
||||
[ 0, 0, 1, 0, 0],
|
||||
[ 0, 0,-3, 0, 0],
|
||||
[ 1, 0, 0, 0, 1]
|
||||
])
|
||||
|
||||
tri3_rot_real = Carry([
|
||||
[ 0, 0, 0,-1, 0, 0, 0],
|
||||
[ 0, 0, 0, 1, 0, 0, 0],
|
||||
[ 0, 0, 0, 0, 0, 0, 0],
|
||||
[ 0, 0, 0, 3, 0, 0, 0],
|
||||
[-1, 0, 0, 0, 0, 0,-1]
|
||||
[ 0, 0, 0,-3, 0, 0, 0],
|
||||
[ 1, 0, 0, 0, 0, 0, 1]
|
||||
])
|
||||
|
||||
tri3_rot2 = Carry([
|
||||
[ 0,-1, 0],
|
||||
[ 0, 3, 0],
|
||||
[-1, 0,-1]
|
||||
[ 0, 1, 0],
|
||||
[ 0,-3, 0],
|
||||
[ 1, 0, 1]
|
||||
])
|
||||
|
||||
tri3_tall = Carry([
|
||||
[ 0,-1, 0],
|
||||
[ 0, 1, 0],
|
||||
[ 0, 0, 0],
|
||||
[ 0, 3, 0],
|
||||
[-1, 0,-1]
|
||||
[ 0,-3, 0],
|
||||
[ 1, 0, 1]
|
||||
])
|
||||
|
||||
tri3_tall2 = Carry([
|
||||
[ 0,-1, 0],
|
||||
[ 0, 3, 0],
|
||||
[ 0, 1, 0],
|
||||
[ 0,-3, 0],
|
||||
[ 0, 0, 0],
|
||||
[-1, 0,-1]
|
||||
[ 1, 0, 1]
|
||||
])
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user