Non-numerical Hessian for Radial[T]
This commit is contained in:
parent
8cd48a1acd
commit
f1a180b5a5
940
squish/core.c
940
squish/core.c
File diff suppressed because it is too large
Load Diff
@ -51,6 +51,7 @@ ctypedef Matrix2x2 (*MatrixCopySclOp)(Matrix2x2*, FLOAT_T) nogil
|
|||||||
|
|
||||||
ctypedef struct VectorSelfOps:
|
ctypedef struct VectorSelfOps:
|
||||||
Vector2D* (*neg)(Vector2D*) nogil
|
Vector2D* (*neg)(Vector2D*) nogil
|
||||||
|
Vector2D* (*rot)(Vector2D*) nogil
|
||||||
|
|
||||||
VectorSelfVecOp vadd
|
VectorSelfVecOp vadd
|
||||||
VectorSelfVecOp vsub
|
VectorSelfVecOp vsub
|
||||||
@ -66,6 +67,7 @@ ctypedef struct VectorSelfOps:
|
|||||||
|
|
||||||
ctypedef struct VectorCopyOps:
|
ctypedef struct VectorCopyOps:
|
||||||
Vector2D (*neg)(Vector2D*) nogil
|
Vector2D (*neg)(Vector2D*) nogil
|
||||||
|
Vector2D (*rot)(Vector2D*) nogil
|
||||||
|
|
||||||
VectorCopyVecOp vadd
|
VectorCopyVecOp vadd
|
||||||
VectorCopyVecOp vsub
|
VectorCopyVecOp vsub
|
||||||
@ -81,6 +83,7 @@ ctypedef struct VectorCopyOps:
|
|||||||
|
|
||||||
ctypedef struct MatrixSelfOps:
|
ctypedef struct MatrixSelfOps:
|
||||||
Matrix2x2* (*neg)(Matrix2x2*) nogil
|
Matrix2x2* (*neg)(Matrix2x2*) nogil
|
||||||
|
Matrix2x2* (*T)(Matrix2x2*) nogil
|
||||||
|
|
||||||
MatrixSelfMatOp madd
|
MatrixSelfMatOp madd
|
||||||
MatrixSelfMatOp msub
|
MatrixSelfMatOp msub
|
||||||
@ -96,6 +99,7 @@ ctypedef struct MatrixSelfOps:
|
|||||||
|
|
||||||
ctypedef struct MatrixCopyOps:
|
ctypedef struct MatrixCopyOps:
|
||||||
Matrix2x2 (*neg)(Matrix2x2*) nogil
|
Matrix2x2 (*neg)(Matrix2x2*) nogil
|
||||||
|
Matrix2x2 (*T)(Matrix2x2*) nogil
|
||||||
|
|
||||||
MatrixCopyMatOp madd
|
MatrixCopyMatOp madd
|
||||||
MatrixCopyMatOp msub
|
MatrixCopyMatOp msub
|
||||||
@ -115,7 +119,7 @@ ctypedef struct Vector2D:
|
|||||||
VectorCopyOps copy
|
VectorCopyOps copy
|
||||||
|
|
||||||
bint (*equals)(Vector2D*, Vector2D) nogil
|
bint (*equals)(Vector2D*, Vector2D) nogil
|
||||||
Vector2D (*rot)(Vector2D*) nogil
|
Matrix2x2 (*vecmul)(Vector2D*, Vector2D) nogil
|
||||||
FLOAT_T (*dot)(Vector2D*, Vector2D) nogil
|
FLOAT_T (*dot)(Vector2D*, Vector2D) nogil
|
||||||
FLOAT_T (*mag)(Vector2D*) nogil
|
FLOAT_T (*mag)(Vector2D*) nogil
|
||||||
|
|
||||||
|
|||||||
@ -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 = \
|
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
|
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 = \
|
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
|
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 = \
|
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
|
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 = \
|
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
|
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.
|
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.x, vec.y = x, y
|
||||||
vec.self, vec.copy = VSO, VCO
|
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
|
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
|
self.x, self.y = self.x*m.a + self.y*m.c, self.x*m.b + self.y*m.d
|
||||||
return self
|
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:
|
cdef inline Vector2D v_neg_c(Vector2D* self) nogil:
|
||||||
return _Vector2D(-self.x, -self.y)
|
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
|
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)
|
return _Vector2D(-self.y, self.x)
|
||||||
|
|
||||||
cdef inline FLOAT_T dot(Vector2D* self, Vector2D w) nogil:
|
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:
|
cdef inline FLOAT_T mag(Vector2D* self) nogil:
|
||||||
return <FLOAT_T>sqrt(<double>(self.x*self.x + self.y*self.y))
|
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 ####
|
#### 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
|
self.c*m.a + self.d*m.c, self.c*m.b + self.d*m.d
|
||||||
return self
|
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:
|
cdef inline Matrix2x2 m_neg_c(Matrix2x2* self) nogil:
|
||||||
return _Matrix2x2(-self.a, -self.b, -self.c, -self.d)
|
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.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
|
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)
|
||||||
@ -1,7 +1,13 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
from typing import Tuple, List, Optional
|
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 matplotlib.ticker import MaxNLocator, FormatStrFormatter
|
||||||
from scipy.spatial import Voronoi, voronoi_plot_2d
|
from scipy.spatial import Voronoi, voronoi_plot_2d
|
||||||
from multiprocessing import Pool, cpu_count
|
from multiprocessing import Pool, cpu_count
|
||||||
@ -123,18 +129,49 @@ class Diagram:
|
|||||||
raise ValueError("Not a valid mode for diagrams!")
|
raise ValueError("Not a valid mode for diagrams!")
|
||||||
|
|
||||||
shape = self.diagrams.shape
|
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):
|
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:
|
else:
|
||||||
axes = np.atleast_2d(axes)
|
# axes = np.atleast_2d(axes)
|
||||||
it = np.nditer(self.diagrams, flags=["multi_index"])
|
it = np.nditer(self.diagrams, flags=["multi_index"])
|
||||||
for diagram in it:
|
for diagram in it:
|
||||||
if diagram == "":
|
if diagram == "":
|
||||||
continue
|
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:
|
if name is None:
|
||||||
name = f"img{frame:05}.png"
|
name = f"img{frame:05}.png"
|
||||||
|
|
||||||
@ -148,28 +185,60 @@ class Diagram:
|
|||||||
domain = self.sim.domains[i]
|
domain = self.sim.domains[i]
|
||||||
n, w, h = domain.n, domain.w, domain.h
|
n, w, h = domain.n, domain.w, domain.h
|
||||||
scale = 1.5
|
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(
|
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")
|
# Mark location axis with 3 ticks.
|
||||||
ax.plot([0, 0], [-h, 2 * h], "r")
|
ax.set_xticks([0, w / 2, w])
|
||||||
ax.plot([w, w], [-h, 2 * h], "r")
|
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.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.set_ylim([(1 - scale) * h / 2, (1 + scale) * h / 2])
|
||||||
ax.title.set_text("Voronoi Visualization")
|
ax.set_title("Voronoi Tessellation")
|
||||||
|
|
||||||
props = dict(boxstyle="round", facecolor="wheat", alpha=0.8)
|
|
||||||
|
|
||||||
|
# Marking sites and defects.
|
||||||
defects = {5: {"x": [], "y": []}, 7: {"x": [], "y": []}}
|
defects = {5: {"x": [], "y": []}, 7: {"x": [], "y": []}}
|
||||||
|
|
||||||
for j in range(n):
|
for j in range(n):
|
||||||
for s in SYMM:
|
for s in SYMM:
|
||||||
vec = self.sim.voronois[i].points[j] + s * self.sim.domains[i].dim
|
vec = self.sim.voronois[i].points[j] + s * self.sim.domains[i].dim
|
||||||
|
|
||||||
if area:
|
if area:
|
||||||
txt = ax.text(
|
txt = ax.text(
|
||||||
*vec, str(round(self.sim.stats[i]["site_areas"][j], 3))
|
*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:
|
elif self.sim.stats[i]["site_edge_count"][j] == 7:
|
||||||
defects[7]["x"].append(vec[0])
|
defects[7]["x"].append(vec[0])
|
||||||
defects[7]["y"].append(vec[1])
|
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(
|
||||||
ax.scatter(defects[7]["x"], defects[7]["y"], marker="*", color="C0")
|
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(
|
ax.text(
|
||||||
0.05,
|
0.065,
|
||||||
0.95,
|
0.935,
|
||||||
f"Energy: {self.sim.energies[i]}",
|
f"VEE: {round(sum(energies)/n - offset, 8)}",
|
||||||
transform=ax.transAxes,
|
transform=ax.transAxes,
|
||||||
fontsize=14,
|
|
||||||
verticalalignment="top",
|
verticalalignment="top",
|
||||||
bbox=props,
|
bbox=props,
|
||||||
)
|
)
|
||||||
@ -305,14 +393,32 @@ class Diagram:
|
|||||||
def eigs_plot(self, i: int, ax: AxesSubplot) -> None:
|
def eigs_plot(self, i: int, ax: AxesSubplot) -> None:
|
||||||
try:
|
try:
|
||||||
eigs = self.sim.stats[i]["eigs"]
|
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(
|
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:
|
except KeyError:
|
||||||
ax.text(0.5, 0.5, "Not Computed")
|
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_xlabel("")
|
||||||
ax.set_ylabel("Value")
|
ax.set_ylabel("Value")
|
||||||
|
|
||||||
|
|||||||
4173
squish/energy.c
4173
squish/energy.c
File diff suppressed because it is too large
Load Diff
@ -4,10 +4,10 @@ from cython.parallel import parallel, prange
|
|||||||
cimport numpy as np
|
cimport numpy as np
|
||||||
from libc.math cimport NAN, pi as PI, atanh
|
from libc.math cimport NAN, pi as PI, atanh
|
||||||
from squish.core cimport INT_T, FLOAT_T, Vector2D, Matrix2x2, BitSet, \
|
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, \
|
from squish.voronoi cimport Site, HalfEdge, EdgeCacheMap, VoronoiInfo, \
|
||||||
_Site, _HalfEdge, _EdgeCacheMap, _VoronoiInfo, VoronoiContainer, \
|
_Site, _HalfEdge, _EdgeCacheMap, _VoronoiInfo, VoronoiContainer, \
|
||||||
R, NAN_MATRIX, NAN_VECTOR
|
R, NAN_MATRIX, NAN_VECTOR
|
||||||
|
|
||||||
#### Constants ####
|
#### 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 EdgeCacheMap RADIALT_ECM = _EdgeCacheMap(0, 4, 6, 8, -1, 10, 11, 12, 13, 14)
|
||||||
|
|
||||||
cdef class AreaEnergy(VoronoiContainer):
|
cdef class AreaEnergy(VoronoiContainer):
|
||||||
"""
|
"""
|
||||||
Class for formulas relevant to the Area energy.
|
Class for formulas relevant to the Area energy.
|
||||||
:param n: [int] how many sites to generate.
|
:param n: [int] how many sites to generate.
|
||||||
:param w: [float] width of the bounding domain.
|
:param w: [float] width of the bounding domain.
|
||||||
:param h: [float] height of the bounding domain.
|
:param h: [float] height of the bounding domain.
|
||||||
:param r: [float] radius of zero energy circle.
|
:param r: [float] radius of zero energy circle.
|
||||||
:param sites: [np.ndarray] collection of sites.
|
:param sites: [np.ndarray] collection of sites.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
attr_str = "area"
|
attr_str = "area"
|
||||||
title_str = "Area"
|
title_str = "Area"
|
||||||
|
|
||||||
def __init__(AreaEnergy self, INT_T n, FLOAT_T w, FLOAT_T h, FLOAT_T r,
|
def __init__(AreaEnergy self, INT_T n, FLOAT_T w, FLOAT_T h, FLOAT_T r,
|
||||||
np.ndarray[FLOAT_T, ndim=2] site_arr):
|
np.ndarray[FLOAT_T, ndim=2] site_arr):
|
||||||
self.edge_cache_map = &AREA_ECM
|
self.edge_cache_map = &AREA_ECM
|
||||||
self.energy = 0.0
|
self.energy = 0.0
|
||||||
|
|
||||||
super().__init__(n, w, h, r, site_arr)
|
super().__init__(n, w, h, r, site_arr)
|
||||||
self.minimum = (<FLOAT_T>n)*(w*h/(<FLOAT_T>n)-PI*r**2)**2
|
self.minimum = (<FLOAT_T>n)*(w*h/(<FLOAT_T>n)-PI*r**2)**2
|
||||||
|
|
||||||
|
|
||||||
cdef void precompute(self) except *:
|
cdef void precompute(self) except *:
|
||||||
cdef VoronoiInfo info = _VoronoiInfo(self.sites, self.edges, self.points,
|
cdef VoronoiInfo info = _VoronoiInfo(self.sites, self.edges, self.points,
|
||||||
self.vertices, self.site_cache, self.edge_cache, self.edge_cache_map)
|
self.vertices, self.site_cache, self.edge_cache, self.edge_cache_map)
|
||||||
|
|
||||||
cdef Site xi
|
cdef Site xi
|
||||||
cdef HalfEdge em, e, ep
|
cdef HalfEdge em, e, ep
|
||||||
cdef Vector2D vdiff
|
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
|
cdef INT_T i, j
|
||||||
for i in prange(self.sites.shape[0], nogil=True):
|
for i in prange(self.sites.shape[0], nogil=True):
|
||||||
xi = _Site(i, &info)
|
xi = _Site(i, &info)
|
||||||
e = xi.edge(&xi)
|
e = xi.edge(&xi)
|
||||||
|
|
||||||
site_energy[i] = (xi.cache.area(&xi, NAN) - site_energy[i])**2
|
site_energy[i] = (xi.cache.area(&xi, NAN) - site_energy[i])**2
|
||||||
xi.cache.energy(&xi, site_energy[i])
|
xi.cache.energy(&xi, site_energy[i])
|
||||||
|
|
||||||
j = 0
|
j = 0
|
||||||
while j < xi.edge_num(&xi):
|
while j < xi.edge_num(&xi):
|
||||||
em, ep = e.prev(&e), e.next(&e)
|
em, ep = e.prev(&e), e.next(&e)
|
||||||
vdiff = em.origin(&em)
|
vdiff = em.origin(&em)
|
||||||
vdiff.self.vsub(&vdiff, ep.origin(&ep))
|
vdiff.self.vsub(&vdiff, ep.origin(&ep))
|
||||||
e.cache.dVdv(&e, R.vecmul(&R, vdiff))
|
e.cache.dVdv(&e, R.vecmul(&R, vdiff))
|
||||||
e.cache.H(&e, VoronoiContainer.calc_H(em, e))
|
e.cache.H(&e, VoronoiContainer.calc_H(em, e))
|
||||||
|
|
||||||
e = e.next(&e)
|
e = e.next(&e)
|
||||||
j = j + 1
|
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 void calc_grad(self) except *:
|
||||||
cdef VoronoiInfo info = _VoronoiInfo(self.sites, self.edges, self.points,
|
cdef VoronoiInfo info = _VoronoiInfo(self.sites, self.edges, self.points,
|
||||||
self.vertices, self.site_cache, self.edge_cache, self.edge_cache_map)
|
self.vertices, self.site_cache, self.edge_cache, self.edge_cache_map)
|
||||||
|
|
||||||
cdef Site xi, xf
|
cdef Site xi, xf
|
||||||
cdef HalfEdge e, f
|
cdef HalfEdge e, f
|
||||||
cdef Vector2D dedxi_p
|
cdef Vector2D dedxi_p
|
||||||
cdef BitSet edge_set
|
cdef BitSet edge_set
|
||||||
|
|
||||||
cdef INT_T num_edges = self.edges.shape[0]
|
cdef INT_T num_edges = self.edges.shape[0]
|
||||||
cdef FLOAT_T A = PI*self.r**2
|
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
|
cdef INT_T i, j
|
||||||
for i in prange(self.n, nogil=True):
|
for i in prange(self.n, nogil=True):
|
||||||
xi = _Site(i, &info)
|
xi = _Site(i, &info)
|
||||||
e = xi.edge(&xi)
|
e = xi.edge(&xi)
|
||||||
edge_set = _BitSet(num_edges)
|
edge_set = _BitSet(num_edges)
|
||||||
j = 0
|
j = 0
|
||||||
while j < xi.edge_num(&xi): # Looping through site edges.
|
while j < xi.edge_num(&xi): # Looping through site edges.
|
||||||
f = e
|
f = e
|
||||||
while True: # Circling this vertex.
|
while True: # Circling this vertex.
|
||||||
if not edge_set.add(&edge_set, f.arr_index):
|
if not edge_set.add(&edge_set, f.arr_index):
|
||||||
xf = f.face(&f)
|
xf = f.face(&f)
|
||||||
dedxi_p = f.cache.dVdv(&f, NAN_VECTOR) #dVdv
|
dedxi_p = f.cache.dVdv(&f, NAN_VECTOR) #dVdv
|
||||||
dedxi_p.self.smul(&dedxi_p, xf.cache.area(&xf, NAN) - A)
|
dedxi_p.self.smul(&dedxi_p, xf.cache.area(&xf, NAN) - A)
|
||||||
dedxi_p.self.matmul(&dedxi_p, e.cache.H(&e, NAN_MATRIX))
|
dedxi_p.self.matmul(&dedxi_p, e.cache.H(&e, NAN_MATRIX))
|
||||||
dedx[i][0] += dedxi_p.x
|
dedx[i][0] += dedxi_p.x
|
||||||
dedx[i][1] += dedxi_p.y
|
dedx[i][1] += dedxi_p.y
|
||||||
|
|
||||||
f = f.twin(&f)
|
f = f.twin(&f)
|
||||||
f = f.next(&f)
|
f = f.next(&f)
|
||||||
if f.arr_index == e.arr_index:
|
if f.arr_index == e.arr_index:
|
||||||
break
|
break
|
||||||
|
|
||||||
e = e.next(&e)
|
e = e.next(&e)
|
||||||
j = j + 1
|
j = j + 1
|
||||||
edge_set.free(&edge_set)
|
edge_set.free(&edge_set)
|
||||||
self.grad = dedx
|
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):
|
cdef class RadialALEnergy(VoronoiContainer):
|
||||||
"""
|
"""
|
||||||
Class for formulas relevant to the Area energy.
|
Class for formulas relevant to the Area energy.
|
||||||
:param n: [int] how many sites to generate.
|
:param n: [int] how many sites to generate.
|
||||||
:param w: [float] width of the bounding domain.
|
:param w: [float] width of the bounding domain.
|
||||||
:param h: [float] height of the bounding domain.
|
:param h: [float] height of the bounding domain.
|
||||||
:param r: [float] radius of zero energy circle.
|
:param r: [float] radius of zero energy circle.
|
||||||
:param sites: [np.ndarray] collection of sites.
|
:param sites: [np.ndarray] collection of sites.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
attr_str = "radial-al"
|
attr_str = "radial-al"
|
||||||
title_str = "Radial[AL]"
|
title_str = "Radial[AL]"
|
||||||
|
|
||||||
|
|
||||||
def __init__(AreaEnergy self, INT_T n, FLOAT_T w, FLOAT_T h, FLOAT_T r,
|
def __init__(AreaEnergy self, INT_T n, FLOAT_T w, FLOAT_T h, FLOAT_T r,
|
||||||
np.ndarray[FLOAT_T, ndim=2] site_arr):
|
np.ndarray[FLOAT_T, ndim=2] site_arr):
|
||||||
#self.edge_cache_map = &AREA_EDGE_CACHE_MAP
|
#self.edge_cache_map = &AREA_EDGE_CACHE_MAP
|
||||||
self.energy = 0.0
|
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 void precompute(self) except *:
|
||||||
cdef VoronoiInfo info = _VoronoiInfo(self.sites, self.edges, self.points,
|
cdef VoronoiInfo info = _VoronoiInfo(self.sites, self.edges, self.points,
|
||||||
self.vertices, self.site_cache, self.edge_cache, self.edge_cache_map)
|
self.vertices, self.site_cache, self.edge_cache, self.edge_cache_map)
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
cdef void calc_grad(self) except *:
|
cdef void calc_grad(self) except *:
|
||||||
cdef VoronoiInfo info = _VoronoiInfo(self.sites, self.edges, self.points,
|
cdef VoronoiInfo info = _VoronoiInfo(self.sites, self.edges, self.points,
|
||||||
self.vertices, self.site_cache, self.edge_cache, self.edge_cache_map)
|
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):
|
cdef class RadialTEnergy(VoronoiContainer):
|
||||||
"""
|
"""
|
||||||
Class for formulas relevant to the Area energy.
|
Class for formulas relevant to the Area energy.
|
||||||
:param n: [int] how many sites to generate.
|
:param n: [int] how many sites to generate.
|
||||||
:param w: [float] width of the bounding domain.
|
:param w: [float] width of the bounding domain.
|
||||||
:param h: [float] height of the bounding domain.
|
:param h: [float] height of the bounding domain.
|
||||||
:param r: [float] radius of zero energy circle.
|
:param r: [float] radius of zero energy circle.
|
||||||
:param sites: [np.ndarray] collection of sites.
|
:param sites: [np.ndarray] collection of sites.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
attr_str = "radial-t"
|
attr_str = "radial-t"
|
||||||
title_str = "Radial[T]"
|
title_str = "Radial[T]"
|
||||||
def __init__(AreaEnergy self, INT_T n, FLOAT_T w, FLOAT_T h, FLOAT_T r,
|
def __init__(AreaEnergy self, INT_T n, FLOAT_T w, FLOAT_T h, FLOAT_T r,
|
||||||
np.ndarray[FLOAT_T, ndim=2] site_arr):
|
np.ndarray[FLOAT_T, ndim=2] site_arr):
|
||||||
self.edge_cache_map = &RADIALT_ECM
|
self.edge_cache_map = &RADIALT_ECM
|
||||||
self.energy = 0.0
|
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 void precompute(self) except *:
|
||||||
cdef VoronoiInfo info = _VoronoiInfo(self.sites, self.edges, self.points,
|
cdef VoronoiInfo info = _VoronoiInfo(self.sites, self.edges, self.points,
|
||||||
self.vertices, self.site_cache, self.edge_cache, self.edge_cache_map)
|
self.vertices, self.site_cache, self.edge_cache, self.edge_cache_map)
|
||||||
|
|
||||||
cdef Site xi
|
cdef Site xi
|
||||||
cdef HalfEdge e, ep
|
cdef HalfEdge e, ep
|
||||||
cdef Vector2D la
|
cdef Vector2D la
|
||||||
|
|
||||||
# All energy has a 2pir_0 term.
|
# 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 [:] 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 [:] avg_radii = np.zeros(self.sites.shape[0])
|
||||||
cdef FLOAT_T sm, sp
|
cdef FLOAT_T sm, sp
|
||||||
|
|
||||||
cdef INT_T i, j
|
cdef INT_T i, j
|
||||||
for i in prange(self.sites.shape[0], nogil=True):
|
for i in prange(self.sites.shape[0], nogil=True):
|
||||||
xi = _Site(i, &info)
|
xi = _Site(i, &info)
|
||||||
e = xi.edge(&xi)
|
e = xi.edge(&xi)
|
||||||
j = 0
|
j = 0
|
||||||
while j < xi.edge_num(&xi):
|
while j < xi.edge_num(&xi):
|
||||||
ep = e.next(&e)
|
ep = e.next(&e)
|
||||||
#e.cache.H(&e, VoronoiContainer.calc_H(em, e))
|
#e.cache.H(&e, VoronoiContainer.calc_H(em, e))
|
||||||
|
|
||||||
la = e.cache.la(&e, NAN_VECTOR)
|
la = e.cache.la(&e, NAN_VECTOR)
|
||||||
sp = la.dot(&la, ep.cache.da(&ep, NAN_VECTOR)) # dap . la
|
sp = la.dot(&la, ep.cache.da(&ep, NAN_VECTOR)) # dap . la
|
||||||
sm = la.dot(&la, e.cache.da(&e, NAN_VECTOR)) # da . 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))
|
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))
|
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)
|
e = e.next(&e)
|
||||||
j = j + 1
|
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.avg_radius(&xi, avg_radii[i]/(2*PI))
|
||||||
xi.cache.energy(&xi, site_energy[i])
|
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 void calc_grad(self) except *:
|
||||||
cdef VoronoiInfo info = _VoronoiInfo(self.sites, self.edges, self.points,
|
cdef VoronoiInfo info = _VoronoiInfo(self.sites, self.edges, self.points,
|
||||||
self.vertices, self.site_cache, self.edge_cache, self.edge_cache_map)
|
self.vertices, self.site_cache, self.edge_cache, self.edge_cache_map)
|
||||||
|
|
||||||
cdef Site xi
|
cdef Site xi
|
||||||
cdef HalfEdge e
|
cdef HalfEdge e
|
||||||
cdef Vector2D dedxi_p
|
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
|
cdef INT_T i, j
|
||||||
for i in prange(self.n, nogil=True):
|
for i in prange(self.n, nogil=True):
|
||||||
xi = _Site(i, &info)
|
xi = _Site(i, &info)
|
||||||
e = xi.edge(&xi)
|
e = xi.edge(&xi)
|
||||||
|
|
||||||
j = 0
|
j = 0
|
||||||
while j < xi.edge_num(&xi): # Looping through site edges.
|
while j < xi.edge_num(&xi): # Looping through site edges.
|
||||||
dedxi_p = e.cache.ya(&e, NAN_VECTOR)
|
dedxi_p = e.cache.ya(&e, NAN_VECTOR)
|
||||||
dedxi_p.self.smul(
|
dedxi_p.self.smul(
|
||||||
&dedxi_p,
|
&dedxi_p,
|
||||||
e.cache.calI(&e, NAN) / e.cache.ya_mag(&e, NAN)
|
e.cache.calI(&e, NAN) / e.cache.ya_mag(&e, NAN)
|
||||||
)
|
)
|
||||||
|
|
||||||
dedx[i][0] += 2*self.r*dedxi_p.x
|
dedx[i][0] += 2*self.r*dedxi_p.x
|
||||||
dedx[i][1] += 2*self.r*dedxi_p.y
|
dedx[i][1] += 2*self.r*dedxi_p.y
|
||||||
|
|
||||||
e = e.next(&e)
|
e = e.next(&e)
|
||||||
j = j + 1
|
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
|
||||||
|
)
|
||||||
|
|||||||
@ -2,11 +2,21 @@ from __future__ import annotations
|
|||||||
from typing import List, Tuple
|
from typing import List, Tuple
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from numpy.linalg import norm as mag
|
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]
|
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]:
|
def configurations(domain: DomainParams) -> List[Config]:
|
||||||
n = domain.n
|
n = domain.n
|
||||||
coprimes, valid = [], []
|
coprimes, valid = [], []
|
||||||
@ -25,6 +35,9 @@ def configurations(domain: DomainParams) -> List[Config]:
|
|||||||
except KeyError:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
for i in range(len(valid)):
|
||||||
|
valid.append((valid[i][1], valid[i][0]))
|
||||||
|
|
||||||
return valid
|
return valid
|
||||||
|
|
||||||
|
|
||||||
@ -106,3 +119,71 @@ def rot(v: numpy.ndarray) -> numpy.ndarray:
|
|||||||
w = np.copy(v)
|
w = np.copy(v)
|
||||||
w[0], w[1] = -w[1], w[0]
|
w[0], w[1] = -w[1], w[0]
|
||||||
return w
|
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
|
||||||
|
|||||||
@ -159,6 +159,7 @@ class Simulation:
|
|||||||
sim, frames = Simulation.load(path)
|
sim, frames = Simulation.load(path)
|
||||||
for frame in frames:
|
for frame in frames:
|
||||||
sim.frames.append(sim.energy.mode(*frame["domain"], frame["arr"]))
|
sim.frames.append(sim.energy.mode(*frame["domain"], frame["arr"]))
|
||||||
|
sim.frames[-1].stats = frame["stats"]
|
||||||
|
|
||||||
return sim
|
return sim
|
||||||
|
|
||||||
@ -238,8 +239,8 @@ class Flow(Simulation):
|
|||||||
|
|
||||||
if self.adaptive:
|
if self.adaptive:
|
||||||
error = change - grad * self.step_size
|
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
|
self.step_size *= (tol / np.linalg.norm(error)) ** 0.5
|
||||||
|
|
||||||
if not save:
|
if not save:
|
||||||
@ -315,7 +316,7 @@ class Search(Simulation):
|
|||||||
new_sites: Optional[numpy.ndarray] = None,
|
new_sites: Optional[numpy.ndarray] = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
if log:
|
if log:
|
||||||
print(f"Travel - {self.domain}", flush=True)
|
print(f"Search - {self.domain} - {len(self)}", flush=True)
|
||||||
if save and len(self) == 0:
|
if save and len(self) == 0:
|
||||||
self.save(self.initial_data, True)
|
self.save(self.initial_data, True)
|
||||||
|
|
||||||
@ -328,16 +329,15 @@ class Search(Simulation):
|
|||||||
sim.run(False, log, log_steps)
|
sim.run(False, log, log_steps)
|
||||||
|
|
||||||
self.frames.append(sim[-1])
|
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:
|
if save:
|
||||||
self.save(self.frame_data(i))
|
self.save(self.frame_data(i))
|
||||||
if log:
|
if log:
|
||||||
print(f"Equilibrium: {i:04}\n", flush=True)
|
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(
|
zero_eigs = np.count_nonzero(
|
||||||
np.isclose(eigs, np.zeros((len(eigs),)), atol=1e-4)
|
np.isclose(eigs, np.zeros((len(eigs),)), atol=1e-4)
|
||||||
)
|
)
|
||||||
|
|||||||
2878
squish/voronoi.c
2878
squish/voronoi.c
File diff suppressed because it is too large
Load Diff
@ -66,7 +66,7 @@ cdef class VoronoiContainer:
|
|||||||
cdef readonly INT_T n
|
cdef readonly INT_T n
|
||||||
cdef readonly FLOAT_T w, h, r, energy
|
cdef readonly FLOAT_T w, h, r, energy
|
||||||
cdef FLOAT_T [2] dim
|
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 INT_T [:, ::1] sites, edges
|
||||||
cdef EdgeCacheMap* edge_cache_map
|
cdef EdgeCacheMap* edge_cache_map
|
||||||
cdef dict __dict__
|
cdef dict __dict__
|
||||||
@ -77,6 +77,7 @@ cdef class VoronoiContainer:
|
|||||||
cdef void common_cache(VoronoiContainer self) except *
|
cdef void common_cache(VoronoiContainer self) except *
|
||||||
cdef void precompute(self) except *
|
cdef void precompute(self) except *
|
||||||
cdef void calc_grad(self) except *
|
cdef void calc_grad(self) except *
|
||||||
|
cdef void calc_hess(self) except *
|
||||||
cdef void get_statistics(VoronoiContainer self) except *
|
cdef void get_statistics(VoronoiContainer self) except *
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|||||||
@ -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
|
from cython.parallel import parallel, prange
|
||||||
|
|
||||||
cimport numpy as np
|
cimport numpy as np
|
||||||
@ -6,8 +6,8 @@ from cpython cimport array
|
|||||||
from libc.math cimport isnan, NAN, pi as PI
|
from libc.math cimport isnan, NAN, pi as PI
|
||||||
|
|
||||||
from squish.core cimport INT_T, FLOAT_T, \
|
from squish.core cimport INT_T, FLOAT_T, \
|
||||||
IArray, FArray, Vector2D, Matrix2x2, \
|
IArray, FArray, Vector2D, Matrix2x2, BitSet, \
|
||||||
_IArray, _FArray, _Vector2D, _Matrix2x2
|
_IArray, _FArray, _Vector2D, _Matrix2x2, _BitSet
|
||||||
|
|
||||||
from squish.voronoi cimport SiteCacheMap, EdgeCacheMap, VoronoiInfo, Site, HalfEdge
|
from squish.voronoi cimport SiteCacheMap, EdgeCacheMap, VoronoiInfo, Site, HalfEdge
|
||||||
|
|
||||||
@ -554,8 +554,8 @@ cdef class VoronoiContainer:
|
|||||||
# vp - vm, vm - xi
|
# vp - vm, vm - xi
|
||||||
la, da = q.copy.vsub(&q, p), p.copy.vsub(&p, xi.vec(&xi))
|
la, da = q.copy.vsub(&q, p), p.copy.vsub(&p, xi.vec(&xi))
|
||||||
la_mag = la.mag(&la)
|
la_mag = la.mag(&la)
|
||||||
area_p = la.dot(&la, da.rot(&da))
|
area_p = la.dot(&la, da.copy.rot(&da))
|
||||||
Rla = la.rot(&la)
|
Rla = la.copy.rot(&la)
|
||||||
ya = Rla.copy.smul(&Rla, -2*area_p/la.dot(&la, la))
|
ya = Rla.copy.smul(&Rla, -2*area_p/la.dot(&la, la))
|
||||||
|
|
||||||
# Calculating centroid.
|
# Calculating centroid.
|
||||||
@ -591,14 +591,14 @@ cdef class VoronoiContainer:
|
|||||||
xj, xk = em.cache.ya(&em, NAN_VECTOR), ep.cache.ya(&ep, NAN_VECTOR)
|
xj, xk = em.cache.ya(&em, NAN_VECTOR), ep.cache.ya(&ep, NAN_VECTOR)
|
||||||
Rxjk = xk.copy.vsub(&xk, xj)
|
Rxjk = xk.copy.vsub(&xk, xj)
|
||||||
Rxjk.self.smul(&Rxjk, 2)
|
Rxjk.self.smul(&Rxjk, 2)
|
||||||
Rxjk = Rxjk.rot(&Rxjk)
|
Rxjk.self.rot(&Rxjk)
|
||||||
|
|
||||||
v = ep.cache.da(&ep, NAN_VECTOR)
|
v = ep.cache.da(&ep, NAN_VECTOR)
|
||||||
top = R.copy.smul(&R, xj.dot(&xj, xj) - xk.dot(&xk, xk))
|
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.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))
|
top.self.sdiv(&top, -Rxjk.dot(&Rxjk, xj))
|
||||||
|
|
||||||
return _Matrix2x2(top.a, top.c, top.b, top.d)
|
return top
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
cdef inline bint sign(FLOAT_T [::1] ref, FLOAT_T [::1] p, FLOAT_T [::1] q):
|
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 *:
|
cdef void calc_grad(self) except *:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
cdef void calc_hess(self) except *:
|
||||||
|
pass
|
||||||
|
|
||||||
cdef void get_statistics(self) except *:
|
cdef void get_statistics(self) except *:
|
||||||
self.stats = {}
|
self.stats = {}
|
||||||
cache = self.site_cache[:self.n, :]
|
cache = self.site_cache[:self.n, :]
|
||||||
@ -660,6 +663,11 @@ cdef class VoronoiContainer:
|
|||||||
def gradient(self):
|
def gradient(self):
|
||||||
return np.asarray(self.grad, dtype=FLOAT)
|
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):
|
def add_sites(self, add):
|
||||||
return (self.site_arr + add) % np.asarray(self.dim, dtype=FLOAT)
|
return (self.site_arr + add) % np.asarray(self.dim, dtype=FLOAT)
|
||||||
|
|
||||||
@ -671,146 +679,6 @@ cdef class VoronoiContainer:
|
|||||||
|
|
||||||
return -(step/2)*(k1+k2), -k1
|
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]
|
def site_vert_arr(self): # -> List[np.ndarray]
|
||||||
cdef VoronoiInfo info = _VoronoiInfo(self.sites, self.edges, self.points,
|
cdef VoronoiInfo info = _VoronoiInfo(self.sites, self.edges, self.points,
|
||||||
self.vertices, self.site_cache, self.edge_cache, self.edge_cache_map)
|
self.vertices, self.site_cache, self.edge_cache, self.edge_cache_map)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user