quantumflow-sdk 0.2.1__py3-none-any.whl → 0.3.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
api/main.py CHANGED
@@ -35,6 +35,7 @@ from api.models import (
35
35
  from api.auth import get_current_user, get_optional_user, get_db_session
36
36
  from api.routes.auth_routes import router as auth_router
37
37
  from api.routes.teleport_routes import router as teleport_router
38
+ from api.routes.algorithm_routes import router as algorithm_router
38
39
 
39
40
  # Import billing routes (optional - only if Stripe is configured)
40
41
  try:
@@ -97,7 +98,7 @@ async def lifespan(app: FastAPI):
97
98
  app = FastAPI(
98
99
  title="QuantumFlow API",
99
100
  description="Quantum-optimized AI agent workflow platform",
100
- version="0.1.0",
101
+ version="0.3.0",
101
102
  lifespan=lifespan,
102
103
  )
103
104
 
@@ -116,6 +117,9 @@ app.include_router(auth_router)
116
117
  # Include teleportation & secure messaging routes
117
118
  app.include_router(teleport_router)
118
119
 
120
+ # Include algorithm routes (QNN, Grover, QAOA, VQE, QSVM, QKD, QRNG, QFT)
121
+ app.include_router(algorithm_router)
122
+
119
123
  # Include billing routes if available
120
124
  if BILLING_ENABLED and billing_router:
121
125
  app.include_router(billing_router)
@@ -128,7 +132,7 @@ async def health_check():
128
132
  """Check API health status."""
129
133
  return HealthResponse(
130
134
  status="healthy",
131
- version="0.1.0",
135
+ version="0.3.0",
132
136
  quantum_ready=_compressor is not None,
133
137
  )
134
138
 
@@ -0,0 +1,895 @@
1
+ """
2
+ Algorithm Routes for QuantumFlow API.
3
+
4
+ Provides endpoints for core quantum algorithms:
5
+ - QNN (Quantum Neural Network) - Forward pass, training, inference
6
+ - Grover's Search - Quantum search with quadratic speedup
7
+ - QAOA - Quantum optimization
8
+ - VQE - Variational eigensolver
9
+
10
+ Authentication:
11
+ - Free tier (no key): QNN forward, Grover, QRNG, QFT, QKD
12
+ - Requires API key: QNN train, QAOA, VQE, QSVM (heavy compute)
13
+ """
14
+
15
+ import time
16
+ from typing import Optional, List
17
+ from fastapi import APIRouter, HTTPException, Depends
18
+ from pydantic import BaseModel, Field
19
+ import numpy as np
20
+
21
+ from api.auth import get_optional_user, get_current_user
22
+ from db.models import User
23
+
24
+ # Import quantum algorithms
25
+ from quantumflow.algorithms.machine_learning import QNN, VQE, QSVM
26
+ from quantumflow.algorithms.optimization import GroverSearch, QAOA
27
+ from quantumflow.backends.base_backend import BackendType
28
+
29
+
30
+ router = APIRouter(prefix="/v1/algorithms", tags=["Algorithms"])
31
+
32
+
33
+ # ============================================================
34
+ # QNN (Quantum Neural Network) Models & Endpoints
35
+ # ============================================================
36
+
37
+ class QNNForwardRequest(BaseModel):
38
+ """Request for QNN forward pass."""
39
+ input_data: List[float] = Field(..., description="Input features (normalized 0-1)")
40
+ weights: Optional[List[float]] = Field(None, description="Model weights (random if not provided)")
41
+ n_qubits: int = Field(default=4, ge=2, le=16, description="Number of qubits")
42
+ n_layers: int = Field(default=2, ge=1, le=10, description="Number of variational layers")
43
+ shots: int = Field(default=1024, ge=100, le=10000)
44
+ backend: str = Field(default="simulator")
45
+
46
+
47
+ class QNNForwardResponse(BaseModel):
48
+ """Response from QNN forward pass."""
49
+ output: float
50
+ output_probabilities: List[float]
51
+ n_qubits: int
52
+ n_layers: int
53
+ n_parameters: int
54
+ weights_used: List[float]
55
+ execution_time_ms: float
56
+ circuit_depth: int
57
+
58
+
59
+ class QNNTrainRequest(BaseModel):
60
+ """Request for QNN training."""
61
+ X_train: List[List[float]] = Field(..., description="Training features")
62
+ y_train: List[int] = Field(..., description="Training labels (0 or 1)")
63
+ n_qubits: int = Field(default=4, ge=2, le=16)
64
+ n_layers: int = Field(default=2, ge=1, le=10)
65
+ epochs: int = Field(default=50, ge=1, le=500)
66
+ learning_rate: float = Field(default=0.1, ge=0.001, le=1.0)
67
+ batch_size: int = Field(default=8, ge=1, le=64)
68
+ shots: int = Field(default=1024)
69
+ backend: str = Field(default="simulator")
70
+
71
+
72
+ class QNNTrainResponse(BaseModel):
73
+ """Response from QNN training."""
74
+ final_weights: List[float]
75
+ loss_history: List[float]
76
+ final_accuracy: float
77
+ n_epochs: int
78
+ n_parameters: int
79
+ execution_time_ms: float
80
+
81
+
82
+ class QNNPredictRequest(BaseModel):
83
+ """Request for QNN prediction."""
84
+ X: List[List[float]] = Field(..., description="Input features to predict")
85
+ weights: List[float] = Field(..., description="Trained model weights")
86
+ n_qubits: int = Field(default=4, ge=2, le=16)
87
+ n_layers: int = Field(default=2, ge=1, le=10)
88
+ return_probabilities: bool = Field(default=False)
89
+ shots: int = Field(default=1024)
90
+
91
+
92
+ class QNNPredictResponse(BaseModel):
93
+ """Response from QNN prediction."""
94
+ predictions: List[int]
95
+ probabilities: Optional[List[float]] = None
96
+ execution_time_ms: float
97
+
98
+
99
+ @router.post("/qnn/forward", response_model=QNNForwardResponse)
100
+ async def qnn_forward(
101
+ request: QNNForwardRequest,
102
+ user: Optional[User] = Depends(get_optional_user),
103
+ ):
104
+ """
105
+ Execute QNN forward pass.
106
+
107
+ Runs input data through a parameterized quantum circuit to produce output.
108
+ This is the inference step of a quantum neural network.
109
+ """
110
+ start_time = time.perf_counter()
111
+
112
+ try:
113
+ # Initialize QNN
114
+ qnn = QNN(
115
+ n_qubits=request.n_qubits,
116
+ n_layers=request.n_layers,
117
+ backend=request.backend,
118
+ shots=request.shots,
119
+ )
120
+
121
+ # Use provided weights or random initialization
122
+ if request.weights:
123
+ if len(request.weights) != qnn.n_params:
124
+ raise ValueError(
125
+ f"Expected {qnn.n_params} weights, got {len(request.weights)}"
126
+ )
127
+ qnn.weights = np.array(request.weights)
128
+
129
+ # Prepare input
130
+ x = np.array(request.input_data)
131
+ if len(x) > request.n_qubits:
132
+ x = x[:request.n_qubits] # Truncate to n_qubits
133
+ elif len(x) < request.n_qubits:
134
+ x = np.pad(x, (0, request.n_qubits - len(x))) # Pad with zeros
135
+
136
+ # Forward pass
137
+ output_prob = qnn._forward(x)
138
+
139
+ # Get all probabilities by running predict_proba
140
+ all_probs = [output_prob, 1.0 - output_prob]
141
+
142
+ execution_time = (time.perf_counter() - start_time) * 1000
143
+
144
+ return QNNForwardResponse(
145
+ output=output_prob,
146
+ output_probabilities=all_probs,
147
+ n_qubits=request.n_qubits,
148
+ n_layers=request.n_layers,
149
+ n_parameters=qnn.n_params,
150
+ weights_used=qnn.weights.tolist(),
151
+ execution_time_ms=execution_time,
152
+ circuit_depth=request.n_layers * (request.n_qubits + 1) + 1, # Approximate
153
+ )
154
+
155
+ except Exception as e:
156
+ raise HTTPException(status_code=400, detail=str(e))
157
+
158
+
159
+ @router.post("/qnn/train", response_model=QNNTrainResponse)
160
+ async def qnn_train(
161
+ request: QNNTrainRequest,
162
+ user: User = Depends(get_current_user), # Requires API key - heavy compute
163
+ ):
164
+ """
165
+ Train a Quantum Neural Network.
166
+
167
+ Uses parameter-shift rule for gradient computation and
168
+ mini-batch gradient descent for optimization.
169
+ """
170
+ start_time = time.perf_counter()
171
+
172
+ try:
173
+ # Initialize QNN
174
+ qnn = QNN(
175
+ n_qubits=request.n_qubits,
176
+ n_layers=request.n_layers,
177
+ backend=request.backend,
178
+ learning_rate=request.learning_rate,
179
+ shots=request.shots,
180
+ )
181
+
182
+ # Prepare data
183
+ X = np.array(request.X_train)
184
+ y = np.array(request.y_train)
185
+
186
+ # Train
187
+ result = qnn.fit(
188
+ X=X,
189
+ y=y,
190
+ epochs=request.epochs,
191
+ batch_size=request.batch_size,
192
+ )
193
+
194
+ execution_time = (time.perf_counter() - start_time) * 1000
195
+
196
+ return QNNTrainResponse(
197
+ final_weights=result.final_weights.tolist(),
198
+ loss_history=result.loss_history,
199
+ final_accuracy=result.accuracy,
200
+ n_epochs=result.n_epochs,
201
+ n_parameters=qnn.n_params,
202
+ execution_time_ms=execution_time,
203
+ )
204
+
205
+ except Exception as e:
206
+ raise HTTPException(status_code=400, detail=str(e))
207
+
208
+
209
+ @router.post("/qnn/predict", response_model=QNNPredictResponse)
210
+ async def qnn_predict(
211
+ request: QNNPredictRequest,
212
+ user: Optional[User] = Depends(get_optional_user),
213
+ ):
214
+ """
215
+ Make predictions using a trained QNN.
216
+ """
217
+ start_time = time.perf_counter()
218
+
219
+ try:
220
+ # Initialize QNN with trained weights
221
+ qnn = QNN(
222
+ n_qubits=request.n_qubits,
223
+ n_layers=request.n_layers,
224
+ shots=request.shots,
225
+ )
226
+ qnn.weights = np.array(request.weights)
227
+
228
+ # Prepare data
229
+ X = np.array(request.X)
230
+
231
+ # Predict
232
+ predictions = qnn.predict(X)
233
+
234
+ probabilities = None
235
+ if request.return_probabilities:
236
+ probabilities = qnn.predict_proba(X).tolist()
237
+
238
+ execution_time = (time.perf_counter() - start_time) * 1000
239
+
240
+ return QNNPredictResponse(
241
+ predictions=predictions.tolist(),
242
+ probabilities=probabilities,
243
+ execution_time_ms=execution_time,
244
+ )
245
+
246
+ except Exception as e:
247
+ raise HTTPException(status_code=400, detail=str(e))
248
+
249
+
250
+ # ============================================================
251
+ # Grover's Search Models & Endpoints
252
+ # ============================================================
253
+
254
+ class GroverSearchRequest(BaseModel):
255
+ """Request for Grover's search."""
256
+ n_qubits: int = Field(..., ge=2, le=20, description="Search space = 2^n_qubits")
257
+ marked_states: List[int] = Field(..., min_length=1, description="States to search for")
258
+ iterations: Optional[int] = Field(None, description="Grover iterations (optimal if not specified)")
259
+ shots: int = Field(default=1024, ge=100, le=10000)
260
+ backend: str = Field(default="simulator")
261
+
262
+
263
+ class GroverSearchResponse(BaseModel):
264
+ """Response from Grover's search."""
265
+ found_state: str
266
+ found_state_decimal: int
267
+ probability: float
268
+ iterations_used: int
269
+ optimal_iterations: int
270
+ search_space_size: int
271
+ speedup_factor: str
272
+ execution_time_ms: float
273
+
274
+
275
+ @router.post("/grover/search", response_model=GroverSearchResponse)
276
+ async def grover_search(
277
+ request: GroverSearchRequest,
278
+ user: Optional[User] = Depends(get_optional_user),
279
+ ):
280
+ """
281
+ Execute Grover's quantum search algorithm.
282
+
283
+ Finds marked states in an unstructured database with O(sqrt(N))
284
+ complexity instead of classical O(N).
285
+ """
286
+ import math
287
+ start_time = time.perf_counter()
288
+
289
+ try:
290
+ # Validate marked states
291
+ N = 2 ** request.n_qubits
292
+ for state in request.marked_states:
293
+ if state < 0 or state >= N:
294
+ raise ValueError(f"Marked state {state} out of range [0, {N-1}]")
295
+
296
+ # Initialize Grover
297
+ grover = GroverSearch(backend=request.backend)
298
+
299
+ # Calculate optimal iterations
300
+ M = len(request.marked_states)
301
+ if M > 0 and M < N:
302
+ theta = math.asin(math.sqrt(M / N))
303
+ optimal_iterations = max(1, int(round(math.pi / (4 * theta) - 0.5)))
304
+ else:
305
+ optimal_iterations = 1
306
+
307
+ # Execute search
308
+ result = grover.search(
309
+ n_qubits=request.n_qubits,
310
+ marked_states=request.marked_states,
311
+ iterations=request.iterations,
312
+ shots=request.shots,
313
+ )
314
+
315
+ execution_time = (time.perf_counter() - start_time) * 1000
316
+
317
+ # Calculate speedup
318
+ classical_ops = N / 2 # Average case classical
319
+ quantum_ops = result.iterations * math.sqrt(N)
320
+ speedup = classical_ops / quantum_ops if quantum_ops > 0 else 1
321
+
322
+ return GroverSearchResponse(
323
+ found_state=result.found_state,
324
+ found_state_decimal=int(result.found_state, 2),
325
+ probability=result.probability,
326
+ iterations_used=result.iterations,
327
+ optimal_iterations=optimal_iterations,
328
+ search_space_size=N,
329
+ speedup_factor=f"{speedup:.1f}x",
330
+ execution_time_ms=execution_time,
331
+ )
332
+
333
+ except Exception as e:
334
+ raise HTTPException(status_code=400, detail=str(e))
335
+
336
+
337
+ # ============================================================
338
+ # QAOA Models & Endpoints
339
+ # ============================================================
340
+
341
+ class QAOARequest(BaseModel):
342
+ """Request for QAOA optimization."""
343
+ problem_type: str = Field(default="maxcut", description="Problem type: maxcut, tsp, portfolio")
344
+ n_nodes: int = Field(..., ge=2, le=20, description="Number of nodes/variables")
345
+ edges: Optional[List[List[int]]] = Field(None, description="Graph edges for MaxCut")
346
+ depth: int = Field(default=2, ge=1, le=10, description="QAOA circuit depth (p)")
347
+ shots: int = Field(default=1024)
348
+ backend: str = Field(default="simulator")
349
+
350
+
351
+ class QAOAResponse(BaseModel):
352
+ """Response from QAOA optimization."""
353
+ best_solution: List[int]
354
+ best_cost: float
355
+ approximation_ratio: float
356
+ optimal_gamma: List[float]
357
+ optimal_beta: List[float]
358
+ iterations: int
359
+ execution_time_ms: float
360
+
361
+
362
+ @router.post("/qaoa/optimize", response_model=QAOAResponse)
363
+ async def qaoa_optimize(
364
+ request: QAOARequest,
365
+ user: User = Depends(get_current_user), # Requires API key - heavy compute
366
+ ):
367
+ """
368
+ Run QAOA for combinatorial optimization.
369
+
370
+ Solves NP-hard problems like MaxCut, TSP, portfolio optimization
371
+ using variational quantum circuits.
372
+ """
373
+ start_time = time.perf_counter()
374
+
375
+ try:
376
+ import random
377
+
378
+ # Generate random graph if edges not provided
379
+ if request.edges is None:
380
+ edges = []
381
+ for i in range(request.n_nodes):
382
+ for j in range(i + 1, request.n_nodes):
383
+ if random.random() > 0.5:
384
+ edges.append((i, j))
385
+ if not edges:
386
+ edges = [(0, 1)] # At least one edge
387
+ else:
388
+ edges = [tuple(e) for e in request.edges]
389
+
390
+ # Initialize QAOA
391
+ qaoa = QAOA(backend=request.backend, p=request.depth, shots=request.shots)
392
+
393
+ # Run MaxCut optimization
394
+ result = qaoa.maxcut(
395
+ edges=edges,
396
+ n_nodes=request.n_nodes,
397
+ max_iterations=50,
398
+ )
399
+
400
+ execution_time = (time.perf_counter() - start_time) * 1000
401
+
402
+ # Extract gamma and beta from optimal params
403
+ optimal_gamma = result.optimal_params[::2].tolist()
404
+ optimal_beta = result.optimal_params[1::2].tolist()
405
+
406
+ # Calculate approximation ratio (simplified)
407
+ max_possible_cut = len(edges)
408
+ approx_ratio = result.best_cost / max_possible_cut if max_possible_cut > 0 else 0
409
+
410
+ return QAOAResponse(
411
+ best_solution=[int(b) for b in result.best_solution],
412
+ best_cost=result.best_cost,
413
+ approximation_ratio=approx_ratio,
414
+ optimal_gamma=optimal_gamma,
415
+ optimal_beta=optimal_beta,
416
+ iterations=result.n_iterations,
417
+ execution_time_ms=execution_time,
418
+ )
419
+
420
+ except Exception as e:
421
+ raise HTTPException(status_code=400, detail=str(e))
422
+
423
+
424
+ # ============================================================
425
+ # VQE Models & Endpoints
426
+ # ============================================================
427
+
428
+ class VQERequest(BaseModel):
429
+ """Request for VQE computation."""
430
+ molecule: str = Field(default="H2", description="Molecule: H2, LiH, H2O")
431
+ n_qubits: int = Field(default=4, ge=2, le=16)
432
+ ansatz: str = Field(default="ry_cnot", description="Ansatz type: ry_cnot, hardware_efficient")
433
+ max_iterations: int = Field(default=100, ge=10, le=1000)
434
+ shots: int = Field(default=1024)
435
+ backend: str = Field(default="simulator")
436
+
437
+
438
+ class VQEResponse(BaseModel):
439
+ """Response from VQE computation."""
440
+ ground_state_energy: float
441
+ optimal_parameters: List[float]
442
+ energy_history: List[float]
443
+ iterations: int
444
+ converged: bool
445
+ chemical_accuracy: bool
446
+ execution_time_ms: float
447
+
448
+
449
+ @router.post("/vqe/compute", response_model=VQEResponse)
450
+ async def vqe_compute(
451
+ request: VQERequest,
452
+ user: User = Depends(get_current_user), # Requires API key - heavy compute
453
+ ):
454
+ """
455
+ Run VQE to find ground state energy.
456
+
457
+ Variational Quantum Eigensolver finds the lowest eigenvalue
458
+ of a Hamiltonian - useful for quantum chemistry.
459
+ """
460
+ start_time = time.perf_counter()
461
+
462
+ try:
463
+ # Define simple molecular Hamiltonians
464
+ molecule_hamiltonians = {
465
+ "H2": [("ZZ", 0.5), ("XI", 0.3), ("IX", 0.3), ("II", -0.5)],
466
+ "LiH": [("ZZ", 0.4), ("ZI", 0.2), ("IZ", 0.2), ("XX", 0.1), ("YY", 0.1)],
467
+ "H2O": [("ZZI", 0.3), ("ZIZ", 0.3), ("IZZ", 0.3), ("XII", 0.2), ("IXI", 0.2)],
468
+ }
469
+
470
+ hamiltonian = molecule_hamiltonians.get(request.molecule, molecule_hamiltonians["H2"])
471
+
472
+ # Initialize VQE
473
+ vqe = VQE(
474
+ n_qubits=request.n_qubits,
475
+ backend=request.backend,
476
+ ansatz=request.ansatz.replace("-", "_"),
477
+ shots=request.shots,
478
+ )
479
+
480
+ # Run VQE
481
+ result = vqe.run(
482
+ hamiltonian=hamiltonian,
483
+ max_iterations=request.max_iterations,
484
+ )
485
+
486
+ execution_time = (time.perf_counter() - start_time) * 1000
487
+
488
+ # Check convergence - if energy stabilized in last iterations
489
+ converged = len(result.energy_history) > 5 and \
490
+ abs(result.energy_history[-1] - result.energy_history[-5]) < 0.01
491
+
492
+ # Chemical accuracy check
493
+ chemical_accuracy = converged and abs(result.ground_energy) < 2.0
494
+
495
+ return VQEResponse(
496
+ ground_state_energy=result.ground_energy,
497
+ optimal_parameters=result.optimal_params.tolist(),
498
+ energy_history=result.energy_history,
499
+ iterations=result.n_iterations,
500
+ converged=converged,
501
+ chemical_accuracy=chemical_accuracy,
502
+ execution_time_ms=execution_time,
503
+ )
504
+
505
+ except Exception as e:
506
+ raise HTTPException(status_code=400, detail=str(e))
507
+
508
+
509
+ # ============================================================
510
+ # Algorithm Info Endpoint
511
+ # ============================================================
512
+
513
+ # ============================================================
514
+ # QSVM Models & Endpoints
515
+ # ============================================================
516
+
517
+ class QSVMTrainRequest(BaseModel):
518
+ """Request for QSVM training."""
519
+ X_train: List[List[float]] = Field(..., description="Training features")
520
+ y_train: List[int] = Field(..., description="Training labels (-1 or 1)")
521
+ feature_map: str = Field(default="zz", description="Feature map: zz, pauli, amplitude")
522
+ reps: int = Field(default=2, ge=1, le=5)
523
+ shots: int = Field(default=1024)
524
+ backend: str = Field(default="simulator")
525
+
526
+
527
+ class QSVMTrainResponse(BaseModel):
528
+ """Response from QSVM training."""
529
+ n_support_vectors: int
530
+ kernel_matrix_shape: List[int]
531
+ training_accuracy: float
532
+ execution_time_ms: float
533
+
534
+
535
+ class QSVMPredictRequest(BaseModel):
536
+ """Request for QSVM prediction."""
537
+ X_train: List[List[float]] = Field(..., description="Training features")
538
+ y_train: List[int] = Field(..., description="Training labels")
539
+ X_test: List[List[float]] = Field(..., description="Test features")
540
+ feature_map: str = Field(default="zz")
541
+ reps: int = Field(default=2)
542
+ shots: int = Field(default=1024)
543
+
544
+
545
+ class QSVMPredictResponse(BaseModel):
546
+ """Response from QSVM prediction."""
547
+ predictions: List[int]
548
+ execution_time_ms: float
549
+
550
+
551
+ @router.post("/qsvm/train", response_model=QSVMTrainResponse)
552
+ async def qsvm_train(
553
+ request: QSVMTrainRequest,
554
+ user: User = Depends(get_current_user), # Requires API key - heavy compute
555
+ ):
556
+ """
557
+ Train a Quantum Support Vector Machine.
558
+
559
+ Uses quantum feature maps to compute kernel in high-dimensional Hilbert space.
560
+ """
561
+ start_time = time.perf_counter()
562
+
563
+ try:
564
+ X = np.array(request.X_train)
565
+ y = np.array(request.y_train)
566
+
567
+ qsvm = QSVM(
568
+ n_features=X.shape[1],
569
+ backend=request.backend,
570
+ feature_map=request.feature_map,
571
+ reps=request.reps,
572
+ shots=request.shots,
573
+ )
574
+
575
+ qsvm.fit(X, y)
576
+ accuracy = qsvm.score(X, y)
577
+
578
+ n_support = int(np.sum(qsvm.alphas > 1e-6))
579
+
580
+ execution_time = (time.perf_counter() - start_time) * 1000
581
+
582
+ return QSVMTrainResponse(
583
+ n_support_vectors=n_support,
584
+ kernel_matrix_shape=list(qsvm.kernel_matrix.shape),
585
+ training_accuracy=accuracy,
586
+ execution_time_ms=execution_time,
587
+ )
588
+
589
+ except Exception as e:
590
+ raise HTTPException(status_code=400, detail=str(e))
591
+
592
+
593
+ @router.post("/qsvm/predict", response_model=QSVMPredictResponse)
594
+ async def qsvm_predict(
595
+ request: QSVMPredictRequest,
596
+ user: Optional[User] = Depends(get_optional_user),
597
+ ):
598
+ """Make predictions using QSVM."""
599
+ start_time = time.perf_counter()
600
+
601
+ try:
602
+ X_train = np.array(request.X_train)
603
+ y_train = np.array(request.y_train)
604
+ X_test = np.array(request.X_test)
605
+
606
+ qsvm = QSVM(
607
+ n_features=X_train.shape[1],
608
+ feature_map=request.feature_map,
609
+ reps=request.reps,
610
+ shots=request.shots,
611
+ )
612
+
613
+ qsvm.fit(X_train, y_train)
614
+ predictions = qsvm.predict(X_test)
615
+
616
+ execution_time = (time.perf_counter() - start_time) * 1000
617
+
618
+ return QSVMPredictResponse(
619
+ predictions=predictions.tolist(),
620
+ execution_time_ms=execution_time,
621
+ )
622
+
623
+ except Exception as e:
624
+ raise HTTPException(status_code=400, detail=str(e))
625
+
626
+
627
+ # ============================================================
628
+ # QKD Models & Endpoints
629
+ # ============================================================
630
+
631
+ class QKDGenerateRequest(BaseModel):
632
+ """Request for QKD key generation."""
633
+ key_length: int = Field(default=256, ge=32, le=4096, description="Desired key length in bits")
634
+ simulate_eavesdropper: bool = Field(default=False, description="Simulate eavesdropping attack")
635
+ backend: str = Field(default="simulator")
636
+
637
+
638
+ class QKDGenerateResponse(BaseModel):
639
+ """Response from QKD key generation."""
640
+ shared_key: str
641
+ key_length: int
642
+ raw_bits_used: int
643
+ error_rate: float
644
+ is_secure: bool
645
+ eavesdropper_detected: bool
646
+ protocol: str
647
+ execution_time_ms: float
648
+
649
+
650
+ @router.post("/qkd/generate", response_model=QKDGenerateResponse)
651
+ async def qkd_generate(
652
+ request: QKDGenerateRequest,
653
+ user: Optional[User] = Depends(get_optional_user),
654
+ ):
655
+ """
656
+ Generate a quantum-secure cryptographic key using BB84 protocol.
657
+
658
+ The key is provably secure against eavesdropping due to quantum mechanics.
659
+ """
660
+ start_time = time.perf_counter()
661
+
662
+ try:
663
+ from quantumflow.algorithms.cryptography import QKD
664
+
665
+ qkd = QKD(backend=request.backend)
666
+
667
+ result = qkd.generate_key(
668
+ key_length=request.key_length,
669
+ with_eavesdropper=request.simulate_eavesdropper,
670
+ )
671
+
672
+ execution_time = (time.perf_counter() - start_time) * 1000
673
+
674
+ return QKDGenerateResponse(
675
+ shared_key=result.shared_key,
676
+ key_length=result.key_length,
677
+ raw_bits_used=result.raw_key_length,
678
+ error_rate=result.error_rate,
679
+ is_secure=result.is_secure,
680
+ eavesdropper_detected=not result.is_secure and request.simulate_eavesdropper,
681
+ protocol="BB84",
682
+ execution_time_ms=execution_time,
683
+ )
684
+
685
+ except Exception as e:
686
+ raise HTTPException(status_code=400, detail=str(e))
687
+
688
+
689
+ # ============================================================
690
+ # QRNG Models & Endpoints
691
+ # ============================================================
692
+
693
+ class QRNGRequest(BaseModel):
694
+ """Request for quantum random number generation."""
695
+ output_type: str = Field(default="bits", description="Output type: bits, integer, float, bytes")
696
+ count: int = Field(default=64, ge=1, le=1024, description="Number of bits/bytes or max value for integer")
697
+ min_value: int = Field(default=0, description="Min value for integer output")
698
+ max_value: Optional[int] = Field(None, description="Max value for integer output")
699
+ backend: str = Field(default="simulator")
700
+
701
+
702
+ class QRNGResponse(BaseModel):
703
+ """Response from quantum random number generation."""
704
+ output_type: str
705
+ bits: Optional[str] = None
706
+ integer: Optional[int] = None
707
+ float_value: Optional[float] = None
708
+ bytes_hex: Optional[str] = None
709
+ n_qubits_used: int
710
+ entropy_bits: int
711
+ execution_time_ms: float
712
+
713
+
714
+ @router.post("/qrng/generate", response_model=QRNGResponse)
715
+ async def qrng_generate(
716
+ request: QRNGRequest,
717
+ user: Optional[User] = Depends(get_optional_user),
718
+ ):
719
+ """
720
+ Generate true random numbers using quantum mechanics.
721
+
722
+ Unlike classical PRNGs, quantum randomness is fundamentally unpredictable.
723
+ """
724
+ start_time = time.perf_counter()
725
+
726
+ try:
727
+ from quantumflow.algorithms.cryptography import QRNG
728
+
729
+ qrng = QRNG(backend=request.backend)
730
+
731
+ bits = None
732
+ integer = None
733
+ float_value = None
734
+ bytes_hex = None
735
+ entropy_bits = request.count
736
+
737
+ if request.output_type == "bits":
738
+ bits = qrng.random_bits(request.count)
739
+ entropy_bits = request.count
740
+ elif request.output_type == "integer":
741
+ max_val = request.max_value if request.max_value else (2 ** request.count - 1)
742
+ integer = qrng.random_int(request.min_value, max_val)
743
+ entropy_bits = int(np.ceil(np.log2(max_val - request.min_value + 1)))
744
+ elif request.output_type == "float":
745
+ float_value = qrng.random_float()
746
+ entropy_bits = 53
747
+ elif request.output_type == "bytes":
748
+ random_bytes = qrng.random_bytes(request.count)
749
+ bytes_hex = random_bytes.hex()
750
+ entropy_bits = request.count * 8
751
+
752
+ execution_time = (time.perf_counter() - start_time) * 1000
753
+
754
+ return QRNGResponse(
755
+ output_type=request.output_type,
756
+ bits=bits,
757
+ integer=integer,
758
+ float_value=float_value,
759
+ bytes_hex=bytes_hex,
760
+ n_qubits_used=min(20, entropy_bits),
761
+ entropy_bits=entropy_bits,
762
+ execution_time_ms=execution_time,
763
+ )
764
+
765
+ except Exception as e:
766
+ raise HTTPException(status_code=400, detail=str(e))
767
+
768
+
769
+ # ============================================================
770
+ # Quantum Fourier Transform Endpoint
771
+ # ============================================================
772
+
773
+ class QFTRequest(BaseModel):
774
+ """Request for QFT."""
775
+ input_data: List[float] = Field(..., description="Input data to transform")
776
+ n_qubits: Optional[int] = Field(None, description="Number of qubits (auto if not specified)")
777
+ inverse: bool = Field(default=False, description="Apply inverse QFT")
778
+ backend: str = Field(default="simulator")
779
+
780
+
781
+ class QFTResponse(BaseModel):
782
+ """Response from QFT."""
783
+ output_coefficients: List[float]
784
+ n_qubits: int
785
+ transform_type: str
786
+ circuit_depth: int
787
+ execution_time_ms: float
788
+
789
+
790
+ @router.post("/qft/transform", response_model=QFTResponse)
791
+ async def qft_transform(
792
+ request: QFTRequest,
793
+ user: Optional[User] = Depends(get_optional_user),
794
+ ):
795
+ """
796
+ Apply Quantum Fourier Transform.
797
+
798
+ Exponentially faster than classical FFT for certain applications.
799
+ """
800
+ start_time = time.perf_counter()
801
+
802
+ try:
803
+ from quantumflow.algorithms.compression import QFTCompression
804
+
805
+ n_qubits = request.n_qubits or int(np.ceil(np.log2(len(request.input_data))))
806
+ n_qubits = max(2, min(n_qubits, 16))
807
+
808
+ qft = QFTCompression(n_qubits=n_qubits)
809
+
810
+ if request.inverse:
811
+ result = qft.inverse_transform(request.input_data)
812
+ else:
813
+ result = qft.transform(request.input_data)
814
+
815
+ execution_time = (time.perf_counter() - start_time) * 1000
816
+
817
+ return QFTResponse(
818
+ output_coefficients=result.tolist() if hasattr(result, 'tolist') else list(result),
819
+ n_qubits=n_qubits,
820
+ transform_type="inverse_QFT" if request.inverse else "QFT",
821
+ circuit_depth=n_qubits * (n_qubits + 1) // 2,
822
+ execution_time_ms=execution_time,
823
+ )
824
+
825
+ except Exception as e:
826
+ raise HTTPException(status_code=400, detail=str(e))
827
+
828
+
829
+ # ============================================================
830
+ # Algorithm Info Endpoint
831
+ # ============================================================
832
+
833
+ @router.get("/info")
834
+ async def list_algorithms():
835
+ """List all available quantum algorithms with descriptions."""
836
+ return {
837
+ "algorithms": [
838
+ {
839
+ "id": "qnn",
840
+ "name": "Quantum Neural Network",
841
+ "description": "Parameterized quantum circuits for machine learning",
842
+ "endpoints": ["/v1/algorithms/qnn/forward", "/v1/algorithms/qnn/train", "/v1/algorithms/qnn/predict"],
843
+ "use_cases": ["Binary classification", "Pattern recognition", "Feature extraction"],
844
+ },
845
+ {
846
+ "id": "grover",
847
+ "name": "Grover's Search",
848
+ "description": "Quantum search with quadratic speedup O(√N)",
849
+ "endpoints": ["/v1/algorithms/grover/search"],
850
+ "use_cases": ["Database search", "SAT solving", "Optimization"],
851
+ },
852
+ {
853
+ "id": "qaoa",
854
+ "name": "QAOA",
855
+ "description": "Quantum Approximate Optimization Algorithm",
856
+ "endpoints": ["/v1/algorithms/qaoa/optimize"],
857
+ "use_cases": ["MaxCut", "Portfolio optimization", "Scheduling"],
858
+ },
859
+ {
860
+ "id": "vqe",
861
+ "name": "VQE",
862
+ "description": "Variational Quantum Eigensolver",
863
+ "endpoints": ["/v1/algorithms/vqe/compute"],
864
+ "use_cases": ["Molecular simulation", "Ground state energy", "Quantum chemistry"],
865
+ },
866
+ {
867
+ "id": "qsvm",
868
+ "name": "Quantum SVM",
869
+ "description": "Quantum kernel-based classification",
870
+ "endpoints": ["/v1/algorithms/qsvm/train", "/v1/algorithms/qsvm/predict"],
871
+ "use_cases": ["Classification", "Pattern recognition", "Anomaly detection"],
872
+ },
873
+ {
874
+ "id": "qkd",
875
+ "name": "Quantum Key Distribution",
876
+ "description": "BB84 protocol for quantum-secure key exchange",
877
+ "endpoints": ["/v1/algorithms/qkd/generate"],
878
+ "use_cases": ["Secure communication", "Cryptography", "Key exchange"],
879
+ },
880
+ {
881
+ "id": "qrng",
882
+ "name": "Quantum Random Number Generator",
883
+ "description": "True random numbers from quantum measurements",
884
+ "endpoints": ["/v1/algorithms/qrng/generate"],
885
+ "use_cases": ["Cryptography", "Simulations", "Gaming"],
886
+ },
887
+ {
888
+ "id": "qft",
889
+ "name": "Quantum Fourier Transform",
890
+ "description": "Exponentially faster Fourier transform",
891
+ "endpoints": ["/v1/algorithms/qft/transform"],
892
+ "use_cases": ["Signal processing", "Phase estimation", "Quantum algorithms"],
893
+ },
894
+ ]
895
+ }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: quantumflow-sdk
3
- Version: 0.2.1
3
+ Version: 0.3.0
4
4
  Summary: Quantum-optimized AI agent workflow platform with 53% token compression
5
5
  Author-email: BlockQuantAI <hello@blockquant.ai>
6
6
  License-Expression: MIT
@@ -1,8 +1,9 @@
1
1
  api/__init__.py,sha256=Oc_JXlNXQ8vZqr7A32xlhaW-FLUk2DfSVqjDoh4cv4Y,31
2
2
  api/auth.py,sha256=8gxgMSwsfsUCK0mM-ZTWM_ZsvTDvyOfVdO0NYLCHg1I,5942
3
- api/main.py,sha256=SJKAzb1HRzGjpUbOvplU8U-Xul6XavM_8yvmDSmJVNc,12494
3
+ api/main.py,sha256=WQgi8h7FAjkwPlSiwGQhnviHZiAn7VZ79g_qeRUg-aQ,12673
4
4
  api/models.py,sha256=i0bwfN697wSxnIchHo13aOWkzZQE90WSRFUArJS0a2M,3262
5
5
  api/routes/__init__.py,sha256=NsndLhwM3PzBnPYSUiKAu0pJKf2JnVkt3vFbaFkA6PA,26
6
+ api/routes/algorithm_routes.py,sha256=jPwogmqbRiW3YHZCY_XuUZEVSI08zTHpBOz2zKac0iA,30139
6
7
  api/routes/auth_routes.py,sha256=f80G08AfUh2XCUdziJbncNH8HT9GlOq3f9BpX9p_ans,5966
7
8
  api/routes/teleport_routes.py,sha256=8G8-lAuB1H2qSom7Im7s1NiiHRy0HBPzlnJ-QAer3DI,12149
8
9
  db/__init__.py,sha256=CLyI_3_AP7wQATuxLV2yHPvYDNikJYmH5BMQ3Oez1xw,280
@@ -56,8 +57,8 @@ quantumflow/integrations/langchain_memory.py,sha256=wgYTdovncZNWpFwcNZjhNUqNRi66
56
57
  quantumflow/integrations/langchain_tools.py,sha256=bDrKZDYSRQJJGSNc9iay1Q4NoIR8CHmtZLcybS5ub_w,12401
57
58
  quantumflow/integrations/mcp_server.py,sha256=KJTAxJOyCVl7-whTD1iss9VZmyi0K1f4gNJCH8Cvl_0,21117
58
59
  quantumflow/integrations/openai_functions.py,sha256=8jQH4XkBxK9AbwC47BEYVIrbRAEWGdsMyw0xbZrGNB4,18412
59
- quantumflow_sdk-0.2.1.dist-info/METADATA,sha256=QcTBk2aAfAE7goV311z5qrdubgYNhormcxUNdYqGsSI,5461
60
- quantumflow_sdk-0.2.1.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
61
- quantumflow_sdk-0.2.1.dist-info/entry_points.txt,sha256=ebX2acoOLgym42XZEqym3OfKCYiPz-mFuPSSGsHFz4c,53
62
- quantumflow_sdk-0.2.1.dist-info/top_level.txt,sha256=hEr_GRvoZ3-83naVIhNuJvoAND1aCvhBag_ynxQguIo,19
63
- quantumflow_sdk-0.2.1.dist-info/RECORD,,
60
+ quantumflow_sdk-0.3.0.dist-info/METADATA,sha256=d-Zb7TDbvirOoWHjSPap2p2V6tHYZPhe0Zu5k7fIbGY,5461
61
+ quantumflow_sdk-0.3.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
62
+ quantumflow_sdk-0.3.0.dist-info/entry_points.txt,sha256=ebX2acoOLgym42XZEqym3OfKCYiPz-mFuPSSGsHFz4c,53
63
+ quantumflow_sdk-0.3.0.dist-info/top_level.txt,sha256=hEr_GRvoZ3-83naVIhNuJvoAND1aCvhBag_ynxQguIo,19
64
+ quantumflow_sdk-0.3.0.dist-info/RECORD,,