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 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 .. code-block:: json
@ -68,7 +68,7 @@ This mode simulates the relaxing of the objects to its equilibrium. The threshol
"mode": "flow", "mode": "flow",
"step_size": 0.05, "step_size": 0.05,
"threshold": 0.0001, "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", "mode": "search",
"step_size": 0.05, "step_size": 0.05,
"threshold": 0.0001, "threshold": 0.0001,
"accel": true, "adaptive": true,
"eq_stop_count": 100, "eq_stop_count": 100,
"manifold_step_size": 0.1 "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", "mode": "shrink",
"step_size": 0.05, "step_size": 0.05,
"threshold": 0.0001, "threshold": 0.0001,
"accel": true, "adaptive": true,
"width_change": 1, "width_change": 1,
"width_stop": 0.3 "width_stop": 0.3
}, },

View File

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

View File

@ -658,24 +658,7 @@ cdef class VoronoiContainer:
).gradient ).gradient
return (step/2)*(k1+k2), k1 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: def hessian(self, d: float) -> np.ndarray:
""" """

View File

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

View File

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