Repository navigation
Expand file tree
/
Copy pathphase_evolution.py
More file actions
172 lines (150 loc) · 6.77 KB
/
Copy pathphase_evolution.py
File metadata and controls
172 lines (150 loc) · 6.77 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
"""Shared snapshot-based, configured phase model for internal engines.
This model identifies supplied structural capacity with a free angular rate:
``theta_next = theta + dt*frequency + dt*coupling`` modulo ``2*pi``.
The neighbor sine term uses only U3-admitted neighbors. This identification
and the coupling strength are constitutive premises, not deductions from
``dEPI/dt = nu_f*DeltaNFR``. The arithmetic uses radians per supplied time unit;
it does not infer cycles per second or apply the optional physical Hz bridge.
Reusing the operator-admission U3 gate as an interaction cutoff in this phase
law is another constitutive choice. The phase row reads neither EPI nor
pressure; at fixed supplied frequency, support and configuration, changing
form or pressure cannot change its proposal. The pressure phase channel has
its own full-support neighbor resultant, so an excluded phase interaction
need not imply zero phase pressure. Crossing the cutoff changes both the sine
sum and its admitted-neighbor denominator; the vector field can be discontinuous.
The nodal optimizer and FFT engine share this model. Ordinary runtime phase
coordination instead uses its separately configured relaxation map. Neither
law may be substituted for the other based only on the nodal EPI identity.
Both optimized consumers pair this proposal with isolated EPI diffusion, whose
pressure does not read phase. The explicit, opt-in composition in
``physics.p2_phase_form`` instead combines this proposal with fresh multichannel
pressure on fixed P2. It retains the same supplied angular-rate premise.
See ``theory/FORCED_SUPPORT_BALANCE.md`` sections 23 and 26. This helper returns
a proposal without mutating the graph.
"""
from __future__ import annotations
import math
from typing import Any
from .._exact_time import finite_represented_real
from ..errors import TNFRValueError
from ..mathematics.unified_numerical import np
__all__ = ["propose_u3_gated_phase_step"]
def _finite_real(value: Any, name: str) -> float:
try:
return finite_represented_real(value, name)[0]
except (TypeError, ValueError) as exc:
raise TNFRValueError(str(exc)) from exc
def _finite_vector(values: Any, count: int, name: str) -> np.ndarray:
"""Validate original scalar kinds before binary64 array conversion."""
try:
original = np.asarray(values, dtype=object)
except (TypeError, ValueError) as exc:
raise TNFRValueError(f"{name} vector must match node order.") from exc
if original.shape != (count,):
raise TNFRValueError("Phase and frequency vectors must match node order.")
return np.array(
[
_finite_real(value, f"{name}[{index}]")
for index, value in enumerate(original)
],
dtype=float,
)
def propose_u3_gated_phase_step(
graph: Any,
nodes: tuple[Any, ...],
phases: Any,
frequencies: Any,
*,
dt: float,
coupling_strength: float,
) -> np.ndarray:
"""Return one simultaneous free-advance plus U3-gated phase proposal.
Phase and capacity vectors contain finite real scalars, not Boolean,
text or complex values. Validation precedes binary64 conversion; no
imaginary component is discarded from an inverse spectral transform.
Nonzero input scalars must remain nonzero when materialized as binary64.
The supplied frequency vector controls free advance; neither stored EPI
nor stored pressure enters this phase proposal.
"""
if tuple(graph.nodes()) != tuple(nodes):
raise TNFRValueError("Phase proposal node order differs from the graph.")
return _propose_u3_phase_from_neighbors(
graph.graph,
nodes,
graph.neighbors,
phases,
frequencies,
dt=dt,
coupling_strength=coupling_strength,
)
def _propose_u3_phase_from_neighbors(
graph_attributes,
nodes,
neighbors,
phases,
frequencies,
*,
dt,
coupling_strength,
):
"""Shared arithmetic for live unique support and observed counted support.
Internal callers supply the node order and neighbor reader. In a counted
quotient, repeated indices stand for distinct fine neighbors; an internal
neighbor contributes to the admitted denominator even when its sine is zero.
Graph metadata and observed multiplicities retain their separate owners.
"""
from ..operators._phase_gate import (
U3PhaseGateError,
resolve_u3_phase_limits,
select_u3_phase_neighbors,
)
count = len(nodes)
phase = _finite_vector(phases, count, "phase")
frequency = _finite_vector(frequencies, count, "structural frequency")
if np.any(frequency < 0.0):
raise TNFRValueError("Structural frequency must be nonnegative.")
time_step = _finite_real(dt, "phase integration dt")
strength = _finite_real(coupling_strength, "phase coupling strength")
if time_step <= 0.0:
raise TNFRValueError("phase integration dt must be positive.")
if strength < 0.0:
raise TNFRValueError("phase coupling strength must be nonnegative.")
try:
_, phase_limit = resolve_u3_phase_limits(graph_attributes, operator_code="UM")
except U3PhaseGateError as exc:
raise TNFRValueError(
"Phase proposal failed the U3 phase gate.",
context={"reason": exc.failed_condition},
) from exc
index = {node: offset for offset, node in enumerate(nodes)}
with np.errstate(over="ignore", invalid="ignore"):
proposal = phase + time_step * frequency
if not np.all(np.isfinite(proposal)):
raise TNFRValueError("Free phase proposal must remain finite.")
for offset, node in enumerate(nodes):
try:
target_phase, compatible, neighbor_phases = select_u3_phase_neighbors(
phase[offset],
neighbors(node),
phase_getter=lambda neighbor: phase[index[neighbor]],
phase_limit=phase_limit,
require_compatible=False,
)
except U3PhaseGateError as exc:
raise TNFRValueError(
"Phase proposal failed the U3 phase gate.",
context={"node": node, "reason": exc.failed_condition},
) from exc
if compatible:
coupling = math.fsum(
math.sin(neighbor_phase - target_phase)
for neighbor_phase in neighbor_phases
)
with np.errstate(over="ignore", invalid="ignore"):
proposal[offset] += time_step * strength * coupling / len(compatible)
if not math.isfinite(float(proposal[offset])):
raise TNFRValueError("Coupled phase proposal must remain finite.")
wrapped = np.mod(proposal, 2.0 * math.pi)
if not np.all(np.isfinite(wrapped)):
raise TNFRValueError("Wrapped phase proposal must remain finite.")
return wrapped