Repository navigation
Expand file tree
/
Copy pathtest_study.py
More file actions
315 lines (264 loc) · 11.6 KB
/
Copy pathtest_study.py
File metadata and controls
315 lines (264 loc) · 11.6 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
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
"""Shared declared-study orchestration, detached evidence and strict JSON boundaries."""
import json
import math
import threading
from copy import deepcopy
from dataclasses import FrozenInstanceError
from fractions import Fraction
import networkx as nx
import pytest
from tnfr.alias import set_dnfr, set_theta
from tnfr.sdk import (
STUDY_TOPOLOGIES,
TNFR,
Network,
StudyResult,
StudySpec,
diagnose_network,
export_to_json,
import_from_json,
list_sequences,
run_study,
study,
)
from tnfr.sdk.fluent import NAMED_SEQUENCES
@pytest.mark.parametrize(
"changes",
[
{"nodes": 0},
{"nodes": True},
{"nodes": 2.0},
{"cycles": -1},
{"cycles": False},
{"cycles": "1"},
{"seed": None},
{"seed": True},
{"seed": -1},
{"seed": 2**32},
{"topology": "unregistered"},
{"topology": []},
{"sequence": "unregistered"},
{"sequence": []},
{"probability": True},
{"probability": math.nan},
{"probability": -0.1},
{"probability": 1.1},
{"name": " "},
{"name": 3},
],
)
def test_recipe_rejects_invalid_domains_before_execution(changes):
with pytest.raises((TypeError, ValueError)):
StudySpec(**changes)
def test_recipe_is_strict_frozen_and_roundtrips():
spec = StudySpec(nodes=3, topology="random", seed=2**32 - 1, cycles=0)
assert StudySpec.from_dict(json.loads(json.dumps(spec.to_dict()))) == spec
with pytest.raises(FrozenInstanceError):
spec.cycles = 5
with pytest.raises(ValueError, match="Unknown study recipe keys"):
StudySpec.from_dict({"steps": 2})
with pytest.raises(TypeError, match="mapping"):
StudySpec.from_dict([])
def test_catalog_reuses_registry_without_exposing_mutable_words():
catalog = list_sequences()
assert {entry["name"] for entry in catalog} == set(NAMED_SEQUENCES)
for entry in catalog:
assert entry["operators"] == NAMED_SEQUENCES[entry["name"]]
assert "live grammar" in entry["scope"]
selected = list_sequences("basic_activation")
selected["operators"].clear()
assert list_sequences("basic_activation")["operators"]
with pytest.raises(ValueError, match="Unknown registered sequence"):
list_sequences("missing")
def test_operator_catalog_includes_public_tokens_for_composition():
from tnfr.operators.operator_contracts import iter_contracts
contracts = {entry.name: entry for entry in iter_contracts()}
assert {row["token"] for row in TNFR.operators()} == set(contracts)
for token, contract in contracts.items():
row = TNFR.operators(token)
assert row["token"] == token
assert row["name"] == contract.english_name
assert row["glyph"] == contract.glyph
@pytest.mark.parametrize("topology", STUDY_TOPOLOGIES)
def test_zero_cycles_record_supplied_state_and_topology_without_synthetic_pressure(
topology,
):
result = run_study(StudySpec(nodes=3, topology=topology, cycles=0)).to_dict()
assert result["execution"]["cycles_completed"] == 0
assert "not elapsed physical time" in result["execution"]["clock"]
assert result["initial_state"] == result["final"]["state"]
assert len(result["initial_state"]["nodes"]) == 3
for row in result["initial_state"]["nodes"]:
assert row["epi"]["value"] == 0.0
assert row["nu_f"]["value"] == 1.0
assert row["phase"]["value"] == 0.0
assert not row["delta_nfr"]["available"]
assert row["delta_nfr"]["value"] is None
json.dumps(result, allow_nan=False)
def test_one_cycle_matches_existing_execution_and_installs_shared_runtime_seed():
spec = StudySpec(nodes=2, seed=37)
result = run_study(spec).to_dict()
expected = TNFR.create(2, name=spec.name, seed=spec.seed).ring()
expected.G.graph["RANDOM_SEED"] = spec.seed
expected.evolve(steps=1, sequence=spec.sequence)
assert result["final"] == diagnose_network(expected)
assert result["execution"]["seed"] == 37
assert (
result["execution"]["sequence"]["operators"] == NAMED_SEQUENCES[spec.sequence]
)
assert result["initial_state"] != result["final"]["state"]
def test_repeated_seeded_topology_and_word_match_in_current_runtime():
spec = StudySpec(nodes=4, topology="random", probability=0.8, seed=7, cycles=1)
assert (
run_study(spec).to_dict()
== run_study(StudySpec.from_dict(spec.to_dict())).to_dict()
)
def test_isolated_random_node_keeps_the_actual_resonance_u3_rejection():
from tnfr.operators.preconditions import OperatorPreconditionError
# This declared topology has an isolate. The study wrapper must not insert
# edges or replace the word to manufacture a successful report.
with pytest.raises(OperatorPreconditionError, match="U3 phase gate"):
run_study(StudySpec(nodes=4, topology="random", probability=0.5, seed=7))
def test_execution_failure_propagates_without_diagnostics_or_repair(monkeypatch):
def refuse(self, **kwargs):
assert self.G.graph["RANDOM_SEED"] == 12
assert kwargs == {"steps": 1, "sequence": "basic_activation"}
raise RuntimeError("operator refused")
monkeypatch.setattr(Network, "evolve", refuse)
monkeypatch.setattr(
study, "diagnose_network", lambda _: pytest.fail("no report after failure")
)
with pytest.raises(RuntimeError, match="operator refused"):
run_study(StudySpec(nodes=2, seed=12))
def test_report_is_detached_and_exports_through_existing_writer(tmp_path):
original = {"nested": {"value": [1, 2]}}
report = StudyResult(original)
original["nested"]["value"].append(3)
exported = report.to_dict()
exported["nested"]["value"].clear()
assert report.to_dict() == {"nested": {"value": [1, 2]}}
destination = tmp_path / "nested" / "study.json"
export_to_json(report, destination)
assert import_from_json(destination) == report.to_dict()
with pytest.raises(ValueError):
StudyResult({"value": math.nan})
with pytest.raises(TypeError, match="mapping"):
StudyResult([])
@pytest.mark.parametrize("mapping", [{1: "integer", "1": "string"}, {"nested": {1: 2}}])
def test_report_constructor_rejects_nonstring_keys_before_json_can_merge_them(mapping):
with pytest.raises(TypeError, match="keys must be strings"):
StudyResult(mapping)
def test_diagnostic_json_admission_preserves_unrepresentable_source_unavailability():
tiny_source = Fraction(1, 10**400)
observed = study._capture(lambda: tiny_source)
assert observed["available"] is False
assert observed["value"] is None
assert observed["error"]["type"] == "ValueError"
assert "underflows" in observed["error"]["message"]
with pytest.raises(ValueError, match="underflows"):
StudyResult({"value": tiny_source})
def test_report_and_capture_share_admission_for_representable_real_sources():
tiny = float.fromhex("0x0.0000000000001p-1022")
source = Fraction.from_float(tiny)
observed = study._capture(lambda: source)
assert observed["available"] is True
assert observed["value"] == tiny
assert (
StudyResult({"nested": {"value": source}}).to_dict()["nested"]["value"] == tiny
)
def _prepared_network():
network = TNFR.create(3).path()
for node in network.G:
network.G.nodes[node]["EPI"] = -1.0 - node
set_dnfr(network.G, node, 0.5 + node)
return network
def test_diagnostics_keep_stored_pressure_and_do_not_touch_graph_or_opaque_resource():
network = _prepared_network()
handle = threading.Lock()
network.G.graph["external_handle"] = handle
prior_nodes = deepcopy(dict(network.G.nodes(data=True)))
prior_edges = deepcopy(list(network.G.edges(data=True)))
prior_metadata = dict(network.G.graph)
report = diagnose_network(network)
assert report["nodal"][0]["value"]["expected_depi_dt"] == 0.5
assert report["state"]["nodes"][0]["epi"]["value"] == -1.0
assert report["tetrad"]["xi_c"]["provenance"]["method"] in {
"autocorrelation_fit",
"spectral_gap",
}
assert dict(network.G.nodes(data=True)) == prior_nodes
assert list(network.G.edges(data=True)) == prior_edges
assert network.G.graph == prior_metadata
assert network.G.graph["external_handle"] is handle
report["state"]["nodes"][0]["epi"]["value"] = 99
assert network.G.nodes[0]["EPI"] == -1.0
def test_phase_cancellation_retains_independent_fields_and_per_node_status():
graph = nx.star_graph(4)
for node, phase in zip(graph, (0.3, 0.0, 0.0, math.pi, -math.pi)):
graph.nodes[node].update(EPI=1.0, nu_f=1.0, phase=phase, delta_nfr=0.0)
report = diagnose_network(Network(graph))
tetrad = report["tetrad"]
assert tetrad["k_phi"]["available"] is False
assert tetrad["k_phi"]["complete"] is False
assert tetrad["k_phi"]["value"][0] is None
assert tetrad["k_phi"]["node_status"][0] == "undefined_represented_resultant"
assert all(value is not None for value in tetrad["k_phi"]["value"][1:])
assert tetrad["phi_s"]["available"] and tetrad["grad_phi"]["available"]
json.dumps(report, allow_nan=False)
def test_invalid_phase_is_unavailable_without_hiding_pressure_field():
network = _prepared_network()
set_theta(network.G, 0, math.nan)
report = diagnose_network(network)
assert report["tetrad"]["k_phi"]["value"] is None
assert report["tetrad"]["grad_phi"]["value"] is None
assert report["tetrad"]["phi_s"]["available"]
assert not report["state"]["nodes"][0]["phase"]["available"]
json.dumps(report, allow_nan=False)
def test_empty_graph_retains_unavailable_xi_provenance():
report = diagnose_network(Network(nx.Graph()))
xi = report["tetrad"]["xi_c"]
assert xi["value"] is None and not xi["available"]
assert xi["provenance"]["method"] == "unavailable"
phase = report["metrics"]["avg_phase"]
assert phase["value"] is None and not phase["available"]
assert phase["error"]["message"] == "Diagnostic owner reported no available value"
json.dumps(report, allow_nan=False)
def test_each_field_owner_is_requested_once(monkeypatch):
calls = []
for name in (
"compute_structural_potential",
"observe_phase_curvature",
"estimate_coherence_length_with_provenance",
):
original = getattr(study, name)
def counted(graph, *, original=original, name=name):
calls.append(name)
return original(graph)
monkeypatch.setattr(study, name, counted)
diagnose_network(Network(nx.Graph()))
assert sorted(calls) == sorted(
[
"compute_structural_potential",
"observe_phase_curvature",
"estimate_coherence_length_with_provenance",
]
)
def test_indexed_observations_do_not_merge_distinct_equal_display_labels():
graph = nx.Graph()
for node in (1, "1"):
graph.add_node(node, EPI=0.0, nu_f=1.0, phase=0.0, delta_nfr=0.0)
graph.add_edge(1, "1")
report = diagnose_network(Network(graph))
assert [row["label"] for row in report["state"]["nodes"]] == ["1", "1"]
assert [row["index"] for row in report["state"]["nodes"]] == [0, 1]
assert [row["value"]["node"] for row in report["nodal"]] == [0, 1]
assert report["state"]["edges"] == [[0, 1]]
def test_guide_only_points_to_current_repository_paths(capsys):
from pathlib import Path
guide = TNFR.guide()
assert capsys.readouterr().out == guide + "\n"
root = Path(__file__).resolve().parents[2]
for line in guide.splitlines():
target = line.split(": ")[-1]
if target.startswith(("docs/", "theory/", "examples/")):
assert (root / target).is_file(), target