Premchan369 commited on
Commit
3405d5a
·
verified ·
1 Parent(s): 09acbf5

Upload qads_complete.py

Browse files
Files changed (1) hide show
  1. qads_complete.py +1086 -0
qads_complete.py ADDED
@@ -0,0 +1,1086 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ Quantum Autonomous Decision System (QADS) - Complete Implementation
4
+ ====================================================================
5
+ A hybrid quantum-classical autonomous intelligence framework for:
6
+ - Uncertainty-aware navigation
7
+ - Adaptive path planning
8
+ - Probabilistic reasoning
9
+ - Dynamic decision optimization
10
+ - Real-time control
11
+ - Edge deployment
12
+
13
+ Architecture:
14
+ Sensors → Perception → World State → Quantum Core → Hybrid Planner → Control → Actions
15
+
16
+ Components:
17
+ - Quantum Decision Core (QAOA, VQC, uncertainty analysis)
18
+ - Hybrid Planner (entropy-based quantum activation)
19
+ - Classical Planners (A*, RRT*)
20
+ - RL Layer (PPO/SAC with quantum reward shaping)
21
+ - Simulation Environment (2D grid with uncertain dynamics)
22
+ """
23
+
24
+ import numpy as np
25
+ import time
26
+ import random
27
+ import heapq
28
+ from typing import Dict, Any, Optional, List, Tuple
29
+ from dataclasses import dataclass, field
30
+ from collections import deque
31
+
32
+ # ==============================================================================
33
+ # CONFIGURATION
34
+ # ==============================================================================
35
+
36
+ @dataclass
37
+ class QADSConfig:
38
+ """Master QADS configuration."""
39
+ n_qubits: int = 8
40
+ n_layers: int = 3
41
+ shots: int = 1000
42
+ activation_entropy: float = 0.6
43
+ grid_resolution: float = 0.5
44
+ max_planning_time_ms: int = 500
45
+ learning_rate: float = 0.01
46
+ quantum_reward_weight: float = 0.3
47
+ gamma: float = 0.99
48
+ debug: bool = False
49
+ use_quantum: bool = True
50
+
51
+ # ==============================================================================
52
+ # WORLD GRAPH BUILDER
53
+ # ==============================================================================
54
+
55
+ class WorldGraph:
56
+ """
57
+ Probabilistic graph representing the environment.
58
+ Each node stores: position, risk, traversal cost, energy cost, uncertainty, obstacle probability
59
+ """
60
+
61
+ def __init__(self, resolution: float = 0.5):
62
+ self.resolution = resolution
63
+ self.nodes = []
64
+ self.edges = {} # node_id -> {neighbor_id: cost}
65
+ self.positions = {} # node_id -> (x, y)
66
+ self.metadata = {} # node_id -> dict
67
+
68
+ def add_node(self, position: Tuple[float, ...],
69
+ risk: float = 0.0, cost: float = 1.0,
70
+ energy: float = 1.0, uncertainty: float = 0.0,
71
+ obstacle_prob: float = 0.0) -> int:
72
+ nid = len(self.nodes)
73
+ self.nodes.append(nid)
74
+ self.positions[nid] = position
75
+ self.metadata[nid] = {
76
+ 'risk': risk, 'cost': cost, 'energy': energy,
77
+ 'uncertainty': uncertainty, 'obstacle_prob': obstacle_prob,
78
+ 'traversal_prob': 1.0 - obstacle_prob
79
+ }
80
+ self.edges[nid] = {}
81
+ return nid
82
+
83
+ def add_edge(self, a: int, b: int, weight: Optional[float] = None):
84
+ if weight is None:
85
+ pos_a = np.array(self.positions[a])
86
+ pos_b = np.array(self.positions[b])
87
+ weight = np.linalg.norm(pos_a - pos_b)
88
+
89
+ # Composite edge cost
90
+ ma, mb = self.metadata[a], self.metadata[b]
91
+ comp = (0.3*weight + 0.2*(ma['risk']+mb['risk'])/2 +
92
+ 0.2*(ma['cost']+mb['cost'])/2 +
93
+ 0.15*(ma['uncertainty']+mb['uncertainty'])/2 +
94
+ 0.15*(ma['obstacle_prob']+mb['obstacle_prob'])/2)
95
+
96
+ self.edges[a][b] = comp
97
+
98
+ def build_grid(self, bounds, obstacle_map=None, uncertainty_map=None):
99
+ (xmin, xmax), (ymin, ymax) = bounds
100
+ nx = int((xmax-xmin)/self.resolution)
101
+ ny = int((ymax-ymin)/self.resolution)
102
+
103
+ for i in range(nx):
104
+ for j in range(ny):
105
+ x, y = xmin+i*self.resolution, ymin+j*self.resolution
106
+ obs, unc = 0.0, 0.0
107
+ if obstacle_map is not None:
108
+ mi = min(int(i*obstacle_map.shape[0]/nx), obstacle_map.shape[0]-1)
109
+ mj = min(int(j*obstacle_map.shape[1]/ny), obstacle_map.shape[1]-1)
110
+ obs = obstacle_map[mi,mj]
111
+ if uncertainty_map is not None:
112
+ mi = min(int(i*uncertainty_map.shape[0]/nx), uncertainty_map.shape[0]-1)
113
+ mj = min(int(j*uncertainty_map.shape[1]/ny), uncertainty_map.shape[1]-1)
114
+ unc = uncertainty_map[mi,mj]
115
+ self.add_node((x,y), risk=obs*0.5+unc*0.3, cost=1+obs,
116
+ uncertainty=unc, obstacle_prob=obs)
117
+
118
+ # 4-connectivity
119
+ for i in range(nx):
120
+ for j in range(ny):
121
+ idx = i*ny+j
122
+ if i < nx-1: self.add_edge(idx, idx+ny); self.add_edge(idx+ny, idx)
123
+ if j < ny-1: self.add_edge(idx, idx+1); self.add_edge(idx+1, idx)
124
+
125
+ def get_entropy(self):
126
+ probs = [self.metadata[n]['traversal_prob'] for n in self.nodes if self.metadata[n]['traversal_prob']>0]
127
+ if not probs: return 0.0
128
+ p = np.array(probs); p = p/p.sum()
129
+ return float(-np.sum(p*np.log2(p+1e-10)))
130
+
131
+ def get_uncertainty(self):
132
+ return float(np.mean([self.metadata[n]['uncertainty'] for n in self.nodes]))
133
+
134
+ def get_obstacle_density(self):
135
+ return float(np.mean([self.metadata[n]['obstacle_prob'] for n in self.nodes]))
136
+
137
+ def find_nearest(self, pos, tol=None):
138
+ if tol is None: tol = self.resolution*2
139
+ pos = np.array(pos)
140
+ best, bestd = None, float('inf')
141
+ for nid, npos in self.positions.items():
142
+ d = np.linalg.norm(pos-np.array(npos))
143
+ if d < tol and d < bestd:
144
+ best, bestd = nid, d
145
+ return best
146
+
147
+ def to_cost_matrix(self):
148
+ n = len(self.nodes)
149
+ M = np.zeros((n,n))
150
+ for u in self.edges:
151
+ for v, w in self.edges[u].items():
152
+ M[u,v] = w
153
+ for nid in self.nodes:
154
+ M[nid,nid] = self.metadata[nid]['cost']
155
+ return M
156
+
157
+ # ==============================================================================
158
+ # QUANTUM DECISION CORE
159
+ # ==============================================================================
160
+
161
+ try:
162
+ import pennylane as qml
163
+ from pennylane import numpy as pnp
164
+ HAS_PENNYLANE = True
165
+ except ImportError:
166
+ HAS_PENNYLANE = False
167
+
168
+ class QuantumCore:
169
+ """
170
+ Quantum Decision Core integrating:
171
+ - QAOA for combinatorial optimization
172
+ - VQC for uncertainty analysis
173
+ - Quantum state encoding
174
+ - Quantum kernel attention
175
+ """
176
+
177
+ def __init__(self, config: QADSConfig):
178
+ self.cfg = config
179
+ self.device = None
180
+ self.qaoa_params = None
181
+ self.vqc_params = None
182
+ self.metrics = {'calls':0, 'avg_time':0.0, 'activations':0}
183
+
184
+ if HAS_PENNYLANE and config.use_quantum:
185
+ self.device = qml.device("default.qubit", wires=config.n_qubits, shots=config.shots)
186
+ self.qaoa_params = pnp.random.uniform(0, np.pi, (2, config.n_layers))
187
+ self.vqc_params = pnp.random.uniform(0, 2*np.pi, (config.n_layers, config.n_qubits, 3))
188
+
189
+ def qaoa_optimize(self, cost_matrix):
190
+ """QAOA for path optimization. Returns optimized path and cost."""
191
+ if not HAS_PENNYLANE or not self.cfg.use_quantum:
192
+ return self._sim_qaoa(cost_matrix)
193
+
194
+ t0 = time.time()
195
+ nq = self.cfg.n_qubits
196
+ nl = self.cfg.n_layers
197
+
198
+ @qml.qnode(self.device)
199
+ def circuit(gamma, beta):
200
+ for i in range(nq): qml.Hadamard(wires=i)
201
+ for layer in range(nl):
202
+ # Cost Hamiltonian
203
+ for i in range(min(nq, cost_matrix.shape[0])):
204
+ for j in range(i+1, min(i+4, nq, cost_matrix.shape[0])):
205
+ qml.CNOT(wires=[i,j])
206
+ qml.RZ(2*gamma[layer]*cost_matrix[i,j], wires=j)
207
+ qml.CNOT(wires=[i,j])
208
+ # Mixer Hamiltonian
209
+ for i in range(nq): qml.RX(2*beta[layer], wires=i)
210
+ return [qml.expval(qml.PauliZ(i)) for i in range(min(nq, cost_matrix.shape[0]))]
211
+
212
+ # Gradient-free optimization
213
+ best_cost, best_params = float('inf'), None
214
+ for _ in range(50):
215
+ g = pnp.random.uniform(0, np.pi, nl)
216
+ b = pnp.random.uniform(0, np.pi, nl)
217
+ samples = circuit(g, b)
218
+ c = sum(cost_matrix[i,j]*(1-samples[i]*samples[j])/2
219
+ for i in range(min(nq, cost_matrix.shape[0]))
220
+ for j in range(i+1, min(nq, cost_matrix.shape[0])))
221
+ if c < best_cost:
222
+ best_cost = c
223
+ best_params = (g, b)
224
+
225
+ # Extract solution from best params
226
+ samples = circuit(best_params[0], best_params[1])
227
+ path = [i for i, s in enumerate(samples) if s > 0]
228
+ if not path: path = list(range(min(nq, cost_matrix.shape[0])))
229
+
230
+ cost = sum(cost_matrix[path[i],path[i+1]] for i in range(len(path)-1)) if len(path)>1 else 0.0
231
+
232
+ elapsed = time.time() - t0
233
+ self.metrics['calls'] += 1
234
+ self.metrics['avg_time'] = (self.metrics['avg_time']*(self.metrics['calls']-1)+elapsed)/self.metrics['calls']
235
+
236
+ return {'path': path, 'cost': float(cost), 'quantum_used': True, 'time': elapsed}
237
+
238
+ def _sim_qaoa(self, cost_matrix):
239
+ """Simulated QAOA using simulated annealing."""
240
+ n = cost_matrix.shape[0]
241
+ best_path, best_cost = None, float('inf')
242
+ path = list(range(n))
243
+
244
+ for it in range(100):
245
+ i, j = random.sample(range(n), 2)
246
+ path[i], path[j] = path[j], path[i]
247
+ cost = sum(cost_matrix[path[k],path[k+1]] for k in range(n-1))
248
+
249
+ if cost < best_cost or random.random() < np.exp(-(cost-best_cost)/(1.0+it)):
250
+ best_cost = cost
251
+ best_path = path.copy()
252
+
253
+ return {'path': best_path, 'cost': float(best_cost), 'quantum_used': False, 'time': 0.0}
254
+
255
+ def analyze_uncertainty(self, state):
256
+ """Quantum uncertainty analysis via VQC."""
257
+ if not HAS_PENNYLANE or not self.cfg.use_quantum:
258
+ return self._classical_uncertainty(state)
259
+
260
+ nq = self.cfg.n_qubits
261
+
262
+ @qml.qnode(self.device)
263
+ def circuit(params, x):
264
+ # Angle embedding
265
+ for i in range(min(nq, len(x))):
266
+ qml.RY(np.arcsin(np.clip(x[i], -0.999, 0.999)), wires=i)
267
+ qml.RZ(x[i]*np.pi, wires=i)
268
+ # Variational layers
269
+ for layer in range(self.cfg.n_layers):
270
+ for i in range(nq):
271
+ qml.RX(params[layer,i,0], wires=i)
272
+ qml.RY(params[layer,i,1], wires=i)
273
+ qml.RZ(params[layer,i,2], wires=i)
274
+ for i in range(nq-1): qml.CNOT(wires=[i,i+1])
275
+ return qml.probs(wires=range(nq))
276
+
277
+ x = np.zeros(nq)
278
+ x[:min(len(state),nq)] = state[:nq]
279
+ x = x/(np.max(np.abs(x))+1e-10) if np.max(np.abs(x))>0 else x
280
+
281
+ probs = np.array(circuit(self.vqc_params, x))
282
+ probs = np.clip(probs, 1e-10, 1.0)
283
+ probs = probs/probs.sum()
284
+ entropy = -np.sum(probs*np.log2(probs))
285
+
286
+ return {
287
+ 'entropy': float(entropy),
288
+ 'confidence': float(1.0-entropy/nq),
289
+ 'risk_score': float(np.std(probs)*2),
290
+ 'quantum_used': True
291
+ }
292
+
293
+ def _classical_uncertainty(self, state):
294
+ x = state.flatten()
295
+ p = np.abs(x)
296
+ p = p/(p.sum()+1e-10)
297
+ p = np.clip(p, 1e-10, 1.0)
298
+ entropy = -np.sum(p*np.log2(p))
299
+ max_ent = np.log2(len(p))
300
+ return {
301
+ 'entropy': float(entropy),
302
+ 'confidence': float(1.0-entropy/max_ent) if max_ent>0 else 0.5,
303
+ 'risk_score': float(np.clip(np.std(x), 0, 1)),
304
+ 'quantum_used': False
305
+ }
306
+
307
+ def evaluate_trajectories(self, trajs, world_state):
308
+ """Score multiple trajectories using quantum analysis."""
309
+ results = []
310
+ for traj in trajs:
311
+ flat = traj.flatten()[:self.cfg.n_qubits*self.cfg.n_qubits]
312
+ if len(flat) < self.cfg.n_qubits:
313
+ flat = np.pad(flat, (0, self.cfg.n_qubits-len(flat)))
314
+
315
+ unc = self.analyze_uncertainty(flat)
316
+
317
+ coherence = 1.0 - unc['entropy']/self.cfg.n_qubits
318
+ score = (0.4*coherence + 0.3*unc['confidence'] +
319
+ 0.2*(1.0-world_state.get('risk_score',0)) +
320
+ 0.1*(1.0-world_state.get('obstacle_density',0)))
321
+
322
+ results.append({
323
+ 'trajectory': traj,
324
+ 'score': float(np.clip(score, 0, 1)),
325
+ 'entropy': unc['entropy'],
326
+ 'confidence': unc['confidence'],
327
+ 'uncertainty': unc
328
+ })
329
+
330
+ return sorted(results, key=lambda x: x['score'], reverse=True)
331
+
332
+ # ==============================================================================
333
+ # CLASSICAL PLANNERS
334
+ # ==============================================================================
335
+
336
+ class AStarPlanner:
337
+ """A* path planning with probabilistic costs."""
338
+
339
+ def plan(self, graph: WorldGraph, start, goal):
340
+ s = graph.find_nearest(start)
341
+ g = graph.find_nearest(goal)
342
+ if s is None or g is None:
343
+ return {'path':[], 'path_positions':[], 'cost':float('inf'), 'success':False, 'explored':0}
344
+
345
+ frontier = [(0.0, s)]
346
+ came_from = {s: None}
347
+ cost_so_far = {s: 0.0}
348
+ explored = 0
349
+ gpos = np.array(graph.positions[g])
350
+
351
+ while frontier:
352
+ _, cur = heapq.heappop(frontier)
353
+ explored += 1
354
+
355
+ if cur == g:
356
+ path = []
357
+ node = g
358
+ while node is not None:
359
+ path.append(node)
360
+ node = came_from[node]
361
+ path.reverse()
362
+ return {
363
+ 'path': path,
364
+ 'path_positions': [graph.positions[n] for n in path],
365
+ 'cost': cost_so_far[g],
366
+ 'success': True,
367
+ 'explored': explored
368
+ }
369
+
370
+ for nbr, w in graph.edges.get(cur, {}).items():
371
+ new_cost = cost_so_far[cur] + w
372
+ if nbr not in cost_so_far or new_cost < cost_so_far[nbr]:
373
+ cost_so_far[nbr] = new_cost
374
+ h = np.linalg.norm(np.array(graph.positions[nbr]) - gpos)
375
+ heapq.heappush(frontier, (new_cost + h, nbr))
376
+ came_from[nbr] = cur
377
+
378
+ return {'path':[], 'path_positions':[], 'cost':float('inf'), 'success':False, 'explored':explored}
379
+
380
+
381
+ class RRTStarPlanner:
382
+ """RRT* sampling-based planner."""
383
+
384
+ def __init__(self, max_iter=500):
385
+ self.max_iter = max_iter
386
+
387
+ def plan(self, graph: WorldGraph, start, goal):
388
+ s = graph.find_nearest(start)
389
+ g = graph.find_nearest(goal)
390
+ if s is None or g is None:
391
+ return {'path':[], 'path_positions':[], 'cost':float('inf'), 'success':False, 'explored':0}
392
+
393
+ tree = {s: {'parent': None, 'cost': 0.0}}
394
+ nodes = graph.nodes.copy()
395
+
396
+ for _ in range(self.max_iter):
397
+ rand = g if random.random() < 0.2 else random.choice(nodes)
398
+
399
+ nearest = min(tree.keys(),
400
+ key=lambda n: np.linalg.norm(np.array(graph.positions[n])-np.array(graph.positions[rand])))
401
+
402
+ if rand not in tree:
403
+ if rand in graph.edges.get(nearest, {}):
404
+ w = graph.edges[nearest][rand]
405
+ tree[rand] = {'parent': nearest, 'cost': tree[nearest]['cost']+w}
406
+ else:
407
+ continue
408
+
409
+ if rand == g:
410
+ path = []
411
+ node = g
412
+ while node is not None:
413
+ path.append(node)
414
+ node = tree[node]['parent']
415
+ path.reverse()
416
+ return {
417
+ 'path': path,
418
+ 'path_positions': [graph.positions[n] for n in path],
419
+ 'cost': tree[g]['cost'],
420
+ 'success': True,
421
+ 'explored': len(tree)
422
+ }
423
+
424
+ if g in tree:
425
+ path = []
426
+ node = g
427
+ while node is not None:
428
+ path.append(node)
429
+ node = tree[node]['parent']
430
+ path.reverse()
431
+ return {
432
+ 'path': path,
433
+ 'path_positions': [graph.positions[n] for n in path],
434
+ 'cost': tree[g]['cost'],
435
+ 'success': True,
436
+ 'explored': len(tree)
437
+ }
438
+
439
+ return {'path':[], 'path_positions':[], 'cost':float('inf'), 'success':False, 'explored':len(tree)}
440
+
441
+ # ==============================================================================
442
+ # HYBRID PLANNER
443
+ # ==============================================================================
444
+
445
+ class HybridPlanner:
446
+ """
447
+ Hybrid classical + quantum planner with entropy-based activation.
448
+
449
+ Simple environments: classical planner only
450
+ Complex uncertain environments: quantum planner activated
451
+ """
452
+
453
+ def __init__(self, config, quantum_core):
454
+ self.cfg = config
455
+ self.qcore = quantum_core
456
+ self.astar = AStarPlanner()
457
+ self.rrt = RRTStarPlanner()
458
+ self.stats = {'classical':0, 'quantum':0, 'total':0}
459
+
460
+ def plan(self, start, goal, world_state=None):
461
+ """Generate plan with automatic quantum activation."""
462
+ self.stats['total'] += 1
463
+
464
+ # Build graph
465
+ graph = self._build_graph(world_state)
466
+
467
+ # Decide if quantum needed
468
+ entropy = graph.get_entropy()
469
+ uncertainty = graph.get_uncertainty()
470
+ obs_density = graph.get_obstacle_density()
471
+
472
+ use_quantum = (self.cfg.use_quantum and
473
+ (entropy > self.cfg.activation_entropy or
474
+ uncertainty > 0.5 or obs_density > 0.4))
475
+
476
+ if use_quantum and self.qcore is not None:
477
+ self.stats['quantum'] += 1
478
+ return self._quantum_plan(graph, start, goal)
479
+ else:
480
+ self.stats['classical'] += 1
481
+ return self._classical_plan(graph, start, goal)
482
+
483
+ def _build_graph(self, world_state):
484
+ if world_state is None:
485
+ g = WorldGraph(self.cfg.grid_resolution)
486
+ g.build_grid(((0,20),(0,20)))
487
+ return g
488
+
489
+ g = WorldGraph(world_state.get('resolution', self.cfg.grid_resolution))
490
+ g.build_grid(
491
+ world_state.get('bounds', ((0,20),(0,20))),
492
+ world_state.get('obstacle_map'),
493
+ world_state.get('uncertainty_map')
494
+ )
495
+ return g
496
+
497
+ def _classical_plan(self, graph, start, goal):
498
+ """Classical planning path."""
499
+ t0 = time.time()
500
+ result = self.astar.plan(graph, start, goal)
501
+ elapsed = time.time() - t0
502
+
503
+ result.update({
504
+ 'quantum_activated': False,
505
+ 'plan_time': elapsed,
506
+ 'start': start, 'goal': goal,
507
+ 'actions': self._to_actions(result.get('path_positions', [])),
508
+ 'goal_reached': result.get('success', False)
509
+ })
510
+ return result
511
+
512
+ def _quantum_plan(self, graph, start, goal):
513
+ """Quantum-enhanced planning path."""
514
+ t0 = time.time()
515
+
516
+ # Generate classical candidates
517
+ candidates = []
518
+ for planner in [self.astar, self.rrt]:
519
+ r = planner.plan(graph, start, goal)
520
+ if r['success']:
521
+ candidates.append(r)
522
+
523
+ if not candidates:
524
+ return self._classical_plan(graph, start, goal)
525
+
526
+ # Quantum evaluate trajectories
527
+ trajs = [np.array(r['path_positions']) for r in candidates if len(r['path_positions'])>0]
528
+ ws = {'entropy': graph.get_entropy(), 'uncertainty': graph.get_uncertainty(),
529
+ 'obstacle_density': graph.get_obstacle_density(),
530
+ 'risk_score': np.mean([m['risk'] for m in graph.metadata.values()])}
531
+
532
+ evaluated = self.qcore.evaluate_trajectories(trajs, ws)
533
+
534
+ if evaluated:
535
+ best = evaluated[0]
536
+ best_traj = best['trajectory']
537
+ path = []
538
+ path_positions = []
539
+ for pos in best_traj:
540
+ path_positions.append(tuple(pos))
541
+ nid = graph.find_nearest(tuple(pos))
542
+ if nid is not None:
543
+ path.append(nid)
544
+
545
+ elapsed = time.time() - t0
546
+ return {
547
+ 'path': path,
548
+ 'path_positions': path_positions,
549
+ 'cost': best['score'],
550
+ 'success': True,
551
+ 'planner': 'hybrid_quantum',
552
+ 'quantum_activated': True,
553
+ 'quantum_score': best['score'],
554
+ 'entropy': best['entropy'],
555
+ 'confidence': best['confidence'],
556
+ 'plan_time': elapsed,
557
+ 'start': start, 'goal': goal,
558
+ 'goal_reached': True,
559
+ 'actions': self._to_actions(path_positions)
560
+ }
561
+
562
+ return self._classical_plan(graph, start, goal)
563
+
564
+ def _to_actions(self, path_positions):
565
+ if len(path_positions) < 2: return []
566
+ return [np.array(path_positions[i+1])-np.array(path_positions[i])
567
+ for i in range(len(path_positions)-1)]
568
+
569
+ # ==============================================================================
570
+ # SIMULATION ENVIRONMENT
571
+ # ==============================================================================
572
+
573
+ class QADSEnv:
574
+ """
575
+ 2D grid navigation environment with:
576
+ - Stochastic obstacles
577
+ - Dynamic obstacles
578
+ - Uncertainty fields
579
+ - Reward shaping
580
+ """
581
+
582
+ def __init__(self, config=None, grid_size=(20,20), obstacle_density=0.2,
583
+ uncertainty_scale=0.1, dynamic_obstacles=True, max_steps=500):
584
+ self.grid_size = grid_size
585
+ self.obstacle_density = obstacle_density
586
+ self.uncertainty_scale = uncertainty_scale
587
+ self.dynamic_obstacles = dynamic_obstacles
588
+ self.max_steps = max_steps
589
+ self.config = config
590
+
591
+ self.position = np.array([0.0, 0.0])
592
+ self.goal = np.array([float(grid_size[0]-1), float(grid_size[1]-1)])
593
+ self.obstacles = None
594
+ self.uncertainty_map = None
595
+ self.step_count = 0
596
+ self.collisions = 0
597
+
598
+ self.reset()
599
+
600
+ def reset(self, seed=None):
601
+ if seed is not None:
602
+ np.random.seed(seed)
603
+
604
+ self.position = np.array([0.0, 0.0])
605
+ self.goal = np.array([float(self.grid_size[0]-1), float(self.grid_size[1]-1)])
606
+ self.step_count = 0
607
+ self.collisions = 0
608
+
609
+ # Generate obstacles
610
+ self.obstacles = np.random.random(self.grid_size) < self.obstacle_density
611
+ self.obstacles[0,0] = False
612
+ self.obstacles[-1,-1] = False
613
+
614
+ # Generate uncertainty map
615
+ self.uncertainty_map = np.random.random(self.grid_size) * self.uncertainty_scale
616
+ self.uncertainty_map += self.obstacles.astype(float) * 0.3
617
+
618
+ return self.get_state(), {}
619
+
620
+ def get_state(self):
621
+ return {
622
+ 'position': self.position.copy(),
623
+ 'goal': self.goal.copy(),
624
+ 'obstacles': self.obstacles.copy(),
625
+ 'uncertainty_map': self.uncertainty_map.copy()
626
+ }
627
+
628
+ def get_world_state(self):
629
+ return {
630
+ 'bounds': ((0, self.grid_size[0]), (0, self.grid_size[1])),
631
+ 'obstacle_map': self.obstacles.astype(float),
632
+ 'uncertainty_map': self.uncertainty_map,
633
+ 'resolution': 1.0,
634
+ 'obstacles': [{'position': (i,j), 'probability': float(self.obstacles[i,j]),
635
+ 'risk': float(self.uncertainty_map[i,j])}
636
+ for i in range(self.grid_size[0]) for j in range(self.grid_size[1])
637
+ if self.obstacles[i,j]]
638
+ }
639
+
640
+ def step(self, action):
641
+ self.step_count += 1
642
+
643
+ # Apply action
644
+ new_pos = self.position + np.array(action)
645
+ new_pos = np.clip(new_pos, [0,0], [self.grid_size[0]-1, self.grid_size[1]-1])
646
+
647
+ # Check collision
648
+ ix, iy = int(new_pos[0]), int(new_pos[1])
649
+ ix = np.clip(ix, 0, self.grid_size[0]-1)
650
+ iy = np.clip(iy, 0, self.grid_size[1]-1)
651
+
652
+ collided = self.obstacles[ix, iy]
653
+ if collided:
654
+ self.collisions += 1
655
+ new_pos = self.position.copy()
656
+
657
+ self.position = new_pos
658
+
659
+ # Distance reward (closer is better)
660
+ old_dist = np.linalg.norm(self.position - self.goal)
661
+ new_dist = np.linalg.norm(new_pos - self.goal)
662
+ reward = old_dist - new_dist
663
+
664
+ # Uncertainty penalty
665
+ reward -= self.uncertainty_map[ix, iy] * 0.5
666
+
667
+ # Collision penalty
668
+ if collided:
669
+ reward -= 1.0
670
+
671
+ # Goal reached bonus
672
+ goal_reached = np.linalg.norm(new_pos - self.goal) < 1.0
673
+ if goal_reached:
674
+ reward += 10.0
675
+
676
+ # Dynamic obstacles
677
+ if self.dynamic_obstacles and self.step_count % 20 == 0:
678
+ self._update_obstacles()
679
+
680
+ terminated = goal_reached or self.collisions >= 3
681
+ truncated = self.step_count >= self.max_steps
682
+
683
+ info = {
684
+ 'collisions': self.collisions,
685
+ 'distance_to_goal': new_dist,
686
+ 'goal_reached': goal_reached,
687
+ 'uncertainty_at_pos': float(self.uncertainty_map[ix, iy])
688
+ }
689
+
690
+ return self.get_state(), reward, terminated, truncated, info
691
+
692
+ def _update_obstacles(self):
693
+ for _ in range(3):
694
+ i, j = random.randint(0, self.grid_size[0]-1), random.randint(0, self.grid_size[1]-1)
695
+ if (i,j) != (0,0) and (i,j) != (self.grid_size[0]-1, self.grid_size[1]-1):
696
+ self.obstacles[i,j] = not self.obstacles[i,j]
697
+
698
+ # ==============================================================================
699
+ # RL AGENT WITH QUANTUM REWARD SHAPING
700
+ # ==============================================================================
701
+
702
+ class QuantumShapedAgent:
703
+ """Simple RL agent with quantum-based reward shaping."""
704
+
705
+ def __init__(self, quantum_core, config=None, grid_size=(20,20)):
706
+ self.qcore = quantum_core
707
+ self.cfg = config
708
+ self.grid_size = grid_size
709
+ self.q_weight = config.quantum_reward_weight if config else 0.3
710
+ self.w = np.random.randn(10, 2) * 0.01
711
+ self.bonus_history = []
712
+
713
+ def select_action(self, obs, deterministic=False):
714
+ state = self._encode(obs)
715
+ mean = state @ self.w
716
+ if not deterministic:
717
+ mean += np.random.randn(2) * 0.1
718
+ return np.clip(mean, -1, 1)
719
+
720
+ def compute_reward(self, state, action, next_state, base_reward):
721
+ if self.qcore is None:
722
+ return base_reward
723
+
724
+ diff = self._encode(next_state) - self._encode(state)
725
+ unc = self.qcore.analyze_uncertainty(diff)
726
+ confidence = unc.get('confidence', 0.5)
727
+ entropy = unc.get('entropy', 0.0)
728
+ risk = unc.get('risk_score', 0.0)
729
+
730
+ bonus = self.q_weight * (confidence * 2.0 - 1.0) - 0.1 * entropy
731
+ if risk > 0.5:
732
+ bonus -= 0.5
733
+
734
+ self.bonus_history.append(bonus)
735
+ return base_reward + bonus
736
+
737
+ def _encode(self, obs):
738
+ pos = obs['position']
739
+ goal = obs['goal']
740
+ s = np.zeros(10)
741
+ s[0:2] = pos / max(self.grid_size)
742
+ s[2:4] = goal / max(self.grid_size)
743
+ s[4:6] = (goal - pos) / max(self.grid_size)
744
+ ix, iy = int(pos[0]), int(pos[1])
745
+ for i, (dx,dy) in enumerate([(1,0),(-1,0),(0,1),(0,-1)]):
746
+ nx, ny = ix+dx, iy+dy
747
+ if 0 <= nx < self.grid_size[0] and 0 <= ny < self.grid_size[1]:
748
+ s[6+i] = float(obs['obstacles'][nx,ny])
749
+ s[8] = obs['uncertainty_map'][ix,iy] if 0 <= ix < self.grid_size[0] and 0 <= iy < self.grid_size[1] else 0
750
+ s[9] = np.linalg.norm(pos-goal) / max(self.grid_size)
751
+ return s
752
+
753
+ # ==============================================================================
754
+ # PERCEPTION LAYER
755
+ # ==============================================================================
756
+
757
+ class PerceptionLayer:
758
+ """Sensor fusion and world state estimation."""
759
+
760
+ def __init__(self, sensors=None):
761
+ self.sensors = sensors or ['lidar', 'camera', 'imu']
762
+ self.ekf_state = np.zeros(6)
763
+ self.ekf_cov = np.eye(6)
764
+ self.detections = []
765
+
766
+ def process(self, raw_sensors):
767
+ """Process sensor readings into structured world state."""
768
+ fused = {
769
+ 'position': raw_sensors.get('gps', [0.0, 0.0]),
770
+ 'velocity': raw_sensors.get('imu_velocity', [0.0, 0.0]),
771
+ 'obstacles': raw_sensors.get('lidar_points', []),
772
+ 'timestamp': time.time()
773
+ }
774
+ return fused
775
+
776
+ def estimate_state(self, measurements):
777
+ """Extended Kalman Filter state update."""
778
+ H = np.eye(6)
779
+ R = np.eye(6) * 0.1
780
+ z = np.array(measurements).flatten()[:6]
781
+ if len(z) < 6:
782
+ z = np.pad(z, (0, 6-len(z)))
783
+
784
+ y = z - H @ self.ekf_state
785
+ S = H @ self.ekf_cov @ H.T + R
786
+ K = self.ekf_cov @ H.T @ np.linalg.inv(S)
787
+ self.ekf_state += K @ y
788
+ self.ekf_cov = (np.eye(6) - K @ H) @ self.ekf_cov
789
+
790
+ return self.ekf_state.copy(), self.ekf_cov.copy()
791
+
792
+ # ==============================================================================
793
+ # CONTROL LAYER
794
+ # ==============================================================================
795
+
796
+ class ControlLayer:
797
+ """Convert planned trajectories to motor commands."""
798
+
799
+ def __init__(self, robot_type='drone'):
800
+ self.robot_type = robot_type
801
+ self.max_speed = 2.0
802
+ self.max_accel = 1.0
803
+
804
+ def trajectory_to_commands(self, path_positions, dt=0.1):
805
+ """Convert path to velocity commands."""
806
+ commands = []
807
+ for i in range(len(path_positions)-1):
808
+ dx = np.array(path_positions[i+1]) - np.array(path_positions[i])
809
+ velocity = dx / dt
810
+ velocity = np.clip(velocity, -self.max_speed, self.max_speed)
811
+ commands.append({
812
+ 'velocity': velocity.tolist(),
813
+ 'duration': dt,
814
+ 'acceleration': np.clip(velocity/dt, -self.max_accel, self.max_accel).tolist()
815
+ })
816
+ return commands
817
+
818
+ def emergency_stop(self):
819
+ return {'velocity': [0.0, 0.0], 'duration': 0.0, 'emergency': True}
820
+
821
+ # ==============================================================================
822
+ # K2 THINK v2 API LAYER
823
+ # ==============================================================================
824
+
825
+ class K2ThinkAPI:
826
+ """
827
+ High-level reasoning engine interface.
828
+ Mission reasoning, contextual memory, multi-agent coordination, explainability.
829
+ """
830
+
831
+ def __init__(self, api_key=None, endpoint=None):
832
+ self.api_key = api_key
833
+ self.endpoint = endpoint
834
+ self.memory = deque(maxlen=100)
835
+ self.mission_history = []
836
+
837
+ def reason(self, mission_state, quantum_scores=None, planner_state=None):
838
+ """Generate high-level strategic reasoning."""
839
+ context = {
840
+ 'mission_state': mission_state,
841
+ 'quantum_scores': quantum_scores or {},
842
+ 'planner_state': planner_state or {},
843
+ 'timestamp': time.time()
844
+ }
845
+
846
+ # Simple rule-based reasoning (replace with actual API call)
847
+ entropy = mission_state.get('entropy', 0)
848
+ uncertainty = mission_state.get('uncertainty', 0)
849
+
850
+ recommendations = []
851
+ if entropy > 0.6:
852
+ recommendations.append("High environment entropy detected - consider quantum-enhanced planning")
853
+ if uncertainty > 0.5:
854
+ recommendations.append("High uncertainty - reduce speed and increase sensor sampling")
855
+ if planner_state.get('quantum_activated'):
856
+ recommendations.append("Quantum planner active - monitoring trajectory quality")
857
+
858
+ decision = {
859
+ 'recommendations': recommendations,
860
+ 'confidence': 1.0 - uncertainty,
861
+ 'strategy': 'cautious' if uncertainty > 0.5 else 'aggressive',
862
+ 'context': context
863
+ }
864
+
865
+ self.memory.append(decision)
866
+ return decision
867
+
868
+ def explain_decision(self, plan_result):
869
+ """Generate human-readable explanation."""
870
+ if plan_result.get('quantum_activated'):
871
+ return (f"Route selected with quantum optimization. "
872
+ f"Confidence: {plan_result.get('confidence', 0):.2f}. "
873
+ f"Entropy: {plan_result.get('entropy', 0):.2f}")
874
+ else:
875
+ return f"Classical A* planning used. Path cost: {plan_result.get('cost', 0):.2f}"
876
+
877
+ # ==============================================================================
878
+ # MAIN QADS SYSTEM
879
+ # ==============================================================================
880
+
881
+ class QADSSystem:
882
+ """
883
+ Complete Quantum Autonomous Decision System.
884
+ Integrates all layers into a unified framework.
885
+ """
886
+
887
+ def __init__(self, config=None):
888
+ self.cfg = config or QADSConfig()
889
+ self.qcore = QuantumCore(self.cfg)
890
+ self.planner = HybridPlanner(self.cfg, self.qcore)
891
+ self.agent = QuantumShapedAgent(self.qcore, self.cfg)
892
+ self.perception = PerceptionLayer()
893
+ self.control = ControlLayer()
894
+ self.k2 = K2ThinkAPI()
895
+ self.env = None
896
+ self.mission_log = []
897
+
898
+ def init_env(self, **kwargs):
899
+ self.env = QADSEnv(self.cfg, **kwargs)
900
+ return self.env
901
+
902
+ def run_mission(self, start=(0,0), goal=None, max_steps=500, use_rl=False):
903
+ if self.env is None:
904
+ self.init_env()
905
+
906
+ if goal is None:
907
+ goal = (self.env.grid_size[0]-1, self.env.grid_size[1]-1)
908
+
909
+ state, _ = self.env.reset()
910
+
911
+ # Perception
912
+ perceived = self.perception.process({'gps': state['position']})
913
+
914
+ # Plan
915
+ ws = self.env.get_world_state()
916
+ plan = self.planner.plan(start, goal, ws)
917
+
918
+ # K2 reasoning
919
+ k2_decision = self.k2.reason(
920
+ mission_state={'entropy': ws.get('entropy', 0), 'uncertainty': ws.get('uncertainty', 0)},
921
+ quantum_scores={'quantum_score': plan.get('quantum_score', 0)},
922
+ planner_state={'quantum_activated': plan.get('quantum_activated', False)}
923
+ )
924
+
925
+ # Execute
926
+ trajectory = []
927
+ rewards = []
928
+
929
+ if plan['success'] and not use_rl:
930
+ # Follow planned path
931
+ commands = self.control.trajectory_to_commands(plan.get('path_positions', []))
932
+ for action in plan.get('actions', []):
933
+ next_state, reward, done, trunc, info = self.env.step(action)
934
+ trajectory.append({
935
+ 'position': next_state['position'].copy(),
936
+ 'action': action,
937
+ 'reward': reward,
938
+ 'info': info
939
+ })
940
+ rewards.append(reward)
941
+ if done or trunc:
942
+ break
943
+ else:
944
+ # RL fallback
945
+ for step in range(max_steps):
946
+ action = self.agent.select_action(state)
947
+ next_state, reward, done, trunc, info = self.env.step(action)
948
+ shaped_reward = self.agent.compute_reward(state, action, next_state, reward)
949
+ trajectory.append({
950
+ 'position': next_state['position'].copy(),
951
+ 'action': action,
952
+ 'reward': shaped_reward,
953
+ 'info': info
954
+ })
955
+ rewards.append(shaped_reward)
956
+ state = next_state
957
+ if done or trunc:
958
+ break
959
+
960
+ final_dist = np.linalg.norm(state['position'] - state['goal'])
961
+ success = final_dist < 1.0
962
+
963
+ result = {
964
+ 'success': success,
965
+ 'plan': plan,
966
+ 'trajectory': trajectory,
967
+ 'total_reward': sum(rewards),
968
+ 'steps': len(trajectory),
969
+ 'final_distance': final_dist,
970
+ 'collisions': self.env.collisions,
971
+ 'quantum_activated': plan.get('quantum_activated', False),
972
+ 'k2_recommendations': k2_decision['recommendations'],
973
+ 'explanation': self.k2.explain_decision(plan)
974
+ }
975
+ self.mission_log.append(result)
976
+ return result
977
+
978
+ def benchmark(self, n_trials=10, obstacle_range=[0.1, 0.3, 0.5],
979
+ uncertainty_range=[0.05, 0.15, 0.3]):
980
+ """Comprehensive classical vs quantum benchmark."""
981
+ results = []
982
+
983
+ for obs_d in obstacle_range:
984
+ for unc_s in uncertainty_range:
985
+ classical_results = []
986
+ quantum_results = []
987
+
988
+ for trial in range(n_trials):
989
+ # Classical only (disable quantum)
990
+ self.cfg.activation_entropy = 10.0
991
+ self.cfg.use_quantum = False
992
+ self.env = QADSEnv(grid_size=(15,15), obstacle_density=obs_d,
993
+ uncertainty_scale=unc_s, dynamic_obstacles=True)
994
+ result_c = self.run_mission()
995
+ classical_results.append(result_c)
996
+
997
+ # Enable quantum
998
+ self.cfg.activation_entropy = 0.6
999
+ self.cfg.use_quantum = True
1000
+ self.env = QADSEnv(grid_size=(15,15), obstacle_density=obs_d,
1001
+ uncertainty_scale=unc_s, dynamic_obstacles=True)
1002
+ result_q = self.run_mission()
1003
+ quantum_results.append(result_q)
1004
+
1005
+ results.append({
1006
+ 'obstacle_density': obs_d,
1007
+ 'uncertainty_scale': unc_s,
1008
+ 'classical_success_rate': np.mean([r['success'] for r in classical_results]),
1009
+ 'quantum_success_rate': np.mean([r['success'] for r in quantum_results]),
1010
+ 'classical_avg_steps': np.mean([r['steps'] for r in classical_results]),
1011
+ 'quantum_avg_steps': np.mean([r['steps'] for r in quantum_results]),
1012
+ 'classical_avg_reward': np.mean([r['total_reward'] for r in classical_results]),
1013
+ 'quantum_avg_reward': np.mean([r['total_reward'] for r in quantum_results]),
1014
+ 'classical_avg_collisions': np.mean([r['collisions'] for r in classical_results]),
1015
+ 'quantum_avg_collisions': np.mean([r['collisions'] for r in quantum_results]),
1016
+ 'quantum_activation_rate': np.mean([r['quantum_activated'] for r in quantum_results]),
1017
+ 'improvement': (
1018
+ np.mean([r['success'] for r in quantum_results]) -
1019
+ np.mean([r['success'] for r in classical_results])
1020
+ )
1021
+ })
1022
+
1023
+ return results
1024
+
1025
+ def get_summary(self):
1026
+ if not self.mission_log:
1027
+ return {}
1028
+ successes = sum(1 for m in self.mission_log if m['success'])
1029
+ return {
1030
+ 'total_missions': len(self.mission_log),
1031
+ 'success_rate': successes/len(self.mission_log),
1032
+ 'avg_steps': np.mean([m['steps'] for m in self.mission_log]),
1033
+ 'avg_reward': np.mean([m['total_reward'] for m in self.mission_log]),
1034
+ 'avg_collisions': np.mean([m['collisions'] for m in self.mission_log]),
1035
+ 'quantum_activations': sum(1 for m in self.mission_log if m.get('quantum_activated', False)),
1036
+ 'planner_stats': self.planner.stats,
1037
+ 'quantum_metrics': self.qcore.metrics
1038
+ }
1039
+
1040
+ # ==============================================================================
1041
+ # DEMO
1042
+ # ==============================================================================
1043
+
1044
+ if __name__ == "__main__":
1045
+ print("="*70)
1046
+ print("QUANTUM AUTONOMOUS DECISION SYSTEM (QADS)")
1047
+ print("Hybrid Quantum-Classical Autonomous Intelligence")
1048
+ print("="*70)
1049
+
1050
+ config = QADSConfig(n_qubits=8, n_layers=3, activation_entropy=0.6, use_quantum=True)
1051
+ qads = QADSSystem(config)
1052
+
1053
+ # Single mission demo
1054
+ print("\n[1] Running single mission demo...")
1055
+ result = qads.run_mission()
1056
+ print(f" ✓ Success: {result['success']}")
1057
+ print(f" ✓ Steps: {result['steps']}")
1058
+ print(f" ✓ Total Reward: {result['total_reward']:.2f}")
1059
+ print(f" ✓ Collisions: {result['collisions']}")
1060
+ print(f" ✓ Quantum Activated: {result['quantum_activated']}")
1061
+ print(f" ✓ Final Distance to Goal: {result['final_distance']:.2f}")
1062
+ print(f" ✓ K2 Reasoning: {result['k2_recommendations']}")
1063
+ print(f" ✓ Explanation: {result['explanation']}")
1064
+
1065
+ # Benchmark
1066
+ print("\n[2] Running benchmark (comparing Classical vs Quantum)...")
1067
+ bench = qads.benchmark(n_trials=5, obstacle_range=[0.1, 0.3], uncertainty_range=[0.05, 0.2])
1068
+
1069
+ print("\n Benchmark Results:")
1070
+ print(" " + "-"*60)
1071
+ for r in bench:
1072
+ print(f" Obs={r['obstacle_density']:.1f} Unc={r['uncertainty_scale']:.2f} | "
1073
+ f"Classical SR={r['classical_success_rate']:.2f} "
1074
+ f"Quantum SR={r['quantum_success_rate']:.2f} "
1075
+ f"Improvement={r['improvement']:+.2f} "
1076
+ f"Q-activ={r['quantum_activation_rate']:.2f}")
1077
+
1078
+ # Summary
1079
+ print("\n[3] System Summary:")
1080
+ summary = qads.get_summary()
1081
+ for k, v in summary.items():
1082
+ print(f" {k}: {v}")
1083
+
1084
+ print("\n" + "="*70)
1085
+ print("QADS demo complete! All modules operational.")
1086
+ print("="*70)