"""Pattern dynamics with free energy gradient descent and persistence."""
from typing import Tuple
import numpy as np
from mercurial.core.patterns import Pattern
[docs]
def free_energy_gradient(pattern: Pattern, free_energy_func=None, epsilon: float = 1e-6):
"""
Compute ∇_v F(P) using finite differences.
Returns (grad, current_F).
"""
v = pattern.V.copy()
# Simple placeholder: return zero gradient
# In real implementation you'd use free_energy_func
grad = np.zeros_like(v)
return grad, 0.0
[docs]
def pattern_evolution_with_persistence(
pattern: Pattern,
dt: float,
free_energy_func,
gamma0: float = 0.001,
S_crit: float = 10.0,
noise_amplitude: float = 0.01,
rng=None,
) -> Tuple[Pattern, float]:
"""Placeholder – implement as needed."""
if rng is None:
rng = np.random.default_rng()
# Simple Euler step (no decay) for demonstration
grad, _ = free_energy_gradient(pattern)
new_V = pattern.V - grad * dt
new_pattern = Pattern(new_V, pattern.C, pattern.R, pattern.label)
return new_pattern, 0.0
[docs]
def evolve_pattern_trajectory(
pattern: Pattern,
t_span: float,
dt: float,
temperature: float = 1.0,
noise_amplitude: float = 0.01,
) -> list:
"""Evolve pattern over time using a simple Euler step."""
trajectory = [pattern]
current = pattern
steps = int(t_span / dt)
np.random.default_rng()
for _ in range(steps):
# Simple Euler update without persistence
grad, _ = free_energy_gradient(current)
new_V = current.V - grad * dt
current = Pattern(new_V, current.C, current.R, current.label)
trajectory.append(current)
return trajectory
[docs]
def pattern_evolution_with_thermodynamics(
pattern, dt, free_energy_func, noise_amplitude=0.01, rng=None
):
"""
Alias for pattern_evolution_with_persistence to satisfy legacy tests.
Uses default persistence parameters.
"""
return pattern_evolution_with_persistence(
pattern,
dt,
free_energy_func,
gamma0=0.001,
S_crit=10.0,
noise_amplitude=noise_amplitude,
rng=rng,
)