extra diagram file refactors
This commit is contained in:
parent
b28f7fd65f
commit
879cbc909f
@ -1,29 +1,20 @@
|
|||||||
from functools import partial
|
from functools import partial
|
||||||
|
import time
|
||||||
|
from threading import Thread
|
||||||
from typing import Callable, Literal
|
from typing import Callable, Literal
|
||||||
|
|
||||||
from matplotlib import animation, pyplot as plt
|
from matplotlib import animation, pyplot as plt
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
from sympy.plotting import plot_implicit
|
||||||
|
|
||||||
from .carry import Carry
|
from .carry import Carry
|
||||||
|
from .expansion import add, times, poly_from_array
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
def animate(
|
def animate(
|
||||||
fig, frames: list[int] | None, **kwargs
|
fig, frames: list[int] | None, **kwargs
|
||||||
) -> Callable[..., animation.FuncAnimation]:
|
) -> Callable[..., animation.FuncAnimation]:
|
||||||
|
"""Decorator-style wrapper for FuncAnimation."""
|
||||||
# Why isn't this how the function is exposed by default?
|
# Why isn't this how the function is exposed by default?
|
||||||
return lambda func: animation.FuncAnimation(fig, func, frames, **kwargs)
|
return lambda func: animation.FuncAnimation(fig, func, frames, **kwargs)
|
||||||
|
|
||||||
@ -38,6 +29,20 @@ def animate_carry_count(
|
|||||||
frames: list[int] | None = None,
|
frames: list[int] | None = None,
|
||||||
interval=200,
|
interval=200,
|
||||||
) -> animation.FuncAnimation:
|
) -> 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 center is None:
|
||||||
if carry.over_pos != (0, 0):
|
if carry.over_pos != (0, 0):
|
||||||
center = (dims // 2, dims // 2)
|
center = (dims // 2, dims // 2)
|
||||||
@ -81,3 +86,90 @@ def animate_carry_count(
|
|||||||
title[0] *= op_val
|
title[0] *= op_val
|
||||||
|
|
||||||
return ret
|
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
|
overflow = -val
|
||||||
over_pos = (i, j)
|
over_pos = (i, j)
|
||||||
|
|
||||||
if coeff_sum < 0:
|
if coeff_sum > 0:
|
||||||
raise ValueError("Sum of coefficients too small")
|
raise ValueError("Sum of coefficients too small")
|
||||||
|
|
||||||
if overflow is None or over_pos is None:
|
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
|
from .carry import Carry
|
||||||
|
|
||||||
xy_2 = Carry([[2,-1],[-1,0]])
|
xy_2 = Carry([[-2,1],[1,0]])
|
||||||
xy_3 = Carry([[3,-1],[-1,0]])
|
xy_3 = Carry([[-3,1],[1,0]])
|
||||||
x2y_3 = Carry([[3,-2],[-1,0]])
|
x2y_3 = Carry([[-3,2],[1,0]])
|
||||||
x3y_4 = Carry([[4,-3],[-1,0]])
|
x3y_4 = Carry([[-4,3],[1,0]])
|
||||||
|
|
||||||
laplace = Carry([[0,-1,0],[-1,4,-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]])
|
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([
|
folium = Carry([
|
||||||
[ 0,0,0,-1],
|
[ 0, 0,0, 1],
|
||||||
[ 0,2,0, 0],
|
[ 0,-2,0, 0],
|
||||||
[ 0,0,0, 0],
|
[ 0, 0,0, 0],
|
||||||
[-1,0,0, 0]
|
[ 1, 0,0, 0]
|
||||||
])
|
])
|
||||||
folium3 = Carry([
|
folium3 = Carry([
|
||||||
[ 0,0,0,-1],
|
[ 0, 0,0, 1],
|
||||||
[ 0,3,0, 0],
|
[ 0,-3,0, 0],
|
||||||
[ 0,0,0, 0],
|
[ 0, 0,0, 0],
|
||||||
[-1,0,0, 0]
|
[ 1, 0,0, 0]
|
||||||
])
|
])
|
||||||
folium4 = Carry([
|
folium4 = Carry([
|
||||||
[ 0, 0, 0,-1, 0],
|
[ 0, 0, 0, 1, 0],
|
||||||
[ 0, 0, 0, 0,-1],
|
[ 0, 0, 0, 0, 1],
|
||||||
[ 0, 0, 4, 0, 0],
|
[ 0, 0,-4, 0, 0],
|
||||||
[-1, 0, 0, 0, 0],
|
[ 1, 0, 0, 0, 0],
|
||||||
[ 0,-1, 0, 0, 0]
|
[ 0, 1, 0, 0, 0]
|
||||||
])
|
])
|
||||||
|
|
||||||
def triangle_spread(n):
|
def triangle_spread(n):
|
||||||
ret = np.zeros((n + 1, n + 1), dtype=np.int32)
|
ret = np.zeros((n + 1, n + 1), dtype=np.int32)
|
||||||
ret[0, 0] = -1
|
ret[0, 0] = 1
|
||||||
ret[1, 1] = 3
|
ret[1, 1] = -3
|
||||||
ret[n, 0] = -1
|
ret[n, 0] = 1
|
||||||
ret[0, n] = -1
|
ret[0, n] = 1
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
triangle1 = Carry(triangle_spread(1))
|
triangle1 = Carry(triangle_spread(1))
|
||||||
@ -45,34 +45,34 @@ triangle3 = Carry(triangle_spread(3)) #factorable!
|
|||||||
triangle4 = Carry(triangle_spread(4))
|
triangle4 = Carry(triangle_spread(4))
|
||||||
|
|
||||||
tri3_rot = Carry([
|
tri3_rot = Carry([
|
||||||
[ 0, 0,-1, 0, 0],
|
[ 0, 0, 1, 0, 0],
|
||||||
[ 0, 0, 3, 0, 0],
|
[ 0, 0,-3, 0, 0],
|
||||||
[-1, 0, 0, 0,-1]
|
[ 1, 0, 0, 0, 1]
|
||||||
])
|
])
|
||||||
|
|
||||||
tri3_rot_real = Carry([
|
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, 0, 0, 0, 0],
|
||||||
[ 0, 0, 0, 3, 0, 0, 0],
|
[ 0, 0, 0,-3, 0, 0, 0],
|
||||||
[-1, 0, 0, 0, 0, 0,-1]
|
[ 1, 0, 0, 0, 0, 0, 1]
|
||||||
])
|
])
|
||||||
|
|
||||||
tri3_rot2 = Carry([
|
tri3_rot2 = Carry([
|
||||||
[ 0,-1, 0],
|
[ 0, 1, 0],
|
||||||
[ 0, 3, 0],
|
[ 0,-3, 0],
|
||||||
[-1, 0,-1]
|
[ 1, 0, 1]
|
||||||
])
|
])
|
||||||
|
|
||||||
tri3_tall = Carry([
|
tri3_tall = Carry([
|
||||||
[ 0,-1, 0],
|
[ 0, 1, 0],
|
||||||
[ 0, 0, 0],
|
[ 0, 0, 0],
|
||||||
[ 0, 3, 0],
|
[ 0,-3, 0],
|
||||||
[-1, 0,-1]
|
[ 1, 0, 1]
|
||||||
])
|
])
|
||||||
|
|
||||||
tri3_tall2 = Carry([
|
tri3_tall2 = Carry([
|
||||||
[ 0,-1, 0],
|
[ 0, 1, 0],
|
||||||
[ 0, 3, 0],
|
[ 0,-3, 0],
|
||||||
[ 0, 0, 0],
|
[ 0, 0, 0],
|
||||||
[-1, 0,-1]
|
[ 1, 0, 1]
|
||||||
])
|
])
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user