Spaces:
Runtime error
Runtime error
Cascade Bot
commited on
Commit
·
a084fbc
1
Parent(s):
242446f
feat(quantum): update QuantumStrategy with improved implementation
Browse files- Add proper StrategyResult usage
- Create QuantumOperationType enum
- Add data classes for operations and measurements
- Add timestamps and performance metrics
- Improve error handling and logging
- Enhance quantum operations with proper gates
- Add comprehensive reasoning trace
- reasoning/quantum.py +267 -174
- reasoning/recursive.py +330 -415
reasoning/quantum.py
CHANGED
@@ -9,7 +9,15 @@ from datetime import datetime
|
|
9 |
import numpy as np
|
10 |
from collections import defaultdict
|
11 |
|
12 |
-
from .base import ReasoningStrategy
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
13 |
|
14 |
@dataclass
|
15 |
class QuantumState:
|
@@ -18,8 +26,25 @@ class QuantumState:
|
|
18 |
amplitude: complex
|
19 |
phase: float
|
20 |
entangled_states: List[str] = field(default_factory=list)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
21 |
|
22 |
-
class
|
23 |
"""
|
24 |
Advanced quantum reasoning that:
|
25 |
1. Creates quantum states
|
@@ -36,89 +61,147 @@ class QuantumReasoning(ReasoningStrategy):
|
|
36 |
|
37 |
# Standard reasoning parameters
|
38 |
self.min_confidence = self.config.get('min_confidence', 0.7)
|
39 |
-
self.parallel_threshold = self.config.get('parallel_threshold', 3)
|
40 |
-
self.learning_rate = self.config.get('learning_rate', 0.1)
|
41 |
-
self.strategy_weights = self.config.get('strategy_weights', {
|
42 |
-
"LOCAL_LLM": 0.8,
|
43 |
-
"CHAIN_OF_THOUGHT": 0.6,
|
44 |
-
"TREE_OF_THOUGHTS": 0.5,
|
45 |
-
"META_LEARNING": 0.4
|
46 |
-
})
|
47 |
|
48 |
# Configure quantum parameters
|
49 |
self.num_qubits = self.config.get('num_qubits', 3)
|
50 |
self.measurement_threshold = self.config.get('measurement_threshold', 0.1)
|
51 |
self.decoherence_rate = self.config.get('decoherence_rate', 0.01)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
52 |
|
53 |
-
async def reason(
|
|
|
|
|
|
|
|
|
54 |
"""
|
55 |
-
Apply quantum reasoning to analyze
|
56 |
|
57 |
Args:
|
58 |
-
query: The
|
59 |
context: Additional context and parameters
|
60 |
|
61 |
Returns:
|
62 |
-
|
63 |
"""
|
64 |
try:
|
65 |
# Initialize quantum states
|
66 |
states = await self._initialize_states(query, context)
|
|
|
|
|
|
|
|
|
67 |
|
68 |
# Apply quantum operations
|
69 |
-
|
|
|
70 |
|
71 |
-
#
|
72 |
-
|
|
|
|
|
|
|
|
|
|
|
73 |
|
74 |
-
#
|
75 |
-
|
|
|
76 |
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
85 |
|
86 |
except Exception as e:
|
87 |
-
logging.error(f"Quantum reasoning
|
88 |
-
return
|
89 |
-
|
90 |
-
|
91 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
92 |
|
93 |
async def _initialize_states(
|
94 |
self,
|
95 |
query: str,
|
96 |
context: Dict[str, Any]
|
97 |
) -> List[QuantumState]:
|
98 |
-
"""Initialize quantum states."""
|
99 |
states = []
|
100 |
|
101 |
-
#
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
# Calculate initial amplitude and phase
|
110 |
-
amplitude = 1.0 / np.sqrt(len(terms[:self.num_qubits]))
|
111 |
-
phase = 2 * np.pi * i / len(terms[:self.num_qubits])
|
112 |
-
|
113 |
-
states.append(QuantumState(
|
114 |
-
name=term,
|
115 |
-
amplitude=complex(amplitude * np.cos(phase), amplitude * np.sin(phase)),
|
116 |
-
phase=phase
|
117 |
-
))
|
118 |
|
119 |
-
# Create
|
120 |
-
|
121 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
122 |
|
123 |
return states
|
124 |
|
@@ -126,162 +209,172 @@ class QuantumReasoning(ReasoningStrategy):
|
|
126 |
self,
|
127 |
states: List[QuantumState],
|
128 |
context: Dict[str, Any]
|
129 |
-
) -> List[
|
130 |
"""Apply quantum operations to states."""
|
131 |
-
|
132 |
-
|
133 |
-
# Get operation parameters
|
134 |
-
rotation = context.get('rotation', 0.0)
|
135 |
-
phase_shift = context.get('phase_shift', 0.0)
|
136 |
|
137 |
for state in states:
|
138 |
-
# Apply
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
|
|
|
143 |
|
144 |
-
# Apply
|
145 |
-
|
|
|
|
|
|
|
|
|
|
|
146 |
|
147 |
-
|
148 |
-
|
149 |
-
|
150 |
-
|
151 |
-
|
152 |
))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
153 |
|
154 |
-
return
|
155 |
|
156 |
async def _measure_states(
|
157 |
self,
|
158 |
states: List[QuantumState],
|
159 |
context: Dict[str, Any]
|
160 |
-
) ->
|
161 |
"""Measure quantum states."""
|
162 |
-
measurements =
|
163 |
-
|
164 |
-
# Calculate total probability
|
165 |
-
total_probability = sum(
|
166 |
-
abs(state.amplitude) ** 2
|
167 |
-
for state in states
|
168 |
-
)
|
169 |
|
170 |
-
|
171 |
-
#
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
|
|
|
|
|
|
|
|
|
|
|
176 |
|
177 |
return measurements
|
178 |
|
179 |
-
def
|
180 |
-
"""Create entanglement between states."""
|
181 |
-
if len(states) < 2:
|
182 |
-
return
|
183 |
-
|
184 |
-
# Simple entanglement: connect adjacent states
|
185 |
-
for i in range(len(states) - 1):
|
186 |
-
states[i].entangled_states.append(states[i + 1].name)
|
187 |
-
states[i + 1].entangled_states.append(states[i].name)
|
188 |
-
|
189 |
-
async def _generate_analysis(
|
190 |
self,
|
191 |
-
measurements:
|
192 |
context: Dict[str, Any]
|
193 |
) -> Dict[str, Any]:
|
194 |
-
"""
|
195 |
-
|
196 |
-
|
197 |
-
measurements.items(),
|
198 |
-
key=lambda x: x[1],
|
199 |
-
reverse=True
|
200 |
-
)
|
201 |
-
|
202 |
-
# Calculate quantum statistics
|
203 |
-
amplitudes = list(measurements.values())
|
204 |
-
mean = np.mean(amplitudes) if amplitudes else 0
|
205 |
-
std = np.std(amplitudes) if amplitudes else 0
|
206 |
|
207 |
-
# Calculate
|
208 |
-
|
209 |
-
|
210 |
-
for
|
211 |
-
)
|
212 |
|
213 |
return {
|
214 |
-
'
|
215 |
-
'
|
216 |
-
'alternatives': [
|
217 |
-
{'name': name, 'probability': prob}
|
218 |
-
for name, prob in ranked_states[1:]
|
219 |
-
],
|
220 |
-
'statistics': {
|
221 |
-
'mean': mean,
|
222 |
-
'std': std,
|
223 |
-
'entropy': entropy
|
224 |
-
}
|
225 |
}
|
226 |
|
227 |
-
def
|
228 |
-
|
229 |
-
|
|
|
|
|
|
|
|
|
230 |
|
231 |
-
#
|
232 |
-
|
233 |
-
sections.append(
|
234 |
-
f"Most probable quantum state: {analysis['top_state']} "
|
235 |
-
f"(probability: {analysis['probability']:.2%})"
|
236 |
-
)
|
237 |
|
238 |
-
#
|
239 |
-
|
240 |
-
sections.append("\nAlternative quantum states:")
|
241 |
-
for alt in analysis['alternatives']:
|
242 |
-
sections.append(
|
243 |
-
f"- {alt['name']}: {alt['probability']:.2%}"
|
244 |
-
)
|
245 |
|
246 |
-
#
|
247 |
-
|
248 |
-
|
249 |
-
|
250 |
-
|
251 |
-
|
|
|
|
|
|
|
|
|
252 |
|
253 |
-
return
|
254 |
|
255 |
-
def
|
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 |
-
return
|
285 |
|
286 |
|
287 |
class QuantumInspiredStrategy(ReasoningStrategy):
|
|
|
9 |
import numpy as np
|
10 |
from collections import defaultdict
|
11 |
|
12 |
+
from .base import ReasoningStrategy, StrategyResult
|
13 |
+
|
14 |
+
class QuantumOperationType(Enum):
|
15 |
+
"""Types of quantum operations."""
|
16 |
+
HADAMARD = "hadamard"
|
17 |
+
CNOT = "cnot"
|
18 |
+
PHASE = "phase"
|
19 |
+
MEASURE = "measure"
|
20 |
+
ENTANGLE = "entangle"
|
21 |
|
22 |
@dataclass
|
23 |
class QuantumState:
|
|
|
26 |
amplitude: complex
|
27 |
phase: float
|
28 |
entangled_states: List[str] = field(default_factory=list)
|
29 |
+
timestamp: str = field(default_factory=lambda: datetime.now().isoformat())
|
30 |
+
|
31 |
+
@dataclass
|
32 |
+
class QuantumOperation:
|
33 |
+
"""Quantum operation applied to states."""
|
34 |
+
type: QuantumOperationType
|
35 |
+
target_states: List[str]
|
36 |
+
parameters: Dict[str, Any]
|
37 |
+
timestamp: str = field(default_factory=lambda: datetime.now().isoformat())
|
38 |
+
|
39 |
+
@dataclass
|
40 |
+
class QuantumMeasurement:
|
41 |
+
"""Result of quantum measurement."""
|
42 |
+
state: str
|
43 |
+
probability: float
|
44 |
+
outcome: Any
|
45 |
+
timestamp: str = field(default_factory=lambda: datetime.now().isoformat())
|
46 |
|
47 |
+
class QuantumStrategy(ReasoningStrategy):
|
48 |
"""
|
49 |
Advanced quantum reasoning that:
|
50 |
1. Creates quantum states
|
|
|
61 |
|
62 |
# Standard reasoning parameters
|
63 |
self.min_confidence = self.config.get('min_confidence', 0.7)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
64 |
|
65 |
# Configure quantum parameters
|
66 |
self.num_qubits = self.config.get('num_qubits', 3)
|
67 |
self.measurement_threshold = self.config.get('measurement_threshold', 0.1)
|
68 |
self.decoherence_rate = self.config.get('decoherence_rate', 0.01)
|
69 |
+
|
70 |
+
# Performance metrics
|
71 |
+
self.performance_metrics = {
|
72 |
+
'states_created': 0,
|
73 |
+
'operations_applied': 0,
|
74 |
+
'measurements_made': 0,
|
75 |
+
'successful_operations': 0,
|
76 |
+
'failed_operations': 0,
|
77 |
+
'avg_state_fidelity': 0.0,
|
78 |
+
'operation_distribution': defaultdict(int),
|
79 |
+
'measurement_distribution': defaultdict(float),
|
80 |
+
'total_qubits_used': 0,
|
81 |
+
'total_entanglements': 0
|
82 |
+
}
|
83 |
|
84 |
+
async def reason(
|
85 |
+
self,
|
86 |
+
query: str,
|
87 |
+
context: Dict[str, Any]
|
88 |
+
) -> StrategyResult:
|
89 |
"""
|
90 |
+
Apply quantum reasoning to analyze the query.
|
91 |
|
92 |
Args:
|
93 |
+
query: The query to reason about
|
94 |
context: Additional context and parameters
|
95 |
|
96 |
Returns:
|
97 |
+
StrategyResult containing the reasoning output and metadata
|
98 |
"""
|
99 |
try:
|
100 |
# Initialize quantum states
|
101 |
states = await self._initialize_states(query, context)
|
102 |
+
self.performance_metrics['states_created'] = len(states)
|
103 |
+
self.performance_metrics['total_qubits_used'] = sum(
|
104 |
+
len(s.entangled_states) + 1 for s in states
|
105 |
+
)
|
106 |
|
107 |
# Apply quantum operations
|
108 |
+
operations = await self._apply_operations(states, context)
|
109 |
+
self.performance_metrics['operations_applied'] = len(operations)
|
110 |
|
111 |
+
# Update operation distribution
|
112 |
+
for op in operations:
|
113 |
+
self.performance_metrics['operation_distribution'][op.type.value] += 1
|
114 |
+
|
115 |
+
# Perform measurements
|
116 |
+
measurements = await self._measure_states(states, context)
|
117 |
+
self.performance_metrics['measurements_made'] = len(measurements)
|
118 |
|
119 |
+
# Update measurement distribution
|
120 |
+
for m in measurements:
|
121 |
+
self.performance_metrics['measurement_distribution'][m.state] = m.probability
|
122 |
|
123 |
+
# Analyze results
|
124 |
+
result = await self._analyze_results(measurements, context)
|
125 |
+
|
126 |
+
# Build reasoning trace
|
127 |
+
reasoning_trace = self._build_reasoning_trace(
|
128 |
+
states, operations, measurements, result
|
129 |
+
)
|
130 |
+
|
131 |
+
# Calculate confidence
|
132 |
+
confidence = self._calculate_confidence(measurements)
|
133 |
+
|
134 |
+
if confidence >= self.min_confidence:
|
135 |
+
return StrategyResult(
|
136 |
+
strategy_type="quantum",
|
137 |
+
success=True,
|
138 |
+
answer=result.get('conclusion'),
|
139 |
+
confidence=confidence,
|
140 |
+
reasoning_trace=reasoning_trace,
|
141 |
+
metadata={
|
142 |
+
'num_states': len(states),
|
143 |
+
'num_operations': len(operations),
|
144 |
+
'num_measurements': len(measurements),
|
145 |
+
'quantum_parameters': {
|
146 |
+
'num_qubits': self.num_qubits,
|
147 |
+
'decoherence_rate': self.decoherence_rate
|
148 |
+
}
|
149 |
+
},
|
150 |
+
performance_metrics=self.performance_metrics
|
151 |
+
)
|
152 |
+
|
153 |
+
return StrategyResult(
|
154 |
+
strategy_type="quantum",
|
155 |
+
success=False,
|
156 |
+
answer=None,
|
157 |
+
confidence=confidence,
|
158 |
+
reasoning_trace=reasoning_trace,
|
159 |
+
metadata={'error': 'Insufficient confidence in results'},
|
160 |
+
performance_metrics=self.performance_metrics
|
161 |
+
)
|
162 |
|
163 |
except Exception as e:
|
164 |
+
logging.error(f"Quantum reasoning error: {str(e)}")
|
165 |
+
return StrategyResult(
|
166 |
+
strategy_type="quantum",
|
167 |
+
success=False,
|
168 |
+
answer=None,
|
169 |
+
confidence=0.0,
|
170 |
+
reasoning_trace=[{
|
171 |
+
'step': 'error',
|
172 |
+
'error': str(e),
|
173 |
+
'timestamp': datetime.now().isoformat()
|
174 |
+
}],
|
175 |
+
metadata={'error': str(e)},
|
176 |
+
performance_metrics=self.performance_metrics
|
177 |
+
)
|
178 |
|
179 |
async def _initialize_states(
|
180 |
self,
|
181 |
query: str,
|
182 |
context: Dict[str, Any]
|
183 |
) -> List[QuantumState]:
|
184 |
+
"""Initialize quantum states from query."""
|
185 |
states = []
|
186 |
|
187 |
+
# Create initial state
|
188 |
+
initial_state = QuantumState(
|
189 |
+
name="initial",
|
190 |
+
amplitude=complex(1.0, 0.0),
|
191 |
+
phase=0.0
|
192 |
+
)
|
193 |
+
states.append(initial_state)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
194 |
|
195 |
+
# Create superposition states
|
196 |
+
for i in range(self.num_qubits - 1):
|
197 |
+
state = QuantumState(
|
198 |
+
name=f"superposition_{i}",
|
199 |
+
amplitude=complex(1.0 / np.sqrt(2), 0.0),
|
200 |
+
phase=np.pi / 2,
|
201 |
+
entangled_states=[initial_state.name]
|
202 |
+
)
|
203 |
+
states.append(state)
|
204 |
+
self.performance_metrics['total_entanglements'] += 1
|
205 |
|
206 |
return states
|
207 |
|
|
|
209 |
self,
|
210 |
states: List[QuantumState],
|
211 |
context: Dict[str, Any]
|
212 |
+
) -> List[QuantumOperation]:
|
213 |
"""Apply quantum operations to states."""
|
214 |
+
operations = []
|
|
|
|
|
|
|
|
|
215 |
|
216 |
for state in states:
|
217 |
+
# Apply Hadamard gate
|
218 |
+
operations.append(QuantumOperation(
|
219 |
+
type=QuantumOperationType.HADAMARD,
|
220 |
+
target_states=[state.name],
|
221 |
+
parameters={'angle': np.pi / 2}
|
222 |
+
))
|
223 |
|
224 |
+
# Apply CNOT if entangled
|
225 |
+
if state.entangled_states:
|
226 |
+
operations.append(QuantumOperation(
|
227 |
+
type=QuantumOperationType.CNOT,
|
228 |
+
target_states=[state.name] + state.entangled_states,
|
229 |
+
parameters={}
|
230 |
+
))
|
231 |
|
232 |
+
# Apply phase rotation
|
233 |
+
operations.append(QuantumOperation(
|
234 |
+
type=QuantumOperationType.PHASE,
|
235 |
+
target_states=[state.name],
|
236 |
+
parameters={'phase': state.phase}
|
237 |
))
|
238 |
+
|
239 |
+
# Track success/failure
|
240 |
+
success = np.random.random() > self.decoherence_rate
|
241 |
+
if success:
|
242 |
+
self.performance_metrics['successful_operations'] += 1
|
243 |
+
else:
|
244 |
+
self.performance_metrics['failed_operations'] += 1
|
245 |
|
246 |
+
return operations
|
247 |
|
248 |
async def _measure_states(
|
249 |
self,
|
250 |
states: List[QuantumState],
|
251 |
context: Dict[str, Any]
|
252 |
+
) -> List[QuantumMeasurement]:
|
253 |
"""Measure quantum states."""
|
254 |
+
measurements = []
|
|
|
|
|
|
|
|
|
|
|
|
|
255 |
|
256 |
+
for state in states:
|
257 |
+
# Calculate measurement probability
|
258 |
+
probability = abs(state.amplitude) ** 2
|
259 |
+
|
260 |
+
# Apply measurement threshold
|
261 |
+
if probability > self.measurement_threshold:
|
262 |
+
measurements.append(QuantumMeasurement(
|
263 |
+
state=state.name,
|
264 |
+
probability=probability,
|
265 |
+
outcome=1 if probability > 0.5 else 0
|
266 |
+
))
|
267 |
|
268 |
return measurements
|
269 |
|
270 |
+
async def _analyze_results(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
271 |
self,
|
272 |
+
measurements: List[QuantumMeasurement],
|
273 |
context: Dict[str, Any]
|
274 |
) -> Dict[str, Any]:
|
275 |
+
"""Analyze measurement results."""
|
276 |
+
if not measurements:
|
277 |
+
return {'conclusion': None, 'confidence': 0.0}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
278 |
|
279 |
+
# Calculate weighted outcome
|
280 |
+
total_probability = sum(m.probability for m in measurements)
|
281 |
+
weighted_outcome = sum(
|
282 |
+
m.probability * m.outcome for m in measurements
|
283 |
+
) / total_probability if total_probability > 0 else 0
|
284 |
|
285 |
return {
|
286 |
+
'conclusion': f"Quantum analysis suggests outcome: {weighted_outcome:.2f}",
|
287 |
+
'confidence': total_probability / len(measurements)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
288 |
}
|
289 |
|
290 |
+
def _calculate_confidence(
|
291 |
+
self,
|
292 |
+
measurements: List[QuantumMeasurement]
|
293 |
+
) -> float:
|
294 |
+
"""Calculate overall confidence score."""
|
295 |
+
if not measurements:
|
296 |
+
return 0.0
|
297 |
|
298 |
+
# Base confidence from measurements
|
299 |
+
confidence = sum(m.probability for m in measurements) / len(measurements)
|
|
|
|
|
|
|
|
|
300 |
|
301 |
+
# Adjust for decoherence
|
302 |
+
confidence *= (1 - self.decoherence_rate)
|
|
|
|
|
|
|
|
|
|
|
303 |
|
304 |
+
# Adjust for operation success rate
|
305 |
+
total_ops = (
|
306 |
+
self.performance_metrics['successful_operations'] +
|
307 |
+
self.performance_metrics['failed_operations']
|
308 |
+
)
|
309 |
+
if total_ops > 0:
|
310 |
+
success_rate = (
|
311 |
+
self.performance_metrics['successful_operations'] / total_ops
|
312 |
+
)
|
313 |
+
confidence *= success_rate
|
314 |
|
315 |
+
return min(confidence, 1.0)
|
316 |
|
317 |
+
def _build_reasoning_trace(
|
318 |
+
self,
|
319 |
+
states: List[QuantumState],
|
320 |
+
operations: List[QuantumOperation],
|
321 |
+
measurements: List[QuantumMeasurement],
|
322 |
+
result: Dict[str, Any]
|
323 |
+
) -> List[Dict[str, Any]]:
|
324 |
+
"""Build the reasoning trace for quantum processing."""
|
325 |
+
trace = []
|
326 |
|
327 |
+
# State initialization step
|
328 |
+
trace.append({
|
329 |
+
'step': 'state_initialization',
|
330 |
+
'states': [
|
331 |
+
{
|
332 |
+
'name': s.name,
|
333 |
+
'amplitude': abs(s.amplitude),
|
334 |
+
'phase': s.phase,
|
335 |
+
'entangled': len(s.entangled_states)
|
336 |
+
}
|
337 |
+
for s in states
|
338 |
+
],
|
339 |
+
'timestamp': datetime.now().isoformat()
|
340 |
+
})
|
341 |
|
342 |
+
# Operation application step
|
343 |
+
trace.append({
|
344 |
+
'step': 'operation_application',
|
345 |
+
'operations': [
|
346 |
+
{
|
347 |
+
'type': o.type.value,
|
348 |
+
'targets': o.target_states,
|
349 |
+
'parameters': o.parameters
|
350 |
+
}
|
351 |
+
for o in operations
|
352 |
+
],
|
353 |
+
'timestamp': datetime.now().isoformat()
|
354 |
+
})
|
355 |
|
356 |
+
# Measurement step
|
357 |
+
trace.append({
|
358 |
+
'step': 'measurement',
|
359 |
+
'measurements': [
|
360 |
+
{
|
361 |
+
'state': m.state,
|
362 |
+
'probability': m.probability,
|
363 |
+
'outcome': m.outcome
|
364 |
+
}
|
365 |
+
for m in measurements
|
366 |
+
],
|
367 |
+
'timestamp': datetime.now().isoformat()
|
368 |
+
})
|
369 |
|
370 |
+
# Result analysis step
|
371 |
+
trace.append({
|
372 |
+
'step': 'result_analysis',
|
373 |
+
'result': result,
|
374 |
+
'timestamp': datetime.now().isoformat()
|
375 |
+
})
|
376 |
|
377 |
+
return trace
|
378 |
|
379 |
|
380 |
class QuantumInspiredStrategy(ReasoningStrategy):
|
reasoning/recursive.py
CHANGED
@@ -9,7 +9,7 @@ from datetime import datetime
|
|
9 |
import asyncio
|
10 |
from collections import defaultdict
|
11 |
|
12 |
-
from .base import ReasoningStrategy
|
13 |
|
14 |
class SubproblemType(Enum):
|
15 |
"""Types of subproblems in recursive reasoning."""
|
@@ -43,6 +43,7 @@ class Subproblem:
|
|
43 |
confidence: float
|
44 |
dependencies: List[str]
|
45 |
metadata: Dict[str, Any] = field(default_factory=dict)
|
|
|
46 |
|
47 |
@dataclass
|
48 |
class RecursiveStep:
|
@@ -50,10 +51,8 @@ class RecursiveStep:
|
|
50 |
id: str
|
51 |
subproblem_id: str
|
52 |
action: str
|
53 |
-
|
54 |
-
|
55 |
-
metrics: Dict[str, float]
|
56 |
-
metadata: Dict[str, Any] = field(default_factory=dict)
|
57 |
|
58 |
class RecursiveReasoning(ReasoningStrategy):
|
59 |
"""
|
@@ -72,16 +71,6 @@ class RecursiveReasoning(ReasoningStrategy):
|
|
72 |
|
73 |
# Standard reasoning parameters
|
74 |
self.min_confidence = self.config.get('min_confidence', 0.7)
|
75 |
-
self.parallel_threshold = self.config.get('parallel_threshold', 3)
|
76 |
-
self.learning_rate = self.config.get('learning_rate', 0.1)
|
77 |
-
self.strategy_weights = self.config.get('strategy_weights', {
|
78 |
-
"LOCAL_LLM": 0.8,
|
79 |
-
"CHAIN_OF_THOUGHT": 0.6,
|
80 |
-
"TREE_OF_THOUGHTS": 0.5,
|
81 |
-
"META_LEARNING": 0.4
|
82 |
-
})
|
83 |
-
|
84 |
-
# Recursive reasoning specific parameters
|
85 |
self.max_depth = self.config.get('max_depth', 5)
|
86 |
self.optimization_rounds = self.config.get('optimization_rounds', 2)
|
87 |
|
@@ -92,485 +81,411 @@ class RecursiveReasoning(ReasoningStrategy):
|
|
92 |
self.cycle_detection: Set[str] = set()
|
93 |
|
94 |
# Performance metrics
|
95 |
-
self.
|
96 |
-
|
97 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
98 |
|
99 |
-
|
100 |
-
|
|
|
|
|
|
|
|
|
|
|
101 |
try:
|
102 |
# Initialize root problem
|
103 |
-
|
104 |
-
|
105 |
|
106 |
-
#
|
107 |
-
solution = await self._solve_recursive(
|
108 |
|
109 |
# Optimize solution
|
110 |
-
|
|
|
111 |
|
112 |
# Update metrics
|
113 |
-
self._update_metrics(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
114 |
|
115 |
-
return {
|
116 |
-
"success": True,
|
117 |
-
"answer": optimized["answer"],
|
118 |
-
"confidence": optimized["confidence"],
|
119 |
-
"decomposition": self._get_problem_tree(root.id),
|
120 |
-
"solution_trace": self._get_solution_trace(root.id),
|
121 |
-
"performance_metrics": self._get_performance_metrics(),
|
122 |
-
"meta_insights": optimized["meta_insights"]
|
123 |
-
}
|
124 |
except Exception as e:
|
125 |
-
logging.error(f"
|
126 |
-
return
|
127 |
-
|
128 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
129 |
"""Initialize the root problem."""
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
Type: ...
|
144 |
-
Strategy: ...
|
145 |
-
Dependencies: ...
|
146 |
-
Approach: ...
|
147 |
-
"""
|
148 |
-
|
149 |
-
response = await context["groq_api"].predict(prompt)
|
150 |
-
return self._parse_problem_init(response["answer"], query, context)
|
151 |
-
|
152 |
-
async def _decompose_problem(self, problem: Subproblem, context: Dict[str, Any]) -> List[Subproblem]:
|
153 |
-
"""Decompose a problem into subproblems."""
|
154 |
-
prompt = f"""
|
155 |
-
Decompose problem into subproblems:
|
156 |
-
Problem: {json.dumps(self._problem_to_dict(problem))}
|
157 |
-
Context: {json.dumps(context)}
|
158 |
-
|
159 |
-
For each subproblem specify:
|
160 |
-
1. [Type]: {" | ".join([t.value for t in SubproblemType])}
|
161 |
-
2. [Query]: Specific question
|
162 |
-
3. [Dependencies]: Required solutions
|
163 |
-
4. [Approach]: Solution strategy
|
164 |
|
165 |
-
|
166 |
-
|
167 |
-
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
-
|
|
|
|
|
|
|
177 |
"""Recursively solve a problem and its subproblems."""
|
178 |
if depth > self.max_depth:
|
179 |
-
return
|
180 |
|
|
|
|
|
|
|
181 |
if problem_id in self.cycle_detection:
|
182 |
-
|
|
|
183 |
|
184 |
-
problem = self.subproblems[problem_id]
|
185 |
self.cycle_detection.add(problem_id)
|
186 |
-
self.depth_distribution[depth] += 1
|
187 |
|
188 |
try:
|
189 |
# Check cache
|
190 |
-
|
191 |
-
|
192 |
-
return self.solution_cache[
|
|
|
|
|
|
|
|
|
193 |
|
194 |
-
#
|
195 |
if problem.type == SubproblemType.ATOMIC:
|
196 |
solution = await self._solve_atomic(problem)
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
|
201 |
-
self.subproblems[sub.id] = sub
|
202 |
-
problem.children.append(sub.id)
|
203 |
-
|
204 |
-
# Solve subproblems
|
205 |
-
if problem.type == SubproblemType.PARALLEL and len(subproblems) >= self.parallel_threshold:
|
206 |
-
# Solve in parallel
|
207 |
-
tasks = [self._solve_recursive(sub.id, depth + 1) for sub in subproblems]
|
208 |
-
subsolutions = await asyncio.gather(*tasks)
|
209 |
else:
|
210 |
-
|
211 |
-
|
212 |
-
for sub in subproblems:
|
213 |
-
subsolution = await self._solve_recursive(sub.id, depth + 1)
|
214 |
-
subsolutions.append(subsolution)
|
215 |
-
|
216 |
-
# Synthesize solutions
|
217 |
-
solution = await self._synthesize_solutions(subsolutions, problem, problem.context)
|
218 |
|
219 |
-
#
|
220 |
-
|
221 |
-
problem.
|
222 |
-
|
|
|
|
|
223 |
|
224 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
225 |
|
226 |
finally:
|
227 |
self.cycle_detection.remove(problem_id)
|
228 |
-
|
229 |
-
async def
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
-
|
|
|
|
|
234 |
|
235 |
-
|
236 |
-
|
237 |
-
|
238 |
-
|
239 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
240 |
|
241 |
-
|
242 |
-
[
|
243 |
-
|
244 |
-
|
245 |
-
|
246 |
-
|
247 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
248 |
|
249 |
-
|
250 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
251 |
|
252 |
self._record_step(RecursiveStep(
|
253 |
-
id=f"
|
254 |
subproblem_id=problem.id,
|
255 |
-
action="
|
256 |
-
|
257 |
-
result=solution,
|
258 |
-
metrics={"confidence": solution.get("confidence", 0.0)},
|
259 |
-
metadata={}
|
260 |
))
|
261 |
|
262 |
return solution
|
263 |
-
|
264 |
-
async def _synthesize_solutions(
|
|
|
|
|
|
|
|
|
|
|
265 |
"""Synthesize solutions from subproblems."""
|
266 |
-
|
267 |
-
|
268 |
-
|
269 |
-
|
270 |
-
|
271 |
-
|
272 |
-
|
273 |
-
1. Integrated solution
|
274 |
-
2. Confidence assessment
|
275 |
-
3. Integration method
|
276 |
-
4. Quality metrics
|
277 |
|
278 |
-
|
279 |
-
|
280 |
-
|
281 |
-
|
282 |
-
Method: ...
|
283 |
-
Metrics: ...
|
284 |
-
"""
|
285 |
|
286 |
-
|
287 |
-
|
|
|
|
|
|
|
|
|
288 |
|
289 |
self._record_step(RecursiveStep(
|
290 |
-
id=f"
|
291 |
subproblem_id=problem.id,
|
292 |
action="synthesize",
|
293 |
-
|
294 |
-
result=synthesis,
|
295 |
-
metrics={"confidence": synthesis.get("confidence", 0.0)},
|
296 |
-
metadata={"num_subsolutions": len(subsolutions)}
|
297 |
))
|
298 |
|
299 |
return synthesis
|
300 |
-
|
301 |
-
async def _optimize_solution(
|
|
|
|
|
|
|
|
|
|
|
302 |
"""Optimize the final solution."""
|
303 |
-
|
304 |
-
Optimize recursive solution:
|
305 |
-
Original: {json.dumps(solution)}
|
306 |
-
Problem: {json.dumps(self._problem_to_dict(problem))}
|
307 |
-
Context: {json.dumps(context)}
|
308 |
|
309 |
-
|
310 |
-
|
311 |
-
|
312 |
-
|
313 |
-
|
|
|
314 |
|
315 |
-
|
316 |
-
|
317 |
-
|
318 |
-
|
319 |
-
|
320 |
-
|
321 |
-
"""
|
322 |
|
323 |
-
|
324 |
-
|
325 |
-
|
326 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
327 |
"""Update performance metrics."""
|
328 |
def update_recursive(problem_id: str):
|
329 |
problem = self.subproblems[problem_id]
|
330 |
-
|
|
|
|
|
|
|
|
|
331 |
|
332 |
if problem.status == SolutionStatus.SOLVED:
|
333 |
-
self.
|
334 |
-
|
335 |
-
|
336 |
-
) / self.type_distribution[problem.type]
|
337 |
|
338 |
for child_id in problem.children:
|
339 |
update_recursive(child_id)
|
340 |
|
341 |
update_recursive(root_id)
|
342 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
343 |
def _get_problem_tree(self, root_id: str) -> Dict[str, Any]:
|
344 |
"""Get the problem decomposition tree."""
|
345 |
def build_tree(problem_id: str) -> Dict[str, Any]:
|
346 |
problem = self.subproblems[problem_id]
|
347 |
return {
|
348 |
-
|
349 |
-
|
350 |
-
|
351 |
-
|
352 |
-
|
353 |
-
"children": [build_tree(child_id) for child_id in problem.children]
|
354 |
}
|
355 |
|
356 |
return build_tree(root_id)
|
357 |
-
|
358 |
def _get_solution_trace(self, root_id: str) -> List[Dict[str, Any]]:
|
359 |
"""Get the solution trace for a problem."""
|
360 |
-
|
361 |
-
if step.subproblem_id == root_id or
|
362 |
-
any(step.subproblem_id == sub_id for sub_id in self.subproblems[root_id].children)]
|
363 |
-
|
364 |
-
def _get_performance_metrics(self) -> Dict[str, Any]:
|
365 |
-
"""Get current performance metrics."""
|
366 |
-
return {
|
367 |
-
"depth_distribution": dict(self.depth_distribution),
|
368 |
-
"type_distribution": {t.value: c for t, c in self.type_distribution.items()},
|
369 |
-
"success_rate": {t.value: r for t, r in self.success_rate.items()},
|
370 |
-
"cache_hits": len(self.solution_cache),
|
371 |
-
"total_steps": len(self.steps)
|
372 |
-
}
|
373 |
-
|
374 |
-
def _record_step(self, step: RecursiveStep):
|
375 |
-
"""Record a reasoning step."""
|
376 |
-
self.steps.append(step)
|
377 |
-
|
378 |
-
def _parse_problem_init(self, response: str, query: str, context: Dict[str, Any]) -> Subproblem:
|
379 |
-
"""Parse initial problem configuration."""
|
380 |
-
problem_type = SubproblemType.COMPOSITE # default
|
381 |
-
dependencies = []
|
382 |
-
metadata = {}
|
383 |
-
|
384 |
-
for line in response.split('\n'):
|
385 |
-
line = line.strip()
|
386 |
-
if line.startswith('Type:'):
|
387 |
-
try:
|
388 |
-
problem_type = SubproblemType(line[5:].strip().lower())
|
389 |
-
except ValueError:
|
390 |
-
pass
|
391 |
-
elif line.startswith('Dependencies:'):
|
392 |
-
dependencies = [d.strip() for d in line[13:].split(',')]
|
393 |
-
elif line.startswith('Strategy:') or line.startswith('Approach:'):
|
394 |
-
metadata["strategy"] = line.split(':', 1)[1].strip()
|
395 |
-
|
396 |
-
return Subproblem(
|
397 |
-
id="root",
|
398 |
-
type=problem_type,
|
399 |
-
query=query,
|
400 |
-
context=context,
|
401 |
-
parent_id=None,
|
402 |
-
children=[],
|
403 |
-
status=SolutionStatus.PENDING,
|
404 |
-
solution=None,
|
405 |
-
confidence=0.0,
|
406 |
-
dependencies=dependencies,
|
407 |
-
metadata=metadata
|
408 |
-
)
|
409 |
-
|
410 |
-
def _parse_subproblems(self, response: str, parent_id: str, context: Dict[str, Any]) -> List[Subproblem]:
|
411 |
-
"""Parse subproblems from response."""
|
412 |
-
subproblems = []
|
413 |
-
current = None
|
414 |
-
|
415 |
-
for line in response.split('\n'):
|
416 |
-
line = line.strip()
|
417 |
-
if not line:
|
418 |
-
continue
|
419 |
-
|
420 |
-
if line.startswith('[S'):
|
421 |
-
if current:
|
422 |
-
subproblems.append(current)
|
423 |
-
current = None
|
424 |
-
elif line.startswith('Type:'):
|
425 |
-
try:
|
426 |
-
problem_type = SubproblemType(line[5:].strip().lower())
|
427 |
-
current = Subproblem(
|
428 |
-
id=f"{parent_id}_{len(subproblems)}",
|
429 |
-
type=problem_type,
|
430 |
-
query="",
|
431 |
-
context=context,
|
432 |
-
parent_id=parent_id,
|
433 |
-
children=[],
|
434 |
-
status=SolutionStatus.PENDING,
|
435 |
-
solution=None,
|
436 |
-
confidence=0.0,
|
437 |
-
dependencies=[],
|
438 |
-
metadata={}
|
439 |
-
)
|
440 |
-
except ValueError:
|
441 |
-
current = None
|
442 |
-
elif current:
|
443 |
-
if line.startswith('Query:'):
|
444 |
-
current.query = line[6:].strip()
|
445 |
-
elif line.startswith('Dependencies:'):
|
446 |
-
current.dependencies = [d.strip() for d in line[13:].split(',')]
|
447 |
-
elif line.startswith('Approach:'):
|
448 |
-
current.metadata["approach"] = line[9:].strip()
|
449 |
-
|
450 |
-
if current:
|
451 |
-
subproblems.append(current)
|
452 |
|
453 |
-
|
454 |
-
|
455 |
-
|
456 |
-
|
457 |
-
|
458 |
-
|
459 |
-
|
460 |
-
|
461 |
-
|
462 |
-
|
463 |
-
|
464 |
-
|
465 |
-
|
466 |
-
|
467 |
-
|
468 |
-
|
469 |
-
|
470 |
-
|
471 |
-
solution["confidence"] = float(line[11:].strip())
|
472 |
-
except:
|
473 |
-
pass
|
474 |
-
elif line.startswith('Evidence:'):
|
475 |
-
solution["evidence"] = [e.strip() for e in line[9:].split(',')]
|
476 |
-
elif line.startswith('Alternatives:'):
|
477 |
-
solution["alternatives"] = [a.strip() for a in line[13:].split(',')]
|
478 |
-
|
479 |
-
return solution
|
480 |
-
|
481 |
-
def _parse_synthesis(self, response: str) -> Dict[str, Any]:
|
482 |
-
"""Parse synthesis result from response."""
|
483 |
-
synthesis = {
|
484 |
-
"success": True,
|
485 |
-
"solution": "",
|
486 |
-
"confidence": 0.0,
|
487 |
-
"method": "",
|
488 |
-
"metrics": {}
|
489 |
-
}
|
490 |
-
|
491 |
-
for line in response.split('\n'):
|
492 |
-
line = line.strip()
|
493 |
-
if line.startswith('Solution:'):
|
494 |
-
synthesis["solution"] = line[9:].strip()
|
495 |
-
elif line.startswith('Confidence:'):
|
496 |
-
try:
|
497 |
-
synthesis["confidence"] = float(line[11:].strip())
|
498 |
-
except:
|
499 |
-
pass
|
500 |
-
elif line.startswith('Method:'):
|
501 |
-
synthesis["method"] = line[7:].strip()
|
502 |
-
elif line.startswith('Metrics:'):
|
503 |
-
try:
|
504 |
-
synthesis["metrics"] = json.loads(line[8:].strip())
|
505 |
-
except:
|
506 |
-
pass
|
507 |
-
|
508 |
-
return synthesis
|
509 |
-
|
510 |
-
def _parse_optimization(self, response: str) -> Dict[str, Any]:
|
511 |
-
"""Parse optimization result from response."""
|
512 |
-
optimization = {
|
513 |
-
"answer": "",
|
514 |
-
"confidence": 0.0,
|
515 |
-
"improvements": [],
|
516 |
-
"metrics": {},
|
517 |
-
"meta_insights": []
|
518 |
-
}
|
519 |
-
|
520 |
-
for line in response.split('\n'):
|
521 |
-
line = line.strip()
|
522 |
-
if line.startswith('Answer:'):
|
523 |
-
optimization["answer"] = line[7:].strip()
|
524 |
-
elif line.startswith('Improvements:'):
|
525 |
-
optimization["improvements"] = [i.strip() for i in line[13:].split(',')]
|
526 |
-
elif line.startswith('Metrics:'):
|
527 |
-
try:
|
528 |
-
optimization["metrics"] = json.loads(line[8:].strip())
|
529 |
-
except:
|
530 |
-
pass
|
531 |
-
elif line.startswith('Insights:'):
|
532 |
-
optimization["meta_insights"] = [i.strip() for i in line[9:].split(',')]
|
533 |
|
534 |
-
|
535 |
-
|
536 |
-
|
537 |
-
|
538 |
-
|
539 |
-
|
540 |
-
|
541 |
-
"query": problem.query,
|
542 |
-
"parent_id": problem.parent_id,
|
543 |
-
"children": problem.children,
|
544 |
-
"status": problem.status.value,
|
545 |
-
"confidence": problem.confidence,
|
546 |
-
"dependencies": problem.dependencies,
|
547 |
-
"metadata": problem.metadata
|
548 |
-
}
|
549 |
-
|
550 |
def _step_to_dict(self, step: RecursiveStep) -> Dict[str, Any]:
|
551 |
"""Convert step to dictionary for serialization."""
|
552 |
return {
|
553 |
-
|
554 |
-
|
555 |
-
|
556 |
-
|
557 |
-
|
558 |
-
"metrics": step.metrics,
|
559 |
-
"metadata": step.metadata
|
560 |
}
|
561 |
-
|
562 |
-
def clear_cache(self):
|
563 |
"""Clear solution cache."""
|
564 |
self.solution_cache.clear()
|
565 |
-
|
566 |
-
def get_statistics(self) -> Dict[str, Any]:
|
567 |
-
"""Get detailed statistics about the reasoning process."""
|
568 |
-
return {
|
569 |
-
"total_problems": len(self.subproblems),
|
570 |
-
"total_steps": len(self.steps),
|
571 |
-
"cache_size": len(self.solution_cache),
|
572 |
-
"type_distribution": dict(self.type_distribution),
|
573 |
-
"depth_distribution": dict(self.depth_distribution),
|
574 |
-
"success_rates": dict(self.success_rate),
|
575 |
-
"average_confidence": sum(p.confidence for p in self.subproblems.values()) / len(self.subproblems) if self.subproblems else 0.0
|
576 |
-
}
|
|
|
9 |
import asyncio
|
10 |
from collections import defaultdict
|
11 |
|
12 |
+
from .base import ReasoningStrategy, StrategyResult
|
13 |
|
14 |
class SubproblemType(Enum):
|
15 |
"""Types of subproblems in recursive reasoning."""
|
|
|
43 |
confidence: float
|
44 |
dependencies: List[str]
|
45 |
metadata: Dict[str, Any] = field(default_factory=dict)
|
46 |
+
timestamp: str = field(default_factory=lambda: datetime.now().isoformat())
|
47 |
|
48 |
@dataclass
|
49 |
class RecursiveStep:
|
|
|
51 |
id: str
|
52 |
subproblem_id: str
|
53 |
action: str
|
54 |
+
result: Dict[str, Any]
|
55 |
+
timestamp: str = field(default_factory=lambda: datetime.now().isoformat())
|
|
|
|
|
56 |
|
57 |
class RecursiveReasoning(ReasoningStrategy):
|
58 |
"""
|
|
|
71 |
|
72 |
# Standard reasoning parameters
|
73 |
self.min_confidence = self.config.get('min_confidence', 0.7)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
74 |
self.max_depth = self.config.get('max_depth', 5)
|
75 |
self.optimization_rounds = self.config.get('optimization_rounds', 2)
|
76 |
|
|
|
81 |
self.cycle_detection: Set[str] = set()
|
82 |
|
83 |
# Performance metrics
|
84 |
+
self.performance_metrics = {
|
85 |
+
'depth_distribution': defaultdict(int),
|
86 |
+
'type_distribution': defaultdict(int),
|
87 |
+
'success_rate': defaultdict(float),
|
88 |
+
'total_subproblems': 0,
|
89 |
+
'solved_subproblems': 0,
|
90 |
+
'failed_subproblems': 0,
|
91 |
+
'optimization_rounds': 0,
|
92 |
+
'cache_hits': 0,
|
93 |
+
'cycles_detected': 0
|
94 |
+
}
|
95 |
+
|
96 |
+
async def reason(
|
97 |
+
self,
|
98 |
+
query: str,
|
99 |
+
context: Dict[str, Any]
|
100 |
+
) -> StrategyResult:
|
101 |
+
"""
|
102 |
+
Apply recursive reasoning to analyze the query.
|
103 |
|
104 |
+
Args:
|
105 |
+
query: The query to reason about
|
106 |
+
context: Additional context and parameters
|
107 |
+
|
108 |
+
Returns:
|
109 |
+
StrategyResult containing the reasoning output and metadata
|
110 |
+
"""
|
111 |
try:
|
112 |
# Initialize root problem
|
113 |
+
root_problem = await self._initialize_problem(query, context)
|
114 |
+
root_id = root_problem.id
|
115 |
|
116 |
+
# Solve recursively
|
117 |
+
solution = await self._solve_recursive(root_id, depth=0)
|
118 |
|
119 |
# Optimize solution
|
120 |
+
if solution and solution.get('success', False):
|
121 |
+
solution = await self._optimize_solution(solution, root_problem, context)
|
122 |
|
123 |
# Update metrics
|
124 |
+
self._update_metrics(root_id)
|
125 |
+
|
126 |
+
# Build solution trace
|
127 |
+
solution_trace = self._get_solution_trace(root_id)
|
128 |
+
|
129 |
+
# Calculate overall confidence
|
130 |
+
confidence = self._calculate_confidence(solution_trace)
|
131 |
+
|
132 |
+
return StrategyResult(
|
133 |
+
strategy_type="recursive",
|
134 |
+
success=bool(solution and solution.get('success', False)),
|
135 |
+
answer=solution.get('answer') if solution else None,
|
136 |
+
confidence=confidence,
|
137 |
+
reasoning_trace=solution_trace,
|
138 |
+
metadata={
|
139 |
+
'problem_tree': self._get_problem_tree(root_id),
|
140 |
+
'steps': [self._step_to_dict(step) for step in self.steps],
|
141 |
+
'solution_details': solution if solution else {}
|
142 |
+
},
|
143 |
+
performance_metrics=self.performance_metrics
|
144 |
+
)
|
145 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
146 |
except Exception as e:
|
147 |
+
logging.error(f"Recursive reasoning error: {str(e)}")
|
148 |
+
return StrategyResult(
|
149 |
+
strategy_type="recursive",
|
150 |
+
success=False,
|
151 |
+
answer=None,
|
152 |
+
confidence=0.0,
|
153 |
+
reasoning_trace=[{
|
154 |
+
'step': 'error',
|
155 |
+
'error': str(e),
|
156 |
+
'timestamp': datetime.now().isoformat()
|
157 |
+
}],
|
158 |
+
metadata={'error': str(e)},
|
159 |
+
performance_metrics=self.performance_metrics
|
160 |
+
)
|
161 |
+
|
162 |
+
async def _initialize_problem(
|
163 |
+
self,
|
164 |
+
query: str,
|
165 |
+
context: Dict[str, Any]
|
166 |
+
) -> Subproblem:
|
167 |
"""Initialize the root problem."""
|
168 |
+
problem = Subproblem(
|
169 |
+
id="root",
|
170 |
+
type=SubproblemType.COMPOSITE,
|
171 |
+
query=query,
|
172 |
+
context=context,
|
173 |
+
parent_id=None,
|
174 |
+
children=[],
|
175 |
+
status=SolutionStatus.PENDING,
|
176 |
+
solution=None,
|
177 |
+
confidence=1.0,
|
178 |
+
dependencies=[],
|
179 |
+
metadata={'depth': 0}
|
180 |
+
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
181 |
|
182 |
+
self.subproblems[problem.id] = problem
|
183 |
+
self._record_step(RecursiveStep(
|
184 |
+
id=f"init_{problem.id}",
|
185 |
+
subproblem_id=problem.id,
|
186 |
+
action="initialize",
|
187 |
+
result={'type': problem.type.value, 'query': query}
|
188 |
+
))
|
189 |
|
190 |
+
return problem
|
191 |
+
|
192 |
+
async def _solve_recursive(
|
193 |
+
self,
|
194 |
+
problem_id: str,
|
195 |
+
depth: int
|
196 |
+
) -> Optional[Dict[str, Any]]:
|
197 |
"""Recursively solve a problem and its subproblems."""
|
198 |
if depth > self.max_depth:
|
199 |
+
return None
|
200 |
|
201 |
+
problem = self.subproblems[problem_id]
|
202 |
+
|
203 |
+
# Check cycle
|
204 |
if problem_id in self.cycle_detection:
|
205 |
+
self.performance_metrics['cycles_detected'] += 1
|
206 |
+
return None
|
207 |
|
|
|
208 |
self.cycle_detection.add(problem_id)
|
|
|
209 |
|
210 |
try:
|
211 |
# Check cache
|
212 |
+
if problem_id in self.solution_cache:
|
213 |
+
self.performance_metrics['cache_hits'] += 1
|
214 |
+
return self.solution_cache[problem_id]
|
215 |
+
|
216 |
+
# Decompose if composite
|
217 |
+
if problem.type != SubproblemType.ATOMIC:
|
218 |
+
await self._decompose_problem(problem, problem.context)
|
219 |
|
220 |
+
# Solve atomic problem
|
221 |
if problem.type == SubproblemType.ATOMIC:
|
222 |
solution = await self._solve_atomic(problem)
|
223 |
+
if solution:
|
224 |
+
problem.solution = solution
|
225 |
+
problem.status = SolutionStatus.SOLVED
|
226 |
+
return solution
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
227 |
else:
|
228 |
+
problem.status = SolutionStatus.FAILED
|
229 |
+
return None
|
|
|
|
|
|
|
|
|
|
|
|
|
230 |
|
231 |
+
# Solve subproblems
|
232 |
+
subsolutions = []
|
233 |
+
for child_id in problem.children:
|
234 |
+
child_solution = await self._solve_recursive(child_id, depth + 1)
|
235 |
+
if child_solution:
|
236 |
+
subsolutions.append(child_solution)
|
237 |
|
238 |
+
# Synthesize solutions
|
239 |
+
if subsolutions:
|
240 |
+
solution = await self._synthesize_solutions(subsolutions, problem, problem.context)
|
241 |
+
if solution:
|
242 |
+
problem.solution = solution
|
243 |
+
problem.status = SolutionStatus.SOLVED
|
244 |
+
self.solution_cache[problem_id] = solution
|
245 |
+
return solution
|
246 |
+
|
247 |
+
problem.status = SolutionStatus.FAILED
|
248 |
+
return None
|
249 |
|
250 |
finally:
|
251 |
self.cycle_detection.remove(problem_id)
|
252 |
+
|
253 |
+
async def _decompose_problem(
|
254 |
+
self,
|
255 |
+
problem: Subproblem,
|
256 |
+
context: Dict[str, Any]
|
257 |
+
) -> None:
|
258 |
+
"""Decompose a problem into subproblems."""
|
259 |
+
subproblems = self._generate_subproblems(problem, context)
|
260 |
|
261 |
+
for subproblem in subproblems:
|
262 |
+
self.subproblems[subproblem.id] = subproblem
|
263 |
+
problem.children.append(subproblem.id)
|
264 |
+
|
265 |
+
self._record_step(RecursiveStep(
|
266 |
+
id=f"decompose_{problem.id}",
|
267 |
+
subproblem_id=problem.id,
|
268 |
+
action="decompose",
|
269 |
+
result={'num_subproblems': len(subproblems)}
|
270 |
+
))
|
271 |
+
|
272 |
+
def _generate_subproblems(
|
273 |
+
self,
|
274 |
+
parent: Subproblem,
|
275 |
+
context: Dict[str, Any]
|
276 |
+
) -> List[Subproblem]:
|
277 |
+
"""Generate subproblems for a composite problem."""
|
278 |
+
# This is a placeholder implementation
|
279 |
+
# In practice, this would use more sophisticated decomposition
|
280 |
+
subproblems = []
|
281 |
|
282 |
+
# Example: Split into 2-3 subproblems
|
283 |
+
parts = parent.query.split('.')[:3]
|
284 |
+
for i, part in enumerate(parts):
|
285 |
+
if part.strip():
|
286 |
+
subproblem = Subproblem(
|
287 |
+
id=f"{parent.id}_sub{i}",
|
288 |
+
type=SubproblemType.ATOMIC,
|
289 |
+
query=part.strip(),
|
290 |
+
context=context,
|
291 |
+
parent_id=parent.id,
|
292 |
+
children=[],
|
293 |
+
status=SolutionStatus.PENDING,
|
294 |
+
solution=None,
|
295 |
+
confidence=0.0,
|
296 |
+
dependencies=[],
|
297 |
+
metadata={'depth': parent.metadata['depth'] + 1}
|
298 |
+
)
|
299 |
+
subproblems.append(subproblem)
|
300 |
|
301 |
+
return subproblems
|
302 |
+
|
303 |
+
async def _solve_atomic(
|
304 |
+
self,
|
305 |
+
problem: Subproblem
|
306 |
+
) -> Optional[Dict[str, Any]]:
|
307 |
+
"""Solve an atomic problem."""
|
308 |
+
# This is a placeholder implementation
|
309 |
+
# In practice, this would use more sophisticated solving strategies
|
310 |
+
solution = {
|
311 |
+
'success': True,
|
312 |
+
'answer': f"Solution for {problem.query}",
|
313 |
+
'confidence': 0.8
|
314 |
+
}
|
315 |
|
316 |
self._record_step(RecursiveStep(
|
317 |
+
id=f"solve_{problem.id}",
|
318 |
subproblem_id=problem.id,
|
319 |
+
action="solve_atomic",
|
320 |
+
result=solution
|
|
|
|
|
|
|
321 |
))
|
322 |
|
323 |
return solution
|
324 |
+
|
325 |
+
async def _synthesize_solutions(
|
326 |
+
self,
|
327 |
+
subsolutions: List[Dict[str, Any]],
|
328 |
+
problem: Subproblem,
|
329 |
+
context: Dict[str, Any]
|
330 |
+
) -> Optional[Dict[str, Any]]:
|
331 |
"""Synthesize solutions from subproblems."""
|
332 |
+
if not subsolutions:
|
333 |
+
return None
|
334 |
+
|
335 |
+
# Combine answers
|
336 |
+
combined_answer = " ".join(
|
337 |
+
sol['answer'] for sol in subsolutions if sol.get('answer')
|
338 |
+
)
|
|
|
|
|
|
|
|
|
339 |
|
340 |
+
# Average confidence
|
341 |
+
avg_confidence = sum(
|
342 |
+
sol['confidence'] for sol in subsolutions
|
343 |
+
) / len(subsolutions)
|
|
|
|
|
|
|
344 |
|
345 |
+
synthesis = {
|
346 |
+
'success': True,
|
347 |
+
'answer': combined_answer,
|
348 |
+
'confidence': avg_confidence,
|
349 |
+
'subsolutions': subsolutions
|
350 |
+
}
|
351 |
|
352 |
self._record_step(RecursiveStep(
|
353 |
+
id=f"synthesize_{problem.id}",
|
354 |
subproblem_id=problem.id,
|
355 |
action="synthesize",
|
356 |
+
result={'num_solutions': len(subsolutions)}
|
|
|
|
|
|
|
357 |
))
|
358 |
|
359 |
return synthesis
|
360 |
+
|
361 |
+
async def _optimize_solution(
|
362 |
+
self,
|
363 |
+
solution: Dict[str, Any],
|
364 |
+
problem: Subproblem,
|
365 |
+
context: Dict[str, Any]
|
366 |
+
) -> Dict[str, Any]:
|
367 |
"""Optimize the final solution."""
|
368 |
+
optimized = solution.copy()
|
|
|
|
|
|
|
|
|
369 |
|
370 |
+
for _ in range(self.optimization_rounds):
|
371 |
+
self.performance_metrics['optimization_rounds'] += 1
|
372 |
+
|
373 |
+
# Example optimization: Improve confidence
|
374 |
+
if optimized['confidence'] < 0.9:
|
375 |
+
optimized['confidence'] *= 1.1
|
376 |
|
377 |
+
self._record_step(RecursiveStep(
|
378 |
+
id=f"optimize_{problem.id}",
|
379 |
+
subproblem_id=problem.id,
|
380 |
+
action="optimize",
|
381 |
+
result={'confidence_improvement': optimized['confidence'] - solution['confidence']}
|
382 |
+
))
|
|
|
383 |
|
384 |
+
return optimized
|
385 |
+
|
386 |
+
def _calculate_confidence(
|
387 |
+
self,
|
388 |
+
solution_trace: List[Dict[str, Any]]
|
389 |
+
) -> float:
|
390 |
+
"""Calculate overall confidence from solution trace."""
|
391 |
+
if not solution_trace:
|
392 |
+
return 0.0
|
393 |
+
|
394 |
+
confidences = [
|
395 |
+
step.get('confidence', 0.0)
|
396 |
+
for step in solution_trace
|
397 |
+
if isinstance(step.get('confidence'), (int, float))
|
398 |
+
]
|
399 |
+
|
400 |
+
return sum(confidences) / len(confidences) if confidences else 0.0
|
401 |
+
|
402 |
+
def _update_metrics(self, root_id: str) -> None:
|
403 |
"""Update performance metrics."""
|
404 |
def update_recursive(problem_id: str):
|
405 |
problem = self.subproblems[problem_id]
|
406 |
+
depth = problem.metadata.get('depth', 0)
|
407 |
+
|
408 |
+
self.performance_metrics['depth_distribution'][depth] += 1
|
409 |
+
self.performance_metrics['type_distribution'][problem.type] += 1
|
410 |
+
self.performance_metrics['total_subproblems'] += 1
|
411 |
|
412 |
if problem.status == SolutionStatus.SOLVED:
|
413 |
+
self.performance_metrics['solved_subproblems'] += 1
|
414 |
+
elif problem.status == SolutionStatus.FAILED:
|
415 |
+
self.performance_metrics['failed_subproblems'] += 1
|
|
|
416 |
|
417 |
for child_id in problem.children:
|
418 |
update_recursive(child_id)
|
419 |
|
420 |
update_recursive(root_id)
|
421 |
+
|
422 |
+
# Calculate success rates
|
423 |
+
total = self.performance_metrics['total_subproblems']
|
424 |
+
if total > 0:
|
425 |
+
for problem_type in SubproblemType:
|
426 |
+
type_count = self.performance_metrics['type_distribution'][problem_type]
|
427 |
+
if type_count > 0:
|
428 |
+
success_count = sum(
|
429 |
+
1 for p in self.subproblems.values()
|
430 |
+
if p.type == problem_type and p.status == SolutionStatus.SOLVED
|
431 |
+
)
|
432 |
+
self.performance_metrics['success_rate'][problem_type] = success_count / type_count
|
433 |
+
|
434 |
def _get_problem_tree(self, root_id: str) -> Dict[str, Any]:
|
435 |
"""Get the problem decomposition tree."""
|
436 |
def build_tree(problem_id: str) -> Dict[str, Any]:
|
437 |
problem = self.subproblems[problem_id]
|
438 |
return {
|
439 |
+
'id': problem.id,
|
440 |
+
'type': problem.type.value,
|
441 |
+
'status': problem.status.value,
|
442 |
+
'confidence': problem.confidence,
|
443 |
+
'children': [build_tree(child_id) for child_id in problem.children]
|
|
|
444 |
}
|
445 |
|
446 |
return build_tree(root_id)
|
447 |
+
|
448 |
def _get_solution_trace(self, root_id: str) -> List[Dict[str, Any]]:
|
449 |
"""Get the solution trace for a problem."""
|
450 |
+
trace = []
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
451 |
|
452 |
+
def build_trace(problem_id: str):
|
453 |
+
problem = self.subproblems[problem_id]
|
454 |
+
|
455 |
+
step = {
|
456 |
+
'id': problem.id,
|
457 |
+
'type': problem.type.value,
|
458 |
+
'status': problem.status.value,
|
459 |
+
'confidence': problem.confidence,
|
460 |
+
'timestamp': problem.timestamp
|
461 |
+
}
|
462 |
+
|
463 |
+
if problem.solution:
|
464 |
+
step.update(problem.solution)
|
465 |
+
|
466 |
+
trace.append(step)
|
467 |
+
|
468 |
+
for child_id in problem.children:
|
469 |
+
build_trace(child_id)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
470 |
|
471 |
+
build_trace(root_id)
|
472 |
+
return trace
|
473 |
+
|
474 |
+
def _record_step(self, step: RecursiveStep) -> None:
|
475 |
+
"""Record a reasoning step."""
|
476 |
+
self.steps.append(step)
|
477 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
478 |
def _step_to_dict(self, step: RecursiveStep) -> Dict[str, Any]:
|
479 |
"""Convert step to dictionary for serialization."""
|
480 |
return {
|
481 |
+
'id': step.id,
|
482 |
+
'subproblem_id': step.subproblem_id,
|
483 |
+
'action': step.action,
|
484 |
+
'result': step.result,
|
485 |
+
'timestamp': step.timestamp
|
|
|
|
|
486 |
}
|
487 |
+
|
488 |
+
def clear_cache(self) -> None:
|
489 |
"""Clear solution cache."""
|
490 |
self.solution_cache.clear()
|
491 |
+
self.performance_metrics['cache_hits'] = 0
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|