Changed adaptive stepping and non-saving Flow simulations no longer store frames

This commit is contained in:
Kenneth Jao 2021-09-29 04:11:08 -04:00
parent 4b472d2200
commit 48e5ff5015
5 changed files with 50 additions and 74 deletions

View File

@ -56,7 +56,7 @@ There are currently three simulation modes, and the configuration changes slight
Flow
""""
This mode simulates the relaxing of the objects to its equilibrium. The threshold is the sufficient condition where the gradient is sufficiently close to zero. Specifically, the simulation stops when the L1 norm of the gradient divided by the number of objects is less than the threshold. The `step-size` parameter only represents the *initial* step size. If ``accel`` is set to ``true``, then adaptive step size is used to make convergence faster.
This mode simulates the relaxing of the objects to its equilibrium. The threshold is the sufficient condition where the gradient is sufficiently close to zero. Specifically, the simulation stops when the L1 norm of the gradient divided by the number of objects is less than the threshold. The `step-size` parameter only represents the *initial* step size. If ``adaptive`` is set to ``true``, then adaptive step size is used to make convergence faster.
.. code-block:: json
@ -68,7 +68,7 @@ This mode simulates the relaxing of the objects to its equilibrium. The threshol
"mode": "flow",
"step_size": 0.05,
"threshold": 0.0001,
"accel": true
"adaptive": true
},
...
}
@ -87,7 +87,7 @@ This mode searches for equilibrium until `eq_stop_count` equilibria are found. A
"mode": "search",
"step_size": 0.05,
"threshold": 0.0001,
"accel": true,
"adaptive": true,
"eq_stop_count": 100,
"manifold_step_size": 0.1
},
@ -109,7 +109,7 @@ This mode simulates the the change in the equilibrium as the width is decreased.
"mode": "shrink",
"step_size": 0.05,
"threshold": 0.0001,
"accel": true,
"adaptive": true,
"width_change": 1,
"width_stop": 0.3
},

View File

@ -10,6 +10,7 @@ import squish.ordered as order
from squish import Simulation, DomainParams
from squish.common import OUTPUT_DIR
def order_process(domain: DomainParams) -> Tuple[float, float, float]:
energies = []
configs = order.configurations(domain)

View File

@ -658,24 +658,7 @@ cdef class VoronoiContainer:
).gradient
return (step/2)*(k1+k2), k1
# k1 = self.gradient
# k2 = self.__class__(self.n, self.w, self.h, self.r,
# self.add_sites(step*k1/2)
# ).gradient
# lower = step*(-k1+ 2*k2)
# k3 = self.__class__(self.n, self.w, self.h, self.r,
# self.add_sites(lower)
# ).gradient
# higher = (step/6)*(k1+2*k2+k3)
#new_sites = self.add_sites(higher)
#error = higher - lower
#return higher, k1
def hessian(self, d: float) -> np.ndarray:
"""

View File

@ -2,6 +2,7 @@ from __future__ import annotations
from typing import Optional
import pickle, numpy as np
from math import log10
from scipy.linalg import null_space
from timeit import default_timer as timer
@ -149,18 +150,18 @@ class Flow(Simulation):
frames (List[VoronoiContainer]): stores frames of the simulation.
step_size (float): size fo step by for each iteration.
thres (float): threshold for the stopping condition.
accel (bool): set to True if accelerated stepping is desired.
adaptive (bool): set to True if adaptive stepping is desired.
"""
__slots__ = ['step_size', 'thres', 'accel']
__slots__ = ['step_size', 'thres', 'adaptive']
attr_str = "flow"
title_str = "Flow"
def __init__(self, domain: DomainParams, energy: Energy, step_size: float, thres: float,
accel: bool, name: Optional[str] = None) -> None:
adaptive: bool, name: Optional[str] = None) -> None:
super().__init__(domain, energy, name=name)
self.step_size, self.thres, self.accel = step_size, thres, accel
self.step_size, self.thres, self.adaptive = step_size, thres, adaptive
@property
@ -171,7 +172,7 @@ class Flow(Simulation):
"energy": self.energy.attr_str,
"step_size": self.step_size,
"thres": self.thres,
"accel": self.accel
"adaptive": self.adaptive
}
return info
@ -181,49 +182,40 @@ class Flow(Simulation):
if save: self.save(self.initial_data, True)
if len(self) == 0: self.add_frame()
i, grad_norm = 0, float('inf')
i, stop = 0, False
trial = 2
while grad_norm > self.thres: # Get to threshold.
if save: self.save(self.frame_data(i))
while not stop: # Get to threshold.
if save:
self.save(self.frame_data(i))
frame = self[i]
else:
frame = self[0]
# Iterate and generate next frame using RK-2
start = timer()
change, grad = self[i].iterate(self.step_size)
new_frame = self.energy.mode(*self.domain, self[i].add_sites(change))
change, grad = frame.iterate(self.step_size)
new_frame = self.energy.mode(*self.domain, frame.add_sites(change))
grad_norm = np.linalg.norm(grad)
end = timer()
if self.accel:
if new_frame.energy < self[i].energy: # If energy decreases.
if trial < 10: # Try increasing step size for 10 times.
factor = 1 + .1**trial
if self.adaptive:
error = change - grad*self.step_size
tol = 10**min(-3, -2+log10(grad_norm))
test_frame = self.energy.mode(*self.domain,
self[i].add_sites(change*factor))
# If increased step has less energy than original step.
if test_frame.energy < new_frame.energy:
self.step_size *= factor
trial = max(2, trial-1)
new_frame = test_frame
else: # Otherwise, increases trials, and use original.
trial += 1
else: # Step size too large, decrease and reset trial counter.
trial = 2
shrink_factor = 1.5
new_frame = self.energy.mode(*self.domain,
self[i].add_sites(change/shrink_factor))
self.step_size /= shrink_factor
self.step_size *= (tol/np.linalg.norm(error))**.5
self.step_size = max(10e-6, self.step_size)
if not save:
del self.frames[0]
self.frames.append(new_frame)
stop = grad_norm < self.thres
i += 1
if(log and i % log_steps == 0):
print(f'Iteration: {i:05} | Energy: {self[i].energy: .5f}' + \
if (log and i % log_steps == 0) or stop:
print(f'Iteration: {i:05} | Energy: {frame.energy: .5f}' + \
f' | Gradient: {grad_norm:.8f} | Step: {self.step_size: .5f} | ' + \
f'Time: {end-start: .3f}', flush=True)
f'Time: {end-start: .3f} |', flush=True)
@ -237,21 +229,21 @@ class Search(Simulation):
frames (List[VoronoiContainer]): stores frames of the simulation.
step_size (float): size fo step by for each iteration.
thres (float): threshold for the stopping condition.
accel (bool): set to True if accelerated stepping is desired.
adaptive (bool): set to True if adaptive stepping is desired.
kernel_step (float): size to step on manifold if nullity of hessian > 2.
count (int): number of equilibria to find.
"""
__slots__ = ['step_size', 'thres', 'accel', 'kernel_step', 'count']
__slots__ = ['step_size', 'thres', 'adaptive', 'kernel_step', 'count']
attr_str = "search"
title_str = "Search"
def __init__(self, domain: DomainParams, energy: Energy, step_size: float, thres: float,
accel: bool, kernel_step: float, count: int,
adaptive: bool, kernel_step: float, count: int,
name: Optional[str] = None) -> None:
super().__init__(domain, energy, name=name)
self.step_size, self.thres, self.accel = step_size, thres, accel
self.step_size, self.thres, self.adaptive = step_size, thres, adaptive
self.kernel_step, self.count = kernel_step, count
@ -263,7 +255,7 @@ class Search(Simulation):
"energy": self.energy.attr_str,
"step_size": self.step_size,
"thres": self.thres,
"accel": self.accel,
"adaptive": self.adaptive,
"kernel_step": self.kernel_step,
"count": self.count
}
@ -282,7 +274,7 @@ class Search(Simulation):
for i in range(self.count):
# Get to equilibrium.
sim = Flow(self.domain, self.energy, self.step_size, self.thres, self.accel)
sim = Flow(self.domain, self.energy, self.step_size, self.thres, self.adaptive)
sim.add_frame(new_sites)
sim.run(False, log, log_steps)
@ -317,22 +309,22 @@ class Shrink(Simulation):
frames (List[VoronoiContainer]): stores frames of the simulation.
step_size (float): size fo step by for each iteration.
thres (float): threshold for the stopping condition.
accel (bool): set to True if accelerated stepping is desired.
adaptive (bool): set to True if adaptive stepping is desired.
delta (float): percent to change w each iteration.
stop_width (float): percent at which to stop iterating.
"""
__slots__ = ['step_size', 'thres', 'accel', 'delta', 'stop_width']
__slots__ = ['step_size', 'thres', 'adaptive', 'delta', 'stop_width']
attr_str = "shrink"
title_str = "Shrink"
def __init__(self, domain: DomainParams, energy: Energy, step_size: float, thres: float,
accel: bool, delta: float, stop_width: float,
adaptive: bool, delta: float, stop_width: float,
name: Optional[str] = None) -> None:
super().__init__(domain, energy, name=name)
self.step_size, self.thres, self.accel = step_size, thres, accel
self.step_size, self.thres, self.adaptive = step_size, thres, adaptive
self.delta, self.stop_width = self.domain.w*delta/100, self.domain.w*stop_width
@ -344,7 +336,7 @@ class Shrink(Simulation):
"energy": self.energy.attr_str,
"step_size": self.step_size,
"thres": self.thres,
"accel": self.accel,
"adaptive": self.adaptive,
"delta": self.delta,
"stop_width": self.stop_width
}
@ -366,7 +358,7 @@ class Shrink(Simulation):
while width >= self.stop_width:
# Get to equilibrium.
new_domain = DomainParams(self.domain.n, width, self.domain.h, self.domain.r)
sim = Flow(new_domain, self.energy, self.step_size, self.thres, self.accel)
sim = Flow(new_domain, self.energy, self.step_size, self.thres, self.adaptive)
sim.add_frame(new_sites)
sim.run(False, log, log_steps)
new_sites = sim[-1].site_arr

View File

@ -96,28 +96,28 @@ def config_sim(args):
else:
points = np.asarray(dmn_params["points"])
check_params(sim_params, ["mode", "step_size", "threshold", "save_sim", "accel"], {
check_params(sim_params, ["mode", "step_size", "threshold", "save_sim", "adaptive"], {
"mode": ["flow", "search", "shrink"], "step_size": "positive", "threshold": "positive",
})
mode, step, thres, accel, save_sim = sim_params["mode"], sim_params["step_size"], \
sim_params["threshold"], sim_params["accel"], \
mode, step, thres, adaptive, save_sim = sim_params["mode"], sim_params["step_size"], \
sim_params["threshold"], sim_params["adaptive"], \
sim_params["save_sim"]
name = sim_params.get("name")
if mode == "flow":
sim = Flow(domain, energy, step, thres, accel, name=name)
sim = Flow(domain, energy, step, thres, adaptive, name=name)
elif mode == "search":
check_params(sim_params, ["manifold_step_size", "eq_stop_count"], {
"manifold_step_size": "positive", "eq_stop_count": "positive"
})
sim = Search(domain, energy, step, thres, accel, sim_params["manifold_step_size"],
sim = Search(domain, energy, step, thres, adaptive, sim_params["manifold_step_size"],
sim_params["eq_stop_count"], name=name)
elif mode == "shrink":
check_params(sim_params, ["width_change", "width_stop"], {
"width_change": "positive", "width_stop": "positive"
})
sim = Shrink(domain, energy, step, thres, accel, sim_params["width_change"],
sim = Shrink(domain, energy, step, thres, adaptive, sim_params["width_change"],
sim_params["width_stop"], name=name)
save_diagram = False