-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbiomind_recursive_dmn.py
More file actions
2214 lines (1811 loc) · 98.6 KB
/
biomind_recursive_dmn.py
File metadata and controls
2214 lines (1811 loc) · 98.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
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
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
"""
BIOMIND Recursive DMN Reflection Loop Implementation
==================================================
Implements a metacognitive reflection cycle within the Decoupled HIPECA v2.5 framework
using a Qwen2-0.5B-Instruct (Q4_K_M) as the DMN Reflector for System-2 thinking.
Enhanced with Memory Integration:
- Similarity-driven memory recall from Wiki-trained knowledge
- Confidence-gated memory access bandwidth
- Counterfactual recall for hypothesis stress-testing
- Self-adversarial memory checking
- Multi-specialist + memory consensus
Key Components:
1. DMNReflector - Qwen2-0.5B metacognitive SLM
2. MemoryRecallSystem - Similarity-driven Wiki knowledge access
3. Recursive GLW Update Rule with reflection injection
4. HIPECA Executive Gating (ACC & Cerebellum)
5. Memory-Integrated Specialist Dispatch with confidence gating
Author: Principal Neuro-AI Engineer
Date: January 7, 2026
"""
import torch
import torch.nn as nn
import torch.nn.functional as F
import numpy as np
from typing import Dict, List, Any, Optional, Tuple
from dataclasses import dataclass, field
from enum import Enum
import time
import json
import re
from pathlib import Path
from real_model_inference import RealSpecialistSystem
@dataclass
class MemoryTrace:
"""Represents a recalled memory trace from Wiki-trained knowledge"""
content: str
embedding: torch.Tensor
relevance_score: float
activation_strength: float
source_type: str # 'wiki_episodic', 'wiki_semantic', 'reasoning_episodic'
timestamp: float
confidence_weight: float
@dataclass
class CounterfactualMemory:
"""Represents contrasting memories for hypothesis testing"""
original_concept: str
contrasting_concept: str
distinction_explanation: str
memory_trace: MemoryTrace
stress_test_score: float
@dataclass
class CognitiveState:
"""Represents the current cognitive state that must change each iteration"""
memory_recall_radius: float = 1.0 # How broad to search memory
abstraction_level: float = 0.5 # How abstract/concrete the thinking
attention_distribution: torch.Tensor = None # Where attention is focused
specialist_role: str = "general" # Current specialist role
question_representation: str = "" # How question is internally framed
confidence_policy: float = 0.5 # "I know how to think about this"
confidence_answer: float = 0.5 # "I trust the result I produced"
last_executed_action: Optional[str] = None
execution_confidence_pre: float = 0.0 # Confidence before execution
execution_confidence_post: float = 0.0 # Confidence after execution
reasoning_history: List[str] = field(default_factory=list) # Raw specialist responses for iterative reasoning
class MDNAction(Enum):
"""MDN planning actions for cognitive control"""
RECALL_MORE_MEMORY = "recall_more_memory"
REFRAME_QUESTION = "reframe_question"
COUNTERFACTUAL_SIMULATE = "counterfactual_simulate"
SWITCH_SPECIALIST = "switch_specialist"
DEEPEN_REASONING = "deepen_reasoning"
REEVALUATE_ANSWER = "reevaluate_answer"
EXPAND_ATTENTION = "expand_attention"
NARROW_FOCUS = "narrow_focus"
INCREASE_ABSTRACTION = "increase_abstraction"
DECREASE_ABSTRACTION = "decrease_abstraction"
EXECUTE_AND_EVALUATE = "execute_and_evaluate"
@dataclass
class MDNActionPlan:
"""MDN action planning result"""
selected_action: MDNAction
expected_confidence_gain: float
state_change_required: Dict[str, Any]
epistemic_value: float # Expected information gain
class MDNPlanner(nn.Module):
"""
MDN Action Planner - selects cognitive actions to maximize epistemic value
Predicts expected confidence gain for each possible cognitive action
and chooses the action that maximizes information gain, not speed.
"""
def __init__(self, glw_dim: int = 512, num_actions: int = len(MDNAction)):
super().__init__()
self.glw_dim = glw_dim
self.num_actions = num_actions
# State encoder
self.state_encoder = nn.Sequential(
nn.Linear(glw_dim, 256),
nn.ReLU(),
nn.Linear(256, 128)
)
# Action value predictor (expected confidence gain)
self.action_value_head = nn.Sequential(
nn.Linear(128, 64),
nn.ReLU(),
nn.Linear(64, num_actions)
)
# Epistemic value predictor (information gain)
self.epistemic_value_head = nn.Sequential(
nn.Linear(128, 64),
nn.ReLU(),
nn.Linear(64, num_actions)
)
# State change predictor
self.state_change_head = nn.Sequential(
nn.Linear(128, 64),
nn.ReLU(),
nn.Linear(64, 32)
)
def forward(self, glw_state: torch.Tensor, cognitive_state: CognitiveState,
memory_context: Dict[str, Any], task_input: str = "", execution_history: List[Dict] = None) -> MDNActionPlan:
"""
Plan the next cognitive action based on current state and memory context
"""
execution_history = execution_history or []
# Encode current GLW state
state_encoded = self.state_encoder(glw_state.squeeze(0))
# Predict action values (expected confidence gain)
action_values = self.action_value_head(state_encoded)
# Predict epistemic values (information gain)
epistemic_values = self.epistemic_value_head(state_encoded)
# Combine confidence gain and information gain
# Weight epistemic value higher for exploration
combined_values = action_values + 1.5 * epistemic_values
# Boost EXECUTE action if confidences are high enough
execute_idx = list(MDNAction).index(MDNAction.EXECUTE_AND_EVALUATE)
if cognitive_state.confidence_policy > 0.6 and cognitive_state.confidence_answer > 0.5:
combined_values[execute_idx] += 2.0 # Significant boost for EXECUTE when ready
elif cognitive_state.confidence_policy > 0.4 or cognitive_state.confidence_answer > 0.3:
combined_values[execute_idx] += 1.0 # Moderate boost for EXECUTE with reasonable confidence
# Select best action
best_action_idx = torch.argmax(combined_values).item()
best_action = list(MDNAction)[best_action_idx]
# Predict state changes required for this action
state_changes = self._predict_state_changes(best_action, cognitive_state, memory_context, task_input)
return MDNActionPlan(
selected_action=best_action,
expected_confidence_gain=action_values[best_action_idx].item(),
state_change_required=state_changes,
epistemic_value=epistemic_values[best_action_idx].item()
)
def _predict_state_changes(self, action: MDNAction, cognitive_state: CognitiveState,
memory_context: Dict[str, Any], task_input: str = "") -> Dict[str, Any]:
"""Predict what state changes are required for the selected action"""
changes = {}
if action == MDNAction.RECALL_MORE_MEMORY:
changes['memory_recall_radius'] = min(2.0, cognitive_state.memory_recall_radius * 1.5)
changes['attention_distribution'] = 'memory_focused'
elif action == MDNAction.REFRAME_QUESTION:
changes['question_representation'] = self._generate_reframed_question(
cognitive_state.question_representation, memory_context
)
changes['abstraction_level'] = cognitive_state.abstraction_level * 0.8 # More concrete
elif action == MDNAction.COUNTERFACTUAL_SIMULATE:
changes['attention_distribution'] = 'counterfactual_focused'
changes['memory_recall_radius'] = cognitive_state.memory_recall_radius * 1.2
elif action == MDNAction.SWITCH_SPECIALIST:
current_role = cognitive_state.specialist_role
changes['specialist_role'] = self._select_alternative_specialist(current_role, task_input)
elif action == MDNAction.DEEPEN_REASONING:
changes['abstraction_level'] = min(1.0, cognitive_state.abstraction_level + 0.2)
changes['memory_recall_radius'] = cognitive_state.memory_recall_radius * 0.9
elif action == MDNAction.REEVALUATE_ANSWER:
changes['attention_distribution'] = 'answer_focused'
changes['confidence_answer'] = cognitive_state.confidence_answer * 0.7 # Reset
elif action == MDNAction.EXPAND_ATTENTION:
changes['attention_distribution'] = 'broad_focus'
changes['memory_recall_radius'] = cognitive_state.memory_recall_radius * 1.3
elif action == MDNAction.NARROW_FOCUS:
changes['attention_distribution'] = 'narrow_focus'
changes['memory_recall_radius'] = cognitive_state.memory_recall_radius * 0.7
elif action == MDNAction.INCREASE_ABSTRACTION:
changes['abstraction_level'] = min(1.0, cognitive_state.abstraction_level + 0.3)
elif action == MDNAction.DECREASE_ABSTRACTION:
changes['abstraction_level'] = max(0.0, cognitive_state.abstraction_level - 0.3)
elif action == MDNAction.EXECUTE_AND_EVALUATE:
changes['attention_distribution'] = 'execution_focused'
# Include explicit answer format instructions for specialists
changes['specialist_instructions'] = self._generate_specialist_instructions(task_input, cognitive_state)
return changes
def _generate_specialist_instructions(self, task_input: str, cognitive_state: CognitiveState) -> str:
"""Generate explicit instructions for specialists based on task type and cognitive context"""
# Determine task type and generate appropriate instructions
task_lower = task_input.lower()
# Math questions - require single letter answers
if ("math" in task_lower or "calculate" in task_lower or "algebra" in task_lower or
"field" in task_lower or "extension" in task_lower or "equation" in task_lower or
"degree" in task_lower or "solve" in task_lower):
return ("You are a mathematical expert. Provide step-by-step reasoning, then give ONLY the single letter "
"of your final answer (A, B, C, or D) at the very end. Format: 'Final answer: B'")
# General reasoning questions
elif ("reasoning" in task_lower or "logic" in task_lower or "analyze" in task_lower):
return ("You are a reasoning expert. Provide clear analysis, then give ONLY the single letter "
"of your final answer (A, B, C, or D) at the very end. Format: 'Final answer: B'")
# General knowledge questions
else:
return ("You are a knowledge expert. Provide a clear explanation, then give ONLY the single letter "
"of your final answer (A, B, C, or D) at the very end. Format: 'Final answer: B'")
def _generate_reframed_question(self, current_question: str, memory_context: Dict[str, Any]) -> str:
"""Generate a reframed version of the question based on memory insights"""
# Simple reframing based on available memories
memories = memory_context.get('recalled_memories', [])
if memories:
# Use memory content to reframe
key_concept = memories[0].content.split(':')[0] if ':' in memories[0].content else memories[0].content[:20]
return f"Considering {key_concept}: {current_question}"
return current_question
def _select_alternative_specialist(self, current_role: str, task_input: str = "") -> str:
"""Select an alternative specialist role using trained router"""
if self.trained_router and task_input:
try:
with torch.no_grad():
router_result = self.trained_router(task_input)
selected = router_result['predicted_specialist']
# Override obviously wrong predictions
task_lower = task_input.lower()
is_math_question = ("math" in task_lower or "calculate" in task_lower or "algebra" in task_lower or
"field" in task_lower or "extension" in task_lower or "group" in task_lower or
"ring" in task_lower or "polynomial" in task_lower or "equation" in task_lower or
"sqrt" in task_lower or "degree" in task_lower or "finite" in task_lower)
if is_math_question and selected != "qwen_math_expert" and selected != current_role:
print(f" [CYCLE] Overriding alternative router ({selected}) -> qwen_math_expert for math question")
return "qwen_math_expert"
if selected != current_role:
return selected
except Exception as e:
print(f"[WARN] Alternative specialist selection failed: {e}")
# Fallback to random selection
roles = ['qwen_math_expert', 'qwen_general_reasoner', 'tiny_llama_planner', 'tiny_llama_critic']
if current_role in roles:
roles.remove(current_role)
return np.random.choice(roles)
def _evaluate_specialist_performance(self, cognitive_state: CognitiveState,
execution_history: List[Dict], task_input: str) -> float:
"""
Evaluate how well the current specialist is performing based on execution history
Returns performance score between 0-1, where 1 is excellent performance
"""
if not execution_history:
return 0.5 # Neutral score with no history
# Analyze recent executions (last 3 cycles)
recent_executions = execution_history[-3:]
# Performance metrics
confidence_stability = []
answer_consistency = []
basal_ganglia_rejections = 0
for execution in recent_executions:
# Confidence stability: how much confidence changes between pre/post execution
conf_pre = execution.get('confidence_pre', 0.5)
conf_post = execution.get('confidence_post', 0.5)
stability = 1.0 - abs(conf_pre - conf_post) # Higher when confidence is stable
confidence_stability.append(stability)
# Basal ganglia rejections: how often cognition is reopened
bg_eval = execution.get('basal_ganglia_evaluation', {})
if bg_eval.get('should_reopen_cognition', False):
basal_ganglia_rejections += 1
# Check if this is a math question that should be handled by math expert
task_lower = task_input.lower()
is_math_question = ("math" in task_lower or "calculate" in task_lower or "algebra" in task_lower or
"field" in task_lower or "extension" in task_lower or "group" in task_lower or
"ring" in task_lower or "polynomial" in task_lower or "equation" in task_lower or
"sqrt" in task_lower or "degree" in task_lower or "finite" in task_lower or
"s_" in task_lower or "symmetric" in task_lower or "permutation" in task_lower or
"index" in task_lower or "order" in task_lower or "subgroup" in task_lower or
"<" in task_lower or ">" in task_lower or "z_" in task_lower or "c_" in task_lower)
# Penalize non-math specialists on math questions
specialist_penalty = 0.0
if is_math_question and cognitive_state.specialist_role != "qwen_math_expert":
specialist_penalty = 0.3 # Significant penalty for wrong specialist on math
# Calculate overall performance score
avg_stability = np.mean(confidence_stability) if confidence_stability else 0.5
rejection_rate = basal_ganglia_rejections / len(recent_executions) if recent_executions else 0.0
# Performance = stability - rejection penalty - specialist penalty
performance = avg_stability - (rejection_rate * 0.5) - specialist_penalty
# Clamp to [0, 1]
performance = max(0.0, min(1.0, performance))
return performance
class BasalGangliaEvaluator(nn.Module):
"""
Basal Ganglia-style post-execution evaluation gate
Measures confidence drop, internal contradiction, memory disagreement
after answer generation. If confidence decreases, suppresses commitment
and reopens DMN loop.
"""
def __init__(self, glw_dim: int = 512):
super().__init__()
self.glw_dim = glw_dim
# Confidence drop detector
self.confidence_drop_detector = nn.Sequential(
nn.Linear(glw_dim + 2, 128), # GLW + pre/post confidence
nn.ReLU(),
nn.Linear(128, 64),
nn.ReLU(),
nn.Linear(64, 1),
nn.Sigmoid() # Probability of significant drop
)
# Internal contradiction detector
self.contradiction_detector = nn.Sequential(
nn.Linear(glw_dim, 128),
nn.ReLU(),
nn.Linear(128, 64),
nn.ReLU(),
nn.Linear(64, 1),
nn.Sigmoid()
)
# Memory disagreement scorer
self.memory_disagreement_scorer = nn.Sequential(
nn.Linear(glw_dim + 10, 64), # GLW + memory features
nn.ReLU(),
nn.Linear(64, 32),
nn.ReLU(),
nn.Linear(32, 1),
nn.Sigmoid()
)
def evaluate_post_execution(self,
glw_state: torch.Tensor,
confidence_pre: float,
confidence_post: float,
generated_answer: str,
recalled_memories: List[MemoryTrace],
task_input: str) -> Dict[str, Any]:
"""
Evaluate the generated answer and decide whether to commit or reopen cognition
"""
# Detect confidence drop
confidence_input = torch.cat([
glw_state.squeeze(0),
torch.tensor([confidence_pre, confidence_post], dtype=torch.float32)
])
confidence_drop_prob = self.confidence_drop_detector(confidence_input.unsqueeze(0)).item()
# Detect internal contradictions
contradiction_prob = self.contradiction_detector(glw_state).item()
# Score memory disagreement
memory_features = self._extract_memory_features(recalled_memories, generated_answer)
memory_input = torch.cat([glw_state.squeeze(0), torch.tensor(memory_features, dtype=torch.float32)])
memory_disagreement = self.memory_disagreement_scorer(memory_input.unsqueeze(0)).item()
# Overall evaluation
confidence_drop_threshold = 0.3 # 30% drop is significant
actual_drop = confidence_pre - confidence_post
evaluation = {
'confidence_drop': actual_drop,
'confidence_drop_significant': actual_drop > confidence_drop_threshold,
'internal_contradictions': contradiction_prob > 0.5,
'memory_disagreement': memory_disagreement > 0.6,
'should_reopen_cognition': False,
'reopen_reason': None
}
# Decision logic: reopen if confidence drops significantly OR high contradiction/disagreement
if evaluation['confidence_drop_significant']:
evaluation['should_reopen_cognition'] = True
evaluation['reopen_reason'] = f"Confidence dropped {actual_drop:.2f} (>{confidence_drop_threshold})"
elif evaluation['internal_contradictions'] and evaluation['memory_disagreement']:
evaluation['should_reopen_cognition'] = True
evaluation['reopen_reason'] = "High internal contradiction and memory disagreement"
return evaluation
def _extract_memory_features(self, memories: List[MemoryTrace], answer: str) -> List[float]:
"""Extract features about memory-answer agreement"""
if not memories:
return [0.0] * 10
features = []
# Average relevance score
features.append(np.mean([m.relevance_score for m in memories]))
# Max relevance score
features.append(max([m.relevance_score for m in memories]))
# Number of memories
features.append(len(memories))
# Semantic overlap with answer (simplified)
answer_words = set(answer.lower().split())
memory_words = set()
for m in memories:
memory_words.update(m.content.lower().split())
overlap = len(answer_words.intersection(memory_words))
features.append(overlap / max(len(answer_words), 1))
# Fill remaining features
while len(features) < 10:
features.append(0.0)
return features[:10]
class CounterfactualReDecision(nn.Module):
"""
Counterfactual re-decision mechanism
When confidence is unstable or low, generates alternative answers
by simulating different cognitive states and memory configurations.
"""
def __init__(self, glw_dim: int = 512, num_alternatives: int = 3):
super().__init__()
self.glw_dim = glw_dim
self.num_alternatives = num_alternatives
# Alternative answer generator
self.alternative_generator = nn.Sequential(
nn.Linear(glw_dim + 100, 256), # GLW + counterfactual features
nn.ReLU(),
nn.Linear(256, 128),
nn.ReLU(),
nn.Linear(128, 64),
nn.ReLU(),
nn.Linear(64, 1) # Confidence score for alternative
)
# Counterfactual state simulator
self.state_simulator = nn.Sequential(
nn.Linear(glw_dim + 20, 128), # GLW + state perturbation
nn.ReLU(),
nn.Linear(128, glw_dim)
)
def generate_alternatives(self,
glw_state: torch.Tensor,
original_answer: str,
confidence: float,
cognitive_state: CognitiveState,
recalled_memories: List[MemoryTrace]) -> List[Dict[str, Any]]:
"""
Generate alternative answers when confidence is unstable
"""
alternatives = []
# Generate counterfactual scenarios
for i in range(self.num_alternatives):
# Perturb cognitive state
state_perturbation = self._generate_state_perturbation(cognitive_state)
perturbed_glw = self.state_simulator(
torch.cat([glw_state.squeeze(0), torch.tensor(state_perturbation)])
)
# Generate alternative based on perturbed state
counterfactual_features = self._extract_counterfactual_features(
original_answer, cognitive_state, recalled_memories, i
)
generator_input = torch.cat([perturbed_glw, torch.tensor(counterfactual_features)])
alt_confidence = self.alternative_generator(generator_input.unsqueeze(0)).item()
# Create alternative answer (simplified - in practice would use full generation)
alternative = self._create_alternative_answer(
original_answer, cognitive_state, recalled_memories, i
)
alternatives.append({
'answer': alternative,
'confidence': alt_confidence,
'state_perturbation': state_perturbation,
'counterfactual_scenario': f"scenario_{i}"
})
# Sort by confidence
alternatives.sort(key=lambda x: x['confidence'], reverse=True)
return alternatives
def _generate_state_perturbation(self, cognitive_state: CognitiveState) -> List[float]:
"""Generate random perturbations to cognitive state"""
perturbation = []
# Perturb memory radius
perturbation.append(cognitive_state.memory_recall_radius * np.random.uniform(0.5, 1.5))
# Perturb abstraction level
perturbation.append(np.clip(
cognitive_state.abstraction_level + np.random.normal(0, 0.2), 0, 1
))
# Perturb attention distribution (simplified)
attention_perturbation = np.random.normal(0, 0.1, 5).tolist()
perturbation.extend(attention_perturbation)
# Perturb specialist role (random switch)
perturbation.append(np.random.randint(0, 5))
return perturbation
def _extract_counterfactual_features(self,
original_answer: str,
cognitive_state: CognitiveState,
memories: List[MemoryTrace],
scenario_idx: int) -> List[float]:
"""Extract features for counterfactual generation"""
features = []
# Original answer length
features.append(len(original_answer))
# Memory count
features.append(len(memories))
# Cognitive state features
features.append(cognitive_state.memory_recall_radius)
features.append(cognitive_state.abstraction_level)
features.extend(cognitive_state.attention_distribution)
# Scenario index (one-hot style)
scenario_onehot = [0.0] * self.num_alternatives
scenario_onehot[scenario_idx] = 1.0
features.extend(scenario_onehot)
# Pad to 100
while len(features) < 100:
features.append(0.0)
return features[:100]
def _create_alternative_answer(self,
original_answer: str,
cognitive_state: CognitiveState,
memories: List[MemoryTrace],
scenario_idx: int) -> str:
"""
Create alternative answer based on counterfactual scenario
(Simplified implementation - would use full generation in practice)
"""
# Different strategies based on scenario
if scenario_idx == 0:
# More conservative approach
return f"Alternative (conservative): {original_answer} (with additional verification needed)"
elif scenario_idx == 1:
# More aggressive approach
return f"Alternative (aggressive): {original_answer} (high confidence despite uncertainty)"
else:
# Balanced approach
return f"Alternative (balanced): {original_answer} (considering {len(memories)} memory traces)"
class TerminationCriteria:
"""
Convergence-based termination criteria
Terminates when information gain diminishes and confidence converges,
not when cycle/time limits are reached.
"""
def __init__(self, min_information_gain: float = 0.01, confidence_stability_threshold: float = 0.05):
self.min_information_gain = min_information_gain
self.confidence_stability_threshold = confidence_stability_threshold
# Track convergence history
self.confidence_history = []
self.information_gain_history = []
self.answer_history = [] # Track recent answers for stability
self.max_history_length = 5
def should_terminate(self,
current_confidence_policy: float,
current_confidence_answer: float,
information_gain: float,
cycle_count: int,
max_cycles: int = 50,
current_answer: str = None,
answer_confidence: float = None) -> Tuple[bool, str]:
"""
Determine if cognitive processing should terminate
"""
# Always terminate after max cycles (safety net)
if cycle_count >= max_cycles:
return True, "Maximum cycles reached"
# Update history
self.confidence_history.append((current_confidence_policy, current_confidence_answer))
self.information_gain_history.append(information_gain)
# Track answer history if provided
if current_answer is not None and answer_confidence is not None:
self.answer_history.append((current_answer, answer_confidence))
# Keep only recent history
if len(self.confidence_history) > self.max_history_length:
self.confidence_history.pop(0)
self.information_gain_history.pop(0)
if len(self.answer_history) > self.max_history_length:
self.answer_history.pop(0)
# Check answer stability (early termination for consistent high-confidence answers)
if len(self.answer_history) >= 2:
recent_answers = self.answer_history[-3:] # Check last 3 answers
# Check if last 2 answers are the same and have high confidence
if len(recent_answers) >= 2:
last_answer, last_confidence = recent_answers[-1]
prev_answer, prev_confidence = recent_answers[-2]
# Same answer with high confidence twice in a row
if (last_answer == prev_answer and
last_confidence > 0.8 and prev_confidence > 0.8):
return True, f"Answer stabilized: '{last_answer}' (confidence: {last_confidence:.2f})"
# Check information gain convergence
if len(self.information_gain_history) >= 3:
recent_gains = self.information_gain_history[-3:]
avg_recent_gain = np.mean(recent_gains)
if avg_recent_gain < self.min_information_gain:
return True, f"Information gain converged ({avg_recent_gain:.4f} < {self.min_information_gain})"
# Check confidence stability
if len(self.confidence_history) >= 3:
recent_confidences = self.confidence_history[-3:]
policy_stable = np.std([c[0] for c in recent_confidences]) < self.confidence_stability_threshold
answer_stable = np.std([c[1] for c in recent_confidences]) < self.confidence_stability_threshold
if policy_stable and answer_stable:
avg_policy = np.mean([c[0] for c in recent_confidences])
avg_answer = np.mean([c[1] for c in recent_confidences])
# Only terminate if both confidences are reasonably high
if avg_policy > 0.8 and avg_answer > 0.7:
return True, f"Confidence converged (policy: {avg_policy:.2f}, answer: {avg_answer:.2f})"
return False, "Continue processing"
def reset(self):
"""Reset convergence tracking for new problem"""
self.confidence_history.clear()
self.information_gain_history.clear()
self.answer_history.clear()
class MemoryRecallSystem(nn.Module):
"""
Similarity-driven memory recall system for Wiki-trained knowledge
Features:
- Confidence-gated recall bandwidth
- Counterfactual memory activation
- Self-adversarial memory checking
- Episodic and semantic memory integration
"""
def __init__(self, embedding_dim: int = 512, memory_capacity: int = 10000):
super().__init__()
self.embedding_dim = embedding_dim
self.memory_capacity = memory_capacity
# Memory storage (simulated - in production would load from Wiki training)
self.episodic_memories: List[MemoryTrace] = []
self.semantic_memories: List[MemoryTrace] = []
# Recall mechanisms
self.similarity_encoder = nn.Sequential(
nn.Linear(embedding_dim, 256),
nn.ReLU(),
nn.Linear(256, 128)
)
self.confidence_gate = nn.Sequential(
nn.Linear(1, 32),
nn.ReLU(),
nn.Linear(32, 1),
nn.Sigmoid()
)
self.counterfactual_detector = nn.Sequential(
nn.Linear(embedding_dim * 2, 256),
nn.ReLU(),
nn.Linear(256, 128),
nn.ReLU(),
nn.Linear(128, 1),
nn.Sigmoid()
)
# Initialize with simulated Wiki-trained knowledge
self._initialize_simulated_wiki_memories()
def _initialize_simulated_wiki_memories(self):
"""Initialize with simulated Wiki-trained knowledge (episodic and semantic)"""
# Simulate episodic memories from Wiki training
episodic_concepts = [
("group theory", "mathematical structures with binary operations"),
("abelian group", "commutative group where order doesn't matter"),
("cyclic group", "group generated by a single element"),
("normal subgroup", "subgroup invariant under conjugation"),
("kernel homomorphism", "set where homomorphism maps to identity"),
("ring structure", "set with addition and multiplication"),
("field definition", "ring where nonzero elements have multiplicative inverses"),
("vector space", "structure with scalars and vector addition"),
("linear transformation", "function preserving vector space structure"),
("eigenvalue problem", "finding scalars where matrix action scales vectors")
]
for concept, description in episodic_concepts:
embedding = torch.randn(self.embedding_dim) * 0.1
memory = MemoryTrace(
content=f"Concept: {concept} - {description}",
embedding=embedding,
relevance_score=0.5,
activation_strength=0.3,
source_type="wiki_episodic",
timestamp=time.time(),
confidence_weight=0.7
)
self.episodic_memories.append(memory)
# Simulate semantic associations
semantic_associations = [
("abelian", "commutative", "groups where ab = ba for all elements"),
("cyclic", "generated", "groups with single generator element"),
("normal", "invariant", "subgroups unchanged by conjugation"),
("kernel", "identity", "elements mapping to group identity"),
("field", "division", "rings with multiplicative inverses"),
("vector", "linear", "structures with scalar multiplication"),
("eigen", "characteristic", "values where matrix scales vectors")
]
for term1, term2, association in semantic_associations:
embedding = torch.randn(self.embedding_dim) * 0.1
memory = MemoryTrace(
content=f"Association: {term1} ↔ {term2} - {association}",
embedding=embedding,
relevance_score=0.4,
activation_strength=0.2,
source_type="wiki_semantic",
timestamp=time.time(),
confidence_weight=0.6
)
self.semantic_memories.append(memory)
def recall_memories(self, query_embedding: torch.Tensor, current_confidence: float,
attention_focus: str = "balanced") -> Tuple[List[MemoryTrace], List[CounterfactualMemory]]:
"""
Recall relevant memories based on similarity and confidence gating
Args:
query_embedding: Current reasoning state embedding
current_confidence: Current inference confidence (0-1)
attention_focus: 'balanced', 'exploratory', 'focused'
Returns:
Tuple of (relevant_memories, counterfactual_memories)
"""
# Confidence-gated recall bandwidth
confidence_tensor = torch.tensor([[current_confidence]], dtype=torch.float32)
recall_bandwidth = self.confidence_gate(confidence_tensor).item()
# Adjust bandwidth based on confidence and attention
if current_confidence < 0.4: # Low confidence - increase recall
recall_bandwidth = min(1.0, recall_bandwidth * 1.5)
elif current_confidence > 0.8: # High confidence - focused recall
recall_bandwidth = max(0.3, recall_bandwidth * 0.7)
if attention_focus == "exploratory":
recall_bandwidth = min(1.0, recall_bandwidth * 1.3)
elif attention_focus == "focused":
recall_bandwidth = max(0.2, recall_bandwidth * 0.6)
# Calculate similarity scores for all memories
relevant_memories = []
all_memories = self.episodic_memories + self.semantic_memories
for memory in all_memories:
# Cosine similarity between query and memory
similarity = F.cosine_similarity(
query_embedding.unsqueeze(0),
memory.embedding.unsqueeze(0)
).item()
# Relevance weighting based on similarity and confidence
relevance_score = similarity * recall_bandwidth * memory.confidence_weight
if relevance_score > 0.01: # Lowered activation threshold for testing
activated_memory = MemoryTrace(
content=memory.content,
embedding=memory.embedding,
relevance_score=relevance_score,
activation_strength=min(1.0, relevance_score * 2.0),
source_type=memory.source_type,
timestamp=time.time(),
confidence_weight=memory.confidence_weight
)
relevant_memories.append(activated_memory)
# Sort by relevance and limit results
relevant_memories.sort(key=lambda x: x.relevance_score, reverse=True)
relevant_memories = relevant_memories[:int(len(relevant_memories) * recall_bandwidth)]
# Generate counterfactual memories for hypothesis testing
counterfactual_memories = self._generate_counterfactual_memories(
query_embedding, relevant_memories, current_confidence
)
return relevant_memories, counterfactual_memories
def _generate_counterfactual_memories(self, query_embedding: torch.Tensor,
relevant_memories: List[MemoryTrace],
current_confidence: float) -> List[CounterfactualMemory]:
"""Generate contrasting memories for hypothesis stress-testing"""
counterfactuals = []
# Common mathematical distinctions to test
distinction_pairs = [
("abelian", "cyclic", "Abelian groups are commutative, cyclic groups are generated by one element"),
("normal", "subgroup", "Normal subgroups are invariant under conjugation"),
("field", "ring", "Fields have multiplicative inverses, rings may not"),
("kernel", "image", "Kernel maps to identity, image is homomorphism range"),
("eigenvalue", "eigenvector", "Eigenvalues are scalars, eigenvectors are vectors"),
("linear", "affine", "Linear maps preserve origin, affine may translate"),
("group", "monoid", "Groups have inverses, monoids may not"),
("ring", "semiring", "Rings have additive inverses, semirings may not")
]
for memory in relevant_memories:
if memory.relevance_score > 0.3: # Only for highly relevant memories
memory_text = memory.content.lower()
# Check if memory contains concepts that have common confusions
for concept1, concept2, distinction in distinction_pairs:
if concept1 in memory_text and concept2 not in memory_text:
# Create counterfactual by finding contrasting memory
contrasting_memory = self._find_contrasting_memory(concept2, memory)
if contrasting_memory:
counterfactual = CounterfactualMemory(
original_concept=concept1,
contrasting_concept=concept2,
distinction_explanation=distinction,
memory_trace=contrasting_memory,
stress_test_score=self._calculate_stress_test_score(
query_embedding, memory, contrasting_memory
)
)
counterfactuals.append(counterfactual)
return counterfactuals
def _find_contrasting_memory(self, concept: str, original_memory: MemoryTrace) -> Optional[MemoryTrace]:
"""Find a memory that contrasts with the original concept"""
all_memories = self.episodic_memories + self.semantic_memories
for memory in all_memories:
if concept.lower() in memory.content.lower():
# Ensure it's different from original
if memory.content != original_memory.content:
return memory
return None
def _calculate_stress_test_score(self, query_embedding: torch.Tensor,
original: MemoryTrace, contrasting: MemoryTrace) -> float:
"""Calculate how much this counterfactual challenges the current hypothesis"""
# Use embedding similarity to measure potential conflict
similarity = F.cosine_similarity(
original.embedding.unsqueeze(0),
contrasting.embedding.unsqueeze(0)
).item()
# Lower similarity = higher stress test potential
stress_score = 1.0 - similarity
# Weight by relevance to query
query_similarity = F.cosine_similarity(
query_embedding.unsqueeze(0),
contrasting.embedding.unsqueeze(0)
).item()
return stress_score * query_similarity
def self_adversarial_check(self, hypothesis: str, recalled_memories: List[MemoryTrace]) -> Dict[str, Any]:
"""
Self-adversarial memory checking for contradictions and overgeneralizations
Returns critique of the hypothesis based on recalled memories
"""
contradictions = []
overgeneralizations = []
supporting_evidence = []
hypothesis_lower = hypothesis.lower()
for memory in recalled_memories:
memory_lower = memory.content.lower()
# Check for direct contradictions
if any(phrase in memory_lower for phrase in ['not always', 'does not imply', 'counterexample']):
if any(word in hypothesis_lower for word in memory_lower.split()):
contradictions.append({
'memory': memory.content,
'conflict_type': 'direct_contradiction',
'strength': memory.relevance_score
})
# Check for overgeneralization warnings
if any(phrase in memory_lower for phrase in ['in general', 'typically', 'usually', 'not necessarily']):
overgeneralizations.append({
'memory': memory.content,
'warning_type': 'overgeneralization_risk',
'strength': memory.relevance_score
})
# Check for supporting evidence
if any(word in hypothesis_lower for word in memory_lower.split() if len(word) > 3):
supporting_evidence.append({
'memory': memory.content,
'support_type': 'semantic_overlap',
'strength': memory.relevance_score
})
return {
'contradictions': contradictions,
'overgeneralizations': overgeneralizations,
'supporting_evidence': supporting_evidence,
'overall_critique': self._synthesize_critique(contradictions, overgeneralizations, supporting_evidence)