"""Small MVP of bifurcation-calibrated delayed two-mode control. The estimator fits the leading displacement model D(y) = V*y**(2*n) + kappa*mu/(abs(y)**(2*q)+epsilon) from section-return observations. The controller uses the resulting safety bound mu_max = r**M*abs(V)/abs(kappa) to cap a requested delay. """ from dataclasses import dataclass import numpy as np @dataclass class Calibration: n: int q: int V: float kappa: float radius: float @property def M(self): return 2 * (self.n + self.q) @property def mu_max(self): if self.V >= 0 or self.kappa <= 0: return 0.0 return self.radius ** self.M * abs(self.V) / self.kappa def predicted_amplitude(self, mu): if self.V >= 0 or self.kappa <= 0: return np.nan return (self.kappa * mu / abs(self.V)) ** (1.0 / self.M) def fit_return_map(y, y_next, mu, n=1, q=1, radius=1.0, epsilon=1e-12): """Least-squares estimate of V and positive kappa from return pairs.""" y=np.asarray(y, dtype=float); y_next=np.asarray(y_next, dtype=float) mu=np.broadcast_to(np.asarray(mu, dtype=float), y.shape) D=y_next-y A=np.column_stack((y**(2*n), mu/(np.abs(y)**(2*q)+epsilon))) coef, *_ = np.linalg.lstsq(A, D, rcond=None) return Calibration(n, q, float(coef[0]), float(abs(coef[1])), radius) class DelayedTwoModeController: """Gate mode R from a delayed scalar section coordinate; otherwise mode L.""" def __init__(self, base_lr, requested_delay, calibration=None): self.base_lr=float(base_lr); self.requested_delay=int(requested_delay) self.calibration=calibration self.delay=self.safe_delay() self.buffer=[0.0]*(self.delay+1) def safe_delay(self): if self.calibration is None or self.calibration.mu_max <= 0: return 0 # mu is approximated by delay times base learning rate. return max(0, min(self.requested_delay, int(self.calibration.mu_max/self.base_lr))) def mode(self, section_value): self.buffer.append(float(section_value)) gate=self.buffer[-1-self.delay] return 'R' if gate > 0 else 'L'