File size: 15,233 Bytes
74f2af5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
"""
Phase 6 Comprehensive Unit Tests

Tests for:
- framework_definitions (StateVector, TensionDefinition, CoherenceMetrics, etc.)
- semantic_tension (SemanticTensionEngine)
- specialization_tracker (SpecializationTracker)
- preflight_predictor (PreFlightConflictPredictor)
"""

import unittest
import numpy as np
import sys
from pathlib import Path
from typing import List, Dict

# Add path for direct imports
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))

# Import Phase 6 components directly (avoid forge_engine initialization)
from reasoning_forge.framework_definitions import (
    StateVector,
    TensionDefinition,
    CoherenceMetrics,
    ConflictPrediction,
    SpecializationScore,
)
from reasoning_forge.semantic_tension import SemanticTensionEngine
from reasoning_forge.specialization_tracker import SpecializationTracker


class TestFrameworkDefinitions(unittest.TestCase):
    """Test mathematical framework definitions."""

    def test_state_vector_creation(self):
        """Test StateVector creation and to_dict()."""
        state = StateVector(psi=0.8, tau=0.6, chi=1.2, phi=0.3, lam=0.7)
        self.assertEqual(state.psi, 0.8)
        self.assertEqual(state.tau, 0.6)
        self.assertAlmostEqual(state.chi, 1.2, places=3)

        state_dict = state.to_dict()
        self.assertIn("psi", state_dict)
        self.assertIn("tau", state_dict)
        self.assertEqual(state_dict["psi"], 0.8)

    def test_state_vector_to_array(self):
        """Test StateVector.to_array() returns numpy array."""
        state = StateVector(psi=0.8, tau=0.6, chi=1.2, phi=0.3, lam=0.7)
        arr = state.to_array()

        self.assertIsInstance(arr, np.ndarray)
        self.assertEqual(len(arr), 5)
        self.assertAlmostEqual(arr[0], 0.8)  # psi
        self.assertAlmostEqual(arr[1], 0.6)  # tau

    def test_state_vector_distance(self):
        """Test Euclidean distance calculation in 5D state space."""
        state_a = StateVector(psi=0.0, tau=0.0, chi=0.0, phi=0.0, lam=0.0)
        state_b = StateVector(psi=1.0, tau=0.0, chi=0.0, phi=0.0, lam=0.0)

        distance = StateVector.distance(state_a, state_b)
        self.assertAlmostEqual(distance, 1.0, places=2)

    def test_state_vector_distance_diagonal(self):
        """Test distance along diagonal (all dimensions)."""
        state_a = StateVector(psi=0.0, tau=0.0, chi=0.0, phi=0.0, lam=0.0)
        state_b = StateVector(psi=1.0, tau=1.0, chi=1.0, phi=1.0, lam=1.0)

        # sqrt(1+1+1+1+1) = sqrt(5)
        distance = StateVector.distance(state_a, state_b)
        self.assertAlmostEqual(distance, np.sqrt(5), places=2)

    def test_coherence_metrics_compute_gamma_healthy(self):
        """Test Gamma computation for healthy state."""
        gamma, health = CoherenceMetrics.compute_gamma(
            perspective_diversity=0.75,
            tension_health=0.65,
            adapter_weight_variance=0.3,
            resolution_rate=0.6
        )

        # (0.25*0.75 + 0.25*0.65 + 0.25*(1-0.3) + 0.25*0.6)
        # = (0.1875 + 0.1625 + 0.175 + 0.15) = 0.6625
        self.assertGreater(gamma, 0.4)
        self.assertLess(gamma, 0.8)
        self.assertEqual(health, "healthy")

    def test_coherence_metrics_compute_gamma_collapsing(self):
        """Test Gamma computation for collapsing state."""
        gamma, health = CoherenceMetrics.compute_gamma(
            perspective_diversity=0.1,
            tension_health=0.2,
            adapter_weight_variance=0.9,
            resolution_rate=0.05
        )

        self.assertLess(gamma, 0.4)
        self.assertEqual(health, "collapsing")

    def test_coherence_metrics_compute_gamma_groupthink(self):
        """Test Gamma computation for groupthink state."""
        gamma, health = CoherenceMetrics.compute_gamma(
            perspective_diversity=0.95,
            tension_health=0.95,
            adapter_weight_variance=0.0,
            resolution_rate=0.95
        )

        self.assertGreater(gamma, 0.8)
        self.assertEqual(health, "groupthinking")

    def test_tension_definition_creation(self):
        """Test TensionDefinition creation."""
        tension = TensionDefinition(
            structural_xi=0.8,
            semantic_xi=0.6,
            combined_xi=0.7,
            opposition_type="contradiction",
            weight_structural=0.4,
            weight_semantic=0.6
        )

        self.assertEqual(tension.structural_xi, 0.8)
        self.assertEqual(tension.opposition_type, "contradiction")

        tension_dict = tension.to_dict()
        self.assertIn("combined_xi", tension_dict)

    def test_specialization_score_creation(self):
        """Test SpecializationScore creation."""
        score = SpecializationScore(
            adapter="Newton",
            domain="physics",
            domain_accuracy=0.85,
            usage_frequency=10,
            specialization_score=0.085,
            convergence_risk=False,
            recommendation="maintain"
        )

        self.assertEqual(score.adapter, "Newton")
        self.assertEqual(score.domain, "physics")

        score_dict = score.to_dict()
        self.assertIn("specialization_score", score_dict)

    def test_conflict_prediction_creation(self):
        """Test ConflictPrediction creation."""
        query_state = StateVector(psi=0.7, tau=0.6, chi=1.0, phi=0.2, lam=0.8)
        prediction = ConflictPrediction(
            query_state=query_state,
            predicted_high_tension_pairs=[{"agent_a": "Newton", "agent_b": "Quantum"}],
            conflict_profiles={"phi_conflicts": [1, 2]},
            recommendations={"boost": ["Ethics"]},
            preflight_confidence=0.82
        )

        self.assertEqual(prediction.preflight_confidence, 0.82)
        pred_dict = prediction.to_dict()
        self.assertIn("predicted_pairs_count", pred_dict)


class TestSemanticTensionEngine(unittest.TestCase):
    """Test semantic tension computation."""

    def setUp(self):
        """Initialize SemanticTensionEngine without Llama (use dummy embeddings)."""
        self.engine = SemanticTensionEngine(llama_model=None)

    def test_semantic_tension_engine_creation(self):
        """Test engine initialization."""
        self.assertIsNotNone(self.engine)
        self.assertEqual(self.engine.embedding_dim, 4096)

    def test_embed_claim_dummy(self):
        """Test embed_claim with dummy embeddings."""
        claim = "The speed of light is constant."
        embedding = self.engine.embed_claim(claim)

        # Should return normalized vector
        self.assertIsInstance(embedding, np.ndarray)
        self.assertEqual(len(embedding), self.engine.embedding_dim)

    def test_embed_claim_caching(self):
        """Test embedding caching."""
        claim = "Same claim"

        embed1 = self.engine.embed_claim(claim, use_cache=True)
        embed2 = self.engine.embed_claim(claim, use_cache=True)

        # Should be identical (from cache)
        np.testing.assert_array_equal(embed1, embed2)

    def test_compute_semantic_tension_identical(self):
        """Test semantic tension for identical claims."""
        claim = "The speed of light is 299,792,458 m/s"
        tension = self.engine.compute_semantic_tension(claim, claim)

        # Identical claims should have zero tension
        self.assertAlmostEqual(tension, 0.0, places=1)

    def test_compute_semantic_tension_range(self):
        """Test that semantic tension is in [0, 1]."""
        claim_a = "Physics is about forces and motion."
        claim_b = "Ethics is about right and wrong."

        tension = self.engine.compute_semantic_tension(claim_a, claim_b)

        self.assertGreaterEqual(tension, 0.0)
        self.assertLessEqual(tension, 1.0)

    def test_compute_polarity(self):
        """Test polarity classification."""
        claim_a = "This is true."
        claim_b = "This is true."

        polarity = self.engine.compute_polarity(claim_a, claim_b)
        self.assertIn(polarity, ["contradiction", "paraphrase", "framework"])

    def test_explain_tension(self):
        """Test tension explanation."""
        claim_a = "Quantum mechanics is weird."
        claim_b = "Classical mechanics is intuitive."

        explanation = self.engine.explain_tension(claim_a, claim_b)

        self.assertIn("semantic_tension", explanation)
        self.assertIn("polarity_type", explanation)
        # Note: embeddings_ready may not be in all implementations
        self.assertIsInstance(explanation, dict)


class TestSpecializationTracker(unittest.TestCase):
    """Test specialization tracking and convergence detection."""

    def setUp(self):
        """Initialize tracker."""
        self.tracker = SpecializationTracker()

    def test_tracker_creation(self):
        """Test tracker initialization."""
        self.assertIsNotNone(self.tracker)
        self.assertEqual(len(self.tracker.domain_accuracy), 0)

    def test_classify_query_domain_single(self):
        """Test domain classification for physics query."""
        query = "What is the relationship between force and acceleration?"
        domains = self.tracker.classify_query_domain(query)

        self.assertIn("physics", domains)

    def test_classify_query_domain_multiple(self):
        """Test domain classification for multi-domain query."""
        query = "Should we use quantum computers for ethical decisions?"
        domains = self.tracker.classify_query_domain(query)

        # Should classify both physics/consciousness and ethics
        self.assertGreater(len(domains), 0)

    def test_classify_query_domain_general(self):
        """Test domain classification for general query."""
        query = "What is the meaning of life?"
        domains = self.tracker.classify_query_domain(query)

        # Should have at least general domain
        self.assertGreater(len(domains), 0)

    def test_record_adapter_performance(self):
        """Test recording adapter performance."""
        self.tracker.record_adapter_performance("Newton", "What is force?", 0.85)

        self.assertIn("Newton", self.tracker.domain_accuracy)
        self.assertIn("physics", self.tracker.domain_accuracy["Newton"])
        self.assertEqual(self.tracker.domain_usage["Newton"]["physics"], 1)

    def test_record_multiple_adapters(self):
        """Test recording multiple adapters."""
        self.tracker.record_adapter_performance("Newton", "force query", 0.85)
        self.tracker.record_adapter_performance("Quantum", "force query", 0.70)
        self.tracker.record_adapter_performance("Newton", "force query 2", 0.90)

        self.assertEqual(self.tracker.domain_usage["Newton"]["physics"], 2)
        self.assertEqual(self.tracker.domain_usage["Quantum"]["physics"], 1)

    def test_compute_specialization(self):
        """Test specialization score computation."""
        self.tracker.record_adapter_performance("Newton", "force query", 0.85)
        self.tracker.record_adapter_performance("Newton", "force query 2", 0.90)
        self.tracker.record_adapter_performance("Newton", "ethics query", 0.50)

        specialization = self.tracker.compute_specialization("Newton")

        self.assertIn("physics", specialization)
        # Should have computed specialization scores
        self.assertGreater(len(specialization), 0)
        # Physics score should be positive
        self.assertGreater(specialization["physics"], 0.0)

    def test_detect_semantic_convergence_no_convergence(self):
        """Test convergence detection with different outputs."""
        outputs = {
            "Newton": "Force equals mass times acceleration (F=ma).",
            "Quantum": "At quantum scales, uncertainty dominates particle behavior."
        }

        # Mock semantic engine with low similarity
        class MockSemanticEngine:
            def embed_claim(self, text):
                # Return different vectors for different texts
                if "Force" in text:
                    return np.array([1.0] + [0.0] * 4095)
                else:
                    return np.array([0.0, 1.0] + [0.0] * 4094)

        self.tracker.semantic_engine = MockSemanticEngine()
        convergence = self.tracker.detect_semantic_convergence(outputs)

        # Should be empty or have low convergence
        self.assertIsInstance(convergence, dict)


class TestIntegration(unittest.TestCase):
    """Integration tests for Phase 6 components."""

    def test_framework_and_semantic_together(self):
        """Test framework definitions with semantic engine."""
        state = StateVector(psi=0.8, tau=0.6, chi=1.2, phi=0.3, lam=0.7)
        engine = SemanticTensionEngine(llama_model=None)

        claim_a = "The universe is deterministic."
        claim_b = "Quantum mechanics introduces indeterminacy."

        semantic_xi = engine.compute_semantic_tension(claim_a, claim_b)
        structural_xi = StateVector.distance(
            state,
            StateVector(psi=0.5, tau=0.7, chi=0.8, phi=-0.2, lam=0.6)
        )

        # Create combined tension definition
        tension = TensionDefinition(
            structural_xi=structural_xi,
            semantic_xi=semantic_xi,
            combined_xi=0.6 * semantic_xi + 0.4 * min(structural_xi / 3.5, 1.0),
            opposition_type="contradiction",
            weight_structural=0.4,
            weight_semantic=0.6
        )

        self.assertGreater(tension.combined_xi, 0.0)
        self.assertLess(tension.combined_xi, 1.5)

    def test_specialization_with_coherence(self):
        """Test specialization tracker with coherence metrics."""
        tracker = SpecializationTracker()

        # Simulate debates
        tracker.record_adapter_performance("Newton", "force query", 0.88)
        tracker.record_adapter_performance("Newton", "force query 2", 0.91)
        tracker.record_adapter_performance("Quantum", "quantum query", 0.82)
        tracker.record_adapter_performance("Quantum", "quantum query 2", 0.85)

        # Compute coherence
        gamma, health = CoherenceMetrics.compute_gamma(
            perspective_diversity=0.8,
            tension_health=0.7,
            adapter_weight_variance=0.2,
            resolution_rate=0.75
        )

        self.assertEqual(health, "healthy")
        self.assertGreater(gamma, 0.5)


def run_tests():
    """Run all tests and report results."""
    loader = unittest.TestLoader()
    suite = unittest.TestSuite()

    suite.addTests(loader.loadTestsFromTestCase(TestFrameworkDefinitions))
    suite.addTests(loader.loadTestsFromTestCase(TestSemanticTensionEngine))
    suite.addTests(loader.loadTestsFromTestCase(TestSpecializationTracker))
    suite.addTests(loader.loadTestsFromTestCase(TestIntegration))

    runner = unittest.TextTestRunner(verbosity=2)
    result = runner.run(suite)

    return result


if __name__ == "__main__":
    result = run_tests()

    # Print summary
    print("\n" + "="*70)
    print("PHASE 6 TEST SUMMARY")
    print("="*70)
    print(f"Tests run: {result.testsRun}")
    print(f"Failures: {len(result.failures)}")
    print(f"Errors: {len(result.errors)}")
    print(f"Success rate: {(result.testsRun - len(result.failures) - len(result.errors)) / result.testsRun * 100:.1f}%")
    print("="*70)