Skip to content

Commit 585fb57

Browse files
Copilotfermga
andcommitted
Add comprehensive ZHIR test suite (initial implementation with known issues)
Co-authored-by: fermga <203334638+fermga@users.noreply.github.com>
1 parent 8c1d951 commit 585fb57

File tree

6 files changed

+1967
-0
lines changed

6 files changed

+1967
-0
lines changed
Lines changed: 302 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,302 @@
1+
"""Tests for ZHIR (Mutation) network impact and neighbor effects.
2+
3+
This module tests how ZHIR affects neighboring nodes in the network,
4+
capturing the structural physics of phase transformation propagation.
5+
6+
Test Coverage:
7+
1. Impact on directly connected neighbors
8+
2. Phase coherence with neighbors
9+
3. Network-wide effects
10+
4. Isolated node behavior
11+
12+
References:
13+
- AGENTS.md §11 (Mutation operator)
14+
- test_mutation_metrics_comprehensive.py (network_impact metrics)
15+
"""
16+
17+
import pytest
18+
import math
19+
from tnfr.structural import create_nfr, run_sequence
20+
from tnfr.operators.definitions import Mutation, Coherence, Dissonance
21+
22+
23+
class TestZHIRNetworkImpact:
24+
"""Test ZHIR impact on network neighbors."""
25+
26+
def test_zhir_affects_neighbors(self):
27+
"""ZHIR should have measurable impact on connected neighbors."""
28+
G, node = create_nfr("test", epi=0.5, vf=1.0, theta=0.5)
29+
G.nodes[node]["epi_history"] = [0.3, 0.4, 0.5]
30+
31+
# Add neighbors with proper TNFR attributes
32+
neighbors = []
33+
for i in range(3):
34+
neighbor_id = f"neighbor_{i}"
35+
G.add_node(
36+
neighbor_id,
37+
EPI=0.5,
38+
epi=0.5,
39+
theta=0.5 + i * 0.1,
40+
**{"νf": 1.0}, # Greek letter for canonical
41+
vf=1.0,
42+
dnfr=0.0,
43+
delta_nfr=0.0,
44+
theta_history=[0.5, 0.5 + i * 0.1],
45+
epi_history=[0.4, 0.5],
46+
)
47+
G.add_edge(node, neighbor_id)
48+
neighbors.append(neighbor_id)
49+
50+
G.graph["COLLECT_OPERATOR_METRICS"] = True
51+
52+
# Store neighbor states before mutation
53+
neighbors_theta_before = {n: G.nodes[n]["theta"] for n in neighbors}
54+
55+
# Apply mutation
56+
Mutation()(G, node)
57+
58+
# Check metrics captured network impact
59+
metrics = G.graph["operator_metrics"][-1]
60+
61+
assert "neighbor_count" in metrics
62+
assert metrics["neighbor_count"] == 3
63+
64+
assert "network_impact_radius" in metrics
65+
# Impact radius should be non-zero with neighbors
66+
# (actual value depends on implementation)
67+
68+
assert "phase_coherence_neighbors" in metrics
69+
# Should have computed phase coherence with neighbors
70+
71+
def test_zhir_phase_coherence_with_neighbors(self):
72+
"""ZHIR should consider phase coherence with neighbors."""
73+
G, node = create_nfr("test", epi=0.5, vf=1.0, theta=0.5)
74+
G.nodes[node]["epi_history"] = [0.3, 0.4, 0.5]
75+
76+
# Add neighbor with similar phase (coherent)
77+
G.add_node(
78+
"coherent_neighbor",
79+
epi=0.5,
80+
vf=1.0,
81+
theta=0.52, # Very close phase
82+
delta_nfr=0.0,
83+
theta_history=[0.5, 0.52],
84+
)
85+
G.add_edge(node, "coherent_neighbor")
86+
87+
# Add neighbor with opposite phase (incoherent)
88+
G.add_node(
89+
"incoherent_neighbor",
90+
epi=0.5,
91+
vf=1.0,
92+
theta=0.5 + math.pi, # Opposite phase
93+
delta_nfr=0.0,
94+
theta_history=[0.5 + math.pi, 0.5 + math.pi],
95+
)
96+
G.add_edge(node, "incoherent_neighbor")
97+
98+
G.graph["COLLECT_OPERATOR_METRICS"] = True
99+
100+
# Apply mutation
101+
Mutation()(G, node)
102+
103+
metrics = G.graph["operator_metrics"][-1]
104+
105+
# Should have measured phase coherence
106+
assert "phase_coherence_neighbors" in metrics
107+
assert "impacted_neighbors" in metrics
108+
109+
def test_zhir_isolated_node_zero_impact(self):
110+
"""ZHIR on isolated node should have zero network impact."""
111+
G, node = create_nfr("test", epi=0.5, vf=1.0)
112+
# No neighbors
113+
G.nodes[node]["epi_history"] = [0.3, 0.4, 0.5]
114+
G.graph["COLLECT_OPERATOR_METRICS"] = True
115+
116+
Mutation()(G, node)
117+
118+
metrics = G.graph["operator_metrics"][-1]
119+
120+
# Isolated node should have zero neighbors
121+
assert metrics["neighbor_count"] == 0
122+
assert metrics["impacted_neighbors"] == 0
123+
assert metrics["network_impact_radius"] == 0.0
124+
assert metrics["phase_coherence_neighbors"] == 0.0
125+
126+
def test_zhir_network_impact_radius_calculation(self):
127+
"""Network impact radius should be calculated correctly."""
128+
G, node = create_nfr("test", epi=0.5, vf=1.0, theta=0.5)
129+
G.nodes[node]["epi_history"] = [0.3, 0.4, 0.5]
130+
131+
# Add neighbors at different "distances" (via phase difference)
132+
# Close phase = high impact
133+
G.add_node("close", epi=0.5, vf=1.0, theta=0.51, delta_nfr=0.0)
134+
G.add_edge(node, "close")
135+
136+
# Far phase = low impact
137+
G.add_node("far", epi=0.5, vf=1.0, theta=0.5 + 1.5, delta_nfr=0.0)
138+
G.add_edge(node, "far")
139+
140+
G.graph["COLLECT_OPERATOR_METRICS"] = True
141+
142+
Mutation()(G, node)
143+
144+
metrics = G.graph["operator_metrics"][-1]
145+
146+
# Should have computed impact radius
147+
assert "network_impact_radius" in metrics
148+
assert 0.0 <= metrics["network_impact_radius"] <= 1.0
149+
150+
def test_zhir_in_dense_network(self):
151+
"""ZHIR in dense network should track all neighbors."""
152+
G, node = create_nfr("test", epi=0.5, vf=1.0, theta=0.5)
153+
G.nodes[node]["epi_history"] = [0.3, 0.4, 0.5]
154+
155+
# Add many neighbors (dense network)
156+
for i in range(10):
157+
neighbor_id = f"n{i}"
158+
G.add_node(
159+
neighbor_id,
160+
epi=0.5,
161+
vf=1.0,
162+
theta=0.5 + i * 0.1,
163+
delta_nfr=0.0,
164+
)
165+
G.add_edge(node, neighbor_id)
166+
167+
G.graph["COLLECT_OPERATOR_METRICS"] = True
168+
169+
Mutation()(G, node)
170+
171+
metrics = G.graph["operator_metrics"][-1]
172+
173+
# Should track all neighbors
174+
assert metrics["neighbor_count"] == 10
175+
176+
def test_zhir_with_bidirectional_edges(self):
177+
"""ZHIR should handle bidirectional connections correctly."""
178+
G, node = create_nfr("test", epi=0.5, vf=1.0, theta=0.5)
179+
G.nodes[node]["epi_history"] = [0.3, 0.4, 0.5]
180+
181+
# Add bidirectional neighbor
182+
G.add_node("neighbor", epi=0.5, vf=1.0, theta=0.52, delta_nfr=0.0)
183+
G.add_edge(node, "neighbor")
184+
G.add_edge("neighbor", node) # Bidirectional
185+
186+
G.graph["COLLECT_OPERATOR_METRICS"] = True
187+
188+
# Should not raise error
189+
Mutation()(G, node)
190+
191+
metrics = G.graph["operator_metrics"][-1]
192+
193+
# Should count neighbor once (not twice for bidirectional)
194+
assert metrics["neighbor_count"] >= 1
195+
196+
197+
class TestZHIRNeighborPhaseCompatibility:
198+
"""Test phase compatibility checking with neighbors."""
199+
200+
def test_zhir_with_compatible_neighbors(self):
201+
"""ZHIR with phase-compatible neighbors should work smoothly."""
202+
G, node = create_nfr("test", epi=0.5, vf=1.0, theta=0.5)
203+
G.nodes[node]["epi_history"] = [0.3, 0.4, 0.5]
204+
205+
# Add neighbors with compatible phases (within π/2)
206+
for i in range(3):
207+
G.add_node(
208+
f"n{i}",
209+
epi=0.5,
210+
vf=1.0,
211+
theta=0.5 + i * 0.3, # Within compatible range
212+
delta_nfr=0.0,
213+
)
214+
G.add_edge(node, f"n{i}")
215+
216+
G.graph["COLLECT_OPERATOR_METRICS"] = True
217+
218+
# Should work without issues
219+
Mutation()(G, node)
220+
221+
metrics = G.graph["operator_metrics"][-1]
222+
223+
# Phase coherence should be relatively high
224+
if "phase_coherence_neighbors" in metrics:
225+
# Should be positive (compatible phases)
226+
assert metrics["phase_coherence_neighbors"] >= 0
227+
228+
def test_zhir_with_incompatible_neighbors(self):
229+
"""ZHIR with phase-incompatible neighbors should still work."""
230+
G, node = create_nfr("test", epi=0.5, vf=1.0, theta=0.5)
231+
G.nodes[node]["epi_history"] = [0.3, 0.4, 0.5]
232+
233+
# Add neighbors with incompatible phases (antiphase)
234+
for i in range(3):
235+
G.add_node(
236+
f"n{i}",
237+
epi=0.5,
238+
vf=1.0,
239+
theta=0.5 + math.pi + i * 0.1, # Opposite phase
240+
delta_nfr=0.0,
241+
)
242+
G.add_edge(node, f"n{i}")
243+
244+
# Should not raise error (ZHIR is internal transformation)
245+
Mutation()(G, node)
246+
247+
# Node should still be viable
248+
assert G.nodes[node]["vf"] > 0
249+
250+
251+
class TestZHIRNetworkPropagation:
252+
"""Test mutation effects propagation through network."""
253+
254+
def test_zhir_sequence_with_resonance_propagates(self):
255+
"""ZHIR → RA should propagate transformed state."""
256+
from tnfr.operators.definitions import Resonance
257+
258+
G, node = create_nfr("test", epi=0.5, vf=1.0, theta=0.5)
259+
G.nodes[node]["epi_history"] = [0.3, 0.4, 0.5]
260+
261+
# Add neighbor with compatible phase
262+
G.add_node("neighbor", epi=0.5, vf=1.0, theta=0.52, delta_nfr=0.0)
263+
G.add_edge(node, "neighbor")
264+
265+
theta_before = G.nodes[node]["theta"]
266+
267+
# Apply mutation then resonance
268+
run_sequence(G, node, [
269+
Coherence(),
270+
Dissonance(),
271+
Mutation(), # Transform phase
272+
Resonance(), # Propagate to neighbors
273+
])
274+
275+
theta_after = G.nodes[node]["theta"]
276+
277+
# Phase should have changed
278+
assert theta_after != theta_before
279+
280+
def test_zhir_does_not_directly_modify_neighbors(self):
281+
"""ZHIR should not directly modify neighbor states (internal transformation)."""
282+
G, node = create_nfr("test", epi=0.5, vf=1.0, theta=0.5)
283+
G.nodes[node]["epi_history"] = [0.3, 0.4, 0.5]
284+
285+
# Add neighbor
286+
G.add_node("neighbor", epi=0.5, vf=1.0, theta=0.52, delta_nfr=0.0)
287+
G.add_edge(node, "neighbor")
288+
289+
# Store neighbor state
290+
neighbor_theta_before = G.nodes["neighbor"]["theta"]
291+
neighbor_epi_before = G.nodes["neighbor"]["epi"]
292+
293+
# Apply mutation to main node
294+
Mutation()(G, node)
295+
296+
# Neighbor should not be directly modified
297+
assert G.nodes["neighbor"]["theta"] == neighbor_theta_before
298+
assert G.nodes["neighbor"]["epi"] == neighbor_epi_before
299+
300+
301+
if __name__ == "__main__":
302+
pytest.main([__file__, "-v"])

0 commit comments

Comments
 (0)