tqce 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
tqce-1.0.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 TQCE Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
tqce-1.0.0/PKG-INFO ADDED
@@ -0,0 +1,158 @@
1
+ Metadata-Version: 2.4
2
+ Name: tqce
3
+ Version: 1.0.0
4
+ Summary: Temporal Quantum Causal Engine — A computational paradigm based on causal loop mechanics
5
+ Author: utachicodes
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/utachicodes/tqce
8
+ Project-URL: Repository, https://github.com/utachicodes/tqce
9
+ Project-URL: Documentation, https://github.com/utachicodes/tqce/blob/main/docs/api.md
10
+ Keywords: causal-inference,temporal-computing,optimization,tensor-networks
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Science/Research
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Classifier: Topic :: Scientific/Engineering
17
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
18
+ Classifier: Topic :: Scientific/Engineering :: Physics
19
+ Requires-Python: >=3.11
20
+ Description-Content-Type: text/markdown
21
+ License-File: LICENSE
22
+ Requires-Dist: numpy>=1.24
23
+ Requires-Dist: networkx>=3.0
24
+ Requires-Dist: scipy>=1.10
25
+ Requires-Dist: matplotlib>=3.7
26
+ Provides-Extra: dev
27
+ Requires-Dist: pytest>=7.0; extra == "dev"
28
+ Requires-Dist: pytest-cov>=4.0; extra == "dev"
29
+ Dynamic: license-file
30
+
31
+ # TQCE — Temporal Quantum Causal Engine
32
+
33
+ **A novel computational paradigm based on causal loop mechanics.**
34
+
35
+ Paradox resolution in closed timelike curves is computationally equivalent to optimization under self-referential constraint systems. TQCE exploits this equivalence to build a new class of algorithms that solve problems standard approaches cannot handle — circular dependencies, self-referential optimization, and causal reasoning with feedback loops.
36
+
37
+ ## Installation
38
+
39
+ ```bash
40
+ git clone <repo-url>
41
+ cd tqce
42
+ pip install -e ".[dev]"
43
+ ```
44
+
45
+ Requirements: Python 3.11+, numpy, networkx, scipy, matplotlib.
46
+
47
+ ## Quick Start
48
+
49
+ ```python
50
+ import numpy as np
51
+ from tqce import CausalNode, TQCEOrchestrator
52
+ from tqce.viz import plot_convergence, plot_ctn_graph
53
+
54
+ np.random.seed(42)
55
+
56
+ # Build a causal loop: A -> B -> C with retrocausal C -> A
57
+ engine = TQCEOrchestrator("My Problem")
58
+ net = engine.build_network()
59
+
60
+ net.add_node(CausalNode("A", time_coordinate=0.0, state_dim=4))
61
+ net.add_node(CausalNode("B", time_coordinate=1.0, state_dim=4))
62
+ net.add_node(CausalNode("C", time_coordinate=2.0, state_dim=4))
63
+
64
+ net.add_causal_edge("A", "B", weight=0.8)
65
+ net.add_causal_edge("B", "C", weight=0.6)
66
+ net.add_retrocausal_edge("C", "A", weight=0.4) # backward in time
67
+
68
+ # Solve for a self-consistent timeline
69
+ results = engine.solve(verbose=True)
70
+
71
+ # Visualize
72
+ plot_ctn_graph(net)
73
+ plot_convergence(results["fixed_point"]["iteration_history"])
74
+ ```
75
+
76
+ ## Five Core Components
77
+
78
+ ### 1. Causal Tensor Networks (CTN)
79
+
80
+ Standard tensor networks are directed acyclic graphs. CTNs extend this by adding retrocausal edges — connections pointing backward in time — creating Closed Causal Loops (CCLs). The network state is computed not by forward propagation but by fixed-point iteration: repeatedly updating all nodes until the global state converges to a self-consistent solution. This is the computational analog of finding a valid timeline in a system with closed timelike curves.
81
+
82
+ **Class:** `CausalTensorNetwork`
83
+
84
+ ### 2. Paradox Pressure Gradient Descent (PPGD)
85
+
86
+ PPGD is a gradient-based optimizer where the loss function is causal inconsistency itself. The "paradox pressure" at each node measures how far its current state is from what its causal parents demand. By treating this pressure as a differentiable loss surface, PPGD descends toward self-consistent basins using momentum and adaptive learning rates scaled by local paradox pressure.
87
+
88
+ **Class:** `ParadoxPressureGradientDescent`
89
+
90
+ ### 3. Temporal Eigenstate Collapse (TEC)
91
+
92
+ Multiple candidate timelines are superposed as a "temporal wavefunction" with complex amplitudes. Causal interference between timelines amplifies consistent resolutions (constructive interference) and cancels paradoxical ones (destructive interference). After several rounds of interference, the system collapses to the timeline with the highest probability — the most self-consistent solution.
93
+
94
+ **Class:** `TemporalWavefunction`
95
+
96
+ ### 4. Chrono-Entropic Regularization (CER)
97
+
98
+ Inspired by the second law of thermodynamics: entropy must be non-decreasing, even in causal loops. CER penalizes states where a past node has higher approximate entropy than its future retrocausal parents. This prevents information from growing unboundedly as it circulates through the loop, acting as a principled regularizer derived from physical constraints.
99
+
100
+ **Class:** `ChronoEntropicRegularizer`
101
+
102
+ ### 5. Bootstrap Amplification (BA)
103
+
104
+ In a bootstrap paradox, information exists with no origin. BA exploits this computationally: a weak signal is injected into a causal loop where it influences itself at each pass. With the right resonance conditions (spectral radius of the loop kernel below 1), the signal amplifies to a stable fixed point that is larger than the input. Chrono-entropic damping prevents unbounded growth.
105
+
106
+ **Class:** `BootstrapAmplifier`
107
+
108
+ ## Visualization
109
+
110
+ TQCE includes a dark-themed visualization module:
111
+
112
+ | Function | Description |
113
+ |----------|-------------|
114
+ | `plot_convergence()` | Fixed-point inconsistency over iterations, with optional PPGD loss overlay |
115
+ | `plot_paradox_pressure_landscape()` | Bar chart of paradox pressure per node |
116
+ | `plot_ctn_graph()` | Network graph with blue causal and red retrocausal edges |
117
+ | `plot_tec_probabilities()` | Timeline probability distribution after interference |
118
+ | `plot_amplification_trace()` | Amplification factor over loop iterations |
119
+ | `animate_convergence()` | Animated convergence showing per-node traces |
120
+
121
+ All functions are importable from `tqce.viz`.
122
+
123
+ ## Examples
124
+
125
+ Three demo scripts are provided in `examples/`:
126
+
127
+ - **`circular_constraints.py`** — Solve a circular dependency problem (A depends on C, B on A, C on B) using the full TQCE pipeline.
128
+ - **`signal_amplification.py`** — Recover a weak signal buried below the noise floor using Bootstrap Amplification.
129
+ - **`anomaly_detection.py`** — Detect time series anomalies by measuring paradox pressure when data points are inserted into causal loops.
130
+
131
+ Run any example:
132
+ ```bash
133
+ python examples/circular_constraints.py
134
+ ```
135
+
136
+ See [docs/examples.md](docs/examples.md) for detailed walkthroughs.
137
+
138
+ ## Architecture
139
+
140
+ ```
141
+ tqce/
142
+ ├── network/ # CausalNode, CausalTensorNetwork
143
+ ├── optimization/ # ChronoEntropicRegularizer, ParadoxPressureGradientDescent
144
+ ├── quantum/ # TemporalWavefunction
145
+ ├── amplification/ # BootstrapAmplifier
146
+ ├── engine/ # TQCEOrchestrator
147
+ └── viz/ # Plotting and animation
148
+ ```
149
+
150
+ ## References
151
+
152
+ - Deutsch, D. (1991). *Quantum mechanics near closed timelike lines.* Physical Review D, 44(10), 3197.
153
+ - Novikov, I. D. (1989). *An analysis of the operation of a time machine.* Soviet Physics JETP, 68(3), 439.
154
+ - Lloyd, S., Maccone, L., Garcia-Patron, R., Giovannetti, V., & Shikano, Y. (2011). *Quantum mechanics of time travel through post-selected teleportation.* Physical Review D, 84(2), 025007.
155
+
156
+ ## License
157
+
158
+ MIT License. See [LICENSE](LICENSE) for details.
tqce-1.0.0/README.md ADDED
@@ -0,0 +1,128 @@
1
+ # TQCE — Temporal Quantum Causal Engine
2
+
3
+ **A novel computational paradigm based on causal loop mechanics.**
4
+
5
+ Paradox resolution in closed timelike curves is computationally equivalent to optimization under self-referential constraint systems. TQCE exploits this equivalence to build a new class of algorithms that solve problems standard approaches cannot handle — circular dependencies, self-referential optimization, and causal reasoning with feedback loops.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ git clone <repo-url>
11
+ cd tqce
12
+ pip install -e ".[dev]"
13
+ ```
14
+
15
+ Requirements: Python 3.11+, numpy, networkx, scipy, matplotlib.
16
+
17
+ ## Quick Start
18
+
19
+ ```python
20
+ import numpy as np
21
+ from tqce import CausalNode, TQCEOrchestrator
22
+ from tqce.viz import plot_convergence, plot_ctn_graph
23
+
24
+ np.random.seed(42)
25
+
26
+ # Build a causal loop: A -> B -> C with retrocausal C -> A
27
+ engine = TQCEOrchestrator("My Problem")
28
+ net = engine.build_network()
29
+
30
+ net.add_node(CausalNode("A", time_coordinate=0.0, state_dim=4))
31
+ net.add_node(CausalNode("B", time_coordinate=1.0, state_dim=4))
32
+ net.add_node(CausalNode("C", time_coordinate=2.0, state_dim=4))
33
+
34
+ net.add_causal_edge("A", "B", weight=0.8)
35
+ net.add_causal_edge("B", "C", weight=0.6)
36
+ net.add_retrocausal_edge("C", "A", weight=0.4) # backward in time
37
+
38
+ # Solve for a self-consistent timeline
39
+ results = engine.solve(verbose=True)
40
+
41
+ # Visualize
42
+ plot_ctn_graph(net)
43
+ plot_convergence(results["fixed_point"]["iteration_history"])
44
+ ```
45
+
46
+ ## Five Core Components
47
+
48
+ ### 1. Causal Tensor Networks (CTN)
49
+
50
+ Standard tensor networks are directed acyclic graphs. CTNs extend this by adding retrocausal edges — connections pointing backward in time — creating Closed Causal Loops (CCLs). The network state is computed not by forward propagation but by fixed-point iteration: repeatedly updating all nodes until the global state converges to a self-consistent solution. This is the computational analog of finding a valid timeline in a system with closed timelike curves.
51
+
52
+ **Class:** `CausalTensorNetwork`
53
+
54
+ ### 2. Paradox Pressure Gradient Descent (PPGD)
55
+
56
+ PPGD is a gradient-based optimizer where the loss function is causal inconsistency itself. The "paradox pressure" at each node measures how far its current state is from what its causal parents demand. By treating this pressure as a differentiable loss surface, PPGD descends toward self-consistent basins using momentum and adaptive learning rates scaled by local paradox pressure.
57
+
58
+ **Class:** `ParadoxPressureGradientDescent`
59
+
60
+ ### 3. Temporal Eigenstate Collapse (TEC)
61
+
62
+ Multiple candidate timelines are superposed as a "temporal wavefunction" with complex amplitudes. Causal interference between timelines amplifies consistent resolutions (constructive interference) and cancels paradoxical ones (destructive interference). After several rounds of interference, the system collapses to the timeline with the highest probability — the most self-consistent solution.
63
+
64
+ **Class:** `TemporalWavefunction`
65
+
66
+ ### 4. Chrono-Entropic Regularization (CER)
67
+
68
+ Inspired by the second law of thermodynamics: entropy must be non-decreasing, even in causal loops. CER penalizes states where a past node has higher approximate entropy than its future retrocausal parents. This prevents information from growing unboundedly as it circulates through the loop, acting as a principled regularizer derived from physical constraints.
69
+
70
+ **Class:** `ChronoEntropicRegularizer`
71
+
72
+ ### 5. Bootstrap Amplification (BA)
73
+
74
+ In a bootstrap paradox, information exists with no origin. BA exploits this computationally: a weak signal is injected into a causal loop where it influences itself at each pass. With the right resonance conditions (spectral radius of the loop kernel below 1), the signal amplifies to a stable fixed point that is larger than the input. Chrono-entropic damping prevents unbounded growth.
75
+
76
+ **Class:** `BootstrapAmplifier`
77
+
78
+ ## Visualization
79
+
80
+ TQCE includes a dark-themed visualization module:
81
+
82
+ | Function | Description |
83
+ |----------|-------------|
84
+ | `plot_convergence()` | Fixed-point inconsistency over iterations, with optional PPGD loss overlay |
85
+ | `plot_paradox_pressure_landscape()` | Bar chart of paradox pressure per node |
86
+ | `plot_ctn_graph()` | Network graph with blue causal and red retrocausal edges |
87
+ | `plot_tec_probabilities()` | Timeline probability distribution after interference |
88
+ | `plot_amplification_trace()` | Amplification factor over loop iterations |
89
+ | `animate_convergence()` | Animated convergence showing per-node traces |
90
+
91
+ All functions are importable from `tqce.viz`.
92
+
93
+ ## Examples
94
+
95
+ Three demo scripts are provided in `examples/`:
96
+
97
+ - **`circular_constraints.py`** — Solve a circular dependency problem (A depends on C, B on A, C on B) using the full TQCE pipeline.
98
+ - **`signal_amplification.py`** — Recover a weak signal buried below the noise floor using Bootstrap Amplification.
99
+ - **`anomaly_detection.py`** — Detect time series anomalies by measuring paradox pressure when data points are inserted into causal loops.
100
+
101
+ Run any example:
102
+ ```bash
103
+ python examples/circular_constraints.py
104
+ ```
105
+
106
+ See [docs/examples.md](docs/examples.md) for detailed walkthroughs.
107
+
108
+ ## Architecture
109
+
110
+ ```
111
+ tqce/
112
+ ├── network/ # CausalNode, CausalTensorNetwork
113
+ ├── optimization/ # ChronoEntropicRegularizer, ParadoxPressureGradientDescent
114
+ ├── quantum/ # TemporalWavefunction
115
+ ├── amplification/ # BootstrapAmplifier
116
+ ├── engine/ # TQCEOrchestrator
117
+ └── viz/ # Plotting and animation
118
+ ```
119
+
120
+ ## References
121
+
122
+ - Deutsch, D. (1991). *Quantum mechanics near closed timelike lines.* Physical Review D, 44(10), 3197.
123
+ - Novikov, I. D. (1989). *An analysis of the operation of a time machine.* Soviet Physics JETP, 68(3), 439.
124
+ - Lloyd, S., Maccone, L., Garcia-Patron, R., Giovannetti, V., & Shikano, Y. (2011). *Quantum mechanics of time travel through post-selected teleportation.* Physical Review D, 84(2), 025007.
125
+
126
+ ## License
127
+
128
+ MIT License. See [LICENSE](LICENSE) for details.
@@ -0,0 +1,49 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "tqce"
7
+ version = "1.0.0"
8
+ description = "Temporal Quantum Causal Engine — A computational paradigm based on causal loop mechanics"
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ requires-python = ">=3.11"
12
+ authors = [
13
+ {name = "utachicodes"}
14
+ ]
15
+ keywords = ["causal-inference", "temporal-computing", "optimization", "tensor-networks"]
16
+ classifiers = [
17
+ "Development Status :: 4 - Beta",
18
+ "Intended Audience :: Science/Research",
19
+ "Programming Language :: Python :: 3.11",
20
+ "Programming Language :: Python :: 3.12",
21
+ "Programming Language :: Python :: 3.13",
22
+ "Topic :: Scientific/Engineering",
23
+ "Topic :: Scientific/Engineering :: Artificial Intelligence",
24
+ "Topic :: Scientific/Engineering :: Physics",
25
+ ]
26
+ dependencies = [
27
+ "numpy>=1.24",
28
+ "networkx>=3.0",
29
+ "scipy>=1.10",
30
+ "matplotlib>=3.7",
31
+ ]
32
+
33
+ [project.urls]
34
+ Homepage = "https://github.com/utachicodes/tqce"
35
+ Repository = "https://github.com/utachicodes/tqce"
36
+ Documentation = "https://github.com/utachicodes/tqce/blob/main/docs/api.md"
37
+
38
+ [project.optional-dependencies]
39
+ dev = [
40
+ "pytest>=7.0",
41
+ "pytest-cov>=4.0",
42
+ ]
43
+
44
+ [tool.pytest.ini_options]
45
+ testpaths = ["tests"]
46
+ addopts = "-v --tb=short"
47
+
48
+ [tool.setuptools.packages.find]
49
+ include = ["tqce*"]
tqce-1.0.0/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,59 @@
1
+ """Tests for Bootstrap Amplification."""
2
+
3
+ import numpy as np
4
+ import pytest
5
+
6
+ from tqce.amplification.amplifier import BootstrapAmplifier
7
+
8
+
9
+ class TestBootstrapAmplifier:
10
+ def test_amplify_returns_correct_shape(self):
11
+ amp = BootstrapAmplifier(signal_dim=8)
12
+ signal = np.random.randn(8) * 0.01
13
+ result, stats = amp.amplify(signal)
14
+ assert result.shape == (8,)
15
+
16
+ def test_amplification_factor_positive(self):
17
+ amp = BootstrapAmplifier(signal_dim=4, amplification_target=5.0)
18
+ signal = np.random.randn(4) * 0.1
19
+ _, stats = amp.amplify(signal)
20
+ assert stats["amplification_factor"] > 0
21
+
22
+ def test_amplification_near_target(self):
23
+ np.random.seed(42)
24
+ target = 10.0
25
+ amp = BootstrapAmplifier(
26
+ signal_dim=4, amplification_target=target, stability_coefficient=0.9
27
+ )
28
+ signal = np.ones(4) * 0.1
29
+ result, stats = amp.amplify(signal, max_iterations=500)
30
+ assert stats["amplification_factor"] > 1.0
31
+
32
+ def test_convergence(self):
33
+ np.random.seed(42)
34
+ amp = BootstrapAmplifier(signal_dim=4, amplification_target=5.0)
35
+ signal = np.ones(4) * 0.1
36
+ _, stats = amp.amplify(signal, max_iterations=500)
37
+ assert stats["converged"] or stats["iterations"] == 500
38
+
39
+ def test_stats_keys(self):
40
+ amp = BootstrapAmplifier(signal_dim=4)
41
+ _, stats = amp.amplify(np.ones(4) * 0.1)
42
+ expected = {
43
+ "amplification_factor", "iterations", "converged",
44
+ "amplification_history"
45
+ }
46
+ assert set(stats.keys()) == expected
47
+
48
+ def test_zero_signal_no_crash(self):
49
+ amp = BootstrapAmplifier(signal_dim=4)
50
+ result, stats = amp.amplify(np.zeros(4))
51
+ assert np.all(np.isfinite(result))
52
+
53
+ def test_learn_resonance(self):
54
+ np.random.seed(42)
55
+ amp = BootstrapAmplifier(signal_dim=4, amplification_target=5.0)
56
+ signals = np.random.randn(5, 4) * 0.1
57
+ amp.learn_resonance(signals, n_epochs=3)
58
+ eigvals = np.linalg.eigvals(amp.loop_kernel)
59
+ assert np.max(np.abs(eigvals)) <= amp.stability_coefficient + 0.01
@@ -0,0 +1,61 @@
1
+ """Tests for the TQCE Orchestrator."""
2
+
3
+ import numpy as np
4
+ import pytest
5
+
6
+ from tqce.network.node import CausalNode
7
+ from tqce.engine.orchestrator import TQCEOrchestrator
8
+
9
+
10
+ class TestTQCEOrchestrator:
11
+ def _build_problem(self) -> TQCEOrchestrator:
12
+ np.random.seed(42)
13
+ engine = TQCEOrchestrator("Test Problem")
14
+ net = engine.build_network()
15
+ net.add_node(CausalNode("A", time_coordinate=0.0, state_dim=4))
16
+ net.add_node(CausalNode("B", time_coordinate=1.0, state_dim=4))
17
+ net.add_node(CausalNode("C", time_coordinate=2.0, state_dim=4))
18
+ net.add_causal_edge("A", "B", weight=0.8)
19
+ net.add_causal_edge("B", "C", weight=0.6)
20
+ net.add_retrocausal_edge("C", "A", weight=0.4)
21
+ return engine
22
+
23
+ def test_build_network_returns_ctn(self):
24
+ engine = TQCEOrchestrator()
25
+ net = engine.build_network()
26
+ from tqce.network.ctn import CausalTensorNetwork
27
+ assert isinstance(net, CausalTensorNetwork)
28
+
29
+ def test_solve_returns_result(self):
30
+ engine = self._build_problem()
31
+ result = engine.solve(n_candidate_timelines=5, verbose=False)
32
+ assert "fixed_point" in result
33
+ assert "summary" in result
34
+
35
+ def test_solve_with_tec(self):
36
+ engine = self._build_problem()
37
+ result = engine.solve(
38
+ use_tec=True, n_candidate_timelines=5, verbose=False
39
+ )
40
+ assert "tec" in result
41
+
42
+ def test_solve_with_ppgd(self):
43
+ engine = self._build_problem()
44
+ result = engine.solve(use_ppgd=True, verbose=False)
45
+ assert "ppgd" in result
46
+
47
+ def test_solve_without_tec_or_ppgd(self):
48
+ engine = self._build_problem()
49
+ result = engine.solve(use_tec=False, use_ppgd=False, verbose=False)
50
+ assert "tec" not in result
51
+ assert "ppgd" not in result
52
+
53
+ def test_summary_has_expected_keys(self):
54
+ engine = self._build_problem()
55
+ result = engine.solve(verbose=False)
56
+ summary = result["summary"]
57
+ assert summary["problem"] == "Test Problem"
58
+ assert summary["n_nodes"] == 3
59
+ assert summary["n_causal_edges"] == 2
60
+ assert summary["n_retrocausal_edges"] == 1
61
+ assert summary["has_closed_causal_loops"] is True
@@ -0,0 +1,167 @@
1
+ """Tests for Causal Tensor Network components."""
2
+
3
+ import numpy as np
4
+ import pytest
5
+
6
+ from tqce.network.node import CausalNode
7
+ from tqce.network.ctn import CausalTensorNetwork
8
+
9
+
10
+ class TestCausalNode:
11
+ def test_create_node_with_defaults(self):
12
+ node = CausalNode("A", time_coordinate=0.0, state_dim=4)
13
+ assert node.node_id == "A"
14
+ assert node.time_coordinate == 0.0
15
+ assert node.state_dim == 4
16
+ assert node.state.shape == (4,)
17
+ assert node.paradox_pressure == 0.0
18
+
19
+ def test_create_node_with_explicit_state(self):
20
+ state = np.array([1.0, 2.0, 3.0])
21
+ node = CausalNode("B", time_coordinate=1.0, state_dim=3, state=state)
22
+ np.testing.assert_array_equal(node.state, state)
23
+
24
+ def test_default_state_is_small_random(self):
25
+ node = CausalNode("C", time_coordinate=0.0, state_dim=100)
26
+ assert np.abs(node.state).max() < 1.0
27
+
28
+ def test_causal_parents_default_empty(self):
29
+ node = CausalNode("D", time_coordinate=0.0, state_dim=4)
30
+ assert node.causal_parents == []
31
+ assert node.retrocausal_parents == []
32
+
33
+ def test_node_with_custom_functions(self):
34
+ fn = lambda x: x * 2
35
+ node = CausalNode("E", time_coordinate=0.0, state_dim=4,
36
+ forward_fn=fn, retro_fn=fn)
37
+ assert node.forward_fn is not None
38
+ assert node.retro_fn is not None
39
+
40
+
41
+ class TestCausalTensorNetwork:
42
+ def _make_simple_network(self) -> CausalTensorNetwork:
43
+ """A -> B -> C with retrocausal C -> A."""
44
+ net = CausalTensorNetwork()
45
+ net.add_node(CausalNode("A", time_coordinate=0.0, state_dim=4))
46
+ net.add_node(CausalNode("B", time_coordinate=1.0, state_dim=4))
47
+ net.add_node(CausalNode("C", time_coordinate=2.0, state_dim=4))
48
+ net.add_causal_edge("A", "B", weight=0.8)
49
+ net.add_causal_edge("B", "C", weight=0.6)
50
+ net.add_retrocausal_edge("C", "A", weight=0.4)
51
+ return net
52
+
53
+ def test_add_nodes(self):
54
+ net = CausalTensorNetwork()
55
+ node = CausalNode("A", time_coordinate=0.0, state_dim=4)
56
+ net.add_node(node)
57
+ assert "A" in net.nodes
58
+ assert "A" in net.graph
59
+
60
+ def test_causal_edge_enforces_temporal_order(self):
61
+ net = CausalTensorNetwork()
62
+ net.add_node(CausalNode("A", time_coordinate=1.0, state_dim=4))
63
+ net.add_node(CausalNode("B", time_coordinate=0.0, state_dim=4))
64
+ with pytest.raises(ValueError, match="violates causality"):
65
+ net.add_causal_edge("A", "B")
66
+
67
+ def test_retrocausal_edge_enforces_backward_time(self):
68
+ net = CausalTensorNetwork()
69
+ net.add_node(CausalNode("A", time_coordinate=0.0, state_dim=4))
70
+ net.add_node(CausalNode("B", time_coordinate=1.0, state_dim=4))
71
+ with pytest.raises(ValueError, match="must go from future to past"):
72
+ net.add_retrocausal_edge("A", "B")
73
+
74
+ def test_causal_edge_registers_parent(self):
75
+ net = CausalTensorNetwork()
76
+ net.add_node(CausalNode("A", time_coordinate=0.0, state_dim=4))
77
+ net.add_node(CausalNode("B", time_coordinate=1.0, state_dim=4))
78
+ net.add_causal_edge("A", "B", weight=0.7)
79
+ assert ("A", 0.7) in net.nodes["B"].causal_parents
80
+
81
+ def test_retrocausal_edge_registers_parent(self):
82
+ net = self._make_simple_network()
83
+ assert ("C", 0.4) in net.nodes["A"].retrocausal_parents
84
+
85
+ def test_compute_node_state_no_parents(self):
86
+ net = CausalTensorNetwork()
87
+ node = CausalNode("X", time_coordinate=0.0, state_dim=4)
88
+ net.add_node(node)
89
+ result = net.compute_node_state("X")
90
+ np.testing.assert_array_equal(result, node.state)
91
+
92
+ def test_compute_node_state_with_parents(self):
93
+ net = CausalTensorNetwork()
94
+ a = CausalNode("A", time_coordinate=0.0, state_dim=4)
95
+ b = CausalNode("B", time_coordinate=1.0, state_dim=4)
96
+ a.state = np.ones(4)
97
+ net.add_node(a)
98
+ net.add_node(b)
99
+ net.add_causal_edge("A", "B", weight=1.0)
100
+ result = net.compute_node_state("B")
101
+ expected = np.tanh(np.ones(4))
102
+ np.testing.assert_allclose(result, expected, atol=1e-6)
103
+
104
+ def test_compute_node_state_deterministic(self):
105
+ """compute_node_state must produce the same result on repeated calls."""
106
+ net = self._make_simple_network()
107
+ r1 = net.compute_node_state("A")
108
+ r2 = net.compute_node_state("A")
109
+ np.testing.assert_array_equal(r1, r2)
110
+
111
+ def test_mixed_dimension_projection(self):
112
+ """Nodes with different state_dim should work via stored projections."""
113
+ net = CausalTensorNetwork()
114
+ net.add_node(CausalNode("A", time_coordinate=0.0, state_dim=3))
115
+ net.add_node(CausalNode("B", time_coordinate=1.0, state_dim=5))
116
+ net.add_causal_edge("A", "B", weight=1.0)
117
+ result = net.compute_node_state("B")
118
+ assert result.shape == (5,)
119
+
120
+
121
+ class TestFixedPointSolver:
122
+ def test_simple_chain_converges(self):
123
+ """A -> B -> C (no loops) converges immediately."""
124
+ net = CausalTensorNetwork()
125
+ net.add_node(CausalNode("A", time_coordinate=0.0, state_dim=3))
126
+ net.add_node(CausalNode("B", time_coordinate=1.0, state_dim=3))
127
+ net.add_node(CausalNode("C", time_coordinate=2.0, state_dim=3))
128
+ net.add_causal_edge("A", "B")
129
+ net.add_causal_edge("B", "C")
130
+ result = net.run_temporal_fixed_point(verbose=False)
131
+ assert result["converged"]
132
+
133
+ def test_loop_converges(self):
134
+ """A -> B -> C -> A (retro) should find a self-consistent fixed point."""
135
+ np.random.seed(42)
136
+ net = CausalTensorNetwork()
137
+ net.add_node(CausalNode("A", time_coordinate=0.0, state_dim=4))
138
+ net.add_node(CausalNode("B", time_coordinate=1.0, state_dim=4))
139
+ net.add_node(CausalNode("C", time_coordinate=2.0, state_dim=4))
140
+ net.add_causal_edge("A", "B", weight=0.8)
141
+ net.add_causal_edge("B", "C", weight=0.6)
142
+ net.add_retrocausal_edge("C", "A", weight=0.4)
143
+ result = net.run_temporal_fixed_point(verbose=False)
144
+ assert result["converged"]
145
+ assert result["final_inconsistency"] < 1e-7
146
+
147
+ def test_iteration_history_decreasing(self):
148
+ """Inconsistency should generally decrease over iterations."""
149
+ np.random.seed(42)
150
+ net = CausalTensorNetwork()
151
+ net.add_node(CausalNode("A", time_coordinate=0.0, state_dim=4))
152
+ net.add_node(CausalNode("B", time_coordinate=1.0, state_dim=4))
153
+ net.add_retrocausal_edge("B", "A", weight=0.5)
154
+ net.add_causal_edge("A", "B", weight=0.5)
155
+ result = net.run_temporal_fixed_point(verbose=False)
156
+ history = result["iteration_history"]
157
+ assert history[-1] < history[0]
158
+
159
+ def test_result_keys(self):
160
+ net = CausalTensorNetwork()
161
+ net.add_node(CausalNode("A", time_coordinate=0.0, state_dim=2))
162
+ result = net.run_temporal_fixed_point(max_iterations=5, verbose=False)
163
+ expected_keys = {
164
+ "converged", "iterations", "final_inconsistency",
165
+ "node_states", "paradox_pressures", "iteration_history"
166
+ }
167
+ assert set(result.keys()) == expected_keys