quantumflow-sdk 0.1.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/__init__.py +1 -0
- api/auth.py +208 -0
- api/main.py +403 -0
- api/models.py +137 -0
- api/routes/__init__.py +1 -0
- api/routes/auth_routes.py +234 -0
- api/routes/teleport_routes.py +415 -0
- db/__init__.py +15 -0
- db/crud.py +319 -0
- db/database.py +93 -0
- db/models.py +197 -0
- quantumflow/__init__.py +47 -0
- quantumflow/algorithms/__init__.py +48 -0
- quantumflow/algorithms/compression/__init__.py +7 -0
- quantumflow/algorithms/compression/amplitude_amplification.py +189 -0
- quantumflow/algorithms/compression/qft_compression.py +133 -0
- quantumflow/algorithms/compression/token_compression.py +261 -0
- quantumflow/algorithms/cryptography/__init__.py +6 -0
- quantumflow/algorithms/cryptography/qkd.py +205 -0
- quantumflow/algorithms/cryptography/qrng.py +231 -0
- quantumflow/algorithms/machine_learning/__init__.py +7 -0
- quantumflow/algorithms/machine_learning/qnn.py +276 -0
- quantumflow/algorithms/machine_learning/qsvm.py +249 -0
- quantumflow/algorithms/machine_learning/vqe.py +229 -0
- quantumflow/algorithms/optimization/__init__.py +7 -0
- quantumflow/algorithms/optimization/grover.py +223 -0
- quantumflow/algorithms/optimization/qaoa.py +251 -0
- quantumflow/algorithms/optimization/quantum_annealing.py +237 -0
- quantumflow/algorithms/utility/__init__.py +6 -0
- quantumflow/algorithms/utility/circuit_optimizer.py +194 -0
- quantumflow/algorithms/utility/error_correction.py +330 -0
- quantumflow/api/__init__.py +1 -0
- quantumflow/api/routes/__init__.py +4 -0
- quantumflow/api/routes/billing_routes.py +520 -0
- quantumflow/backends/__init__.py +33 -0
- quantumflow/backends/base_backend.py +184 -0
- quantumflow/backends/braket_backend.py +345 -0
- quantumflow/backends/ibm_backend.py +112 -0
- quantumflow/backends/simulator_backend.py +86 -0
- quantumflow/billing/__init__.py +25 -0
- quantumflow/billing/models.py +126 -0
- quantumflow/billing/stripe_service.py +619 -0
- quantumflow/core/__init__.py +12 -0
- quantumflow/core/entanglement.py +164 -0
- quantumflow/core/memory.py +147 -0
- quantumflow/core/quantum_backprop.py +394 -0
- quantumflow/core/quantum_compressor.py +309 -0
- quantumflow/core/teleportation.py +386 -0
- quantumflow/integrations/__init__.py +107 -0
- quantumflow/integrations/autogen_tools.py +501 -0
- quantumflow/integrations/crewai_agents.py +425 -0
- quantumflow/integrations/crewai_tools.py +407 -0
- quantumflow/integrations/langchain_memory.py +385 -0
- quantumflow/integrations/langchain_tools.py +366 -0
- quantumflow/integrations/mcp_server.py +575 -0
- quantumflow_sdk-0.1.0.dist-info/METADATA +190 -0
- quantumflow_sdk-0.1.0.dist-info/RECORD +60 -0
- quantumflow_sdk-0.1.0.dist-info/WHEEL +5 -0
- quantumflow_sdk-0.1.0.dist-info/entry_points.txt +2 -0
- quantumflow_sdk-0.1.0.dist-info/top_level.txt +3 -0
api/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""QuantumFlow API Package."""
|
api/auth.py
ADDED
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Authentication for QuantumFlow API.
|
|
3
|
+
|
|
4
|
+
Supports:
|
|
5
|
+
- API Key authentication
|
|
6
|
+
- JWT tokens for user sessions
|
|
7
|
+
- Database-backed user management
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import os
|
|
11
|
+
from datetime import datetime, timedelta
|
|
12
|
+
from typing import Optional
|
|
13
|
+
from uuid import UUID
|
|
14
|
+
|
|
15
|
+
from fastapi import HTTPException, Security, status, Depends
|
|
16
|
+
from fastapi.security import APIKeyHeader, HTTPBearer
|
|
17
|
+
from jose import JWTError, jwt
|
|
18
|
+
from pydantic import BaseModel
|
|
19
|
+
from sqlalchemy.orm import Session
|
|
20
|
+
|
|
21
|
+
from db.database import get_db
|
|
22
|
+
from db import crud
|
|
23
|
+
from db.models import User, APIKey as APIKeyModel
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
# Configuration
|
|
27
|
+
API_KEY_HEADER = APIKeyHeader(name="X-API-Key", auto_error=False)
|
|
28
|
+
BEARER_SCHEME = HTTPBearer(auto_error=False)
|
|
29
|
+
|
|
30
|
+
SECRET_KEY = os.getenv("JWT_SECRET", "dev-secret-key-change-in-production")
|
|
31
|
+
ALGORITHM = "HS256"
|
|
32
|
+
ACCESS_TOKEN_EXPIRE_MINUTES = 60 * 24 # 24 hours
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class TokenData(BaseModel):
|
|
36
|
+
"""JWT token payload."""
|
|
37
|
+
user_id: str
|
|
38
|
+
exp: Optional[datetime] = None
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class TokenResponse(BaseModel):
|
|
42
|
+
"""Token response model."""
|
|
43
|
+
access_token: str
|
|
44
|
+
token_type: str = "bearer"
|
|
45
|
+
expires_in: int
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class UserResponse(BaseModel):
|
|
49
|
+
"""User response model."""
|
|
50
|
+
id: str
|
|
51
|
+
email: str
|
|
52
|
+
name: Optional[str]
|
|
53
|
+
tier: str
|
|
54
|
+
is_active: bool
|
|
55
|
+
|
|
56
|
+
class Config:
|
|
57
|
+
from_attributes = True
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class APIKeyResponse(BaseModel):
|
|
61
|
+
"""API key response (without full key)."""
|
|
62
|
+
id: str
|
|
63
|
+
name: str
|
|
64
|
+
prefix: str
|
|
65
|
+
created_at: datetime
|
|
66
|
+
last_used: Optional[datetime]
|
|
67
|
+
is_active: bool
|
|
68
|
+
|
|
69
|
+
class Config:
|
|
70
|
+
from_attributes = True
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
# ============== JWT Functions ==============
|
|
74
|
+
|
|
75
|
+
def create_access_token(user_id: str, expires_delta: Optional[timedelta] = None) -> str:
|
|
76
|
+
"""Create a JWT access token."""
|
|
77
|
+
expire = datetime.utcnow() + (expires_delta or timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES))
|
|
78
|
+
to_encode = {"sub": user_id, "exp": expire}
|
|
79
|
+
return jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def verify_token(token: str) -> Optional[TokenData]:
|
|
83
|
+
"""Verify and decode a JWT token."""
|
|
84
|
+
try:
|
|
85
|
+
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
|
|
86
|
+
user_id: str = payload.get("sub")
|
|
87
|
+
if user_id is None:
|
|
88
|
+
return None
|
|
89
|
+
return TokenData(user_id=user_id, exp=payload.get("exp"))
|
|
90
|
+
except JWTError:
|
|
91
|
+
return None
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
# ============== Auth Dependencies ==============
|
|
95
|
+
|
|
96
|
+
def get_db_session():
|
|
97
|
+
"""Get database session."""
|
|
98
|
+
db = next(get_db())
|
|
99
|
+
try:
|
|
100
|
+
yield db
|
|
101
|
+
finally:
|
|
102
|
+
db.close()
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
async def get_current_user(
|
|
106
|
+
api_key: Optional[str] = Security(API_KEY_HEADER),
|
|
107
|
+
bearer: Optional[object] = Security(BEARER_SCHEME),
|
|
108
|
+
db: Session = Depends(get_db_session),
|
|
109
|
+
) -> User:
|
|
110
|
+
"""
|
|
111
|
+
Get the current authenticated user.
|
|
112
|
+
|
|
113
|
+
Supports both API Key and Bearer token authentication.
|
|
114
|
+
Returns the User object from database.
|
|
115
|
+
"""
|
|
116
|
+
# Try API Key first
|
|
117
|
+
if api_key:
|
|
118
|
+
key_record = crud.get_api_key(db, api_key)
|
|
119
|
+
if key_record:
|
|
120
|
+
crud.update_api_key_usage(db, key_record)
|
|
121
|
+
user = crud.get_user(db, key_record.user_id)
|
|
122
|
+
if user and user.is_active:
|
|
123
|
+
return user
|
|
124
|
+
|
|
125
|
+
# Try Bearer token
|
|
126
|
+
if bearer and hasattr(bearer, 'credentials'):
|
|
127
|
+
token_data = verify_token(bearer.credentials)
|
|
128
|
+
if token_data:
|
|
129
|
+
try:
|
|
130
|
+
user_id = UUID(token_data.user_id)
|
|
131
|
+
user = crud.get_user(db, user_id)
|
|
132
|
+
if user and user.is_active:
|
|
133
|
+
return user
|
|
134
|
+
except ValueError:
|
|
135
|
+
pass
|
|
136
|
+
|
|
137
|
+
# Fallback: Allow dev key in development
|
|
138
|
+
if api_key == "qf_dev_key_123" and os.getenv("ENV", "development") == "development":
|
|
139
|
+
# Create or get dev user
|
|
140
|
+
dev_user = crud.get_user_by_email(db, "dev@quantumflow.local")
|
|
141
|
+
if not dev_user:
|
|
142
|
+
dev_user = crud.create_user(db, "dev@quantumflow.local", "devpassword", "Dev User")
|
|
143
|
+
return dev_user
|
|
144
|
+
|
|
145
|
+
raise HTTPException(
|
|
146
|
+
status_code=status.HTTP_401_UNAUTHORIZED,
|
|
147
|
+
detail="Invalid or missing authentication",
|
|
148
|
+
headers={"WWW-Authenticate": "Bearer"},
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
async def get_optional_user(
|
|
153
|
+
api_key: Optional[str] = Security(API_KEY_HEADER),
|
|
154
|
+
bearer: Optional[object] = Security(BEARER_SCHEME),
|
|
155
|
+
db: Session = Depends(get_db_session),
|
|
156
|
+
) -> Optional[User]:
|
|
157
|
+
"""Get user if authenticated, None otherwise."""
|
|
158
|
+
try:
|
|
159
|
+
return await get_current_user(api_key, bearer, db)
|
|
160
|
+
except HTTPException:
|
|
161
|
+
return None
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
async def get_current_active_user(
|
|
165
|
+
current_user: User = Depends(get_current_user),
|
|
166
|
+
) -> User:
|
|
167
|
+
"""Ensure user is active."""
|
|
168
|
+
if not current_user.is_active:
|
|
169
|
+
raise HTTPException(
|
|
170
|
+
status_code=status.HTTP_403_FORBIDDEN,
|
|
171
|
+
detail="User account is disabled",
|
|
172
|
+
)
|
|
173
|
+
return current_user
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
async def check_user_quota(
|
|
177
|
+
current_user: User = Depends(get_current_active_user),
|
|
178
|
+
db: Session = Depends(get_db_session),
|
|
179
|
+
) -> User:
|
|
180
|
+
"""Check if user is within their usage quota."""
|
|
181
|
+
if not crud.check_quota(db, current_user):
|
|
182
|
+
raise HTTPException(
|
|
183
|
+
status_code=status.HTTP_429_TOO_MANY_REQUESTS,
|
|
184
|
+
detail="Monthly API quota exceeded. Please upgrade your plan.",
|
|
185
|
+
)
|
|
186
|
+
return current_user
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
# ============== Helper Functions ==============
|
|
190
|
+
|
|
191
|
+
def authenticate_user(db: Session, email: str, password: str) -> Optional[User]:
|
|
192
|
+
"""Authenticate user by email and password."""
|
|
193
|
+
return crud.authenticate_user(db, email, password)
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def create_user(db: Session, email: str, password: str, name: Optional[str] = None) -> User:
|
|
197
|
+
"""Create a new user."""
|
|
198
|
+
return crud.create_user(db, email, password, name)
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
def create_api_key_for_user(
|
|
202
|
+
db: Session,
|
|
203
|
+
user_id: UUID,
|
|
204
|
+
name: str,
|
|
205
|
+
scopes: Optional[list[str]] = None,
|
|
206
|
+
) -> tuple[APIKeyModel, str]:
|
|
207
|
+
"""Create API key for user. Returns (key_record, raw_key)."""
|
|
208
|
+
return crud.create_api_key(db, user_id, name, scopes)
|
api/main.py
ADDED
|
@@ -0,0 +1,403 @@
|
|
|
1
|
+
"""
|
|
2
|
+
QuantumFlow API - FastAPI Application.
|
|
3
|
+
|
|
4
|
+
Endpoints:
|
|
5
|
+
- POST /v1/compress - Token compression (Paper 1)
|
|
6
|
+
- POST /v1/gradient - Quantum backprop (Paper 2)
|
|
7
|
+
- GET /v1/backends - Available quantum backends
|
|
8
|
+
- POST /v1/memory/* - Quantum memory operations
|
|
9
|
+
- POST /v1/entangle - Create entangled states
|
|
10
|
+
- /auth/* - Authentication and API key management
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
import os
|
|
14
|
+
import sys
|
|
15
|
+
import time
|
|
16
|
+
from contextlib import asynccontextmanager
|
|
17
|
+
from typing import Optional
|
|
18
|
+
|
|
19
|
+
from fastapi import FastAPI, HTTPException, Depends, Request, status
|
|
20
|
+
from fastapi.middleware.cors import CORSMiddleware
|
|
21
|
+
import numpy as np
|
|
22
|
+
|
|
23
|
+
# Add src to path for imports
|
|
24
|
+
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|
25
|
+
|
|
26
|
+
from api.models import (
|
|
27
|
+
CompressRequest, CompressResponse,
|
|
28
|
+
GradientRequest, GradientResponse,
|
|
29
|
+
BackendStatus, BackendsResponse,
|
|
30
|
+
MemoryStoreRequest, MemoryStoreResponse,
|
|
31
|
+
MemoryRetrieveResponse, MemoryStatsResponse,
|
|
32
|
+
EntangleRequest, EntangleResponse,
|
|
33
|
+
HealthResponse,
|
|
34
|
+
)
|
|
35
|
+
from api.auth import get_current_user, get_optional_user, get_db_session
|
|
36
|
+
from api.routes.auth_routes import router as auth_router
|
|
37
|
+
from api.routes.teleport_routes import router as teleport_router
|
|
38
|
+
|
|
39
|
+
# Import billing routes (optional - only if Stripe is configured)
|
|
40
|
+
try:
|
|
41
|
+
from quantumflow.api.routes.billing_routes import router as billing_router
|
|
42
|
+
BILLING_ENABLED = True
|
|
43
|
+
except ImportError:
|
|
44
|
+
BILLING_ENABLED = False
|
|
45
|
+
billing_router = None
|
|
46
|
+
|
|
47
|
+
from quantumflow.core.quantum_compressor import QuantumCompressor
|
|
48
|
+
from quantumflow.core.quantum_backprop import QuantumBackprop
|
|
49
|
+
from quantumflow.core.entanglement import Entangler
|
|
50
|
+
from quantumflow.core.memory import QuantumMemory
|
|
51
|
+
from quantumflow.backends.base_backend import BackendType
|
|
52
|
+
|
|
53
|
+
from db.database import init_db
|
|
54
|
+
from db.models import User
|
|
55
|
+
from db import crud
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
# Global instances (initialized on startup)
|
|
59
|
+
_compressor: Optional[QuantumCompressor] = None
|
|
60
|
+
_backprop: Optional[QuantumBackprop] = None
|
|
61
|
+
_entangler: Optional[Entangler] = None
|
|
62
|
+
_memory: Optional[QuantumMemory] = None
|
|
63
|
+
_db_initialized: bool = False
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
@asynccontextmanager
|
|
67
|
+
async def lifespan(app: FastAPI):
|
|
68
|
+
"""Initialize quantum components and database on startup."""
|
|
69
|
+
global _compressor, _backprop, _entangler, _memory, _db_initialized
|
|
70
|
+
|
|
71
|
+
# Initialize quantum components
|
|
72
|
+
_compressor = QuantumCompressor(backend="simulator")
|
|
73
|
+
_backprop = QuantumBackprop(backend="simulator")
|
|
74
|
+
_entangler = Entangler(backend="simulator")
|
|
75
|
+
_memory = QuantumMemory(backend="simulator")
|
|
76
|
+
|
|
77
|
+
# Initialize database
|
|
78
|
+
try:
|
|
79
|
+
init_db()
|
|
80
|
+
_db_initialized = True
|
|
81
|
+
print("Database initialized successfully")
|
|
82
|
+
except Exception as e:
|
|
83
|
+
print(f"Database initialization failed: {e}")
|
|
84
|
+
print("Running without database - some features will be limited")
|
|
85
|
+
_db_initialized = False
|
|
86
|
+
|
|
87
|
+
yield
|
|
88
|
+
|
|
89
|
+
# Cleanup
|
|
90
|
+
_compressor = None
|
|
91
|
+
_backprop = None
|
|
92
|
+
_entangler = None
|
|
93
|
+
_memory = None
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
# Create FastAPI app
|
|
97
|
+
app = FastAPI(
|
|
98
|
+
title="QuantumFlow API",
|
|
99
|
+
description="Quantum-optimized AI agent workflow platform",
|
|
100
|
+
version="0.1.0",
|
|
101
|
+
lifespan=lifespan,
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
# CORS middleware
|
|
105
|
+
app.add_middleware(
|
|
106
|
+
CORSMiddleware,
|
|
107
|
+
allow_origins=["*"], # Configure for production
|
|
108
|
+
allow_credentials=True,
|
|
109
|
+
allow_methods=["*"],
|
|
110
|
+
allow_headers=["*"],
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
# Include auth routes
|
|
114
|
+
app.include_router(auth_router)
|
|
115
|
+
|
|
116
|
+
# Include teleportation & secure messaging routes
|
|
117
|
+
app.include_router(teleport_router)
|
|
118
|
+
|
|
119
|
+
# Include billing routes if available
|
|
120
|
+
if BILLING_ENABLED and billing_router:
|
|
121
|
+
app.include_router(billing_router)
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
# === Health Endpoints ===
|
|
125
|
+
|
|
126
|
+
@app.get("/health", response_model=HealthResponse, tags=["Health"])
|
|
127
|
+
async def health_check():
|
|
128
|
+
"""Check API health status."""
|
|
129
|
+
return HealthResponse(
|
|
130
|
+
status="healthy",
|
|
131
|
+
version="0.1.0",
|
|
132
|
+
quantum_ready=_compressor is not None,
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
@app.get("/", tags=["Health"])
|
|
137
|
+
async def root():
|
|
138
|
+
"""API root endpoint."""
|
|
139
|
+
return {
|
|
140
|
+
"name": "QuantumFlow API",
|
|
141
|
+
"version": "0.1.0",
|
|
142
|
+
"docs": "/docs",
|
|
143
|
+
"database": "connected" if _db_initialized else "not connected",
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
# === Compression Endpoints (Paper 1) ===
|
|
148
|
+
|
|
149
|
+
@app.post("/v1/compress", response_model=CompressResponse, tags=["Compression"])
|
|
150
|
+
async def compress_tokens(
|
|
151
|
+
request: CompressRequest,
|
|
152
|
+
http_request: Request,
|
|
153
|
+
user: Optional[User] = Depends(get_optional_user),
|
|
154
|
+
):
|
|
155
|
+
"""
|
|
156
|
+
Compress tokens using quantum amplitude encoding.
|
|
157
|
+
|
|
158
|
+
Achieves 53% token reduction via quantum superposition.
|
|
159
|
+
"""
|
|
160
|
+
if not _compressor:
|
|
161
|
+
raise HTTPException(status_code=503, detail="Quantum compressor not initialized")
|
|
162
|
+
|
|
163
|
+
start_time = time.perf_counter()
|
|
164
|
+
|
|
165
|
+
try:
|
|
166
|
+
if request.execute:
|
|
167
|
+
result = _compressor.compress_and_execute(
|
|
168
|
+
tokens=request.tokens,
|
|
169
|
+
compression_level=request.compression_level,
|
|
170
|
+
shots=request.shots,
|
|
171
|
+
)
|
|
172
|
+
fidelity = result.execution_result.fidelity if result.execution_result else None
|
|
173
|
+
else:
|
|
174
|
+
result = _compressor.compress(
|
|
175
|
+
tokens=request.tokens,
|
|
176
|
+
compression_level=request.compression_level,
|
|
177
|
+
)
|
|
178
|
+
fidelity = None
|
|
179
|
+
|
|
180
|
+
execution_time = (time.perf_counter() - start_time) * 1000
|
|
181
|
+
|
|
182
|
+
# Track usage if user is authenticated and db is available
|
|
183
|
+
if user and _db_initialized:
|
|
184
|
+
try:
|
|
185
|
+
db = next(get_db_session())
|
|
186
|
+
crud.create_usage_record(
|
|
187
|
+
db,
|
|
188
|
+
user_id=user.id,
|
|
189
|
+
endpoint="/v1/compress",
|
|
190
|
+
method="POST",
|
|
191
|
+
tokens_input=len(request.tokens),
|
|
192
|
+
tokens_output=result.n_qubits,
|
|
193
|
+
qubits_used=result.n_qubits,
|
|
194
|
+
execution_time_ms=execution_time,
|
|
195
|
+
ip_address=http_request.client.host if http_request.client else None,
|
|
196
|
+
)
|
|
197
|
+
except Exception:
|
|
198
|
+
pass # Don't fail request if usage tracking fails
|
|
199
|
+
|
|
200
|
+
return CompressResponse(
|
|
201
|
+
input_tokens=result.input_token_count,
|
|
202
|
+
output_qubits=result.n_qubits,
|
|
203
|
+
tokens_saved=result.tokens_saved,
|
|
204
|
+
compression_ratio=result.compression_ratio,
|
|
205
|
+
compression_percent=result.compression_percentage,
|
|
206
|
+
fidelity=fidelity,
|
|
207
|
+
execution_time_ms=execution_time,
|
|
208
|
+
backend_used=request.backend,
|
|
209
|
+
)
|
|
210
|
+
|
|
211
|
+
except Exception as e:
|
|
212
|
+
raise HTTPException(status_code=400, detail=str(e))
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
# === Gradient Endpoints (Paper 2) ===
|
|
216
|
+
|
|
217
|
+
@app.post("/v1/gradient", response_model=GradientResponse, tags=["Backpropagation"])
|
|
218
|
+
async def compute_gradient(
|
|
219
|
+
request: GradientRequest,
|
|
220
|
+
user: Optional[User] = Depends(get_optional_user),
|
|
221
|
+
):
|
|
222
|
+
"""
|
|
223
|
+
Compute gradient using quantum teleportation protocol.
|
|
224
|
+
|
|
225
|
+
Achieves 97.78% similarity with classical gradients.
|
|
226
|
+
"""
|
|
227
|
+
if not _backprop:
|
|
228
|
+
raise HTTPException(status_code=503, detail="Quantum backprop not initialized")
|
|
229
|
+
|
|
230
|
+
start_time = time.perf_counter()
|
|
231
|
+
|
|
232
|
+
try:
|
|
233
|
+
result = _backprop.compute_gradient(
|
|
234
|
+
input_state=np.array(request.input_state),
|
|
235
|
+
target_state=np.array(request.target_state),
|
|
236
|
+
weights=np.array(request.weights),
|
|
237
|
+
shots=request.shots,
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
execution_time = (time.perf_counter() - start_time) * 1000
|
|
241
|
+
|
|
242
|
+
return GradientResponse(
|
|
243
|
+
gradients=result.gradients.tolist(),
|
|
244
|
+
bit_x=result.bit_x,
|
|
245
|
+
bit_z=result.bit_z,
|
|
246
|
+
gradient_direction=result.gradient_direction,
|
|
247
|
+
gradient_magnitude=result.gradient_magnitude,
|
|
248
|
+
classical_similarity=abs(result.similarity),
|
|
249
|
+
execution_time_ms=execution_time,
|
|
250
|
+
)
|
|
251
|
+
|
|
252
|
+
except Exception as e:
|
|
253
|
+
raise HTTPException(status_code=400, detail=str(e))
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
# === Backend Endpoints ===
|
|
257
|
+
|
|
258
|
+
@app.get("/v1/backends", response_model=BackendsResponse, tags=["Backends"])
|
|
259
|
+
async def list_backends():
|
|
260
|
+
"""List available quantum backends."""
|
|
261
|
+
backends = [
|
|
262
|
+
BackendStatus(
|
|
263
|
+
name="simulator",
|
|
264
|
+
status="online",
|
|
265
|
+
is_simulator=True,
|
|
266
|
+
max_qubits=30,
|
|
267
|
+
),
|
|
268
|
+
BackendStatus(
|
|
269
|
+
name="ibm",
|
|
270
|
+
status="available",
|
|
271
|
+
is_simulator=False,
|
|
272
|
+
max_qubits=156,
|
|
273
|
+
queue_position=None,
|
|
274
|
+
),
|
|
275
|
+
# AWS Braket backends
|
|
276
|
+
BackendStatus(
|
|
277
|
+
name="aws_sv1",
|
|
278
|
+
status="available",
|
|
279
|
+
is_simulator=True,
|
|
280
|
+
max_qubits=34,
|
|
281
|
+
),
|
|
282
|
+
BackendStatus(
|
|
283
|
+
name="aws_ionq",
|
|
284
|
+
status="available",
|
|
285
|
+
is_simulator=False,
|
|
286
|
+
max_qubits=25,
|
|
287
|
+
),
|
|
288
|
+
BackendStatus(
|
|
289
|
+
name="aws_rigetti",
|
|
290
|
+
status="available",
|
|
291
|
+
is_simulator=False,
|
|
292
|
+
max_qubits=80,
|
|
293
|
+
),
|
|
294
|
+
]
|
|
295
|
+
return BackendsResponse(backends=backends)
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
# === Memory Endpoints ===
|
|
299
|
+
|
|
300
|
+
@app.post("/v1/memory/store", response_model=MemoryStoreResponse, tags=["Memory"])
|
|
301
|
+
async def memory_store(
|
|
302
|
+
request: MemoryStoreRequest,
|
|
303
|
+
user: Optional[User] = Depends(get_optional_user),
|
|
304
|
+
):
|
|
305
|
+
"""Store data in quantum memory."""
|
|
306
|
+
if not _memory:
|
|
307
|
+
raise HTTPException(status_code=503, detail="Quantum memory not initialized")
|
|
308
|
+
|
|
309
|
+
try:
|
|
310
|
+
slot = _memory.store(request.key, request.values, compress=request.compress)
|
|
311
|
+
|
|
312
|
+
return MemoryStoreResponse(
|
|
313
|
+
key=request.key,
|
|
314
|
+
stored_count=len(request.values),
|
|
315
|
+
qubits_used=slot.compressed.n_qubits if slot.compressed else None,
|
|
316
|
+
compression_ratio=slot.compressed.compression_ratio if slot.compressed else None,
|
|
317
|
+
)
|
|
318
|
+
|
|
319
|
+
except Exception as e:
|
|
320
|
+
raise HTTPException(status_code=400, detail=str(e))
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
@app.get("/v1/memory/{key}", response_model=MemoryRetrieveResponse, tags=["Memory"])
|
|
324
|
+
async def memory_retrieve(
|
|
325
|
+
key: str,
|
|
326
|
+
user: Optional[User] = Depends(get_optional_user),
|
|
327
|
+
):
|
|
328
|
+
"""Retrieve data from quantum memory."""
|
|
329
|
+
if not _memory:
|
|
330
|
+
raise HTTPException(status_code=503, detail="Quantum memory not initialized")
|
|
331
|
+
|
|
332
|
+
try:
|
|
333
|
+
values = _memory.retrieve(key)
|
|
334
|
+
return MemoryRetrieveResponse(key=key, values=values)
|
|
335
|
+
except KeyError:
|
|
336
|
+
raise HTTPException(status_code=404, detail=f"Key '{key}' not found")
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+
@app.delete("/v1/memory/{key}", tags=["Memory"])
|
|
340
|
+
async def memory_delete(
|
|
341
|
+
key: str,
|
|
342
|
+
user: Optional[User] = Depends(get_optional_user),
|
|
343
|
+
):
|
|
344
|
+
"""Delete data from quantum memory."""
|
|
345
|
+
if not _memory:
|
|
346
|
+
raise HTTPException(status_code=503, detail="Quantum memory not initialized")
|
|
347
|
+
|
|
348
|
+
if _memory.delete(key):
|
|
349
|
+
return {"deleted": True, "key": key}
|
|
350
|
+
raise HTTPException(status_code=404, detail=f"Key '{key}' not found")
|
|
351
|
+
|
|
352
|
+
|
|
353
|
+
@app.get("/v1/memory", response_model=MemoryStatsResponse, tags=["Memory"])
|
|
354
|
+
async def memory_stats(user: Optional[User] = Depends(get_optional_user)):
|
|
355
|
+
"""Get quantum memory statistics."""
|
|
356
|
+
if not _memory:
|
|
357
|
+
raise HTTPException(status_code=503, detail="Quantum memory not initialized")
|
|
358
|
+
|
|
359
|
+
stats = _memory.get_stats()
|
|
360
|
+
return MemoryStatsResponse(
|
|
361
|
+
total_items=stats.total_items,
|
|
362
|
+
classical_size=stats.classical_size,
|
|
363
|
+
quantum_size=stats.quantum_size,
|
|
364
|
+
compression_ratio=stats.compression_ratio,
|
|
365
|
+
memory_saved_percent=stats.memory_saved_percent,
|
|
366
|
+
)
|
|
367
|
+
|
|
368
|
+
|
|
369
|
+
# === Entanglement Endpoints ===
|
|
370
|
+
|
|
371
|
+
@app.post("/v1/entangle", response_model=EntangleResponse, tags=["Entanglement"])
|
|
372
|
+
async def create_entanglement(
|
|
373
|
+
request: EntangleRequest,
|
|
374
|
+
user: Optional[User] = Depends(get_optional_user),
|
|
375
|
+
):
|
|
376
|
+
"""Create entangled state from multiple contexts."""
|
|
377
|
+
if not _entangler:
|
|
378
|
+
raise HTTPException(status_code=503, detail="Entangler not initialized")
|
|
379
|
+
|
|
380
|
+
try:
|
|
381
|
+
if len(request.contexts) == 2:
|
|
382
|
+
state = _entangler.entangle_contexts(
|
|
383
|
+
request.contexts[0],
|
|
384
|
+
request.contexts[1],
|
|
385
|
+
)
|
|
386
|
+
else:
|
|
387
|
+
state = _entangler.create_ghz_state(len(request.contexts))
|
|
388
|
+
|
|
389
|
+
return EntangleResponse(
|
|
390
|
+
n_qubits=state.n_qubits,
|
|
391
|
+
n_parties=state.n_parties,
|
|
392
|
+
entropy=state.entropy,
|
|
393
|
+
is_maximally_entangled=state.is_maximally_entangled,
|
|
394
|
+
)
|
|
395
|
+
|
|
396
|
+
except Exception as e:
|
|
397
|
+
raise HTTPException(status_code=400, detail=str(e))
|
|
398
|
+
|
|
399
|
+
|
|
400
|
+
# Run with: uvicorn api.main:app --reload
|
|
401
|
+
if __name__ == "__main__":
|
|
402
|
+
import uvicorn
|
|
403
|
+
uvicorn.run(app, host="0.0.0.0", port=8000)
|