Non-numerical Hessian for Radial[T]

This commit is contained in:
Kenneth Jao 2022-01-27 20:25:30 -05:00
parent 8cd48a1acd
commit f1a180b5a5
11 changed files with 4879 additions and 4083 deletions

File diff suppressed because it is too large Load Diff

View File

@ -51,6 +51,7 @@ ctypedef Matrix2x2 (*MatrixCopySclOp)(Matrix2x2*, FLOAT_T) nogil
ctypedef struct VectorSelfOps:
Vector2D* (*neg)(Vector2D*) nogil
Vector2D* (*rot)(Vector2D*) nogil
VectorSelfVecOp vadd
VectorSelfVecOp vsub
@ -66,6 +67,7 @@ ctypedef struct VectorSelfOps:
ctypedef struct VectorCopyOps:
Vector2D (*neg)(Vector2D*) nogil
Vector2D (*rot)(Vector2D*) nogil
VectorCopyVecOp vadd
VectorCopyVecOp vsub
@ -81,6 +83,7 @@ ctypedef struct VectorCopyOps:
ctypedef struct MatrixSelfOps:
Matrix2x2* (*neg)(Matrix2x2*) nogil
Matrix2x2* (*T)(Matrix2x2*) nogil
MatrixSelfMatOp madd
MatrixSelfMatOp msub
@ -96,6 +99,7 @@ ctypedef struct MatrixSelfOps:
ctypedef struct MatrixCopyOps:
Matrix2x2 (*neg)(Matrix2x2*) nogil
Matrix2x2 (*T)(Matrix2x2*) nogil
MatrixCopyMatOp madd
MatrixCopyMatOp msub
@ -115,7 +119,7 @@ ctypedef struct Vector2D:
VectorCopyOps copy
bint (*equals)(Vector2D*, Vector2D) nogil
Vector2D (*rot)(Vector2D*) nogil
Matrix2x2 (*vecmul)(Vector2D*, Vector2D) nogil
FLOAT_T (*dot)(Vector2D*, Vector2D) nogil
FLOAT_T (*mag)(Vector2D*) nogil

View File

@ -18,19 +18,19 @@ cdef MatrixCopyOps MCO
VSO.neg, VSO.vadd, VSO.vsub, VSO.vmul, VSO.vdiv, VSO.sadd, VSO.ssub, VSO.smul, VSO.sdiv = \
v_neg_s, v_vadd_s, v_vsub_s, v_vmul_s, v_vdiv_s, v_sadd_s, v_ssub_s, v_smul_s, v_sdiv_s
VSO.matmul = v_matmul_s
VSO.matmul, VSO.rot = v_matmul_s, rot_s
VCO.neg, VCO.vadd, VCO.vsub, VCO.vmul, VCO.vdiv, VCO.sadd, VCO.ssub, VCO.smul, VCO.sdiv = \
v_neg_c, v_vadd_c, v_vsub_c, v_vmul_c, v_vdiv_c, v_sadd_c, v_ssub_c, v_smul_c, v_sdiv_c
VCO.matmul = v_matmul_c
VCO.matmul, VCO.rot = v_matmul_c, rot_c
MSO.neg, MSO.madd, MSO.msub, MSO.mmul, MSO.mdiv, MSO.sadd, MSO.ssub, MSO.smul, MSO.sdiv = \
m_neg_s, m_madd_s, m_msub_s, m_mmul_s, m_mdiv_s, m_sadd_s, m_ssub_s, m_smul_s, m_sdiv_s
MSO.matmul = m_matmul_s
MSO.matmul, MSO.T = m_matmul_s, m_transpose_s
MCO.neg, MCO.madd, MCO.msub, MCO.mmul, MCO.mdiv, MCO.sadd, MCO.ssub, MCO.smul, MCO.sdiv = \
m_neg_c, m_madd_c, m_msub_c, m_mmul_c, m_mdiv_c, m_sadd_c, m_ssub_c, m_smul_c, m_sdiv_c
MCO.matmul = m_matmul_c
MCO.matmul, MCO.T = m_matmul_c, m_transpose_c
"""
If bound checking is desired, uncomment out ..._valid_indices functions.
@ -143,7 +143,7 @@ cdef inline Vector2D _Vector2D(FLOAT_T x, FLOAT_T y) nogil:
vec.x, vec.y = x, y
vec.self, vec.copy = VSO, VCO
vec.equals, vec.rot, vec.dot, vec.mag = &v_equals, &rot, &dot, &mag
vec.equals, vec.vecmul, vec.dot, vec.mag = &v_equals, &v_vecmul, &dot, &mag
return vec
@ -200,6 +200,10 @@ cdef inline Vector2D* v_matmul_s(Vector2D* self, Matrix2x2 m) nogil:
self.x, self.y = self.x*m.a + self.y*m.c, self.x*m.b + self.y*m.d
return self
cdef inline Vector2D* rot_s(Vector2D* self) nogil:
self.x, self.y = -self.y, self.x
return self
cdef inline Vector2D v_neg_c(Vector2D* self) nogil:
return _Vector2D(-self.x, -self.y)
@ -232,7 +236,7 @@ cdef inline Vector2D v_matmul_c(Vector2D* self, Matrix2x2 m) nogil:
self.x*m.a + self.y*m.c, self.x*m.b + self.y*m.d
)
cdef inline Vector2D rot(Vector2D* self) nogil:
cdef inline Vector2D rot_c(Vector2D* self) nogil:
return _Vector2D(-self.y, self.x)
cdef inline FLOAT_T dot(Vector2D* self, Vector2D w) nogil:
@ -241,6 +245,9 @@ cdef inline FLOAT_T dot(Vector2D* self, Vector2D w) nogil:
cdef inline FLOAT_T mag(Vector2D* self) nogil:
return <FLOAT_T>sqrt(<double>(self.x*self.x + self.y*self.y))
cdef inline Matrix2x2 v_vecmul(Vector2D* self, Vector2D v) nogil:
return _Matrix2x2(self.x*v.x, self.x*v.y, self.y*v.x, self.y*v.y)
#### Matrix2x2 Methods ####
@ -329,6 +336,10 @@ cdef inline Matrix2x2* m_matmul_s(Matrix2x2* self, Matrix2x2 m) nogil:
self.c*m.a + self.d*m.c, self.c*m.b + self.d*m.d
return self
cdef inline Matrix2x2* m_transpose_s(Matrix2x2* self) nogil:
self.b, self.c = self.c, self.b
return self
cdef inline Matrix2x2 m_neg_c(Matrix2x2* self) nogil:
return _Matrix2x2(-self.a, -self.b, -self.c, -self.d)
@ -361,3 +372,6 @@ cdef inline Matrix2x2 m_matmul_c(Matrix2x2* self, Matrix2x2 m) nogil:
self.a*m.a + self.b*m.c, self.a*m.b + self.b*m.d,
self.c*m.a + self.d*m.c, self.c*m.b + self.d*m.d
)
cdef inline Matrix2x2 m_transpose_c(Matrix2x2* self) nogil:
return _Matrix2x2(self.a, self.c, self.b, self.d)

View File

@ -1,7 +1,13 @@
from __future__ import annotations
from typing import Tuple, List, Optional
import matplotlib.pyplot as plt, numpy as np, os
import matplotlib as mpl
import matplotlib.cm as cm
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
from mpl_toolkits.axes_grid1.axes_divider import make_axes_locatable
import numpy as np, os, math
from matplotlib.ticker import MaxNLocator, FormatStrFormatter
from scipy.spatial import Voronoi, voronoi_plot_2d
from multiprocessing import Pool, cpu_count
@ -123,18 +129,49 @@ class Diagram:
raise ValueError("Not a valid mode for diagrams!")
shape = self.diagrams.shape
fig, axes = plt.subplots(*shape, figsize=(shape[1] * 8, shape[0] * 8))
plt.rcParams.update(
{
"axes.titlesize": 45,
"axes.labelsize": 45,
"xtick.labelsize": 40,
"ytick.labelsize": 40,
"xtick.major.width": 2,
"ytick.major.width": 2,
"xtick.major.size": 5,
"ytick.major.size": 5,
"xtick.minor.width": 1,
"ytick.minor.width": 1,
"xtick.minor.size": 3,
"ytick.minor.size": 3,
"legend.fontsize": 40,
"lines.linewidth": 3,
"font.family": "cm",
"font.size": 40,
"text.usetex": True,
"text.latex.preamble": r"\usepackage{amsmath}",
"figure.constrained_layout.use": True,
}
)
fig = plt.figure(figsize=(shape[1] * 15, shape[0] * 15))
gs = fig.add_gridspec(shape[0], shape[1])
# fig, axes = plt.subplots(*shape, figsize=(shape[1] * 15, shape[0] * 15))
if self.diagrams.shape == (1, 1):
getattr(self, str(self.diagrams[0][0]) + "_plot")(frame, axes)
ax = fig.add_subplot(gs[0])
getattr(self, str(self.diagrams[0][0]) + "_plot")(frame, ax)
else:
axes = np.atleast_2d(axes)
# axes = np.atleast_2d(axes)
it = np.nditer(self.diagrams, flags=["multi_index"])
for diagram in it:
if diagram == "":
continue
getattr(self, str(diagram) + "_plot")(frame, axes[it.multi_index])
plt.tight_layout()
ax = fig.add_subplot(gs[it.multi_index])
getattr(self, str(diagram) + "_plot")(frame, ax)
# plt.tight_layout()
if name is None:
name = f"img{frame:05}.png"
@ -148,28 +185,60 @@ class Diagram:
domain = self.sim.domains[i]
n, w, h = domain.n, domain.w, domain.h
scale = 1.5
area = n <= 60
area = n <= 50
offset = (
2
- 2 * domain.r * (6 * 3 ** (-0.25) * math.sqrt(2) * math.atanh(0.5))
+ 2 * math.pi * domain.r ** 2
)
# Make color map axis.
divider = make_axes_locatable(ax)
cax = divider.append_axes("right", size="5%", pad=0.05)
voronoi_plot_2d(
self.sim.voronois[i], ax, show_vertices=False, point_size=7 - n / 100
self.sim.voronois[i], ax, show_vertices=False, show_points=False
)
ax.plot([-w, 2 * w], [0, 0], "r")
ax.plot([-w, 2 * w], [h, h], "r")
ax.plot([0, 0], [-h, 2 * h], "r")
ax.plot([w, w], [-h, 2 * h], "r")
# Mark location axis with 3 ticks.
ax.set_xticks([0, w / 2, w])
ax.set_yticks([0, h / 2, h])
# Obtain site energies, and make color map.
energies = self.sim.stats[i]["site_energies"][:n]
norm = mpl.colors.Normalize(vmin=-2, vmax=2, clip=True)
mapper = cm.ScalarMappable(norm=norm, cmap=cm.magma)
cbar = plt.colorbar(mapper, cax=cax, ticks=np.linspace(-2, 2, 5))
# Fill polygons with energy colormap.
for j, p in enumerate(self.sim.voronois[i].point_region):
region = self.sim.voronois[i].regions[p]
if not -1 in region:
polygon = [self.sim.voronois[i].vertices[k] for k in region]
ax.fill(
*zip(*polygon),
color=mapper.to_rgba(energies[j % n] - offset),
zorder=0,
)
line_color, point_color = "white", "lightseagreen"
# Periodic border
ax.plot([-w, 2 * w], [0, 0], line_color, linewidth="4")
ax.plot([-w, 2 * w], [h, h], line_color, linewidth="4")
ax.plot([0, 0], [-h, 2 * h], line_color, linewidth="4")
ax.plot([w, w], [-h, 2 * h], line_color, linewidth="4")
ax.axis("equal")
ax.set_xlim([(1 - scale) * w / 2, (1 + scale) * w / 2])
ax.set_xlim([(1 - 0.85 * scale) * w / 2, (1 + 0.85 * scale) * w / 2])
ax.set_ylim([(1 - scale) * h / 2, (1 + scale) * h / 2])
ax.title.set_text("Voronoi Visualization")
props = dict(boxstyle="round", facecolor="wheat", alpha=0.8)
ax.set_title("Voronoi Tessellation")
# Marking sites and defects.
defects = {5: {"x": [], "y": []}, 7: {"x": [], "y": []}}
for j in range(n):
for s in SYMM:
vec = self.sim.voronois[i].points[j] + s * self.sim.domains[i].dim
if area:
txt = ax.text(
*vec, str(round(self.sim.stats[i]["site_areas"][j], 3))
@ -182,16 +251,35 @@ class Diagram:
elif self.sim.stats[i]["site_edge_count"][j] == 7:
defects[7]["x"].append(vec[0])
defects[7]["y"].append(vec[1])
else:
ax.scatter(
vec[0], vec[1], s=(40 - n / 100), color=point_color, zorder=1
)
ax.scatter(defects[5]["x"], defects[5]["y"], marker="p", color="C0")
ax.scatter(defects[7]["x"], defects[7]["y"], marker="*", color="C0")
ax.scatter(
defects[5]["x"],
defects[5]["y"],
marker="p",
s=(200 - n / 100),
color=point_color,
zorder=1,
)
ax.scatter(
defects[7]["x"],
defects[7]["y"],
marker="*",
s=(200 - n / 100),
color=point_color,
zorder=1,
)
# Make VEE text in top left.
props = dict(boxstyle="round", facecolor="white", alpha=0.8, zorder=20)
ax.text(
0.05,
0.95,
f"Energy: {self.sim.energies[i]}",
0.065,
0.935,
f"VEE: {round(sum(energies)/n - offset, 8)}",
transform=ax.transAxes,
fontsize=14,
verticalalignment="top",
bbox=props,
)
@ -305,14 +393,32 @@ class Diagram:
def eigs_plot(self, i: int, ax: AxesSubplot) -> None:
try:
eigs = self.sim.stats[i]["eigs"]
for i, eig in enumerate(eigs):
if eig > 1e-4:
ax.annotate(
f"Coercivity: {eig:.5f}",
xy=(i, eig),
xytext=(50, -50),
textcoords="offset points",
arrowprops={"arrowstyle": "->", "color": "black"},
)
break
ax.plot(
list(range(len(eigs))), eigs, marker="o", linestyle="dashed", color="C0"
list(range(40)),
eigs[:40],
marker="o",
linestyle="dashed",
color="C0",
markersize=8,
)
ax.plot([0, len(eigs)], [0, 0], color="red")
ax.plot([0, 40], [0, 0], color="red")
except KeyError:
ax.text(0.5, 0.5, "Not Computed")
ax.title.set_text("Hessian Eigenvalues")
ax.grid()
ax.set_title("Sorted Hessian Eigenvalues")
ax.set_xlabel("")
ax.set_ylabel("Value")

File diff suppressed because it is too large Load Diff

View File

@ -4,10 +4,10 @@ from cython.parallel import parallel, prange
cimport numpy as np
from libc.math cimport NAN, pi as PI, atanh
from squish.core cimport INT_T, FLOAT_T, Vector2D, Matrix2x2, BitSet, \
_Vector2D, _Matrix2x2, _BitSet
_Vector2D, _Matrix2x2, _BitSet
from squish.voronoi cimport Site, HalfEdge, EdgeCacheMap, VoronoiInfo, \
_Site, _HalfEdge, _EdgeCacheMap, _VoronoiInfo, VoronoiContainer, \
R, NAN_MATRIX, NAN_VECTOR
_Site, _HalfEdge, _EdgeCacheMap, _VoronoiInfo, VoronoiContainer, \
R, NAN_MATRIX, NAN_VECTOR
#### Constants ####
@ -18,228 +18,405 @@ cdef EdgeCacheMap AREA_ECM = _EdgeCacheMap(0, 4, 6, 8, 10, 12, 13, -1, -1, 14)
cdef EdgeCacheMap RADIALT_ECM = _EdgeCacheMap(0, 4, 6, 8, -1, 10, 11, 12, 13, 14)
cdef class AreaEnergy(VoronoiContainer):
"""
Class for formulas relevant to the Area energy.
:param n: [int] how many sites to generate.
:param w: [float] width of the bounding domain.
:param h: [float] height of the bounding domain.
:param r: [float] radius of zero energy circle.
:param sites: [np.ndarray] collection of sites.
"""
"""
Class for formulas relevant to the Area energy.
:param n: [int] how many sites to generate.
:param w: [float] width of the bounding domain.
:param h: [float] height of the bounding domain.
:param r: [float] radius of zero energy circle.
:param sites: [np.ndarray] collection of sites.
"""
attr_str = "area"
title_str = "Area"
attr_str = "area"
title_str = "Area"
def __init__(AreaEnergy self, INT_T n, FLOAT_T w, FLOAT_T h, FLOAT_T r,
np.ndarray[FLOAT_T, ndim=2] site_arr):
self.edge_cache_map = &AREA_ECM
self.energy = 0.0
def __init__(AreaEnergy self, INT_T n, FLOAT_T w, FLOAT_T h, FLOAT_T r,
np.ndarray[FLOAT_T, ndim=2] site_arr):
self.edge_cache_map = &AREA_ECM
self.energy = 0.0
super().__init__(n, w, h, r, site_arr)
self.minimum = (<FLOAT_T>n)*(w*h/(<FLOAT_T>n)-PI*r**2)**2
super().__init__(n, w, h, r, site_arr)
self.minimum = (<FLOAT_T>n)*(w*h/(<FLOAT_T>n)-PI*r**2)**2
cdef void precompute(self) except *:
cdef VoronoiInfo info = _VoronoiInfo(self.sites, self.edges, self.points,
self.vertices, self.site_cache, self.edge_cache, self.edge_cache_map)
cdef void precompute(self) except *:
cdef VoronoiInfo info = _VoronoiInfo(self.sites, self.edges, self.points,
self.vertices, self.site_cache, self.edge_cache, self.edge_cache_map)
cdef Site xi
cdef HalfEdge em, e, ep
cdef Vector2D vdiff
cdef Site xi
cdef HalfEdge em, e, ep
cdef Vector2D vdiff
cdef FLOAT_T [:] site_energy = np.full(self.sites.shape[0], PI*self.r**2)
cdef FLOAT_T [:] site_energy = np.full(self.sites.shape[0], PI*self.r**2)
cdef INT_T i, j
for i in prange(self.sites.shape[0], nogil=True):
xi = _Site(i, &info)
e = xi.edge(&xi)
cdef INT_T i, j
for i in prange(self.sites.shape[0], nogil=True):
xi = _Site(i, &info)
e = xi.edge(&xi)
site_energy[i] = (xi.cache.area(&xi, NAN) - site_energy[i])**2
xi.cache.energy(&xi, site_energy[i])
site_energy[i] = (xi.cache.area(&xi, NAN) - site_energy[i])**2
xi.cache.energy(&xi, site_energy[i])
j = 0
while j < xi.edge_num(&xi):
em, ep = e.prev(&e), e.next(&e)
vdiff = em.origin(&em)
vdiff.self.vsub(&vdiff, ep.origin(&ep))
e.cache.dVdv(&e, R.vecmul(&R, vdiff))
e.cache.H(&e, VoronoiContainer.calc_H(em, e))
j = 0
while j < xi.edge_num(&xi):
em, ep = e.prev(&e), e.next(&e)
vdiff = em.origin(&em)
vdiff.self.vsub(&vdiff, ep.origin(&ep))
e.cache.dVdv(&e, R.vecmul(&R, vdiff))
e.cache.H(&e, VoronoiContainer.calc_H(em, e))
e = e.next(&e)
j = j + 1
e = e.next(&e)
j = j + 1
self.energy = np.sum(site_energy[:self.n])
self.energy = np.sum(site_energy[:self.n])
cdef void calc_grad(self) except *:
cdef VoronoiInfo info = _VoronoiInfo(self.sites, self.edges, self.points,
self.vertices, self.site_cache, self.edge_cache, self.edge_cache_map)
cdef void calc_grad(self) except *:
cdef VoronoiInfo info = _VoronoiInfo(self.sites, self.edges, self.points,
self.vertices, self.site_cache, self.edge_cache, self.edge_cache_map)
cdef Site xi, xf
cdef HalfEdge e, f
cdef Vector2D dedxi_p
cdef BitSet edge_set
cdef Site xi, xf
cdef HalfEdge e, f
cdef Vector2D dedxi_p
cdef BitSet edge_set
cdef INT_T num_edges = self.edges.shape[0]
cdef FLOAT_T A = PI*self.r**2
cdef INT_T num_edges = self.edges.shape[0]
cdef FLOAT_T A = PI*self.r**2
cdef FLOAT_T [:, ::1] dedx = np.zeros((self.n, 2), dtype=FLOAT)
cdef FLOAT_T [:, ::1] dedx = np.zeros((self.n, 2), dtype=FLOAT)
cdef INT_T i, j
for i in prange(self.n, nogil=True):
xi = _Site(i, &info)
e = xi.edge(&xi)
edge_set = _BitSet(num_edges)
j = 0
while j < xi.edge_num(&xi): # Looping through site edges.
f = e
while True: # Circling this vertex.
if not edge_set.add(&edge_set, f.arr_index):
xf = f.face(&f)
dedxi_p = f.cache.dVdv(&f, NAN_VECTOR) #dVdv
dedxi_p.self.smul(&dedxi_p, xf.cache.area(&xf, NAN) - A)
dedxi_p.self.matmul(&dedxi_p, e.cache.H(&e, NAN_MATRIX))
dedx[i][0] += dedxi_p.x
dedx[i][1] += dedxi_p.y
cdef INT_T i, j
for i in prange(self.n, nogil=True):
xi = _Site(i, &info)
e = xi.edge(&xi)
edge_set = _BitSet(num_edges)
j = 0
while j < xi.edge_num(&xi): # Looping through site edges.
f = e
while True: # Circling this vertex.
if not edge_set.add(&edge_set, f.arr_index):
xf = f.face(&f)
dedxi_p = f.cache.dVdv(&f, NAN_VECTOR) #dVdv
dedxi_p.self.smul(&dedxi_p, xf.cache.area(&xf, NAN) - A)
dedxi_p.self.matmul(&dedxi_p, e.cache.H(&e, NAN_MATRIX))
dedx[i][0] += dedxi_p.x
dedx[i][1] += dedxi_p.y
f = f.twin(&f)
f = f.next(&f)
if f.arr_index == e.arr_index:
break
f = f.twin(&f)
f = f.next(&f)
if f.arr_index == e.arr_index:
break
e = e.next(&e)
j = j + 1
edge_set.free(&edge_set)
self.grad = dedx
e = e.next(&e)
j = j + 1
edge_set.free(&edge_set)
self.grad = dedx
cdef void calc_hess(self) except *:
d = 10e-5
HE = np.zeros((2*self.n, 2*self.n))
new_sites = np.copy(self.site_arr) # Maintain one copy for speed.
for i in range(self.n):
for j in range(2):
mod = self.w if j == 0 else self.h
new_sites[i][j] = (new_sites[i][j] + d) % mod
Ep = self.__class__(self.n, self.w, self.h, self.r, new_sites)
new_sites[i][j] = (new_sites[i][j] - 2*d) % mod
Em = self.__class__(self.n, self.w, self.h, self.r, new_sites)
new_sites[i][j] = (new_sites[i][j] + d) % mod
HE[:, 2*i+j] = ((Ep.gradient - Em.gradient)/(2*d)).flatten()
# Average out discrepencies, since it should be symmetric.
for i in range(2*self.n):
for j in range(i, 2*self.n):
HE[i][j] = (HE[i][j] + HE[j][i])/2
HE[j][i] = HE[i][j]
self.hess = HE
cdef class RadialALEnergy(VoronoiContainer):
"""
Class for formulas relevant to the Area energy.
:param n: [int] how many sites to generate.
:param w: [float] width of the bounding domain.
:param h: [float] height of the bounding domain.
:param r: [float] radius of zero energy circle.
:param sites: [np.ndarray] collection of sites.
"""
"""
Class for formulas relevant to the Area energy.
:param n: [int] how many sites to generate.
:param w: [float] width of the bounding domain.
:param h: [float] height of the bounding domain.
:param r: [float] radius of zero energy circle.
:param sites: [np.ndarray] collection of sites.
"""
attr_str = "radial-al"
title_str = "Radial[AL]"
attr_str = "radial-al"
title_str = "Radial[AL]"
def __init__(AreaEnergy self, INT_T n, FLOAT_T w, FLOAT_T h, FLOAT_T r,
np.ndarray[FLOAT_T, ndim=2] site_arr):
#self.edge_cache_map = &AREA_EDGE_CACHE_MAP
self.energy = 0.0
def __init__(AreaEnergy self, INT_T n, FLOAT_T w, FLOAT_T h, FLOAT_T r,
np.ndarray[FLOAT_T, ndim=2] site_arr):
#self.edge_cache_map = &AREA_EDGE_CACHE_MAP
self.energy = 0.0
super().__init__(n, w, h, r, site_arr)
super().__init__(n, w, h, r, site_arr)
cdef void precompute(self) except *:
cdef VoronoiInfo info = _VoronoiInfo(self.sites, self.edges, self.points,
self.vertices, self.site_cache, self.edge_cache, self.edge_cache_map)
cdef void precompute(self) except *:
cdef VoronoiInfo info = _VoronoiInfo(self.sites, self.edges, self.points,
self.vertices, self.site_cache, self.edge_cache, self.edge_cache_map)
pass
pass
cdef void calc_grad(self) except *:
cdef VoronoiInfo info = _VoronoiInfo(self.sites, self.edges, self.points,
self.vertices, self.site_cache, self.edge_cache, self.edge_cache_map)
cdef void calc_grad(self) except *:
cdef VoronoiInfo info = _VoronoiInfo(self.sites, self.edges, self.points,
self.vertices, self.site_cache, self.edge_cache, self.edge_cache_map)
pass
pass
cdef void calc_hess(self) except *:
pass
cdef class RadialTEnergy(VoronoiContainer):
"""
Class for formulas relevant to the Area energy.
:param n: [int] how many sites to generate.
:param w: [float] width of the bounding domain.
:param h: [float] height of the bounding domain.
:param r: [float] radius of zero energy circle.
:param sites: [np.ndarray] collection of sites.
"""
"""
Class for formulas relevant to the Area energy.
:param n: [int] how many sites to generate.
:param w: [float] width of the bounding domain.
:param h: [float] height of the bounding domain.
:param r: [float] radius of zero energy circle.
:param sites: [np.ndarray] collection of sites.
"""
attr_str = "radial-t"
title_str = "Radial[T]"
def __init__(AreaEnergy self, INT_T n, FLOAT_T w, FLOAT_T h, FLOAT_T r,
np.ndarray[FLOAT_T, ndim=2] site_arr):
self.edge_cache_map = &RADIALT_ECM
self.energy = 0.0
attr_str = "radial-t"
title_str = "Radial[T]"
def __init__(AreaEnergy self, INT_T n, FLOAT_T w, FLOAT_T h, FLOAT_T r,
np.ndarray[FLOAT_T, ndim=2] site_arr):
self.edge_cache_map = &RADIALT_ECM
self.energy = 0.0
super().__init__(n, w, h, r, site_arr)
super().__init__(n, w, h, r, site_arr)
cdef void precompute(self) except *:
cdef VoronoiInfo info = _VoronoiInfo(self.sites, self.edges, self.points,
self.vertices, self.site_cache, self.edge_cache, self.edge_cache_map)
cdef void precompute(self) except *:
cdef VoronoiInfo info = _VoronoiInfo(self.sites, self.edges, self.points,
self.vertices, self.site_cache, self.edge_cache, self.edge_cache_map)
cdef Site xi
cdef HalfEdge e, ep
cdef Vector2D la
cdef Site xi
cdef HalfEdge e, ep
cdef Vector2D la
# All energy has a 2pir_0 term.
cdef FLOAT_T [:] site_energy = np.full(self.sites.shape[0], 2*PI*self.r**2)
cdef FLOAT_T [:] avg_radii = np.zeros(self.sites.shape[0])
cdef FLOAT_T sm, sp
# All energy has a 2pir_0 term.
cdef FLOAT_T [:] site_energy = np.full(self.sites.shape[0], 2*PI*self.r**2)
cdef FLOAT_T [:] avg_radii = np.zeros(self.sites.shape[0])
cdef FLOAT_T sm, sp
cdef INT_T i, j
for i in prange(self.sites.shape[0], nogil=True):
xi = _Site(i, &info)
e = xi.edge(&xi)
j = 0
while j < xi.edge_num(&xi):
ep = e.next(&e)
#e.cache.H(&e, VoronoiContainer.calc_H(em, e))
cdef INT_T i, j
for i in prange(self.sites.shape[0], nogil=True):
xi = _Site(i, &info)
e = xi.edge(&xi)
j = 0
while j < xi.edge_num(&xi):
ep = e.next(&e)
#e.cache.H(&e, VoronoiContainer.calc_H(em, e))
la = e.cache.la(&e, NAN_VECTOR)
sp = la.dot(&la, ep.cache.da(&ep, NAN_VECTOR)) # dap . la
sm = la.dot(&la, e.cache.da(&e, NAN_VECTOR)) # da . la
la = e.cache.la(&e, NAN_VECTOR)
sp = la.dot(&la, ep.cache.da(&ep, NAN_VECTOR)) # dap . la
sm = la.dot(&la, e.cache.da(&e, NAN_VECTOR)) # da . la
sp = sp / (ep.cache.da_mag(&ep, NAN) * e.cache.la_mag(&e, NAN))
sm = sm / (e.cache.da_mag(&e, NAN) * e.cache.la_mag(&e, NAN))
sp = sp / (ep.cache.da_mag(&ep, NAN) * e.cache.la_mag(&e, NAN))
sm = sm / (e.cache.da_mag(&e, NAN) * e.cache.la_mag(&e, NAN))
e.cache.calI(&e, <FLOAT_T>(atanh(<double>sp) - atanh(<double>sm)))
e.cache.calI(&e, <FLOAT_T>(atanh(<double>sp) - atanh(<double>sm)))
avg_radii[i] += e.cache.ya_mag(&e, NAN) * e.cache.calI(&e, NAN) / 2
avg_radii[i] += e.cache.ya_mag(&e, NAN) * e.cache.calI(&e, NAN) / 2
e = e.next(&e)
j = j + 1
e = e.next(&e)
j = j + 1
site_energy[i] += 2*(xi.cache.area(&xi, NAN) - self.r*avg_radii[i])
site_energy[i] += 2*(xi.cache.area(&xi, NAN) - self.r*avg_radii[i])
xi.cache.avg_radius(&xi, avg_radii[i]/(2*PI))
xi.cache.energy(&xi, site_energy[i])
xi.cache.avg_radius(&xi, avg_radii[i]/(2*PI))
xi.cache.energy(&xi, site_energy[i])
self.energy = np.sum(site_energy[:self.n])
self.energy = np.sum(site_energy[:self.n])
cdef void calc_grad(self) except *:
cdef VoronoiInfo info = _VoronoiInfo(self.sites, self.edges, self.points,
self.vertices, self.site_cache, self.edge_cache, self.edge_cache_map)
cdef void calc_grad(self) except *:
cdef VoronoiInfo info = _VoronoiInfo(self.sites, self.edges, self.points,
self.vertices, self.site_cache, self.edge_cache, self.edge_cache_map)
cdef Site xi
cdef HalfEdge e
cdef Vector2D dedxi_p
cdef Site xi
cdef HalfEdge e
cdef Vector2D dedxi_p
cdef FLOAT_T [:, ::1] dedx = np.zeros((self.n, 2), dtype=FLOAT)
cdef FLOAT_T [:, ::1] dedx = np.zeros((self.n, 2), dtype=FLOAT)
cdef INT_T i, j
for i in prange(self.n, nogil=True):
xi = _Site(i, &info)
e = xi.edge(&xi)
cdef INT_T i, j
for i in prange(self.n, nogil=True):
xi = _Site(i, &info)
e = xi.edge(&xi)
j = 0
while j < xi.edge_num(&xi): # Looping through site edges.
dedxi_p = e.cache.ya(&e, NAN_VECTOR)
dedxi_p.self.smul(
&dedxi_p,
e.cache.calI(&e, NAN) / e.cache.ya_mag(&e, NAN)
)
j = 0
while j < xi.edge_num(&xi): # Looping through site edges.
dedxi_p = e.cache.ya(&e, NAN_VECTOR)
dedxi_p.self.smul(
&dedxi_p,
e.cache.calI(&e, NAN) / e.cache.ya_mag(&e, NAN)
)
dedx[i][0] += 2*self.r*dedxi_p.x
dedx[i][1] += 2*self.r*dedxi_p.y
dedx[i][0] += 2*self.r*dedxi_p.x
dedx[i][1] += 2*self.r*dedxi_p.y
e = e.next(&e)
j = j + 1
e = e.next(&e)
j = j + 1
self.grad = dedx
self.grad = dedx
cdef void calc_hess(self) except *:
cdef VoronoiInfo info = _VoronoiInfo(self.sites, self.edges, self.points,
self.vertices, self.site_cache,
self.edge_cache, self.edge_cache_map)
cdef Site xi, xk
cdef HalfEdge em, e, ep, f
cdef Vector2D temp1, temp2
cdef Matrix2x2 dsite, q, tempm
cdef BitSet edge_set
cdef INT_T num_edges = self.edges.shape[0]
cdef FLOAT_T [:,:] HE = np.zeros((2*self.n, 2*self.n))
cdef INT_T i, j, k
for i in prange(self.sites.shape[0], nogil=True):
xi = _Site(i, &info)
e = xi.edge(&xi)
j = 0
while j < xi.edge_num(&xi):
em, ep = e.prev(&e), e.next(&e)
e.cache.H(&e, VoronoiContainer.calc_H(em, e))
e = e.next(&e)
j = j + 1
for i in range(self.n):
xi = _Site(i, &info)
e = xi.edge(&xi)
edge_set = _BitSet(num_edges)
j = 0
while j < xi.edge_num(&xi):
em, ep = e.prev(&e), e.next(&e)
# Calculating of p
temp1 = em.cache.la(&em, NAN_VECTOR)
temp1.self.rot(&temp1)
temp1.self.sdiv(
&temp1,
em.cache.la_mag(&em, NAN) * em.cache.ya_mag(&em, NAN) / 2
)
temp2 = e.cache.la(&e, NAN_VECTOR)
temp2.self.rot(&temp2)
temp2.self.sdiv(
&temp2,
e.cache.la_mag(&e, NAN) * e.cache.ya_mag(&e, NAN) / 2
)
temp1.self.vsub(&temp1, temp2) # (lm/Am - l/A)
temp2 = e.cache.da(&e, NAN_VECTOR) # rot(d) / |d|
temp2.self.sdiv(&temp2, e.cache.da_mag(&e, NAN))
temp2.self.rot(&temp2)
dsite = temp1.vecmul(&temp1, temp2)
HE[2*i, 2*i] -= dsite.a
HE[2*i, 2*i+1] -= dsite.b
HE[2*i+1, 2*i] -= dsite.c
HE[2*i+1, 2*i+1] -= dsite.d
# Calculating of q
temp2 = e.cache.la(&e, NAN_VECTOR)
temp1 = temp2.copy.rot(&temp2)
q = temp1.vecmul(&temp1, temp2)
q.self.sdiv(&q, e.cache.la_mag(&e, NAN)**2)
q.self.msub(&q, R)
q.self.smul(
&q,
e.cache.calI(&e, NAN) / e.cache.la_mag(&e, NAN)
)
temp1 = e.cache.la(&e, NAN_VECTOR)
temp1.self.rot(&temp1)
tempm = temp1.vecmul(&temp1, temp1)
tempm.self.smul(
&tempm,
ep.cache.da_mag(&ep, NAN) - e.cache.da_mag(&e, NAN)
)
tempm.self.sdiv(
&tempm,
e.cache.la_mag(&e, NAN)**3 * e.cache.ya_mag(&e, NAN) / 2
)
q.self.madd(&q, tempm)
# Minus portion
temp2 = em.cache.la(&em, NAN_VECTOR)
temp1 = temp2.copy.rot(&temp2)
tempm = temp1.vecmul(&temp1, temp2)
tempm.self.sdiv(&tempm, em.cache.la_mag(&em, NAN)**2)
tempm = R.copy.msub(&R, tempm)
tempm.self.smul(
&tempm,
em.cache.calI(&em, NAN) / em.cache.la_mag(&em, NAN)
)
q.self.madd(&q, tempm)
temp1 = em.cache.la(&em, NAN_VECTOR)
temp1.self.rot(&temp1)
tempm = temp1.vecmul(&temp1, temp1)
tempm.self.smul(
&tempm,
e.cache.da_mag(&e, NAN) - em.cache.da_mag(&em, NAN)
)
tempm.self.sdiv(
&tempm,
em.cache.la_mag(&em, NAN)**3 * em.cache.ya_mag(&em, NAN) / 2
)
q.self.msub(&q, tempm)
# Add p to q, so p = p, q = p+q
q.self.madd(&q, dsite)
f = e
while True:
xk = f.face(&f)
k = xk.index(&xk) % self.n
if k < 0:
k = k + self.n
if not edge_set.add(&edge_set, f.arr_index):
tempm = q.copy.matmul(&q, f.cache.H(&f, NAN_MATRIX))
HE[2*i, 2*k] += tempm.a
HE[2*i, 2*k+1] += tempm.b
HE[2*i+1, 2*k] += tempm.c
HE[2*i+1, 2*k+1] += tempm.d
f = f.twin(&f)
f = f.next(&f)
if f.arr_index == e.arr_index:
break
e = e.next(&e)
j = j + 1
edge_set.free(&edge_set)
self.hess = -2*self.r*np.asarray(HE, dtype=FLOAT)
self.hess = (
( np.asarray(self.hess, dtype=FLOAT)
+ np.asarray(self.hess, dtype=FLOAT).T )
/ 2
)

View File

@ -2,11 +2,21 @@ from __future__ import annotations
from typing import List, Tuple
import numpy as np
from numpy.linalg import norm as mag
from math import gcd, sqrt, log, tan, atan, pi
from math import gcd, sqrt, log, tan, atan, atanh, pi
import cmath
from fractions import Fraction
Config = Tuple[int, int]
def e_hex(domain: DomainParams) -> float:
return (
2
- 2 * domain.r * (6 * 3 ** (-0.25) * sqrt(2) * atanh(0.5))
+ 2 * pi * domain.r ** 2
)
def configurations(domain: DomainParams) -> List[Config]:
n = domain.n
coprimes, valid = [], []
@ -25,6 +35,9 @@ def configurations(domain: DomainParams) -> List[Config]:
except KeyError:
pass
for i in range(len(valid)):
valid.append((valid[i][1], valid[i][0]))
return valid
@ -106,3 +119,71 @@ def rot(v: numpy.ndarray) -> numpy.ndarray:
w = np.copy(v)
w[0], w[1] = -w[1], w[0]
return w
def divisors(n: int) -> List[int]:
divs = [[i, n // i] for i in range(1, int(sqrt(n)) + 1) if n % i == 0]
return sorted(set(list(sum(divs, []))))
def factorize(n: int) -> Dict[int, int]:
primes = [i for i in range(1, n + 1) if len(divisors(i)) == 2]
prime_fac = {}
for prime in primes:
i = 0
while n % prime ** (i + 1) == 0:
i += 1
if i > 0:
prime_fac[prime] = i
return prime_fac
def hexagon_alpha(n: int, fraction: bool = False) -> List[int]:
if n % 2 == 1:
return []
fac = factorize(n)
q = 1
for prime in fac:
if prime % 3 != 2:
q *= prime ** fac[prime]
divq = divisors(q)
ratios, thres = [], 1 / sqrt(3)
for g in divq:
us = n // (2 * g)
divu = divisors(us)
for u in divu:
d = 2 * g * u * u
f = Fraction(n, d)
if f <= thres:
ratios.append(f)
else:
ratios.append(Fraction(d, 3 * n))
ratios = sorted(set(ratios))
if fraction:
return ratios
else:
return [float(x) * sqrt(3) for x in ratios]
def hexagon_alpha_brute(n: int):
w = cmath.rect(1, 2 * pi / 3)
divs = divisors(n / 2)
ratios, thres = [], 1 / sqrt(3)
for a in range(n):
for b in range(1, a + 1):
if a == 0 and b == 0:
continue
z2, g = a * a - a * b + b * b, gcd(a - 2 * b, 2 * a - b)
if z2 // g in divs:
f = Fraction(n, 2 * z2)
if f <= thres:
ratios.append(f)
else:
ratios.append(Fraction(2 * z2, 3 * n))
ratios = sorted(set([float(x) * sqrt(3) for x in ratios]))
return ratios

View File

@ -159,6 +159,7 @@ class Simulation:
sim, frames = Simulation.load(path)
for frame in frames:
sim.frames.append(sim.energy.mode(*frame["domain"], frame["arr"]))
sim.frames[-1].stats = frame["stats"]
return sim
@ -238,8 +239,8 @@ class Flow(Simulation):
if self.adaptive:
error = change - grad * self.step_size
tol = 10 ** min(-3, -2 + log10(grad_norm))
tol = 10 ** min(-4, -3 + log10(grad_norm))
# tol = 10 ** -7
self.step_size *= (tol / np.linalg.norm(error)) ** 0.5
if not save:
@ -315,7 +316,7 @@ class Search(Simulation):
new_sites: Optional[numpy.ndarray] = None,
) -> None:
if log:
print(f"Travel - {self.domain}", flush=True)
print(f"Search - {self.domain} - {len(self)}", flush=True)
if save and len(self) == 0:
self.save(self.initial_data, True)
@ -328,16 +329,15 @@ class Search(Simulation):
sim.run(False, log, log_steps)
self.frames.append(sim[-1])
# Get Hessian,and check nullity. If > 2, perturb.
hess = self.frames[i].hessian
eigs = np.sort(np.linalg.eig(hess)[0])
self.frames[i].stats["eigs"] = eigs
if save:
self.save(self.frame_data(i))
if log:
print(f"Equilibrium: {i:04}\n", flush=True)
# Get Hessian,and check nullity. If > 2, perturb.
hess = self.frames[i].hessian(10e-5)
eigs = np.sort(np.linalg.eig(hess)[0])
self.frames[i].stats["eigs"] = eigs
zero_eigs = np.count_nonzero(
np.isclose(eigs, np.zeros((len(eigs),)), atol=1e-4)
)

File diff suppressed because it is too large Load Diff

View File

@ -66,7 +66,7 @@ cdef class VoronoiContainer:
cdef readonly INT_T n
cdef readonly FLOAT_T w, h, r, energy
cdef FLOAT_T [2] dim
cdef FLOAT_T [:, ::1] points, vertices, site_cache, edge_cache, grad
cdef FLOAT_T [:, ::1] points, vertices, site_cache, edge_cache, grad, hess
cdef INT_T [:, ::1] sites, edges
cdef EdgeCacheMap* edge_cache_map
cdef dict __dict__
@ -77,6 +77,7 @@ cdef class VoronoiContainer:
cdef void common_cache(VoronoiContainer self) except *
cdef void precompute(self) except *
cdef void calc_grad(self) except *
cdef void calc_hess(self) except *
cdef void get_statistics(VoronoiContainer self) except *
@staticmethod

View File

@ -1,4 +1,4 @@
import array, scipy.spatial, numpy as np
import array, scipy.spatial, numpy as np, math
from cython.parallel import parallel, prange
cimport numpy as np
@ -6,8 +6,8 @@ from cpython cimport array
from libc.math cimport isnan, NAN, pi as PI
from squish.core cimport INT_T, FLOAT_T, \
IArray, FArray, Vector2D, Matrix2x2, \
_IArray, _FArray, _Vector2D, _Matrix2x2
IArray, FArray, Vector2D, Matrix2x2, BitSet, \
_IArray, _FArray, _Vector2D, _Matrix2x2, _BitSet
from squish.voronoi cimport SiteCacheMap, EdgeCacheMap, VoronoiInfo, Site, HalfEdge
@ -554,8 +554,8 @@ cdef class VoronoiContainer:
# vp - vm, vm - xi
la, da = q.copy.vsub(&q, p), p.copy.vsub(&p, xi.vec(&xi))
la_mag = la.mag(&la)
area_p = la.dot(&la, da.rot(&da))
Rla = la.rot(&la)
area_p = la.dot(&la, da.copy.rot(&da))
Rla = la.copy.rot(&la)
ya = Rla.copy.smul(&Rla, -2*area_p/la.dot(&la, la))
# Calculating centroid.
@ -591,14 +591,14 @@ cdef class VoronoiContainer:
xj, xk = em.cache.ya(&em, NAN_VECTOR), ep.cache.ya(&ep, NAN_VECTOR)
Rxjk = xk.copy.vsub(&xk, xj)
Rxjk.self.smul(&Rxjk, 2)
Rxjk = Rxjk.rot(&Rxjk)
Rxjk.self.rot(&Rxjk)
v = ep.cache.da(&ep, NAN_VECTOR)
top = R.copy.smul(&R, xj.dot(&xj, xj) - xk.dot(&xk, xk))
top.self.msub(&top, _Matrix2x2(v.x*Rxjk.x, v.x*Rxjk.y, v.y*Rxjk.x, v.y*Rxjk.y))
top.self.sdiv(&top, -Rxjk.dot(&Rxjk, xj))
return _Matrix2x2(top.a, top.c, top.b, top.d)
return top
@staticmethod
cdef inline bint sign(FLOAT_T [::1] ref, FLOAT_T [::1] p, FLOAT_T [::1] q):
@ -621,6 +621,9 @@ cdef class VoronoiContainer:
cdef void calc_grad(self) except *:
pass
cdef void calc_hess(self) except *:
pass
cdef void get_statistics(self) except *:
self.stats = {}
cache = self.site_cache[:self.n, :]
@ -660,6 +663,11 @@ cdef class VoronoiContainer:
def gradient(self):
return np.asarray(self.grad, dtype=FLOAT)
@property
def hessian(self):
self.calc_hess()
return np.asarray(self.hess, dtype=FLOAT)
def add_sites(self, add):
return (self.site_arr + add) % np.asarray(self.dim, dtype=FLOAT)
@ -671,146 +679,6 @@ cdef class VoronoiContainer:
return -(step/2)*(k1+k2), -k1
def approx_hessian(self, d: float) -> np.ndarray:
"""
Obtains the approximate Hessian.
:param d: [float] small d for approximation.
:return: 2Nx2N array that represents Hessian.
"""
HE = np.zeros((2*self.n, 2*self.n))
new_sites = np.copy(self.site_arr) # Maintain one copy for speed.
for i in range(self.n):
for j in range(2):
mod = self.w if j == 0 else self.h
new_sites[i][j] = (new_sites[i][j] + d) % mod
Ep = self.__class__(self.n, self.w, self.h, self.r, new_sites)
new_sites[i][j] = (new_sites[i][j] - 2*d) % mod
Em = self.__class__(self.n, self.w, self.h, self.r, new_sites)
new_sites[i][j] = (new_sites[i][j] + d) % mod
HE[:, 2*i+j] = ((Ep.gradient - Em.gradient)/(2*d)).flatten()
# Average out discrepencies, since it should be symmetric.
for i in range(2*self.n):
for j in range(i, 2*self.n):
HE[i][j] = (HE[i][j] + HE[j][i])/2
HE[j][i] = HE[i][j]
return HE
def radialt_hessian(self) -> np.ndarray:
HE = np.zeros((2*self.n, 2*self.n))
cdef VoronoiInfo info = _VoronoiInfo(self.sites, self.edges, self.points,
self.vertices, self.site_cache,
self.edge_cache, self.edge_cache_map)
cdef Site xi, xk
cdef HalfEdge e, em, ep, fj, fk
cdef Vector2D temp1, temp2, dau, dapu
cdef Matrix2x2 sigI, sigJ, sigK, p, q, tempm, toI, toJ, toK
cdef INT_T i, j, k, z
for i in range(self.n):
xi = _Site(i, &info)
ep = xi.edge(&xi)
e = ep.prev(&ep)
j = 0
while j < xi.edge_num(&xi):
e.cache.H(&e, VoronoiContainer.calc_H(e, ep))
e = e.next(&e)
j = j + 1
for i in range(self.n):
xi = _Site(i, &info)
e = xi.edge(&xi)
z = 0
while z < xi.edge_num(&xi):
em, ep = e.prev(&e), e.next(&e)
fj, fk = em.twin(&em), e.twin(&e)
fj, fk = fj.next(&fj), fk.next(&fk)
xj, xk = fj.face(&fj), fk.face(&fk)
j, k = xj.index(&xj) % self.n, xk.index(&xk) % self.n
if k < 0:
k = k + self.n
if j < 0:
j = j + self.n
sigI = e.cache.H(&e, NAN_MATRIX)
sigJ = fj.cache.H(&fj, NAN_MATRIX)
sigK = fk.cache.H(&fk, NAN_MATRIX)
### Calculating of p
temp1 = e.cache.la(&e, NAN_VECTOR)
temp1 = temp1.rot(&temp1)
temp1.self.sdiv(
&temp1,
e.cache.la_mag(&e, NAN) * e.cache.ya_mag(&e, NAN) / 2
)
dau = e.cache.da(&e, NAN_VECTOR)
dau.self.sdiv(&dau, e.cache.da_mag(&e, NAN))
dapu = ep.cache.da(&ep, NAN_VECTOR)
dapu.self.sdiv(&dapu, ep.cache.da_mag(&ep, NAN))
temp2 = dapu.copy.vsub(&dapu, dau)
temp2 = temp2.rot(&temp2)
p = _Matrix2x2(
temp1.x*temp2.x, temp1.x*temp2.y,
temp1.y*temp2.x, temp1.y*temp2.y
)
### Calculating of q
temp2 = e.cache.la(&e, NAN_VECTOR)
temp1 = temp2.rot(&temp2)
q = _Matrix2x2(
temp1.x*temp2.x, temp1.x*temp2.y,
temp1.y*temp2.x, temp1.y*temp2.y
)
q.self.sdiv(&q, e.cache.la_mag(&e, NAN)**2)
q.self.msub(&q, R)
q.self.smul(
&q,
e.cache.calI(&e, NAN) / e.cache.la_mag(&e, NAN)
)
temp2 = em.cache.la(&em, NAN_VECTOR)
temp1 = temp2.rot(&temp2)
tempm = _Matrix2x2(
temp1.x*temp2.x, temp1.x*temp2.y,
temp1.y*temp2.x, temp1.y*temp2.y
)
tempm.self.sdiv(&tempm, em.cache.la_mag(&em, NAN)**2)
tempm = R.copy.msub(&R, tempm)
tempm.self.smul(
&tempm,
em.cache.calI(&em, NAN) / em.cache.la_mag(&em, NAN)
)
q.self.madd(&q, tempm)
# Calculating components that go to the respective sites
toI = sigI.copy.mmul(&sigI, p.copy.madd(&p, q))
toI.self.msub(&toI, p)
toJ = sigJ.copy.mmul(&sigJ, p.copy.madd(&p, q))
toK = sigK.copy.mmul(&sigK, p.copy.madd(&p, q))
HE[2*i: 2*(i+1), 2*i: 2*(i+1)] += np.array([[toI.a, toI.b], [toI.c, toI.d]])
HE[2*i: 2*(i+1), 2*j: 2*(j+1)] += np.array([[toJ.a, toJ.b], [toJ.c, toJ.d]])
HE[2*i: 2*(i+1), 2*k: 2*(k+1)] += np.array([[toK.a, toK.b], [toK.c, toK.d]])
e = e.next(&e)
z = z + 1
return -2*self.r*HE
def site_vert_arr(self): # -> List[np.ndarray]
cdef VoronoiInfo info = _VoronoiInfo(self.sites, self.edges, self.points,
self.vertices, self.site_cache, self.edge_cache, self.edge_cache_map)