Spaces:
Sleeping
Sleeping
Deploy Quantum Finance Analyzer
Browse files- .gitignore +2 -0
- README.md +49 -5
- app.py +837 -0
- config/agents.yaml +48 -0
- config/tasks.yaml +108 -0
- main.py +216 -0
- requirements.txt +23 -0
- src/__init__.py +8 -0
- src/quantum_finance_crew/__init__.py +11 -0
- src/quantum_finance_crew/crew.py +174 -0
- src/tools/__init__.py +25 -0
- src/tools/finance_tools.py +365 -0
- src/tools/quantum_tools.py +365 -0
- src/utils/__init__.py +21 -0
- src/utils/evaluation.py +377 -0
.gitignore
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
__pycache__/
|
| 2 |
+
*.pyc
|
README.md
CHANGED
|
@@ -1,14 +1,58 @@
|
|
| 1 |
---
|
| 2 |
title: Quantum Finance Analyzer
|
| 3 |
-
emoji:
|
| 4 |
colorFrom: indigo
|
| 5 |
-
colorTo:
|
| 6 |
sdk: gradio
|
| 7 |
-
sdk_version:
|
| 8 |
app_file: app.py
|
| 9 |
pinned: false
|
| 10 |
license: mit
|
| 11 |
-
short_description: CrewAI for searching through quantum finance applications
|
| 12 |
---
|
| 13 |
|
| 14 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
---
|
| 2 |
title: Quantum Finance Analyzer
|
| 3 |
+
emoji: "⚗"
|
| 4 |
colorFrom: indigo
|
| 5 |
+
colorTo: purple
|
| 6 |
sdk: gradio
|
| 7 |
+
sdk_version: "4.44.0"
|
| 8 |
app_file: app.py
|
| 9 |
pinned: false
|
| 10 |
license: mit
|
|
|
|
| 11 |
---
|
| 12 |
|
| 13 |
+
# Quantum Finance Feasibility Analyzer
|
| 14 |
+
|
| 15 |
+
An interactive tool for evaluating quantum computing applications in finance.
|
| 16 |
+
Assess whether your quantum finance ideas are viable on current NISQ hardware.
|
| 17 |
+
|
| 18 |
+
## Features
|
| 19 |
+
|
| 20 |
+
- **Resource Estimation**: Calculate quantum resources for QAOA, Amplitude Estimation, and Grover's Search
|
| 21 |
+
- **Classical Benchmarks**: Compare quantum approaches against classical implementations (portfolio optimization, option pricing)
|
| 22 |
+
- **Use Case Analysis**: Pre-built feasibility analysis for common quantum finance applications
|
| 23 |
+
- **Custom Evaluation**: Evaluate your own quantum finance ideas with quick analysis or full CrewAI multi-agent evaluation
|
| 24 |
+
|
| 25 |
+
## Supported Quantum Hardware
|
| 26 |
+
|
| 27 |
+
- IBM Osprey (433 qubits)
|
| 28 |
+
- IBM Condor (1121 qubits)
|
| 29 |
+
- IonQ Forte (36 qubits)
|
| 30 |
+
- Google Sycamore (72 qubits)
|
| 31 |
+
|
| 32 |
+
## Use Cases
|
| 33 |
+
|
| 34 |
+
1. **Portfolio Optimization (QAOA)** - Quantum optimization for asset allocation
|
| 35 |
+
2. **Option Pricing (Amplitude Estimation)** - Quantum speedup for derivatives pricing
|
| 36 |
+
3. **Fraud Detection (Quantum ML)** - Variational quantum classifiers for anomaly detection
|
| 37 |
+
4. **Risk Analysis (Quantum Monte Carlo)** - VaR calculations with quantum acceleration
|
| 38 |
+
5. **Credit Scoring (VQC)** - Quantum-enhanced credit risk models
|
| 39 |
+
|
| 40 |
+
## Local Development
|
| 41 |
+
|
| 42 |
+
```bash
|
| 43 |
+
pip install -r requirements.txt
|
| 44 |
+
python app.py
|
| 45 |
+
```
|
| 46 |
+
|
| 47 |
+
## CLI Usage
|
| 48 |
+
|
| 49 |
+
```bash
|
| 50 |
+
python main.py --idea "Your quantum finance idea"
|
| 51 |
+
python main.py --batch # Run batch evaluation
|
| 52 |
+
```
|
| 53 |
+
|
| 54 |
+
## Built With
|
| 55 |
+
|
| 56 |
+
- [CrewAI](https://crewai.com) - Multi-agent AI framework
|
| 57 |
+
- [Gradio](https://gradio.app) - Web interface
|
| 58 |
+
- [Qiskit](https://qiskit.org) - Quantum computing framework
|
app.py
ADDED
|
@@ -0,0 +1,837 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""
|
| 3 |
+
Gradio Demo App for Quantum Finance Feasibility Analysis Framework.
|
| 4 |
+
|
| 5 |
+
This app provides an interactive interface for:
|
| 6 |
+
- Quantum resource estimation (QAOA, Amplitude Estimation, Grover's)
|
| 7 |
+
- Classical benchmark comparisons (portfolio optimization, option pricing)
|
| 8 |
+
- Multi-agent evaluation of quantum finance ideas
|
| 9 |
+
- Pre-built use case demonstrations
|
| 10 |
+
"""
|
| 11 |
+
|
| 12 |
+
import sys
|
| 13 |
+
from pathlib import Path
|
| 14 |
+
|
| 15 |
+
# Add src to path
|
| 16 |
+
sys.path.insert(0, str(Path(__file__).parent / "src"))
|
| 17 |
+
|
| 18 |
+
import gradio as gr
|
| 19 |
+
import numpy as np
|
| 20 |
+
import pandas as pd
|
| 21 |
+
|
| 22 |
+
from tools import (
|
| 23 |
+
QuantumResourceEstimator,
|
| 24 |
+
ClassicalPortfolioOptimizer,
|
| 25 |
+
OptionPricer,
|
| 26 |
+
FinanceDataCollector,
|
| 27 |
+
)
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
# ============================================================================
|
| 31 |
+
# QUANTUM RESOURCE ESTIMATION TAB
|
| 32 |
+
# ============================================================================
|
| 33 |
+
|
| 34 |
+
def estimate_qaoa_resources(hardware: str, num_assets: int, p_layers: int):
|
| 35 |
+
"""Estimate QAOA resources for portfolio optimization."""
|
| 36 |
+
hardware_map = {
|
| 37 |
+
"IBM Osprey (433 qubits)": "ibm_osprey",
|
| 38 |
+
"IBM Condor (1121 qubits)": "ibm_condor",
|
| 39 |
+
"IonQ Forte (36 qubits)": "ionq_forte",
|
| 40 |
+
"Google Sycamore (72 qubits)": "google_sycamore",
|
| 41 |
+
}
|
| 42 |
+
|
| 43 |
+
estimator = QuantumResourceEstimator(hardware_map[hardware])
|
| 44 |
+
result = estimator.estimate_qaoa_resources(num_assets=int(num_assets), p_layers=int(p_layers))
|
| 45 |
+
|
| 46 |
+
# Format output
|
| 47 |
+
feasibility = "FEASIBLE" if result['feasible_on_hardware'] else "NOT FEASIBLE"
|
| 48 |
+
feasibility_color = "green" if result['feasible_on_hardware'] else "red"
|
| 49 |
+
|
| 50 |
+
output = f"""## QAOA Resource Estimation Results
|
| 51 |
+
|
| 52 |
+
### Hardware: {hardware}
|
| 53 |
+
|
| 54 |
+
| Metric | Value |
|
| 55 |
+
|--------|-------|
|
| 56 |
+
| Qubits Required | {result['qubits_required']} |
|
| 57 |
+
| Qubits Available | {result['qubits_available']} |
|
| 58 |
+
| 1-Qubit Gates | {result['total_1q_gates']:,} |
|
| 59 |
+
| 2-Qubit Gates | {result['total_2q_gates']:,} |
|
| 60 |
+
| Circuit Depth | {result['circuit_depth']} |
|
| 61 |
+
| Execution Time | {result['execution_time_us']:.2f} us |
|
| 62 |
+
| Coherence Time | {result['coherence_time_us']:.0f} us |
|
| 63 |
+
| Success Probability | {result['success_probability']:.2e} |
|
| 64 |
+
|
| 65 |
+
### Feasibility: **{feasibility}**
|
| 66 |
+
|
| 67 |
+
**Bottleneck:** {result['bottleneck']}
|
| 68 |
+
"""
|
| 69 |
+
return output
|
| 70 |
+
|
| 71 |
+
|
| 72 |
+
def estimate_amplitude_resources(hardware: str, precision_bits: int, oracle_qubits: int):
|
| 73 |
+
"""Estimate Amplitude Estimation resources for option pricing."""
|
| 74 |
+
hardware_map = {
|
| 75 |
+
"IBM Osprey (433 qubits)": "ibm_osprey",
|
| 76 |
+
"IBM Condor (1121 qubits)": "ibm_condor",
|
| 77 |
+
"IonQ Forte (36 qubits)": "ionq_forte",
|
| 78 |
+
"Google Sycamore (72 qubits)": "google_sycamore",
|
| 79 |
+
}
|
| 80 |
+
|
| 81 |
+
estimator = QuantumResourceEstimator(hardware_map[hardware])
|
| 82 |
+
result = estimator.estimate_amplitude_estimation_resources(
|
| 83 |
+
precision_bits=int(precision_bits),
|
| 84 |
+
num_qubits_oracle=int(oracle_qubits)
|
| 85 |
+
)
|
| 86 |
+
|
| 87 |
+
feasibility = "FEASIBLE" if result['feasible_on_hardware'] else "NOT FEASIBLE"
|
| 88 |
+
|
| 89 |
+
output = f"""## Amplitude Estimation Resource Results
|
| 90 |
+
|
| 91 |
+
### Hardware: {hardware}
|
| 92 |
+
|
| 93 |
+
| Metric | Value |
|
| 94 |
+
|--------|-------|
|
| 95 |
+
| Qubits Required | {result['qubits_required']} |
|
| 96 |
+
| Qubits Available | {result['qubits_available']} |
|
| 97 |
+
| Oracle Calls | {result['oracle_calls']:,} |
|
| 98 |
+
| 2-Qubit Gates | {result['total_2q_gates']:,} |
|
| 99 |
+
| Execution Time | {result['execution_time_us']:.2f} us |
|
| 100 |
+
| Coherence Time | {result['coherence_time_us']:.0f} us |
|
| 101 |
+
| Success Probability | {result['success_probability']:.2e} |
|
| 102 |
+
|
| 103 |
+
### Feasibility: **{feasibility}**
|
| 104 |
+
|
| 105 |
+
**Bottleneck:** {result['bottleneck']}
|
| 106 |
+
|
| 107 |
+
**Note:** Amplitude estimation provides quadratic speedup over classical Monte Carlo
|
| 108 |
+
for option pricing, but requires fault-tolerant quantum computers for practical precision.
|
| 109 |
+
"""
|
| 110 |
+
return output
|
| 111 |
+
|
| 112 |
+
|
| 113 |
+
def estimate_grover_resources(hardware: str, search_space_log: int):
|
| 114 |
+
"""Estimate Grover's search resources for fraud detection."""
|
| 115 |
+
hardware_map = {
|
| 116 |
+
"IBM Osprey (433 qubits)": "ibm_osprey",
|
| 117 |
+
"IBM Condor (1121 qubits)": "ibm_condor",
|
| 118 |
+
"IonQ Forte (36 qubits)": "ionq_forte",
|
| 119 |
+
"Google Sycamore (72 qubits)": "google_sycamore",
|
| 120 |
+
}
|
| 121 |
+
|
| 122 |
+
search_space_size = 10 ** int(search_space_log)
|
| 123 |
+
estimator = QuantumResourceEstimator(hardware_map[hardware])
|
| 124 |
+
result = estimator.estimate_grover_resources(search_space_size=search_space_size)
|
| 125 |
+
|
| 126 |
+
feasibility = "FEASIBLE" if result['feasible_on_hardware'] else "NOT FEASIBLE"
|
| 127 |
+
|
| 128 |
+
output = f"""## Grover's Search Resource Results
|
| 129 |
+
|
| 130 |
+
### Hardware: {hardware}
|
| 131 |
+
### Search Space: 10^{search_space_log} = {search_space_size:,} records
|
| 132 |
+
|
| 133 |
+
| Metric | Value |
|
| 134 |
+
|--------|-------|
|
| 135 |
+
| Qubits Required | {result['qubits_required']} |
|
| 136 |
+
| Qubits Available | {result['qubits_available']} |
|
| 137 |
+
| Grover Iterations | {result['grover_iterations']:,} |
|
| 138 |
+
| 2-Qubit Gates | {result['total_2q_gates']:,} |
|
| 139 |
+
| Execution Time | {result['execution_time_us']:.2f} us |
|
| 140 |
+
| Coherence Time | {result['coherence_time_us']:.0f} us |
|
| 141 |
+
| Success Probability | {result['success_probability']:.2e} |
|
| 142 |
+
|
| 143 |
+
### Feasibility: **{feasibility}**
|
| 144 |
+
|
| 145 |
+
**Classical Speedup:** {result['classical_speedup']}
|
| 146 |
+
|
| 147 |
+
**Bottleneck:** {result['bottleneck']}
|
| 148 |
+
"""
|
| 149 |
+
return output
|
| 150 |
+
|
| 151 |
+
|
| 152 |
+
# ============================================================================
|
| 153 |
+
# CLASSICAL BENCHMARKS TAB
|
| 154 |
+
# ============================================================================
|
| 155 |
+
|
| 156 |
+
def run_portfolio_optimization(n_assets: int, n_trials: int):
|
| 157 |
+
"""Run classical portfolio optimization benchmark."""
|
| 158 |
+
collector = FinanceDataCollector(
|
| 159 |
+
tickers=FinanceDataCollector.DEFAULT_TICKERS[:int(n_assets)]
|
| 160 |
+
)
|
| 161 |
+
|
| 162 |
+
prices = collector.fetch_historical_data(period="1y")
|
| 163 |
+
returns = collector.calculate_returns(prices)
|
| 164 |
+
cov_matrix = collector.calculate_covariance_matrix(returns)
|
| 165 |
+
exp_returns = collector.calculate_expected_returns(returns)
|
| 166 |
+
|
| 167 |
+
optimizer = ClassicalPortfolioOptimizer(
|
| 168 |
+
exp_returns.values,
|
| 169 |
+
cov_matrix.values
|
| 170 |
+
)
|
| 171 |
+
|
| 172 |
+
result = optimizer.optimize_markowitz()
|
| 173 |
+
timing = optimizer.benchmark_timing(n_trials=int(n_trials))
|
| 174 |
+
|
| 175 |
+
# Format weights table
|
| 176 |
+
weights_df = pd.DataFrame({
|
| 177 |
+
'Asset': exp_returns.index,
|
| 178 |
+
'Weight': [f"{w:.4f}" for w in result['weights']],
|
| 179 |
+
'Expected Return': [f"{r:.4f}" for r in exp_returns.values]
|
| 180 |
+
})
|
| 181 |
+
|
| 182 |
+
# Top allocations
|
| 183 |
+
top_indices = np.argsort(result['weights'])[-5:][::-1]
|
| 184 |
+
top_assets = [(exp_returns.index[i], result['weights'][i]) for i in top_indices]
|
| 185 |
+
|
| 186 |
+
output = f"""## Classical Portfolio Optimization Results
|
| 187 |
+
|
| 188 |
+
### Portfolio Statistics
|
| 189 |
+
|
| 190 |
+
| Metric | Value |
|
| 191 |
+
|--------|-------|
|
| 192 |
+
| Number of Assets | {n_assets} |
|
| 193 |
+
| Expected Annual Return | {result['expected_return']:.4f} ({result['expected_return']*100:.2f}%) |
|
| 194 |
+
| Annual Volatility | {result['volatility']:.4f} ({result['volatility']*100:.2f}%) |
|
| 195 |
+
| Sharpe Ratio | {result['sharpe_ratio']:.4f} |
|
| 196 |
+
| Solver | {result['solver']} |
|
| 197 |
+
|
| 198 |
+
### Top 5 Portfolio Allocations
|
| 199 |
+
|
| 200 |
+
| Asset | Weight |
|
| 201 |
+
|-------|--------|
|
| 202 |
+
"""
|
| 203 |
+
for asset, weight in top_assets:
|
| 204 |
+
output += f"| {asset} | {weight:.4f} ({weight*100:.2f}%) |\n"
|
| 205 |
+
|
| 206 |
+
output += f"""
|
| 207 |
+
### Timing Benchmark ({n_trials} trials)
|
| 208 |
+
|
| 209 |
+
| Metric | Value |
|
| 210 |
+
|--------|-------|
|
| 211 |
+
| Mean Time | {timing['mean_time_ms']:.3f} ms |
|
| 212 |
+
| Std Dev | {timing['std_time_ms']:.3f} ms |
|
| 213 |
+
| Min Time | {timing['min_time_ms']:.3f} ms |
|
| 214 |
+
| Max Time | {timing['max_time_ms']:.3f} ms |
|
| 215 |
+
|
| 216 |
+
**Quantum Comparison:** QAOA would require ~{n_assets} qubits with O(n^2) 2-qubit gates per layer.
|
| 217 |
+
Classical optimization at this scale is highly efficient and quantum advantage is unlikely.
|
| 218 |
+
"""
|
| 219 |
+
return output
|
| 220 |
+
|
| 221 |
+
|
| 222 |
+
def run_option_pricing(spot: float, strike: float, maturity: float, rate: float, volatility: float, n_paths: int):
|
| 223 |
+
"""Run option pricing comparison."""
|
| 224 |
+
# Black-Scholes analytical
|
| 225 |
+
bs_price = OptionPricer.black_scholes_call(
|
| 226 |
+
S=spot, K=strike, T=maturity, r=rate, sigma=volatility
|
| 227 |
+
)
|
| 228 |
+
|
| 229 |
+
# Monte Carlo
|
| 230 |
+
mc_result = OptionPricer.monte_carlo_call(
|
| 231 |
+
S=spot, K=strike, T=maturity, r=rate, sigma=volatility,
|
| 232 |
+
n_paths=int(n_paths)
|
| 233 |
+
)
|
| 234 |
+
|
| 235 |
+
# Timing benchmark
|
| 236 |
+
import time
|
| 237 |
+
times = []
|
| 238 |
+
for _ in range(10):
|
| 239 |
+
start = time.perf_counter()
|
| 240 |
+
OptionPricer.monte_carlo_call(
|
| 241 |
+
S=spot, K=strike, T=maturity, r=rate, sigma=volatility,
|
| 242 |
+
n_paths=int(n_paths)
|
| 243 |
+
)
|
| 244 |
+
times.append(time.perf_counter() - start)
|
| 245 |
+
|
| 246 |
+
mean_time = np.mean(times) * 1000
|
| 247 |
+
|
| 248 |
+
output = f"""## Option Pricing Comparison
|
| 249 |
+
|
| 250 |
+
### Parameters
|
| 251 |
+
|
| 252 |
+
| Parameter | Value |
|
| 253 |
+
|-----------|-------|
|
| 254 |
+
| Spot Price (S) | ${spot:.2f} |
|
| 255 |
+
| Strike Price (K) | ${strike:.2f} |
|
| 256 |
+
| Time to Maturity | {maturity:.2f} years |
|
| 257 |
+
| Risk-Free Rate | {rate*100:.2f}% |
|
| 258 |
+
| Volatility | {volatility*100:.2f}% |
|
| 259 |
+
|
| 260 |
+
### Results
|
| 261 |
+
|
| 262 |
+
| Method | Price | Notes |
|
| 263 |
+
|--------|-------|-------|
|
| 264 |
+
| Black-Scholes (Analytical) | ${bs_price:.4f} | Exact solution |
|
| 265 |
+
| Monte Carlo ({n_paths:,} paths) | ${mc_result['price']:.4f} | Std Error: {mc_result['std_error']:.6f} |
|
| 266 |
+
|
| 267 |
+
**95% Confidence Interval:** ${mc_result['confidence_interval_95'][0]:.4f} - ${mc_result['confidence_interval_95'][1]:.4f}
|
| 268 |
+
|
| 269 |
+
### Monte Carlo Timing (10 trials)
|
| 270 |
+
|
| 271 |
+
| Metric | Value |
|
| 272 |
+
|--------|-------|
|
| 273 |
+
| Mean Time | {mean_time:.3f} ms |
|
| 274 |
+
| Paths/Second | {int(n_paths)/(mean_time/1000):,.0f} |
|
| 275 |
+
|
| 276 |
+
### Quantum Advantage Analysis
|
| 277 |
+
|
| 278 |
+
**Amplitude Estimation** promises quadratic speedup over Monte Carlo:
|
| 279 |
+
- Classical: O(1/epsilon^2) paths for precision epsilon
|
| 280 |
+
- Quantum: O(1/epsilon) oracle calls
|
| 281 |
+
|
| 282 |
+
For {volatility*100:.0f}% vol option with 0.01% precision:
|
| 283 |
+
- Classical Monte Carlo: ~100M paths needed
|
| 284 |
+
- Quantum (theoretical): ~10K oracle calls
|
| 285 |
+
|
| 286 |
+
**Reality Check:** Current NISQ hardware cannot achieve the required circuit depth
|
| 287 |
+
for meaningful amplitude estimation. Error rates and coherence times are limiting factors.
|
| 288 |
+
"""
|
| 289 |
+
return output
|
| 290 |
+
|
| 291 |
+
|
| 292 |
+
# ============================================================================
|
| 293 |
+
# USE CASES TAB
|
| 294 |
+
# ============================================================================
|
| 295 |
+
|
| 296 |
+
TEST_CASES = [
|
| 297 |
+
{
|
| 298 |
+
'id': 'portfolio_optimization',
|
| 299 |
+
'name': 'Portfolio Optimization (QAOA)',
|
| 300 |
+
'idea': 'Quantum portfolio optimization using QAOA for a 100-asset portfolio with mean-variance objective',
|
| 301 |
+
'category': 'optimization',
|
| 302 |
+
'description': 'Use QAOA to find optimal portfolio weights minimizing variance for target return.'
|
| 303 |
+
},
|
| 304 |
+
{
|
| 305 |
+
'id': 'option_pricing',
|
| 306 |
+
'name': 'Option Pricing (Amplitude Estimation)',
|
| 307 |
+
'idea': 'Quantum amplitude estimation for pricing European call options with 8-bit precision',
|
| 308 |
+
'category': 'pricing',
|
| 309 |
+
'description': 'Use quantum amplitude estimation to price derivatives faster than Monte Carlo.'
|
| 310 |
+
},
|
| 311 |
+
{
|
| 312 |
+
'id': 'fraud_detection',
|
| 313 |
+
'name': 'Fraud Detection (Quantum ML)',
|
| 314 |
+
'idea': 'Quantum machine learning classifier for real-time credit card fraud detection',
|
| 315 |
+
'category': 'ml',
|
| 316 |
+
'description': 'Use variational quantum classifiers for pattern recognition in transactions.'
|
| 317 |
+
},
|
| 318 |
+
{
|
| 319 |
+
'id': 'risk_analysis',
|
| 320 |
+
'name': 'Risk Analysis (Quantum Monte Carlo)',
|
| 321 |
+
'idea': 'Quantum Monte Carlo for Value-at-Risk (VaR) calculation on a derivatives portfolio',
|
| 322 |
+
'category': 'risk',
|
| 323 |
+
'description': 'Use quantum speedup for risk metric calculations.'
|
| 324 |
+
},
|
| 325 |
+
{
|
| 326 |
+
'id': 'credit_scoring',
|
| 327 |
+
'name': 'Credit Scoring (VQC)',
|
| 328 |
+
'idea': 'Variational quantum classifier for credit scoring using customer financial data',
|
| 329 |
+
'category': 'ml',
|
| 330 |
+
'description': 'Use VQC for binary classification of creditworthiness.'
|
| 331 |
+
}
|
| 332 |
+
]
|
| 333 |
+
|
| 334 |
+
|
| 335 |
+
def analyze_use_case(case_name: str):
|
| 336 |
+
"""Analyze a pre-built use case."""
|
| 337 |
+
case = next((c for c in TEST_CASES if c['name'] == case_name), None)
|
| 338 |
+
if not case:
|
| 339 |
+
return "Use case not found"
|
| 340 |
+
|
| 341 |
+
# Run resource estimation based on category
|
| 342 |
+
estimator = QuantumResourceEstimator('ibm_osprey')
|
| 343 |
+
|
| 344 |
+
if case['category'] == 'optimization':
|
| 345 |
+
resources = estimator.estimate_qaoa_resources(num_assets=100, p_layers=3)
|
| 346 |
+
algorithm = "QAOA"
|
| 347 |
+
classical_time = "~10ms with scipy"
|
| 348 |
+
elif case['category'] == 'pricing':
|
| 349 |
+
resources = estimator.estimate_amplitude_estimation_resources(
|
| 350 |
+
precision_bits=8, num_qubits_oracle=20
|
| 351 |
+
)
|
| 352 |
+
algorithm = "Amplitude Estimation"
|
| 353 |
+
classical_time = "~100ms Monte Carlo (1M paths)"
|
| 354 |
+
elif case['category'] == 'risk':
|
| 355 |
+
resources = estimator.estimate_amplitude_estimation_resources(
|
| 356 |
+
precision_bits=10, num_qubits_oracle=30
|
| 357 |
+
)
|
| 358 |
+
algorithm = "Quantum Monte Carlo"
|
| 359 |
+
classical_time = "~1s Monte Carlo (10M paths)"
|
| 360 |
+
else: # ml
|
| 361 |
+
resources = estimator.estimate_qaoa_resources(num_assets=50, p_layers=5)
|
| 362 |
+
algorithm = "Variational Quantum Classifier"
|
| 363 |
+
classical_time = "~5ms classical ML inference"
|
| 364 |
+
|
| 365 |
+
feasibility = "FEASIBLE" if resources['feasible_on_hardware'] else "NOT FEASIBLE"
|
| 366 |
+
|
| 367 |
+
output = f"""## Use Case Analysis: {case['name']}
|
| 368 |
+
|
| 369 |
+
### Description
|
| 370 |
+
{case['description']}
|
| 371 |
+
|
| 372 |
+
### Proposed Idea
|
| 373 |
+
> {case['idea']}
|
| 374 |
+
|
| 375 |
+
### Algorithm: {algorithm}
|
| 376 |
+
|
| 377 |
+
### Resource Requirements (IBM Osprey)
|
| 378 |
+
|
| 379 |
+
| Metric | Value |
|
| 380 |
+
|--------|-------|
|
| 381 |
+
| Qubits Required | {resources['qubits_required']} |
|
| 382 |
+
| Qubits Available | {resources['qubits_available']} |
|
| 383 |
+
| Total 2-Qubit Gates | {resources.get('total_2q_gates', 'N/A'):,} |
|
| 384 |
+
| Execution Time | {resources['execution_time_us']:.2f} us |
|
| 385 |
+
| Coherence Time | {resources['coherence_time_us']:.0f} us |
|
| 386 |
+
| Success Probability | {resources['success_probability']:.2e} |
|
| 387 |
+
|
| 388 |
+
### Feasibility Assessment: **{feasibility}**
|
| 389 |
+
|
| 390 |
+
**Bottleneck:** {resources['bottleneck']}
|
| 391 |
+
|
| 392 |
+
### Quantum vs Classical Comparison
|
| 393 |
+
|
| 394 |
+
| Aspect | Quantum | Classical |
|
| 395 |
+
|--------|---------|-----------|
|
| 396 |
+
| Execution Time | {resources['execution_time_us']:.2f} us (per shot) | {classical_time} |
|
| 397 |
+
| Error Rate | {(1-resources['success_probability'])*100:.2f}% failure | Deterministic |
|
| 398 |
+
| Scalability | Limited by coherence | Memory-bound |
|
| 399 |
+
|
| 400 |
+
### Verdict
|
| 401 |
+
|
| 402 |
+
"""
|
| 403 |
+
if resources['feasible_on_hardware']:
|
| 404 |
+
output += """**Potentially viable** on current hardware, but likely no practical advantage over
|
| 405 |
+
classical methods due to:
|
| 406 |
+
- High shot count requirements for statistical accuracy
|
| 407 |
+
- Variational parameter optimization overhead
|
| 408 |
+
- Limited problem sizes that fit in coherence window
|
| 409 |
+
"""
|
| 410 |
+
else:
|
| 411 |
+
output += f"""**Not viable** on current NISQ hardware due to:
|
| 412 |
+
- {resources['bottleneck']}
|
| 413 |
+
|
| 414 |
+
**Timeline:** This application likely requires fault-tolerant quantum computers
|
| 415 |
+
(estimated 2030+ for practical advantage).
|
| 416 |
+
"""
|
| 417 |
+
|
| 418 |
+
return output
|
| 419 |
+
|
| 420 |
+
|
| 421 |
+
# ============================================================================
|
| 422 |
+
# IDEA EVALUATION TAB (CrewAI Integration)
|
| 423 |
+
# ============================================================================
|
| 424 |
+
|
| 425 |
+
def evaluate_idea_quick(idea: str):
|
| 426 |
+
"""Quick evaluation without full CrewAI (for demo purposes)."""
|
| 427 |
+
if not idea.strip():
|
| 428 |
+
return "Please enter a quantum finance idea to evaluate."
|
| 429 |
+
|
| 430 |
+
# Analyze the idea based on keywords
|
| 431 |
+
idea_lower = idea.lower()
|
| 432 |
+
|
| 433 |
+
# Determine algorithm type
|
| 434 |
+
if any(word in idea_lower for word in ['portfolio', 'optimization', 'qaoa']):
|
| 435 |
+
algorithm = "QAOA"
|
| 436 |
+
estimator = QuantumResourceEstimator('ibm_osprey')
|
| 437 |
+
# Extract asset count if mentioned
|
| 438 |
+
import re
|
| 439 |
+
match = re.search(r'(\d+)[- ]?asset', idea_lower)
|
| 440 |
+
n_assets = int(match.group(1)) if match else 50
|
| 441 |
+
resources = estimator.estimate_qaoa_resources(num_assets=n_assets, p_layers=3)
|
| 442 |
+
|
| 443 |
+
elif any(word in idea_lower for word in ['option', 'pricing', 'amplitude', 'derivative']):
|
| 444 |
+
algorithm = "Amplitude Estimation"
|
| 445 |
+
estimator = QuantumResourceEstimator('ibm_osprey')
|
| 446 |
+
resources = estimator.estimate_amplitude_estimation_resources(
|
| 447 |
+
precision_bits=8, num_qubits_oracle=20
|
| 448 |
+
)
|
| 449 |
+
|
| 450 |
+
elif any(word in idea_lower for word in ['fraud', 'detection', 'search', 'grover']):
|
| 451 |
+
algorithm = "Grover's Search / Quantum ML"
|
| 452 |
+
estimator = QuantumResourceEstimator('ibm_osprey')
|
| 453 |
+
resources = estimator.estimate_grover_resources(search_space_size=1_000_000)
|
| 454 |
+
|
| 455 |
+
elif any(word in idea_lower for word in ['risk', 'var', 'monte carlo', 'simulation']):
|
| 456 |
+
algorithm = "Quantum Monte Carlo"
|
| 457 |
+
estimator = QuantumResourceEstimator('ibm_osprey')
|
| 458 |
+
resources = estimator.estimate_amplitude_estimation_resources(
|
| 459 |
+
precision_bits=10, num_qubits_oracle=25
|
| 460 |
+
)
|
| 461 |
+
|
| 462 |
+
elif any(word in idea_lower for word in ['credit', 'scoring', 'classifier', 'ml', 'machine learning']):
|
| 463 |
+
algorithm = "Variational Quantum Classifier"
|
| 464 |
+
estimator = QuantumResourceEstimator('ibm_osprey')
|
| 465 |
+
resources = estimator.estimate_qaoa_resources(num_assets=30, p_layers=5)
|
| 466 |
+
|
| 467 |
+
else:
|
| 468 |
+
algorithm = "General Variational Algorithm"
|
| 469 |
+
estimator = QuantumResourceEstimator('ibm_osprey')
|
| 470 |
+
resources = estimator.estimate_qaoa_resources(num_assets=20, p_layers=2)
|
| 471 |
+
|
| 472 |
+
feasibility = "FEASIBLE" if resources['feasible_on_hardware'] else "NOT FEASIBLE"
|
| 473 |
+
|
| 474 |
+
# Generate assessment scores
|
| 475 |
+
scores = {
|
| 476 |
+
'algorithm_fit': 0.7 if resources['feasible_on_hardware'] else 0.3,
|
| 477 |
+
'hardware_readiness': resources['success_probability'],
|
| 478 |
+
'classical_comparison': 0.2 if not resources['feasible_on_hardware'] else 0.5,
|
| 479 |
+
'business_viability': 0.4 if resources['feasible_on_hardware'] else 0.1,
|
| 480 |
+
}
|
| 481 |
+
|
| 482 |
+
output = f"""## Quick Feasibility Analysis
|
| 483 |
+
|
| 484 |
+
### Your Idea
|
| 485 |
+
> {idea}
|
| 486 |
+
|
| 487 |
+
### Identified Algorithm: {algorithm}
|
| 488 |
+
|
| 489 |
+
### Hardware Feasibility (IBM Osprey)
|
| 490 |
+
|
| 491 |
+
| Metric | Value |
|
| 492 |
+
|--------|-------|
|
| 493 |
+
| Qubits Required | {resources['qubits_required']} |
|
| 494 |
+
| Qubits Available | {resources['qubits_available']} |
|
| 495 |
+
| Execution Time | {resources['execution_time_us']:.2f} us |
|
| 496 |
+
| Coherence Time | {resources['coherence_time_us']:.0f} us |
|
| 497 |
+
| Success Probability | {resources['success_probability']:.2e} |
|
| 498 |
+
|
| 499 |
+
### Overall Feasibility: **{feasibility}**
|
| 500 |
+
|
| 501 |
+
**Primary Bottleneck:** {resources['bottleneck']}
|
| 502 |
+
|
| 503 |
+
### Assessment Scores (0-1 scale)
|
| 504 |
+
|
| 505 |
+
| Dimension | Score | Interpretation |
|
| 506 |
+
|-----------|-------|----------------|
|
| 507 |
+
| Algorithm Fit | {scores['algorithm_fit']:.2f} | {"Good match" if scores['algorithm_fit'] > 0.5 else "Poor match"} |
|
| 508 |
+
| Hardware Readiness | {scores['hardware_readiness']:.2e} | {"Ready" if scores['hardware_readiness'] > 0.01 else "Not ready"} |
|
| 509 |
+
| Classical Advantage | {scores['classical_comparison']:.2f} | {"Potential" if scores['classical_comparison'] > 0.4 else "Unlikely"} |
|
| 510 |
+
| Business Viability | {scores['business_viability']:.2f} | {"Viable" if scores['business_viability'] > 0.3 else "Premature"} |
|
| 511 |
+
|
| 512 |
+
### Recommendations
|
| 513 |
+
|
| 514 |
+
"""
|
| 515 |
+
|
| 516 |
+
if resources['feasible_on_hardware']:
|
| 517 |
+
output += """1. **Proof-of-concept possible** - The idea can be demonstrated on current hardware
|
| 518 |
+
2. **Focus on small instances** - Limit problem size to stay within coherence window
|
| 519 |
+
3. **Benchmark carefully** - Compare against optimized classical implementations
|
| 520 |
+
4. **Hybrid approach** - Consider quantum-classical hybrid strategies
|
| 521 |
+
"""
|
| 522 |
+
else:
|
| 523 |
+
output += """1. **Scale down** - Reduce problem size to fit hardware constraints
|
| 524 |
+
2. **Wait for hardware** - Better quantum computers expected in 2-5 years
|
| 525 |
+
3. **Classical alternatives** - Current classical methods likely more practical
|
| 526 |
+
4. **Research angle** - Frame as algorithmic research rather than near-term application
|
| 527 |
+
"""
|
| 528 |
+
|
| 529 |
+
output += """
|
| 530 |
+
---
|
| 531 |
+
*Note: This is a quick analysis. For comprehensive multi-agent evaluation,
|
| 532 |
+
use the full CrewAI framework via CLI: `python main.py --idea "your idea"`*
|
| 533 |
+
"""
|
| 534 |
+
|
| 535 |
+
return output
|
| 536 |
+
|
| 537 |
+
|
| 538 |
+
def run_full_evaluation(idea: str):
|
| 539 |
+
"""Run full CrewAI evaluation (may take several minutes)."""
|
| 540 |
+
if not idea.strip():
|
| 541 |
+
return "Please enter a quantum finance idea to evaluate."
|
| 542 |
+
|
| 543 |
+
try:
|
| 544 |
+
from quantum_finance_crew import QuantumFinanceCrew
|
| 545 |
+
|
| 546 |
+
crew = QuantumFinanceCrew()
|
| 547 |
+
result = crew.evaluate(idea, verbose=False)
|
| 548 |
+
|
| 549 |
+
output = f"""## Full Multi-Agent Evaluation
|
| 550 |
+
|
| 551 |
+
### Your Idea
|
| 552 |
+
> {idea}
|
| 553 |
+
|
| 554 |
+
### CrewAI Analysis Complete
|
| 555 |
+
|
| 556 |
+
**Tasks Completed:** {result.get('tasks_completed', 'N/A')}
|
| 557 |
+
|
| 558 |
+
### Final Assessment
|
| 559 |
+
|
| 560 |
+
{result.get('result', 'No result available')}
|
| 561 |
+
|
| 562 |
+
---
|
| 563 |
+
*Evaluated by: Quantum Algorithm Expert, Error Correction Expert,
|
| 564 |
+
Classical Computing Expert, and Finance Domain Expert*
|
| 565 |
+
"""
|
| 566 |
+
return output
|
| 567 |
+
|
| 568 |
+
except Exception as e:
|
| 569 |
+
return f"""## Evaluation Error
|
| 570 |
+
|
| 571 |
+
Could not run full CrewAI evaluation: {str(e)}
|
| 572 |
+
|
| 573 |
+
**Possible causes:**
|
| 574 |
+
- Missing API keys (OPENAI_API_KEY or ANTHROPIC_API_KEY)
|
| 575 |
+
- CrewAI configuration issues
|
| 576 |
+
|
| 577 |
+
**Alternative:** Use the Quick Analysis above for instant resource estimation.
|
| 578 |
+
"""
|
| 579 |
+
|
| 580 |
+
|
| 581 |
+
# ============================================================================
|
| 582 |
+
# BUILD GRADIO APP
|
| 583 |
+
# ============================================================================
|
| 584 |
+
|
| 585 |
+
def create_app():
|
| 586 |
+
"""Create the Gradio application."""
|
| 587 |
+
|
| 588 |
+
with gr.Blocks(
|
| 589 |
+
title="Quantum Finance Feasibility Analyzer",
|
| 590 |
+
theme=gr.themes.Soft()
|
| 591 |
+
) as app:
|
| 592 |
+
|
| 593 |
+
gr.Markdown("""
|
| 594 |
+
# Quantum Finance Feasibility Analyzer
|
| 595 |
+
|
| 596 |
+
An interactive tool for evaluating quantum computing applications in finance.
|
| 597 |
+
Assess whether your quantum finance ideas are viable on current NISQ hardware.
|
| 598 |
+
|
| 599 |
+
**Features:**
|
| 600 |
+
- Quantum resource estimation for QAOA, Amplitude Estimation, and Grover's Search
|
| 601 |
+
- Classical benchmark comparisons (portfolio optimization, option pricing)
|
| 602 |
+
- Pre-built use case analysis
|
| 603 |
+
- Custom idea evaluation
|
| 604 |
+
""")
|
| 605 |
+
|
| 606 |
+
with gr.Tabs():
|
| 607 |
+
# Tab 1: Resource Estimation
|
| 608 |
+
with gr.TabItem("Resource Estimation"):
|
| 609 |
+
gr.Markdown("## Quantum Resource Calculator")
|
| 610 |
+
gr.Markdown("Estimate the quantum resources required for different finance algorithms.")
|
| 611 |
+
|
| 612 |
+
with gr.Tabs():
|
| 613 |
+
# QAOA
|
| 614 |
+
with gr.TabItem("QAOA (Portfolio Optimization)"):
|
| 615 |
+
with gr.Row():
|
| 616 |
+
with gr.Column():
|
| 617 |
+
qaoa_hardware = gr.Dropdown(
|
| 618 |
+
choices=[
|
| 619 |
+
"IBM Osprey (433 qubits)",
|
| 620 |
+
"IBM Condor (1121 qubits)",
|
| 621 |
+
"IonQ Forte (36 qubits)",
|
| 622 |
+
"Google Sycamore (72 qubits)"
|
| 623 |
+
],
|
| 624 |
+
value="IBM Osprey (433 qubits)",
|
| 625 |
+
label="Target Hardware"
|
| 626 |
+
)
|
| 627 |
+
qaoa_assets = gr.Slider(
|
| 628 |
+
minimum=5, maximum=200, value=50, step=5,
|
| 629 |
+
label="Number of Assets"
|
| 630 |
+
)
|
| 631 |
+
qaoa_layers = gr.Slider(
|
| 632 |
+
minimum=1, maximum=10, value=3, step=1,
|
| 633 |
+
label="QAOA Layers (p)"
|
| 634 |
+
)
|
| 635 |
+
qaoa_btn = gr.Button("Estimate Resources", variant="primary")
|
| 636 |
+
with gr.Column():
|
| 637 |
+
qaoa_output = gr.Markdown()
|
| 638 |
+
|
| 639 |
+
qaoa_btn.click(
|
| 640 |
+
estimate_qaoa_resources,
|
| 641 |
+
inputs=[qaoa_hardware, qaoa_assets, qaoa_layers],
|
| 642 |
+
outputs=qaoa_output
|
| 643 |
+
)
|
| 644 |
+
|
| 645 |
+
# Amplitude Estimation
|
| 646 |
+
with gr.TabItem("Amplitude Estimation (Option Pricing)"):
|
| 647 |
+
with gr.Row():
|
| 648 |
+
with gr.Column():
|
| 649 |
+
ae_hardware = gr.Dropdown(
|
| 650 |
+
choices=[
|
| 651 |
+
"IBM Osprey (433 qubits)",
|
| 652 |
+
"IBM Condor (1121 qubits)",
|
| 653 |
+
"IonQ Forte (36 qubits)",
|
| 654 |
+
"Google Sycamore (72 qubits)"
|
| 655 |
+
],
|
| 656 |
+
value="IBM Osprey (433 qubits)",
|
| 657 |
+
label="Target Hardware"
|
| 658 |
+
)
|
| 659 |
+
ae_precision = gr.Slider(
|
| 660 |
+
minimum=2, maximum=12, value=8, step=1,
|
| 661 |
+
label="Precision Bits"
|
| 662 |
+
)
|
| 663 |
+
ae_oracle = gr.Slider(
|
| 664 |
+
minimum=5, maximum=50, value=20, step=5,
|
| 665 |
+
label="Oracle Qubits"
|
| 666 |
+
)
|
| 667 |
+
ae_btn = gr.Button("Estimate Resources", variant="primary")
|
| 668 |
+
with gr.Column():
|
| 669 |
+
ae_output = gr.Markdown()
|
| 670 |
+
|
| 671 |
+
ae_btn.click(
|
| 672 |
+
estimate_amplitude_resources,
|
| 673 |
+
inputs=[ae_hardware, ae_precision, ae_oracle],
|
| 674 |
+
outputs=ae_output
|
| 675 |
+
)
|
| 676 |
+
|
| 677 |
+
# Grover's Search
|
| 678 |
+
with gr.TabItem("Grover's Search (Fraud Detection)"):
|
| 679 |
+
with gr.Row():
|
| 680 |
+
with gr.Column():
|
| 681 |
+
grover_hardware = gr.Dropdown(
|
| 682 |
+
choices=[
|
| 683 |
+
"IBM Osprey (433 qubits)",
|
| 684 |
+
"IBM Condor (1121 qubits)",
|
| 685 |
+
"IonQ Forte (36 qubits)",
|
| 686 |
+
"Google Sycamore (72 qubits)"
|
| 687 |
+
],
|
| 688 |
+
value="IBM Osprey (433 qubits)",
|
| 689 |
+
label="Target Hardware"
|
| 690 |
+
)
|
| 691 |
+
grover_space = gr.Slider(
|
| 692 |
+
minimum=3, maximum=9, value=6, step=1,
|
| 693 |
+
label="Search Space Size (10^x records)"
|
| 694 |
+
)
|
| 695 |
+
grover_btn = gr.Button("Estimate Resources", variant="primary")
|
| 696 |
+
with gr.Column():
|
| 697 |
+
grover_output = gr.Markdown()
|
| 698 |
+
|
| 699 |
+
grover_btn.click(
|
| 700 |
+
estimate_grover_resources,
|
| 701 |
+
inputs=[grover_hardware, grover_space],
|
| 702 |
+
outputs=grover_output
|
| 703 |
+
)
|
| 704 |
+
|
| 705 |
+
# Tab 2: Classical Benchmarks
|
| 706 |
+
with gr.TabItem("Classical Benchmarks"):
|
| 707 |
+
gr.Markdown("## Classical Finance Benchmarks")
|
| 708 |
+
gr.Markdown("Compare quantum approaches against classical implementations.")
|
| 709 |
+
|
| 710 |
+
with gr.Tabs():
|
| 711 |
+
with gr.TabItem("Portfolio Optimization"):
|
| 712 |
+
with gr.Row():
|
| 713 |
+
with gr.Column():
|
| 714 |
+
port_assets = gr.Slider(
|
| 715 |
+
minimum=5, maximum=25, value=15, step=1,
|
| 716 |
+
label="Number of Assets"
|
| 717 |
+
)
|
| 718 |
+
port_trials = gr.Slider(
|
| 719 |
+
minimum=10, maximum=500, value=100, step=10,
|
| 720 |
+
label="Timing Trials"
|
| 721 |
+
)
|
| 722 |
+
port_btn = gr.Button("Run Optimization", variant="primary")
|
| 723 |
+
with gr.Column():
|
| 724 |
+
port_output = gr.Markdown()
|
| 725 |
+
|
| 726 |
+
port_btn.click(
|
| 727 |
+
run_portfolio_optimization,
|
| 728 |
+
inputs=[port_assets, port_trials],
|
| 729 |
+
outputs=port_output
|
| 730 |
+
)
|
| 731 |
+
|
| 732 |
+
with gr.TabItem("Option Pricing"):
|
| 733 |
+
with gr.Row():
|
| 734 |
+
with gr.Column():
|
| 735 |
+
opt_spot = gr.Number(value=100, label="Spot Price ($)")
|
| 736 |
+
opt_strike = gr.Number(value=100, label="Strike Price ($)")
|
| 737 |
+
opt_maturity = gr.Slider(
|
| 738 |
+
minimum=0.1, maximum=2.0, value=1.0, step=0.1,
|
| 739 |
+
label="Time to Maturity (years)"
|
| 740 |
+
)
|
| 741 |
+
opt_rate = gr.Slider(
|
| 742 |
+
minimum=0.01, maximum=0.10, value=0.05, step=0.01,
|
| 743 |
+
label="Risk-Free Rate"
|
| 744 |
+
)
|
| 745 |
+
opt_vol = gr.Slider(
|
| 746 |
+
minimum=0.1, maximum=0.5, value=0.2, step=0.05,
|
| 747 |
+
label="Volatility"
|
| 748 |
+
)
|
| 749 |
+
opt_paths = gr.Slider(
|
| 750 |
+
minimum=10000, maximum=1000000, value=100000, step=10000,
|
| 751 |
+
label="Monte Carlo Paths"
|
| 752 |
+
)
|
| 753 |
+
opt_btn = gr.Button("Price Option", variant="primary")
|
| 754 |
+
with gr.Column():
|
| 755 |
+
opt_output = gr.Markdown()
|
| 756 |
+
|
| 757 |
+
opt_btn.click(
|
| 758 |
+
run_option_pricing,
|
| 759 |
+
inputs=[opt_spot, opt_strike, opt_maturity, opt_rate, opt_vol, opt_paths],
|
| 760 |
+
outputs=opt_output
|
| 761 |
+
)
|
| 762 |
+
|
| 763 |
+
# Tab 3: Use Cases
|
| 764 |
+
with gr.TabItem("Use Cases"):
|
| 765 |
+
gr.Markdown("## Pre-Built Use Case Analysis")
|
| 766 |
+
gr.Markdown("Explore detailed feasibility analysis for common quantum finance applications.")
|
| 767 |
+
|
| 768 |
+
with gr.Row():
|
| 769 |
+
with gr.Column():
|
| 770 |
+
use_case = gr.Dropdown(
|
| 771 |
+
choices=[c['name'] for c in TEST_CASES],
|
| 772 |
+
value=TEST_CASES[0]['name'],
|
| 773 |
+
label="Select Use Case"
|
| 774 |
+
)
|
| 775 |
+
use_case_btn = gr.Button("Analyze Use Case", variant="primary")
|
| 776 |
+
with gr.Column():
|
| 777 |
+
use_case_output = gr.Markdown()
|
| 778 |
+
|
| 779 |
+
use_case_btn.click(
|
| 780 |
+
analyze_use_case,
|
| 781 |
+
inputs=[use_case],
|
| 782 |
+
outputs=use_case_output
|
| 783 |
+
)
|
| 784 |
+
|
| 785 |
+
# Tab 4: Idea Evaluation
|
| 786 |
+
with gr.TabItem("Evaluate Your Idea"):
|
| 787 |
+
gr.Markdown("## Custom Idea Evaluation")
|
| 788 |
+
gr.Markdown("Enter your quantum finance idea for feasibility analysis.")
|
| 789 |
+
|
| 790 |
+
with gr.Row():
|
| 791 |
+
with gr.Column():
|
| 792 |
+
idea_input = gr.Textbox(
|
| 793 |
+
lines=4,
|
| 794 |
+
placeholder="Example: Quantum optimization for rebalancing a 50-asset ETF portfolio using QAOA with real-time market data...",
|
| 795 |
+
label="Your Quantum Finance Idea"
|
| 796 |
+
)
|
| 797 |
+
with gr.Row():
|
| 798 |
+
quick_btn = gr.Button("Quick Analysis", variant="primary")
|
| 799 |
+
full_btn = gr.Button("Full CrewAI Evaluation", variant="secondary")
|
| 800 |
+
|
| 801 |
+
gr.Markdown("""
|
| 802 |
+
**Quick Analysis:** Instant resource estimation and feasibility check.
|
| 803 |
+
|
| 804 |
+
**Full CrewAI Evaluation:** Comprehensive multi-agent analysis (requires API keys, may take several minutes).
|
| 805 |
+
""")
|
| 806 |
+
|
| 807 |
+
with gr.Column():
|
| 808 |
+
idea_output = gr.Markdown()
|
| 809 |
+
|
| 810 |
+
quick_btn.click(
|
| 811 |
+
evaluate_idea_quick,
|
| 812 |
+
inputs=[idea_input],
|
| 813 |
+
outputs=idea_output
|
| 814 |
+
)
|
| 815 |
+
|
| 816 |
+
full_btn.click(
|
| 817 |
+
run_full_evaluation,
|
| 818 |
+
inputs=[idea_input],
|
| 819 |
+
outputs=idea_output
|
| 820 |
+
)
|
| 821 |
+
|
| 822 |
+
gr.Markdown("""
|
| 823 |
+
---
|
| 824 |
+
**Quantum Finance Feasibility Analysis Framework**
|
| 825 |
+
|
| 826 |
+
Built with CrewAI for multi-agent evaluation. Resource estimates based on current NISQ hardware specifications.
|
| 827 |
+
|
| 828 |
+
*For command-line usage:* `python main.py --help`
|
| 829 |
+
""")
|
| 830 |
+
|
| 831 |
+
return app
|
| 832 |
+
|
| 833 |
+
|
| 834 |
+
# Main entry point
|
| 835 |
+
if __name__ == "__main__":
|
| 836 |
+
app = create_app()
|
| 837 |
+
app.launch()
|
config/agents.yaml
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
quantum_algorithm_expert:
|
| 2 |
+
role: "Quantum Algorithm Expert"
|
| 3 |
+
goal: "Assess whether proposed finance applications map to known quantum algorithms (QAOA, VQE, Grover's, Amplitude Estimation) and estimate their computational complexity on NISQ hardware"
|
| 4 |
+
backstory: |
|
| 5 |
+
You are a leading expert in quantum algorithms with deep knowledge of variational quantum
|
| 6 |
+
eigensolver (VQE), Quantum Approximate Optimization Algorithm (QAOA), Grover's search,
|
| 7 |
+
and quantum amplitude estimation. You understand the theoretical speedups these algorithms
|
| 8 |
+
offer and their practical limitations on near-term intermediate-scale quantum (NISQ) devices.
|
| 9 |
+
You critically evaluate claims of quantum advantage and can identify when classical
|
| 10 |
+
algorithms remain competitive.
|
| 11 |
+
verbose: true
|
| 12 |
+
allow_delegation: true
|
| 13 |
+
|
| 14 |
+
quantum_error_correction_expert:
|
| 15 |
+
role: "Quantum Error Correction Expert"
|
| 16 |
+
goal: "Evaluate the impact of noise, decoherence, and error rates on proposed quantum finance applications using NISQ hardware constraints"
|
| 17 |
+
backstory: |
|
| 18 |
+
You specialize in quantum error correction and noise modeling for NISQ devices. You understand
|
| 19 |
+
current hardware limitations including qubit counts (<1,000 qubits), gate fidelities (99-99.9%),
|
| 20 |
+
coherence times, and connectivity constraints. You can estimate circuit depth limits and
|
| 21 |
+
determine whether proposed applications are feasible given realistic error budgets.
|
| 22 |
+
You are familiar with error mitigation techniques and can assess their effectiveness.
|
| 23 |
+
verbose: true
|
| 24 |
+
allow_delegation: true
|
| 25 |
+
|
| 26 |
+
classical_computing_expert:
|
| 27 |
+
role: "Classical Computing Expert"
|
| 28 |
+
goal: "Provide rigorous classical baselines and benchmarks to compare against proposed quantum solutions, identifying when classical methods are sufficient"
|
| 29 |
+
backstory: |
|
| 30 |
+
You are an expert in classical optimization, machine learning, and high-performance computing.
|
| 31 |
+
You know the state-of-the-art in classical solvers (Gurobi, CPLEX), GPU-accelerated computing,
|
| 32 |
+
tensor network methods, and Monte Carlo simulations. You can estimate classical runtime
|
| 33 |
+
complexity and identify when quantum approaches offer no practical advantage over
|
| 34 |
+
well-optimized classical implementations.
|
| 35 |
+
verbose: true
|
| 36 |
+
allow_delegation: true
|
| 37 |
+
|
| 38 |
+
finance_domain_expert:
|
| 39 |
+
role: "Finance Domain Expert"
|
| 40 |
+
goal: "Evaluate the commercial viability, regulatory fit, and practical constraints of quantum finance applications from an industry perspective"
|
| 41 |
+
backstory: |
|
| 42 |
+
You are a senior quantitative finance professional with expertise in portfolio optimization,
|
| 43 |
+
derivatives pricing, risk management, and fraud detection. You understand regulatory
|
| 44 |
+
requirements (Basel III/IV, SEC rules), latency constraints in trading, and the practical
|
| 45 |
+
challenges of deploying new technologies in financial institutions. You can assess whether
|
| 46 |
+
proposed quantum solutions address real business needs and fit within existing infrastructure.
|
| 47 |
+
verbose: true
|
| 48 |
+
allow_delegation: true
|
config/tasks.yaml
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
analyze_quantum_feasibility:
|
| 2 |
+
description: |
|
| 3 |
+
Analyze the quantum algorithm feasibility for the proposed finance application: {idea}
|
| 4 |
+
|
| 5 |
+
Evaluate:
|
| 6 |
+
1. Which quantum algorithms (QAOA, VQE, Grover's, Amplitude Estimation, etc.) could apply
|
| 7 |
+
2. Theoretical complexity improvements over classical approaches
|
| 8 |
+
3. Required qubit count and circuit depth estimates
|
| 9 |
+
4. Known limitations and open problems for this algorithm class
|
| 10 |
+
|
| 11 |
+
Provide a feasibility score (0-1) with detailed justification.
|
| 12 |
+
expected_output: |
|
| 13 |
+
A structured analysis containing:
|
| 14 |
+
- Applicable quantum algorithms with rationale
|
| 15 |
+
- Complexity analysis (quantum vs classical)
|
| 16 |
+
- Resource requirements (qubits, gates, depth)
|
| 17 |
+
- Feasibility score with justification
|
| 18 |
+
- Key bottlenecks and risks
|
| 19 |
+
agent: quantum_algorithm_expert
|
| 20 |
+
|
| 21 |
+
assess_nisq_constraints:
|
| 22 |
+
description: |
|
| 23 |
+
Assess the NISQ hardware constraints for implementing: {idea}
|
| 24 |
+
|
| 25 |
+
Consider:
|
| 26 |
+
1. Current hardware capabilities (IBM, IonQ, Google - 2024-2026 roadmaps)
|
| 27 |
+
2. Noise impact on algorithm performance
|
| 28 |
+
3. Error mitigation strategies and their overhead
|
| 29 |
+
4. Realistic timeline for hardware sufficient to run this application
|
| 30 |
+
|
| 31 |
+
Provide a hardware readiness score (0-1).
|
| 32 |
+
expected_output: |
|
| 33 |
+
A structured assessment containing:
|
| 34 |
+
- Hardware requirements vs current capabilities
|
| 35 |
+
- Noise sensitivity analysis
|
| 36 |
+
- Recommended error mitigation approaches
|
| 37 |
+
- Hardware readiness score with timeline estimate
|
| 38 |
+
- Critical hardware milestones needed
|
| 39 |
+
agent: quantum_error_correction_expert
|
| 40 |
+
|
| 41 |
+
benchmark_classical_alternatives:
|
| 42 |
+
description: |
|
| 43 |
+
Benchmark classical alternatives for: {idea}
|
| 44 |
+
|
| 45 |
+
Analyze:
|
| 46 |
+
1. Best classical algorithms and solvers for this problem
|
| 47 |
+
2. State-of-the-art performance on relevant benchmarks
|
| 48 |
+
3. GPU/TPU acceleration potential
|
| 49 |
+
4. Quantum-inspired classical methods (tensor networks, etc.)
|
| 50 |
+
|
| 51 |
+
Provide a classical competitiveness score (0-1, where 1 = classical is fully sufficient).
|
| 52 |
+
expected_output: |
|
| 53 |
+
A structured benchmark containing:
|
| 54 |
+
- Best classical approaches with performance data
|
| 55 |
+
- Scalability analysis
|
| 56 |
+
- Hardware costs (classical vs quantum)
|
| 57 |
+
- Classical competitiveness score
|
| 58 |
+
- Crossover point estimate (if any)
|
| 59 |
+
agent: classical_computing_expert
|
| 60 |
+
|
| 61 |
+
evaluate_business_viability:
|
| 62 |
+
description: |
|
| 63 |
+
Evaluate the business viability of: {idea}
|
| 64 |
+
|
| 65 |
+
Consider:
|
| 66 |
+
1. Real business value and use case fit
|
| 67 |
+
2. Regulatory and compliance implications
|
| 68 |
+
3. Integration with existing financial infrastructure
|
| 69 |
+
4. Cost-benefit analysis (quantum vs classical deployment)
|
| 70 |
+
5. Risk tolerance of financial institutions for new technology
|
| 71 |
+
|
| 72 |
+
Provide a commercial viability score (0-1).
|
| 73 |
+
expected_output: |
|
| 74 |
+
A structured evaluation containing:
|
| 75 |
+
- Business value assessment
|
| 76 |
+
- Regulatory considerations
|
| 77 |
+
- Integration challenges
|
| 78 |
+
- Cost-benefit analysis
|
| 79 |
+
- Commercial viability score with timeline
|
| 80 |
+
- Recommended next steps
|
| 81 |
+
agent: finance_domain_expert
|
| 82 |
+
|
| 83 |
+
synthesize_final_assessment:
|
| 84 |
+
description: |
|
| 85 |
+
Synthesize all expert analyses into a final feasibility assessment for: {idea}
|
| 86 |
+
|
| 87 |
+
Integrate findings from:
|
| 88 |
+
- Quantum algorithm feasibility analysis
|
| 89 |
+
- NISQ hardware constraints assessment
|
| 90 |
+
- Classical benchmarking results
|
| 91 |
+
- Business viability evaluation
|
| 92 |
+
|
| 93 |
+
Determine overall quantum advantage potential and provide actionable recommendations.
|
| 94 |
+
expected_output: |
|
| 95 |
+
A comprehensive final report containing:
|
| 96 |
+
- Executive summary (2-3 sentences)
|
| 97 |
+
- Overall feasibility score (0-1) with breakdown
|
| 98 |
+
- Quantum advantage assessment (Yes/No/Hybrid with justification)
|
| 99 |
+
- Key bottlenecks ranked by severity
|
| 100 |
+
- Recommended alternatives if quantum not viable
|
| 101 |
+
- Actionable next steps
|
| 102 |
+
- Timeline estimate for viable implementation
|
| 103 |
+
agent: quantum_algorithm_expert
|
| 104 |
+
context:
|
| 105 |
+
- analyze_quantum_feasibility
|
| 106 |
+
- assess_nisq_constraints
|
| 107 |
+
- benchmark_classical_alternatives
|
| 108 |
+
- evaluate_business_viability
|
main.py
ADDED
|
@@ -0,0 +1,216 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""
|
| 3 |
+
Main entry point for the Quantum Finance Feasibility Analysis Framework.
|
| 4 |
+
|
| 5 |
+
Usage:
|
| 6 |
+
python main.py # Run demo evaluation
|
| 7 |
+
python main.py --idea "Your idea here" # Evaluate specific idea
|
| 8 |
+
python main.py --batch # Run batch evaluation on test cases
|
| 9 |
+
"""
|
| 10 |
+
|
| 11 |
+
import argparse
|
| 12 |
+
import sys
|
| 13 |
+
from pathlib import Path
|
| 14 |
+
|
| 15 |
+
# Add src to path
|
| 16 |
+
sys.path.insert(0, str(Path(__file__).parent / "src"))
|
| 17 |
+
|
| 18 |
+
from quantum_finance_crew import QuantumFinanceCrew
|
| 19 |
+
from tools import (
|
| 20 |
+
QuantumResourceEstimator,
|
| 21 |
+
collect_experiment_data,
|
| 22 |
+
ClassicalPortfolioOptimizer
|
| 23 |
+
)
|
| 24 |
+
from utils import MetricsCollector, EvaluationMetrics
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
# Standard test cases for experiments
|
| 28 |
+
TEST_CASES = [
|
| 29 |
+
{
|
| 30 |
+
'id': 'portfolio_optimization',
|
| 31 |
+
'idea': 'Quantum portfolio optimization using QAOA for a 100-asset portfolio with mean-variance objective',
|
| 32 |
+
'category': 'optimization'
|
| 33 |
+
},
|
| 34 |
+
{
|
| 35 |
+
'id': 'option_pricing',
|
| 36 |
+
'idea': 'Quantum amplitude estimation for pricing European call options with 8-bit precision',
|
| 37 |
+
'category': 'pricing'
|
| 38 |
+
},
|
| 39 |
+
{
|
| 40 |
+
'id': 'fraud_detection',
|
| 41 |
+
'idea': 'Quantum machine learning classifier for real-time credit card fraud detection',
|
| 42 |
+
'category': 'ml'
|
| 43 |
+
},
|
| 44 |
+
{
|
| 45 |
+
'id': 'risk_analysis',
|
| 46 |
+
'idea': 'Quantum Monte Carlo for Value-at-Risk (VaR) calculation on a derivatives portfolio',
|
| 47 |
+
'category': 'risk'
|
| 48 |
+
},
|
| 49 |
+
{
|
| 50 |
+
'id': 'credit_scoring',
|
| 51 |
+
'idea': 'Variational quantum classifier for credit scoring using customer financial data',
|
| 52 |
+
'category': 'ml'
|
| 53 |
+
}
|
| 54 |
+
]
|
| 55 |
+
|
| 56 |
+
|
| 57 |
+
def run_resource_estimation_demo():
|
| 58 |
+
"""Demonstrate quantum resource estimation capabilities."""
|
| 59 |
+
print("\n" + "=" * 60)
|
| 60 |
+
print("QUANTUM RESOURCE ESTIMATION DEMO")
|
| 61 |
+
print("=" * 60)
|
| 62 |
+
|
| 63 |
+
estimator = QuantumResourceEstimator('ibm_osprey')
|
| 64 |
+
|
| 65 |
+
# Portfolio optimization
|
| 66 |
+
print("\n1. QAOA for 50-Asset Portfolio (p=3 layers):")
|
| 67 |
+
print("-" * 50)
|
| 68 |
+
result = estimator.estimate_qaoa_resources(num_assets=50, p_layers=3)
|
| 69 |
+
for key, value in result.items():
|
| 70 |
+
print(f" {key}: {value}")
|
| 71 |
+
|
| 72 |
+
# Option pricing
|
| 73 |
+
print("\n2. Amplitude Estimation for Option Pricing (8-bit precision):")
|
| 74 |
+
print("-" * 50)
|
| 75 |
+
result = estimator.estimate_amplitude_estimation_resources(
|
| 76 |
+
precision_bits=8, num_qubits_oracle=20
|
| 77 |
+
)
|
| 78 |
+
for key, value in result.items():
|
| 79 |
+
print(f" {key}: {value}")
|
| 80 |
+
|
| 81 |
+
# Fraud detection
|
| 82 |
+
print("\n3. Grover's Search for Pattern Matching (1M records):")
|
| 83 |
+
print("-" * 50)
|
| 84 |
+
result = estimator.estimate_grover_resources(search_space_size=1_000_000)
|
| 85 |
+
for key, value in result.items():
|
| 86 |
+
print(f" {key}: {value}")
|
| 87 |
+
|
| 88 |
+
|
| 89 |
+
def run_classical_benchmark_demo():
|
| 90 |
+
"""Demonstrate classical benchmarking capabilities."""
|
| 91 |
+
print("\n" + "=" * 60)
|
| 92 |
+
print("CLASSICAL BENCHMARK DEMO")
|
| 93 |
+
print("=" * 60)
|
| 94 |
+
|
| 95 |
+
print("\nCollecting financial data...")
|
| 96 |
+
data = collect_experiment_data(n_assets=15)
|
| 97 |
+
print(f"Loaded {data['n_observations']} days of data for {data['n_assets']} assets")
|
| 98 |
+
|
| 99 |
+
print("\nRunning classical portfolio optimization:")
|
| 100 |
+
print("-" * 50)
|
| 101 |
+
optimizer = ClassicalPortfolioOptimizer(
|
| 102 |
+
data['expected_returns'].values,
|
| 103 |
+
data['covariance_matrix'].values
|
| 104 |
+
)
|
| 105 |
+
result = optimizer.optimize_markowitz()
|
| 106 |
+
print(f" Expected Return: {result['expected_return']:.4f}")
|
| 107 |
+
print(f" Volatility: {result['volatility']:.4f}")
|
| 108 |
+
print(f" Sharpe Ratio: {result['sharpe_ratio']:.4f}")
|
| 109 |
+
|
| 110 |
+
print("\nTiming benchmark (100 runs):")
|
| 111 |
+
timing = optimizer.benchmark_timing(n_trials=100)
|
| 112 |
+
print(f" Mean time: {timing['mean_time_ms']:.3f} ms")
|
| 113 |
+
print(f" Std time: {timing['std_time_ms']:.3f} ms")
|
| 114 |
+
|
| 115 |
+
|
| 116 |
+
def run_crew_evaluation(idea: str, verbose: bool = True):
|
| 117 |
+
"""Run the full crew evaluation on an idea."""
|
| 118 |
+
print("\n" + "=" * 60)
|
| 119 |
+
print("QUANTUM FINANCE FEASIBILITY ANALYSIS")
|
| 120 |
+
print("=" * 60)
|
| 121 |
+
print(f"\nIdea: {idea}")
|
| 122 |
+
print("-" * 60)
|
| 123 |
+
|
| 124 |
+
crew = QuantumFinanceCrew()
|
| 125 |
+
result = crew.evaluate(idea, verbose=verbose)
|
| 126 |
+
|
| 127 |
+
print("\n" + "=" * 60)
|
| 128 |
+
print("EVALUATION COMPLETE")
|
| 129 |
+
print("=" * 60)
|
| 130 |
+
|
| 131 |
+
return result
|
| 132 |
+
|
| 133 |
+
|
| 134 |
+
def run_batch_evaluation(verbose: bool = False):
|
| 135 |
+
"""Run evaluation on all test cases."""
|
| 136 |
+
print("\n" + "=" * 60)
|
| 137 |
+
print("BATCH EVALUATION - ALL TEST CASES")
|
| 138 |
+
print("=" * 60)
|
| 139 |
+
|
| 140 |
+
crew = QuantumFinanceCrew()
|
| 141 |
+
metrics_collector = MetricsCollector()
|
| 142 |
+
|
| 143 |
+
results = []
|
| 144 |
+
for i, case in enumerate(TEST_CASES):
|
| 145 |
+
print(f"\n[{i+1}/{len(TEST_CASES)}] Evaluating: {case['id']}")
|
| 146 |
+
print(f" {case['idea'][:60]}...")
|
| 147 |
+
|
| 148 |
+
metrics = metrics_collector.start_evaluation(case['idea'])
|
| 149 |
+
|
| 150 |
+
try:
|
| 151 |
+
result = crew.evaluate(case['idea'], verbose=verbose)
|
| 152 |
+
metrics.total_agent_rounds = result.get('tasks_completed', 0)
|
| 153 |
+
result['case_id'] = case['id']
|
| 154 |
+
results.append(result)
|
| 155 |
+
except Exception as e:
|
| 156 |
+
print(f" ERROR: {e}")
|
| 157 |
+
result = {'case_id': case['id'], 'error': str(e)}
|
| 158 |
+
results.append(result)
|
| 159 |
+
|
| 160 |
+
metrics.complete()
|
| 161 |
+
|
| 162 |
+
print("\n" + "=" * 60)
|
| 163 |
+
print("BATCH EVALUATION SUMMARY")
|
| 164 |
+
print("=" * 60)
|
| 165 |
+
summary = metrics_collector.get_summary_statistics()
|
| 166 |
+
for key, value in summary.items():
|
| 167 |
+
print(f" {key}: {value}")
|
| 168 |
+
|
| 169 |
+
return results
|
| 170 |
+
|
| 171 |
+
|
| 172 |
+
def main():
|
| 173 |
+
parser = argparse.ArgumentParser(
|
| 174 |
+
description='Quantum Finance Feasibility Analysis Framework'
|
| 175 |
+
)
|
| 176 |
+
parser.add_argument(
|
| 177 |
+
'--idea', type=str,
|
| 178 |
+
help='Specific quantum finance idea to evaluate'
|
| 179 |
+
)
|
| 180 |
+
parser.add_argument(
|
| 181 |
+
'--batch', action='store_true',
|
| 182 |
+
help='Run batch evaluation on all test cases'
|
| 183 |
+
)
|
| 184 |
+
parser.add_argument(
|
| 185 |
+
'--demo', action='store_true',
|
| 186 |
+
help='Run resource estimation and benchmark demos'
|
| 187 |
+
)
|
| 188 |
+
parser.add_argument(
|
| 189 |
+
'--verbose', '-v', action='store_true',
|
| 190 |
+
help='Enable verbose output'
|
| 191 |
+
)
|
| 192 |
+
|
| 193 |
+
args = parser.parse_args()
|
| 194 |
+
|
| 195 |
+
if args.demo:
|
| 196 |
+
run_resource_estimation_demo()
|
| 197 |
+
run_classical_benchmark_demo()
|
| 198 |
+
elif args.batch:
|
| 199 |
+
run_batch_evaluation(verbose=args.verbose)
|
| 200 |
+
elif args.idea:
|
| 201 |
+
run_crew_evaluation(args.idea, verbose=args.verbose)
|
| 202 |
+
else:
|
| 203 |
+
# Default: run demo
|
| 204 |
+
print("Quantum Finance Feasibility Analysis Framework")
|
| 205 |
+
print("=" * 50)
|
| 206 |
+
print("\nUsage:")
|
| 207 |
+
print(" python main.py --demo # Resource estimation demos")
|
| 208 |
+
print(" python main.py --idea 'text' # Evaluate specific idea")
|
| 209 |
+
print(" python main.py --batch # Batch evaluate test cases")
|
| 210 |
+
print("\nRunning demo mode...")
|
| 211 |
+
run_resource_estimation_demo()
|
| 212 |
+
run_classical_benchmark_demo()
|
| 213 |
+
|
| 214 |
+
|
| 215 |
+
if __name__ == "__main__":
|
| 216 |
+
main()
|
requirements.txt
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Core framework
|
| 2 |
+
crewai>=1.7.0
|
| 3 |
+
crewai-tools>=1.7.0
|
| 4 |
+
|
| 5 |
+
# Quantum simulation
|
| 6 |
+
qiskit>=1.0.0
|
| 7 |
+
pennylane>=0.35.0
|
| 8 |
+
|
| 9 |
+
# Finance data and analysis
|
| 10 |
+
yfinance>=0.2.36
|
| 11 |
+
pandas>=2.0.0
|
| 12 |
+
numpy>=1.24.0
|
| 13 |
+
scipy>=1.10.0
|
| 14 |
+
|
| 15 |
+
# Visualization
|
| 16 |
+
matplotlib>=3.7.0
|
| 17 |
+
|
| 18 |
+
# Web interface
|
| 19 |
+
gradio>=4.0.0
|
| 20 |
+
|
| 21 |
+
# Utilities
|
| 22 |
+
pyyaml>=6.0
|
| 23 |
+
python-dotenv>=1.0.0
|
src/__init__.py
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Quantum Finance Feasibility Analysis Framework
|
| 3 |
+
|
| 4 |
+
An agentic AI framework for evaluating the feasibility of near-term
|
| 5 |
+
quantum computing applications in finance.
|
| 6 |
+
"""
|
| 7 |
+
|
| 8 |
+
__version__ = "0.1.0"
|
src/quantum_finance_crew/__init__.py
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Quantum Finance Feasibility Crew
|
| 3 |
+
|
| 4 |
+
An agentic AI framework for evaluating the feasibility of near-term
|
| 5 |
+
quantum computing applications in finance.
|
| 6 |
+
"""
|
| 7 |
+
|
| 8 |
+
from .crew import QuantumFinanceCrew
|
| 9 |
+
|
| 10 |
+
__version__ = "0.1.0"
|
| 11 |
+
__all__ = ["QuantumFinanceCrew"]
|
src/quantum_finance_crew/crew.py
ADDED
|
@@ -0,0 +1,174 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Main CrewAI implementation for quantum finance feasibility analysis.
|
| 3 |
+
"""
|
| 4 |
+
|
| 5 |
+
import yaml
|
| 6 |
+
from pathlib import Path
|
| 7 |
+
from crewai import Agent, Crew, Task, Process
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
class QuantumFinanceCrew:
|
| 11 |
+
"""
|
| 12 |
+
Multi-agent crew for evaluating quantum finance application feasibility.
|
| 13 |
+
|
| 14 |
+
This crew consists of four specialized agents:
|
| 15 |
+
- Quantum Algorithm Expert: Evaluates algorithm applicability and complexity
|
| 16 |
+
- Quantum Error Correction Expert: Assesses NISQ hardware constraints
|
| 17 |
+
- Classical Computing Expert: Benchmarks classical alternatives
|
| 18 |
+
- Finance Domain Expert: Evaluates business viability
|
| 19 |
+
"""
|
| 20 |
+
|
| 21 |
+
def __init__(self, config_path: str = None):
|
| 22 |
+
"""Initialize the crew with configuration."""
|
| 23 |
+
if config_path is None:
|
| 24 |
+
config_path = Path(__file__).parent.parent.parent / "config"
|
| 25 |
+
else:
|
| 26 |
+
config_path = Path(config_path)
|
| 27 |
+
|
| 28 |
+
self.agents_config = self._load_yaml(config_path / "agents.yaml")
|
| 29 |
+
self.tasks_config = self._load_yaml(config_path / "tasks.yaml")
|
| 30 |
+
|
| 31 |
+
self.agents = self._create_agents()
|
| 32 |
+
self.evaluation_history = []
|
| 33 |
+
|
| 34 |
+
def _load_yaml(self, path: Path) -> dict:
|
| 35 |
+
"""Load YAML configuration file."""
|
| 36 |
+
with open(path, 'r') as f:
|
| 37 |
+
return yaml.safe_load(f)
|
| 38 |
+
|
| 39 |
+
def _create_agents(self) -> dict:
|
| 40 |
+
"""Create all agents from configuration."""
|
| 41 |
+
agents = {}
|
| 42 |
+
|
| 43 |
+
for agent_name, config in self.agents_config.items():
|
| 44 |
+
agents[agent_name] = Agent(
|
| 45 |
+
role=config['role'],
|
| 46 |
+
goal=config['goal'],
|
| 47 |
+
backstory=config['backstory'],
|
| 48 |
+
verbose=config.get('verbose', True),
|
| 49 |
+
allow_delegation=config.get('allow_delegation', True)
|
| 50 |
+
)
|
| 51 |
+
|
| 52 |
+
return agents
|
| 53 |
+
|
| 54 |
+
def _create_tasks(self, idea: str) -> list:
|
| 55 |
+
"""Create tasks for evaluating a specific idea."""
|
| 56 |
+
tasks = []
|
| 57 |
+
task_objects = {}
|
| 58 |
+
|
| 59 |
+
# Create tasks in order (context dependencies handled)
|
| 60 |
+
task_order = [
|
| 61 |
+
'analyze_quantum_feasibility',
|
| 62 |
+
'assess_nisq_constraints',
|
| 63 |
+
'benchmark_classical_alternatives',
|
| 64 |
+
'evaluate_business_viability',
|
| 65 |
+
'synthesize_final_assessment'
|
| 66 |
+
]
|
| 67 |
+
|
| 68 |
+
for task_name in task_order:
|
| 69 |
+
config = self.tasks_config[task_name]
|
| 70 |
+
agent_name = config['agent']
|
| 71 |
+
|
| 72 |
+
# Build context from previous tasks if specified
|
| 73 |
+
context = []
|
| 74 |
+
if 'context' in config:
|
| 75 |
+
context = [task_objects[ctx] for ctx in config['context'] if ctx in task_objects]
|
| 76 |
+
|
| 77 |
+
task = Task(
|
| 78 |
+
description=config['description'].format(idea=idea),
|
| 79 |
+
expected_output=config['expected_output'],
|
| 80 |
+
agent=self.agents[agent_name],
|
| 81 |
+
context=context if context else None
|
| 82 |
+
)
|
| 83 |
+
|
| 84 |
+
task_objects[task_name] = task
|
| 85 |
+
tasks.append(task)
|
| 86 |
+
|
| 87 |
+
return tasks
|
| 88 |
+
|
| 89 |
+
def evaluate(self, idea: str, verbose: bool = True) -> dict:
|
| 90 |
+
"""
|
| 91 |
+
Evaluate a quantum finance application idea.
|
| 92 |
+
|
| 93 |
+
Args:
|
| 94 |
+
idea: Description of the proposed quantum finance application
|
| 95 |
+
verbose: Whether to print detailed progress
|
| 96 |
+
|
| 97 |
+
Returns:
|
| 98 |
+
Dictionary containing the evaluation results and metrics
|
| 99 |
+
"""
|
| 100 |
+
tasks = self._create_tasks(idea)
|
| 101 |
+
|
| 102 |
+
crew = Crew(
|
| 103 |
+
agents=list(self.agents.values()),
|
| 104 |
+
tasks=tasks,
|
| 105 |
+
process=Process.sequential,
|
| 106 |
+
verbose=verbose
|
| 107 |
+
)
|
| 108 |
+
|
| 109 |
+
result = crew.kickoff()
|
| 110 |
+
|
| 111 |
+
# Store evaluation in history
|
| 112 |
+
evaluation = {
|
| 113 |
+
'idea': idea,
|
| 114 |
+
'result': result,
|
| 115 |
+
'tasks_completed': len(tasks)
|
| 116 |
+
}
|
| 117 |
+
self.evaluation_history.append(evaluation)
|
| 118 |
+
|
| 119 |
+
return evaluation
|
| 120 |
+
|
| 121 |
+
def batch_evaluate(self, ideas: list, verbose: bool = False) -> list:
|
| 122 |
+
"""
|
| 123 |
+
Evaluate multiple quantum finance application ideas.
|
| 124 |
+
|
| 125 |
+
Args:
|
| 126 |
+
ideas: List of idea descriptions to evaluate
|
| 127 |
+
verbose: Whether to print detailed progress
|
| 128 |
+
|
| 129 |
+
Returns:
|
| 130 |
+
List of evaluation results
|
| 131 |
+
"""
|
| 132 |
+
results = []
|
| 133 |
+
for i, idea in enumerate(ideas):
|
| 134 |
+
print(f"\n{'='*60}")
|
| 135 |
+
print(f"Evaluating idea {i+1}/{len(ideas)}: {idea[:50]}...")
|
| 136 |
+
print('='*60)
|
| 137 |
+
|
| 138 |
+
result = self.evaluate(idea, verbose=verbose)
|
| 139 |
+
results.append(result)
|
| 140 |
+
|
| 141 |
+
return results
|
| 142 |
+
|
| 143 |
+
def get_evaluation_summary(self) -> dict:
|
| 144 |
+
"""Get summary statistics of all evaluations."""
|
| 145 |
+
return {
|
| 146 |
+
'total_evaluations': len(self.evaluation_history),
|
| 147 |
+
'ideas_evaluated': [e['idea'] for e in self.evaluation_history]
|
| 148 |
+
}
|
| 149 |
+
|
| 150 |
+
|
| 151 |
+
def main():
|
| 152 |
+
"""Example usage of the QuantumFinanceCrew."""
|
| 153 |
+
crew = QuantumFinanceCrew()
|
| 154 |
+
|
| 155 |
+
# Example finance use cases to evaluate
|
| 156 |
+
test_ideas = [
|
| 157 |
+
"Quantum portfolio optimization using QAOA for a 100-asset portfolio",
|
| 158 |
+
"Quantum Monte Carlo for option pricing on European call options",
|
| 159 |
+
"Quantum machine learning for credit card fraud detection"
|
| 160 |
+
]
|
| 161 |
+
|
| 162 |
+
# Evaluate first idea as demo
|
| 163 |
+
print("Quantum Finance Feasibility Analysis Framework")
|
| 164 |
+
print("=" * 50)
|
| 165 |
+
print(f"\nEvaluating: {test_ideas[0]}")
|
| 166 |
+
|
| 167 |
+
result = crew.evaluate(test_ideas[0])
|
| 168 |
+
print("\n" + "=" * 50)
|
| 169 |
+
print("EVALUATION COMPLETE")
|
| 170 |
+
print("=" * 50)
|
| 171 |
+
|
| 172 |
+
|
| 173 |
+
if __name__ == "__main__":
|
| 174 |
+
main()
|
src/tools/__init__.py
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Tools for quantum finance feasibility analysis.
|
| 3 |
+
"""
|
| 4 |
+
|
| 5 |
+
from .quantum_tools import (
|
| 6 |
+
QuantumResourceEstimator,
|
| 7 |
+
NISQNoiseModel,
|
| 8 |
+
run_qaoa_simulation
|
| 9 |
+
)
|
| 10 |
+
from .finance_tools import (
|
| 11 |
+
FinanceDataCollector,
|
| 12 |
+
ClassicalPortfolioOptimizer,
|
| 13 |
+
OptionPricer,
|
| 14 |
+
collect_experiment_data
|
| 15 |
+
)
|
| 16 |
+
|
| 17 |
+
__all__ = [
|
| 18 |
+
'QuantumResourceEstimator',
|
| 19 |
+
'NISQNoiseModel',
|
| 20 |
+
'run_qaoa_simulation',
|
| 21 |
+
'FinanceDataCollector',
|
| 22 |
+
'ClassicalPortfolioOptimizer',
|
| 23 |
+
'OptionPricer',
|
| 24 |
+
'collect_experiment_data'
|
| 25 |
+
]
|
src/tools/finance_tools.py
ADDED
|
@@ -0,0 +1,365 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Finance data tools using Yahoo Finance and analysis utilities.
|
| 3 |
+
|
| 4 |
+
Provides utilities for:
|
| 5 |
+
- Historical price data retrieval
|
| 6 |
+
- Portfolio optimization benchmarks
|
| 7 |
+
- Option pricing models
|
| 8 |
+
- Risk metrics calculation
|
| 9 |
+
"""
|
| 10 |
+
|
| 11 |
+
import numpy as np
|
| 12 |
+
import pandas as pd
|
| 13 |
+
from datetime import datetime, timedelta
|
| 14 |
+
from typing import Optional
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
class FinanceDataCollector:
|
| 18 |
+
"""Collect and process financial data for quantum finance experiments."""
|
| 19 |
+
|
| 20 |
+
# Default benchmark assets
|
| 21 |
+
DEFAULT_TICKERS = [
|
| 22 |
+
'AAPL', 'MSFT', 'GOOGL', 'AMZN', 'META', # Tech
|
| 23 |
+
'JPM', 'BAC', 'GS', 'MS', 'C', # Finance
|
| 24 |
+
'JNJ', 'PFE', 'UNH', 'MRK', 'ABBV', # Healthcare
|
| 25 |
+
'XOM', 'CVX', 'COP', 'SLB', 'EOG', # Energy
|
| 26 |
+
'PG', 'KO', 'PEP', 'WMT', 'COST' # Consumer
|
| 27 |
+
]
|
| 28 |
+
|
| 29 |
+
def __init__(self, tickers: Optional[list] = None):
|
| 30 |
+
"""Initialize with list of tickers to track."""
|
| 31 |
+
self.tickers = tickers or self.DEFAULT_TICKERS
|
| 32 |
+
|
| 33 |
+
def fetch_historical_data(
|
| 34 |
+
self,
|
| 35 |
+
start_date: str = None,
|
| 36 |
+
end_date: str = None,
|
| 37 |
+
period: str = "1y"
|
| 38 |
+
) -> pd.DataFrame:
|
| 39 |
+
"""
|
| 40 |
+
Fetch historical price data using yfinance.
|
| 41 |
+
|
| 42 |
+
Args:
|
| 43 |
+
start_date: Start date (YYYY-MM-DD format)
|
| 44 |
+
end_date: End date (YYYY-MM-DD format)
|
| 45 |
+
period: Alternative to start/end - e.g., "1y", "6mo", "1mo"
|
| 46 |
+
|
| 47 |
+
Returns:
|
| 48 |
+
DataFrame with adjusted close prices
|
| 49 |
+
"""
|
| 50 |
+
try:
|
| 51 |
+
import yfinance as yf
|
| 52 |
+
|
| 53 |
+
if start_date and end_date:
|
| 54 |
+
data = yf.download(
|
| 55 |
+
self.tickers,
|
| 56 |
+
start=start_date,
|
| 57 |
+
end=end_date,
|
| 58 |
+
progress=False
|
| 59 |
+
)
|
| 60 |
+
else:
|
| 61 |
+
data = yf.download(
|
| 62 |
+
self.tickers,
|
| 63 |
+
period=period,
|
| 64 |
+
progress=False
|
| 65 |
+
)
|
| 66 |
+
|
| 67 |
+
# Extract adjusted close prices
|
| 68 |
+
if len(data) == 0:
|
| 69 |
+
print("No data from yfinance, using synthetic data...")
|
| 70 |
+
return self._generate_synthetic_data()
|
| 71 |
+
|
| 72 |
+
if 'Adj Close' in data.columns.get_level_values(0):
|
| 73 |
+
prices = data['Adj Close']
|
| 74 |
+
else:
|
| 75 |
+
prices = data['Close']
|
| 76 |
+
|
| 77 |
+
# If prices are empty, use synthetic
|
| 78 |
+
if prices.empty or prices.isna().all().all():
|
| 79 |
+
print("Empty price data, using synthetic data...")
|
| 80 |
+
return self._generate_synthetic_data()
|
| 81 |
+
|
| 82 |
+
return prices
|
| 83 |
+
|
| 84 |
+
except (ImportError, Exception) as e:
|
| 85 |
+
print(f"yfinance error ({e}), using synthetic data...")
|
| 86 |
+
return self._generate_synthetic_data()
|
| 87 |
+
|
| 88 |
+
def _generate_synthetic_data(self, days: int = 252) -> pd.DataFrame:
|
| 89 |
+
"""Generate synthetic price data for testing when yfinance unavailable."""
|
| 90 |
+
np.random.seed(42)
|
| 91 |
+
dates = pd.date_range(end=datetime.now(), periods=days, freq='D')
|
| 92 |
+
|
| 93 |
+
data = {}
|
| 94 |
+
for ticker in self.tickers:
|
| 95 |
+
# Geometric Brownian Motion simulation
|
| 96 |
+
initial_price = np.random.uniform(50, 500)
|
| 97 |
+
returns = np.random.normal(0.0005, 0.02, days)
|
| 98 |
+
prices = initial_price * np.cumprod(1 + returns)
|
| 99 |
+
data[ticker] = prices
|
| 100 |
+
|
| 101 |
+
return pd.DataFrame(data, index=dates)
|
| 102 |
+
|
| 103 |
+
def calculate_returns(self, prices: pd.DataFrame) -> pd.DataFrame:
|
| 104 |
+
"""Calculate daily returns from price data."""
|
| 105 |
+
return prices.pct_change(fill_method=None).dropna()
|
| 106 |
+
|
| 107 |
+
def calculate_covariance_matrix(self, returns: pd.DataFrame) -> pd.DataFrame:
|
| 108 |
+
"""Calculate annualized covariance matrix."""
|
| 109 |
+
return returns.cov() * 252 # Annualize
|
| 110 |
+
|
| 111 |
+
def calculate_expected_returns(self, returns: pd.DataFrame) -> pd.Series:
|
| 112 |
+
"""Calculate annualized expected returns."""
|
| 113 |
+
return returns.mean() * 252 # Annualize
|
| 114 |
+
|
| 115 |
+
|
| 116 |
+
class ClassicalPortfolioOptimizer:
|
| 117 |
+
"""Classical portfolio optimization for benchmarking quantum approaches."""
|
| 118 |
+
|
| 119 |
+
def __init__(self, expected_returns: np.ndarray, covariance_matrix: np.ndarray):
|
| 120 |
+
"""
|
| 121 |
+
Initialize optimizer.
|
| 122 |
+
|
| 123 |
+
Args:
|
| 124 |
+
expected_returns: Expected returns vector
|
| 125 |
+
covariance_matrix: Covariance matrix of returns
|
| 126 |
+
"""
|
| 127 |
+
self.mu = expected_returns
|
| 128 |
+
self.sigma = covariance_matrix
|
| 129 |
+
self.n_assets = len(expected_returns)
|
| 130 |
+
|
| 131 |
+
def optimize_markowitz(self, target_return: float = None) -> dict:
|
| 132 |
+
"""
|
| 133 |
+
Solve Markowitz mean-variance optimization.
|
| 134 |
+
|
| 135 |
+
Args:
|
| 136 |
+
target_return: Target portfolio return (if None, maximize Sharpe)
|
| 137 |
+
|
| 138 |
+
Returns:
|
| 139 |
+
Optimization results
|
| 140 |
+
"""
|
| 141 |
+
try:
|
| 142 |
+
from scipy.optimize import minimize
|
| 143 |
+
|
| 144 |
+
def portfolio_volatility(weights):
|
| 145 |
+
return np.sqrt(weights @ self.sigma @ weights)
|
| 146 |
+
|
| 147 |
+
def negative_sharpe(weights):
|
| 148 |
+
ret = weights @ self.mu
|
| 149 |
+
vol = portfolio_volatility(weights)
|
| 150 |
+
return -ret / vol if vol > 0 else 0
|
| 151 |
+
|
| 152 |
+
# Constraints: weights sum to 1, all weights >= 0
|
| 153 |
+
constraints = [{'type': 'eq', 'fun': lambda w: np.sum(w) - 1}]
|
| 154 |
+
bounds = [(0, 1) for _ in range(self.n_assets)]
|
| 155 |
+
|
| 156 |
+
# Initial guess: equal weights
|
| 157 |
+
w0 = np.ones(self.n_assets) / self.n_assets
|
| 158 |
+
|
| 159 |
+
if target_return is not None:
|
| 160 |
+
constraints.append({
|
| 161 |
+
'type': 'eq',
|
| 162 |
+
'fun': lambda w: w @ self.mu - target_return
|
| 163 |
+
})
|
| 164 |
+
result = minimize(
|
| 165 |
+
portfolio_volatility, w0,
|
| 166 |
+
method='SLSQP', bounds=bounds, constraints=constraints
|
| 167 |
+
)
|
| 168 |
+
else:
|
| 169 |
+
result = minimize(
|
| 170 |
+
negative_sharpe, w0,
|
| 171 |
+
method='SLSQP', bounds=bounds, constraints=constraints
|
| 172 |
+
)
|
| 173 |
+
|
| 174 |
+
optimal_weights = result.x
|
| 175 |
+
portfolio_return = optimal_weights @ self.mu
|
| 176 |
+
portfolio_vol = portfolio_volatility(optimal_weights)
|
| 177 |
+
sharpe = portfolio_return / portfolio_vol if portfolio_vol > 0 else 0
|
| 178 |
+
|
| 179 |
+
return {
|
| 180 |
+
'weights': optimal_weights,
|
| 181 |
+
'expected_return': portfolio_return,
|
| 182 |
+
'volatility': portfolio_vol,
|
| 183 |
+
'sharpe_ratio': sharpe,
|
| 184 |
+
'optimization_success': result.success,
|
| 185 |
+
'solver': 'scipy.optimize.minimize (SLSQP)'
|
| 186 |
+
}
|
| 187 |
+
|
| 188 |
+
except ImportError:
|
| 189 |
+
return {'error': 'scipy not available'}
|
| 190 |
+
|
| 191 |
+
def benchmark_timing(self, n_trials: int = 100) -> dict:
|
| 192 |
+
"""
|
| 193 |
+
Benchmark classical optimization timing.
|
| 194 |
+
|
| 195 |
+
Args:
|
| 196 |
+
n_trials: Number of optimization runs
|
| 197 |
+
|
| 198 |
+
Returns:
|
| 199 |
+
Timing statistics
|
| 200 |
+
"""
|
| 201 |
+
import time
|
| 202 |
+
|
| 203 |
+
times = []
|
| 204 |
+
for _ in range(n_trials):
|
| 205 |
+
start = time.perf_counter()
|
| 206 |
+
self.optimize_markowitz()
|
| 207 |
+
times.append(time.perf_counter() - start)
|
| 208 |
+
|
| 209 |
+
return {
|
| 210 |
+
'n_assets': self.n_assets,
|
| 211 |
+
'n_trials': n_trials,
|
| 212 |
+
'mean_time_ms': np.mean(times) * 1000,
|
| 213 |
+
'std_time_ms': np.std(times) * 1000,
|
| 214 |
+
'min_time_ms': np.min(times) * 1000,
|
| 215 |
+
'max_time_ms': np.max(times) * 1000
|
| 216 |
+
}
|
| 217 |
+
|
| 218 |
+
|
| 219 |
+
class OptionPricer:
|
| 220 |
+
"""Classical option pricing for benchmarking quantum amplitude estimation."""
|
| 221 |
+
|
| 222 |
+
@staticmethod
|
| 223 |
+
def black_scholes_call(S: float, K: float, T: float, r: float, sigma: float) -> float:
|
| 224 |
+
"""
|
| 225 |
+
Black-Scholes European call option price.
|
| 226 |
+
|
| 227 |
+
Args:
|
| 228 |
+
S: Current stock price
|
| 229 |
+
K: Strike price
|
| 230 |
+
T: Time to maturity (years)
|
| 231 |
+
r: Risk-free rate
|
| 232 |
+
sigma: Volatility
|
| 233 |
+
|
| 234 |
+
Returns:
|
| 235 |
+
Call option price
|
| 236 |
+
"""
|
| 237 |
+
from scipy.stats import norm
|
| 238 |
+
|
| 239 |
+
d1 = (np.log(S/K) + (r + 0.5*sigma**2)*T) / (sigma*np.sqrt(T))
|
| 240 |
+
d2 = d1 - sigma*np.sqrt(T)
|
| 241 |
+
|
| 242 |
+
return S * norm.cdf(d1) - K * np.exp(-r*T) * norm.cdf(d2)
|
| 243 |
+
|
| 244 |
+
@staticmethod
|
| 245 |
+
def monte_carlo_call(
|
| 246 |
+
S: float, K: float, T: float, r: float, sigma: float,
|
| 247 |
+
n_paths: int = 100000
|
| 248 |
+
) -> dict:
|
| 249 |
+
"""
|
| 250 |
+
Monte Carlo European call option pricing.
|
| 251 |
+
|
| 252 |
+
Args:
|
| 253 |
+
S: Current stock price
|
| 254 |
+
K: Strike price
|
| 255 |
+
T: Time to maturity (years)
|
| 256 |
+
r: Risk-free rate
|
| 257 |
+
sigma: Volatility
|
| 258 |
+
n_paths: Number of simulation paths
|
| 259 |
+
|
| 260 |
+
Returns:
|
| 261 |
+
Price estimate with confidence interval
|
| 262 |
+
"""
|
| 263 |
+
np.random.seed(42)
|
| 264 |
+
|
| 265 |
+
# Simulate terminal prices
|
| 266 |
+
Z = np.random.standard_normal(n_paths)
|
| 267 |
+
ST = S * np.exp((r - 0.5*sigma**2)*T + sigma*np.sqrt(T)*Z)
|
| 268 |
+
|
| 269 |
+
# Calculate payoffs
|
| 270 |
+
payoffs = np.maximum(ST - K, 0)
|
| 271 |
+
discounted = np.exp(-r*T) * payoffs
|
| 272 |
+
|
| 273 |
+
price = np.mean(discounted)
|
| 274 |
+
std_error = np.std(discounted) / np.sqrt(n_paths)
|
| 275 |
+
|
| 276 |
+
return {
|
| 277 |
+
'price': price,
|
| 278 |
+
'std_error': std_error,
|
| 279 |
+
'confidence_interval_95': (price - 1.96*std_error, price + 1.96*std_error),
|
| 280 |
+
'n_paths': n_paths
|
| 281 |
+
}
|
| 282 |
+
|
| 283 |
+
@staticmethod
|
| 284 |
+
def benchmark_monte_carlo_timing(
|
| 285 |
+
n_paths_list: list = None,
|
| 286 |
+
n_trials: int = 10
|
| 287 |
+
) -> list:
|
| 288 |
+
"""Benchmark Monte Carlo timing for different path counts."""
|
| 289 |
+
import time
|
| 290 |
+
|
| 291 |
+
if n_paths_list is None:
|
| 292 |
+
n_paths_list = [1000, 10000, 100000, 1000000]
|
| 293 |
+
|
| 294 |
+
results = []
|
| 295 |
+
for n_paths in n_paths_list:
|
| 296 |
+
times = []
|
| 297 |
+
for _ in range(n_trials):
|
| 298 |
+
start = time.perf_counter()
|
| 299 |
+
OptionPricer.monte_carlo_call(
|
| 300 |
+
S=100, K=100, T=1, r=0.05, sigma=0.2,
|
| 301 |
+
n_paths=n_paths
|
| 302 |
+
)
|
| 303 |
+
times.append(time.perf_counter() - start)
|
| 304 |
+
|
| 305 |
+
results.append({
|
| 306 |
+
'n_paths': n_paths,
|
| 307 |
+
'mean_time_ms': np.mean(times) * 1000,
|
| 308 |
+
'std_time_ms': np.std(times) * 1000
|
| 309 |
+
})
|
| 310 |
+
|
| 311 |
+
return results
|
| 312 |
+
|
| 313 |
+
|
| 314 |
+
def collect_experiment_data(n_assets: int = 25) -> dict:
|
| 315 |
+
"""
|
| 316 |
+
Collect data for quantum finance experiments.
|
| 317 |
+
|
| 318 |
+
Args:
|
| 319 |
+
n_assets: Number of assets to include
|
| 320 |
+
|
| 321 |
+
Returns:
|
| 322 |
+
Dictionary with prices, returns, and optimization inputs
|
| 323 |
+
"""
|
| 324 |
+
collector = FinanceDataCollector(
|
| 325 |
+
tickers=FinanceDataCollector.DEFAULT_TICKERS[:n_assets]
|
| 326 |
+
)
|
| 327 |
+
|
| 328 |
+
print(f"Fetching data for {n_assets} assets...")
|
| 329 |
+
prices = collector.fetch_historical_data(period="1y")
|
| 330 |
+
returns = collector.calculate_returns(prices)
|
| 331 |
+
cov_matrix = collector.calculate_covariance_matrix(returns)
|
| 332 |
+
exp_returns = collector.calculate_expected_returns(returns)
|
| 333 |
+
|
| 334 |
+
return {
|
| 335 |
+
'prices': prices,
|
| 336 |
+
'returns': returns,
|
| 337 |
+
'covariance_matrix': cov_matrix,
|
| 338 |
+
'expected_returns': exp_returns,
|
| 339 |
+
'n_assets': n_assets,
|
| 340 |
+
'n_observations': len(returns)
|
| 341 |
+
}
|
| 342 |
+
|
| 343 |
+
|
| 344 |
+
if __name__ == "__main__":
|
| 345 |
+
# Demo data collection and classical benchmarking
|
| 346 |
+
print("Finance Data Collection Demo")
|
| 347 |
+
print("=" * 50)
|
| 348 |
+
|
| 349 |
+
data = collect_experiment_data(n_assets=10)
|
| 350 |
+
print(f"Collected {data['n_observations']} days of data for {data['n_assets']} assets")
|
| 351 |
+
|
| 352 |
+
print("\nClassical Portfolio Optimization:")
|
| 353 |
+
print("-" * 50)
|
| 354 |
+
optimizer = ClassicalPortfolioOptimizer(
|
| 355 |
+
data['expected_returns'].values,
|
| 356 |
+
data['covariance_matrix'].values
|
| 357 |
+
)
|
| 358 |
+
result = optimizer.optimize_markowitz()
|
| 359 |
+
print(f"Expected Return: {result['expected_return']:.4f}")
|
| 360 |
+
print(f"Volatility: {result['volatility']:.4f}")
|
| 361 |
+
print(f"Sharpe Ratio: {result['sharpe_ratio']:.4f}")
|
| 362 |
+
|
| 363 |
+
print("\nOptimization Timing Benchmark:")
|
| 364 |
+
timing = optimizer.benchmark_timing(n_trials=100)
|
| 365 |
+
print(f"Mean time: {timing['mean_time_ms']:.3f} ms")
|
src/tools/quantum_tools.py
ADDED
|
@@ -0,0 +1,365 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Quantum simulation tools using Qiskit and PennyLane.
|
| 3 |
+
|
| 4 |
+
Provides utilities for:
|
| 5 |
+
- QAOA circuit simulation
|
| 6 |
+
- VQE implementations
|
| 7 |
+
- Noise modeling for NISQ assessment
|
| 8 |
+
- Resource estimation
|
| 9 |
+
"""
|
| 10 |
+
|
| 11 |
+
import numpy as np
|
| 12 |
+
from typing import Optional
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
class QuantumResourceEstimator:
|
| 16 |
+
"""Estimate quantum resources required for finance applications."""
|
| 17 |
+
|
| 18 |
+
# Current NISQ hardware constraints (2024-2026 estimates)
|
| 19 |
+
HARDWARE_SPECS = {
|
| 20 |
+
'ibm_osprey': {
|
| 21 |
+
'qubits': 433,
|
| 22 |
+
'gate_fidelity_1q': 0.9996,
|
| 23 |
+
'gate_fidelity_2q': 0.99,
|
| 24 |
+
'coherence_time_us': 100,
|
| 25 |
+
'gate_time_1q_ns': 35,
|
| 26 |
+
'gate_time_2q_ns': 300,
|
| 27 |
+
},
|
| 28 |
+
'ibm_condor': {
|
| 29 |
+
'qubits': 1121,
|
| 30 |
+
'gate_fidelity_1q': 0.9995,
|
| 31 |
+
'gate_fidelity_2q': 0.985,
|
| 32 |
+
'coherence_time_us': 80,
|
| 33 |
+
'gate_time_1q_ns': 35,
|
| 34 |
+
'gate_time_2q_ns': 300,
|
| 35 |
+
},
|
| 36 |
+
'ionq_forte': {
|
| 37 |
+
'qubits': 36,
|
| 38 |
+
'gate_fidelity_1q': 0.9999,
|
| 39 |
+
'gate_fidelity_2q': 0.995,
|
| 40 |
+
'coherence_time_us': 10000000, # Ion traps have very long coherence
|
| 41 |
+
'gate_time_1q_ns': 10000,
|
| 42 |
+
'gate_time_2q_ns': 200000,
|
| 43 |
+
},
|
| 44 |
+
'google_sycamore': {
|
| 45 |
+
'qubits': 72,
|
| 46 |
+
'gate_fidelity_1q': 0.9985,
|
| 47 |
+
'gate_fidelity_2q': 0.995,
|
| 48 |
+
'coherence_time_us': 20,
|
| 49 |
+
'gate_time_1q_ns': 25,
|
| 50 |
+
'gate_time_2q_ns': 32,
|
| 51 |
+
}
|
| 52 |
+
}
|
| 53 |
+
|
| 54 |
+
def __init__(self, hardware: str = 'ibm_osprey'):
|
| 55 |
+
"""Initialize with target hardware specifications."""
|
| 56 |
+
if hardware not in self.HARDWARE_SPECS:
|
| 57 |
+
raise ValueError(f"Unknown hardware: {hardware}. Choose from {list(self.HARDWARE_SPECS.keys())}")
|
| 58 |
+
self.hardware = hardware
|
| 59 |
+
self.specs = self.HARDWARE_SPECS[hardware]
|
| 60 |
+
|
| 61 |
+
def estimate_qaoa_resources(self, num_assets: int, p_layers: int = 1) -> dict:
|
| 62 |
+
"""
|
| 63 |
+
Estimate resources for QAOA portfolio optimization.
|
| 64 |
+
|
| 65 |
+
Args:
|
| 66 |
+
num_assets: Number of assets in portfolio
|
| 67 |
+
p_layers: Number of QAOA layers (depth parameter)
|
| 68 |
+
|
| 69 |
+
Returns:
|
| 70 |
+
Dictionary with resource estimates
|
| 71 |
+
"""
|
| 72 |
+
# QAOA for portfolio optimization typically requires n qubits for n assets
|
| 73 |
+
qubits_required = num_assets
|
| 74 |
+
|
| 75 |
+
# Gates per layer: roughly O(n^2) for cost Hamiltonian + O(n) for mixer
|
| 76 |
+
two_qubit_gates_per_layer = num_assets * (num_assets - 1) // 2
|
| 77 |
+
one_qubit_gates_per_layer = num_assets * 2
|
| 78 |
+
|
| 79 |
+
total_2q_gates = two_qubit_gates_per_layer * p_layers
|
| 80 |
+
total_1q_gates = one_qubit_gates_per_layer * p_layers
|
| 81 |
+
|
| 82 |
+
# Circuit depth estimate
|
| 83 |
+
circuit_depth = p_layers * (num_assets + 2)
|
| 84 |
+
|
| 85 |
+
# Total execution time
|
| 86 |
+
exec_time_ns = (total_1q_gates * self.specs['gate_time_1q_ns'] +
|
| 87 |
+
total_2q_gates * self.specs['gate_time_2q_ns'])
|
| 88 |
+
exec_time_us = exec_time_ns / 1000
|
| 89 |
+
|
| 90 |
+
# Error probability estimate
|
| 91 |
+
success_prob = (self.specs['gate_fidelity_1q'] ** total_1q_gates *
|
| 92 |
+
self.specs['gate_fidelity_2q'] ** total_2q_gates)
|
| 93 |
+
|
| 94 |
+
# Feasibility check
|
| 95 |
+
feasible = (
|
| 96 |
+
qubits_required <= self.specs['qubits'] and
|
| 97 |
+
exec_time_us < self.specs['coherence_time_us'] and
|
| 98 |
+
success_prob > 0.01 # At least 1% success probability
|
| 99 |
+
)
|
| 100 |
+
|
| 101 |
+
return {
|
| 102 |
+
'qubits_required': qubits_required,
|
| 103 |
+
'qubits_available': self.specs['qubits'],
|
| 104 |
+
'total_1q_gates': total_1q_gates,
|
| 105 |
+
'total_2q_gates': total_2q_gates,
|
| 106 |
+
'circuit_depth': circuit_depth,
|
| 107 |
+
'execution_time_us': exec_time_us,
|
| 108 |
+
'coherence_time_us': self.specs['coherence_time_us'],
|
| 109 |
+
'success_probability': success_prob,
|
| 110 |
+
'feasible_on_hardware': feasible,
|
| 111 |
+
'bottleneck': self._identify_bottleneck(
|
| 112 |
+
qubits_required, exec_time_us, success_prob
|
| 113 |
+
)
|
| 114 |
+
}
|
| 115 |
+
|
| 116 |
+
def estimate_amplitude_estimation_resources(
|
| 117 |
+
self,
|
| 118 |
+
precision_bits: int,
|
| 119 |
+
num_qubits_oracle: int
|
| 120 |
+
) -> dict:
|
| 121 |
+
"""
|
| 122 |
+
Estimate resources for quantum amplitude estimation (option pricing).
|
| 123 |
+
|
| 124 |
+
Args:
|
| 125 |
+
precision_bits: Number of bits of precision required
|
| 126 |
+
num_qubits_oracle: Qubits needed for the oracle (problem encoding)
|
| 127 |
+
|
| 128 |
+
Returns:
|
| 129 |
+
Dictionary with resource estimates
|
| 130 |
+
"""
|
| 131 |
+
# Total qubits: oracle + precision register
|
| 132 |
+
qubits_required = num_qubits_oracle + precision_bits
|
| 133 |
+
|
| 134 |
+
# Amplitude estimation requires O(2^precision) oracle calls
|
| 135 |
+
oracle_calls = 2 ** precision_bits
|
| 136 |
+
|
| 137 |
+
# Assume oracle has O(n^2) gates
|
| 138 |
+
gates_per_oracle = num_qubits_oracle ** 2
|
| 139 |
+
total_2q_gates = oracle_calls * gates_per_oracle
|
| 140 |
+
|
| 141 |
+
# Execution time
|
| 142 |
+
exec_time_us = (total_2q_gates * self.specs['gate_time_2q_ns']) / 1000
|
| 143 |
+
|
| 144 |
+
# Success probability
|
| 145 |
+
success_prob = self.specs['gate_fidelity_2q'] ** total_2q_gates
|
| 146 |
+
|
| 147 |
+
feasible = (
|
| 148 |
+
qubits_required <= self.specs['qubits'] and
|
| 149 |
+
exec_time_us < self.specs['coherence_time_us'] * 0.5 and
|
| 150 |
+
success_prob > 0.001
|
| 151 |
+
)
|
| 152 |
+
|
| 153 |
+
return {
|
| 154 |
+
'qubits_required': qubits_required,
|
| 155 |
+
'qubits_available': self.specs['qubits'],
|
| 156 |
+
'oracle_calls': oracle_calls,
|
| 157 |
+
'total_2q_gates': total_2q_gates,
|
| 158 |
+
'execution_time_us': exec_time_us,
|
| 159 |
+
'coherence_time_us': self.specs['coherence_time_us'],
|
| 160 |
+
'success_probability': success_prob,
|
| 161 |
+
'feasible_on_hardware': feasible,
|
| 162 |
+
'bottleneck': self._identify_bottleneck(
|
| 163 |
+
qubits_required, exec_time_us, success_prob
|
| 164 |
+
)
|
| 165 |
+
}
|
| 166 |
+
|
| 167 |
+
def estimate_grover_resources(self, search_space_size: int) -> dict:
|
| 168 |
+
"""
|
| 169 |
+
Estimate resources for Grover's search (fraud detection).
|
| 170 |
+
|
| 171 |
+
Args:
|
| 172 |
+
search_space_size: Size of search space N
|
| 173 |
+
|
| 174 |
+
Returns:
|
| 175 |
+
Dictionary with resource estimates
|
| 176 |
+
"""
|
| 177 |
+
# Qubits: log2(N) for encoding
|
| 178 |
+
qubits_required = int(np.ceil(np.log2(search_space_size)))
|
| 179 |
+
|
| 180 |
+
# Grover iterations: O(sqrt(N))
|
| 181 |
+
iterations = int(np.ceil(np.sqrt(search_space_size) * np.pi / 4))
|
| 182 |
+
|
| 183 |
+
# Gates per iteration: O(n) for oracle + O(n) for diffusion
|
| 184 |
+
gates_per_iteration = qubits_required * 4
|
| 185 |
+
total_2q_gates = iterations * gates_per_iteration
|
| 186 |
+
|
| 187 |
+
exec_time_us = (total_2q_gates * self.specs['gate_time_2q_ns']) / 1000
|
| 188 |
+
success_prob = self.specs['gate_fidelity_2q'] ** total_2q_gates
|
| 189 |
+
|
| 190 |
+
feasible = (
|
| 191 |
+
qubits_required <= self.specs['qubits'] and
|
| 192 |
+
exec_time_us < self.specs['coherence_time_us'] and
|
| 193 |
+
success_prob > 0.01
|
| 194 |
+
)
|
| 195 |
+
|
| 196 |
+
return {
|
| 197 |
+
'qubits_required': qubits_required,
|
| 198 |
+
'qubits_available': self.specs['qubits'],
|
| 199 |
+
'grover_iterations': iterations,
|
| 200 |
+
'total_2q_gates': total_2q_gates,
|
| 201 |
+
'execution_time_us': exec_time_us,
|
| 202 |
+
'coherence_time_us': self.specs['coherence_time_us'],
|
| 203 |
+
'success_probability': success_prob,
|
| 204 |
+
'feasible_on_hardware': feasible,
|
| 205 |
+
'classical_speedup': f"O(sqrt(N)) vs O(N)",
|
| 206 |
+
'bottleneck': self._identify_bottleneck(
|
| 207 |
+
qubits_required, exec_time_us, success_prob
|
| 208 |
+
)
|
| 209 |
+
}
|
| 210 |
+
|
| 211 |
+
def _identify_bottleneck(
|
| 212 |
+
self,
|
| 213 |
+
qubits_required: int,
|
| 214 |
+
exec_time_us: float,
|
| 215 |
+
success_prob: float
|
| 216 |
+
) -> str:
|
| 217 |
+
"""Identify the primary bottleneck for feasibility."""
|
| 218 |
+
bottlenecks = []
|
| 219 |
+
|
| 220 |
+
if qubits_required > self.specs['qubits']:
|
| 221 |
+
bottlenecks.append(f"Qubit count ({qubits_required} > {self.specs['qubits']})")
|
| 222 |
+
|
| 223 |
+
if exec_time_us > self.specs['coherence_time_us']:
|
| 224 |
+
ratio = exec_time_us / self.specs['coherence_time_us']
|
| 225 |
+
bottlenecks.append(f"Coherence time (circuit {ratio:.1f}x longer than coherence)")
|
| 226 |
+
|
| 227 |
+
if success_prob < 0.01:
|
| 228 |
+
bottlenecks.append(f"Gate errors (success prob {success_prob:.2e})")
|
| 229 |
+
|
| 230 |
+
return "; ".join(bottlenecks) if bottlenecks else "None - appears feasible"
|
| 231 |
+
|
| 232 |
+
|
| 233 |
+
class NISQNoiseModel:
|
| 234 |
+
"""Model noise effects on NISQ quantum circuits."""
|
| 235 |
+
|
| 236 |
+
def __init__(self, depolarizing_rate: float = 0.01, measurement_error: float = 0.02):
|
| 237 |
+
"""
|
| 238 |
+
Initialize noise model.
|
| 239 |
+
|
| 240 |
+
Args:
|
| 241 |
+
depolarizing_rate: Single-qubit depolarizing error rate
|
| 242 |
+
measurement_error: Measurement error probability
|
| 243 |
+
"""
|
| 244 |
+
self.depolarizing_rate = depolarizing_rate
|
| 245 |
+
self.measurement_error = measurement_error
|
| 246 |
+
|
| 247 |
+
def estimate_output_fidelity(self, num_gates: int, num_qubits: int) -> float:
|
| 248 |
+
"""
|
| 249 |
+
Estimate output state fidelity after noisy circuit execution.
|
| 250 |
+
|
| 251 |
+
Args:
|
| 252 |
+
num_gates: Total number of gates in circuit
|
| 253 |
+
num_qubits: Number of qubits
|
| 254 |
+
|
| 255 |
+
Returns:
|
| 256 |
+
Estimated fidelity (0 to 1)
|
| 257 |
+
"""
|
| 258 |
+
# Simplified noise model: each gate reduces fidelity
|
| 259 |
+
gate_fidelity = (1 - self.depolarizing_rate) ** num_gates
|
| 260 |
+
|
| 261 |
+
# Measurement errors
|
| 262 |
+
meas_fidelity = (1 - self.measurement_error) ** num_qubits
|
| 263 |
+
|
| 264 |
+
return gate_fidelity * meas_fidelity
|
| 265 |
+
|
| 266 |
+
def required_shots_for_precision(
|
| 267 |
+
self,
|
| 268 |
+
target_precision: float,
|
| 269 |
+
success_probability: float
|
| 270 |
+
) -> int:
|
| 271 |
+
"""
|
| 272 |
+
Calculate required measurement shots for target precision.
|
| 273 |
+
|
| 274 |
+
Args:
|
| 275 |
+
target_precision: Desired precision (e.g., 0.01 for 1%)
|
| 276 |
+
success_probability: Probability of successful circuit execution
|
| 277 |
+
|
| 278 |
+
Returns:
|
| 279 |
+
Number of shots required
|
| 280 |
+
"""
|
| 281 |
+
# Using Hoeffding bound: shots >= 1/(2 * precision^2 * success_prob)
|
| 282 |
+
if success_probability < 1e-10:
|
| 283 |
+
return float('inf')
|
| 284 |
+
|
| 285 |
+
shots = int(np.ceil(1 / (2 * target_precision**2 * success_probability)))
|
| 286 |
+
return min(shots, 10**9) # Cap at 1 billion shots
|
| 287 |
+
|
| 288 |
+
|
| 289 |
+
def run_qaoa_simulation(num_assets: int = 10, p_layers: int = 1) -> dict:
|
| 290 |
+
"""
|
| 291 |
+
Run a simplified QAOA simulation for portfolio optimization.
|
| 292 |
+
|
| 293 |
+
This is a demonstration of the simulation capability.
|
| 294 |
+
Full implementation would use Qiskit or PennyLane.
|
| 295 |
+
|
| 296 |
+
Args:
|
| 297 |
+
num_assets: Number of assets
|
| 298 |
+
p_layers: QAOA depth
|
| 299 |
+
|
| 300 |
+
Returns:
|
| 301 |
+
Simulation results
|
| 302 |
+
"""
|
| 303 |
+
try:
|
| 304 |
+
import pennylane as qml
|
| 305 |
+
|
| 306 |
+
# Create a simple QAOA-style circuit
|
| 307 |
+
dev = qml.device('default.qubit', wires=min(num_assets, 10))
|
| 308 |
+
|
| 309 |
+
@qml.qnode(dev)
|
| 310 |
+
def qaoa_circuit(gamma, beta):
|
| 311 |
+
# Initial superposition
|
| 312 |
+
for i in range(min(num_assets, 10)):
|
| 313 |
+
qml.Hadamard(wires=i)
|
| 314 |
+
|
| 315 |
+
# Simplified cost layer
|
| 316 |
+
for i in range(min(num_assets, 10) - 1):
|
| 317 |
+
qml.CNOT(wires=[i, i+1])
|
| 318 |
+
qml.RZ(gamma, wires=i+1)
|
| 319 |
+
qml.CNOT(wires=[i, i+1])
|
| 320 |
+
|
| 321 |
+
# Mixer layer
|
| 322 |
+
for i in range(min(num_assets, 10)):
|
| 323 |
+
qml.RX(beta, wires=i)
|
| 324 |
+
|
| 325 |
+
return qml.expval(qml.PauliZ(0))
|
| 326 |
+
|
| 327 |
+
# Run with sample parameters
|
| 328 |
+
result = qaoa_circuit(0.5, 0.3)
|
| 329 |
+
|
| 330 |
+
return {
|
| 331 |
+
'status': 'success',
|
| 332 |
+
'expectation_value': float(result),
|
| 333 |
+
'num_qubits_used': min(num_assets, 10),
|
| 334 |
+
'simulator': 'pennylane.default.qubit'
|
| 335 |
+
}
|
| 336 |
+
|
| 337 |
+
except ImportError:
|
| 338 |
+
return {
|
| 339 |
+
'status': 'pennylane_not_available',
|
| 340 |
+
'message': 'PennyLane not installed. Install with: pip install pennylane'
|
| 341 |
+
}
|
| 342 |
+
except Exception as e:
|
| 343 |
+
return {
|
| 344 |
+
'status': 'error',
|
| 345 |
+
'message': str(e)
|
| 346 |
+
}
|
| 347 |
+
|
| 348 |
+
|
| 349 |
+
if __name__ == "__main__":
|
| 350 |
+
# Demo resource estimation
|
| 351 |
+
estimator = QuantumResourceEstimator('ibm_osprey')
|
| 352 |
+
|
| 353 |
+
print("QAOA Resource Estimation for 50-asset portfolio:")
|
| 354 |
+
print("-" * 50)
|
| 355 |
+
result = estimator.estimate_qaoa_resources(num_assets=50, p_layers=3)
|
| 356 |
+
for key, value in result.items():
|
| 357 |
+
print(f" {key}: {value}")
|
| 358 |
+
|
| 359 |
+
print("\nAmplitude Estimation for Option Pricing (8-bit precision):")
|
| 360 |
+
print("-" * 50)
|
| 361 |
+
result = estimator.estimate_amplitude_estimation_resources(
|
| 362 |
+
precision_bits=8, num_qubits_oracle=20
|
| 363 |
+
)
|
| 364 |
+
for key, value in result.items():
|
| 365 |
+
print(f" {key}: {value}")
|
src/utils/__init__.py
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Utility modules for quantum finance framework.
|
| 3 |
+
"""
|
| 4 |
+
|
| 5 |
+
from .evaluation import (
|
| 6 |
+
EvaluationMetrics,
|
| 7 |
+
MetricsCollector,
|
| 8 |
+
HallucinationChecker,
|
| 9 |
+
calculate_expert_alignment,
|
| 10 |
+
extract_scores_from_text,
|
| 11 |
+
LITERATURE_CONSENSUS
|
| 12 |
+
)
|
| 13 |
+
|
| 14 |
+
__all__ = [
|
| 15 |
+
'EvaluationMetrics',
|
| 16 |
+
'MetricsCollector',
|
| 17 |
+
'HallucinationChecker',
|
| 18 |
+
'calculate_expert_alignment',
|
| 19 |
+
'extract_scores_from_text',
|
| 20 |
+
'LITERATURE_CONSENSUS'
|
| 21 |
+
]
|
src/utils/evaluation.py
ADDED
|
@@ -0,0 +1,377 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Evaluation metrics for the quantum finance feasibility framework.
|
| 3 |
+
|
| 4 |
+
Metrics defined per plan.md:
|
| 5 |
+
1. Expert Alignment: Agreement with literature/expert consensus
|
| 6 |
+
2. Hallucination Rate: Factual accuracy of agent outputs
|
| 7 |
+
3. Computational Efficiency: Agent rounds and time per evaluation
|
| 8 |
+
"""
|
| 9 |
+
|
| 10 |
+
import re
|
| 11 |
+
import time
|
| 12 |
+
from dataclasses import dataclass, field
|
| 13 |
+
from typing import Optional
|
| 14 |
+
from datetime import datetime
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
@dataclass
|
| 18 |
+
class EvaluationMetrics:
|
| 19 |
+
"""Container for evaluation metrics of a single run."""
|
| 20 |
+
idea: str
|
| 21 |
+
start_time: datetime = field(default_factory=datetime.now)
|
| 22 |
+
end_time: Optional[datetime] = None
|
| 23 |
+
|
| 24 |
+
# Computational efficiency metrics
|
| 25 |
+
total_agent_rounds: int = 0
|
| 26 |
+
total_tokens_used: int = 0
|
| 27 |
+
wall_clock_time_seconds: float = 0.0
|
| 28 |
+
|
| 29 |
+
# Quality metrics (to be assessed manually or via comparison)
|
| 30 |
+
expert_alignment_score: Optional[float] = None # 0-1 scale
|
| 31 |
+
hallucination_count: int = 0
|
| 32 |
+
factual_claims_count: int = 0
|
| 33 |
+
|
| 34 |
+
# Output scores from agents
|
| 35 |
+
quantum_feasibility_score: Optional[float] = None
|
| 36 |
+
hardware_readiness_score: Optional[float] = None
|
| 37 |
+
classical_competitiveness_score: Optional[float] = None
|
| 38 |
+
business_viability_score: Optional[float] = None
|
| 39 |
+
overall_score: Optional[float] = None
|
| 40 |
+
|
| 41 |
+
def complete(self):
|
| 42 |
+
"""Mark evaluation as complete and calculate duration."""
|
| 43 |
+
self.end_time = datetime.now()
|
| 44 |
+
self.wall_clock_time_seconds = (self.end_time - self.start_time).total_seconds()
|
| 45 |
+
|
| 46 |
+
@property
|
| 47 |
+
def hallucination_rate(self) -> Optional[float]:
|
| 48 |
+
"""Calculate hallucination rate as fraction of factual claims."""
|
| 49 |
+
if self.factual_claims_count == 0:
|
| 50 |
+
return None
|
| 51 |
+
return self.hallucination_count / self.factual_claims_count
|
| 52 |
+
|
| 53 |
+
def to_dict(self) -> dict:
|
| 54 |
+
"""Convert to dictionary for serialization."""
|
| 55 |
+
return {
|
| 56 |
+
'idea': self.idea,
|
| 57 |
+
'start_time': self.start_time.isoformat(),
|
| 58 |
+
'end_time': self.end_time.isoformat() if self.end_time else None,
|
| 59 |
+
'total_agent_rounds': self.total_agent_rounds,
|
| 60 |
+
'total_tokens_used': self.total_tokens_used,
|
| 61 |
+
'wall_clock_time_seconds': self.wall_clock_time_seconds,
|
| 62 |
+
'expert_alignment_score': self.expert_alignment_score,
|
| 63 |
+
'hallucination_rate': self.hallucination_rate,
|
| 64 |
+
'quantum_feasibility_score': self.quantum_feasibility_score,
|
| 65 |
+
'hardware_readiness_score': self.hardware_readiness_score,
|
| 66 |
+
'classical_competitiveness_score': self.classical_competitiveness_score,
|
| 67 |
+
'business_viability_score': self.business_viability_score,
|
| 68 |
+
'overall_score': self.overall_score
|
| 69 |
+
}
|
| 70 |
+
|
| 71 |
+
|
| 72 |
+
class MetricsCollector:
|
| 73 |
+
"""Collect and aggregate metrics across multiple evaluations."""
|
| 74 |
+
|
| 75 |
+
def __init__(self):
|
| 76 |
+
self.evaluations: list[EvaluationMetrics] = []
|
| 77 |
+
|
| 78 |
+
def start_evaluation(self, idea: str) -> EvaluationMetrics:
|
| 79 |
+
"""Start tracking a new evaluation."""
|
| 80 |
+
metrics = EvaluationMetrics(idea=idea)
|
| 81 |
+
self.evaluations.append(metrics)
|
| 82 |
+
return metrics
|
| 83 |
+
|
| 84 |
+
def get_summary_statistics(self) -> dict:
|
| 85 |
+
"""Calculate summary statistics across all evaluations."""
|
| 86 |
+
if not self.evaluations:
|
| 87 |
+
return {'error': 'No evaluations recorded'}
|
| 88 |
+
|
| 89 |
+
completed = [e for e in self.evaluations if e.end_time is not None]
|
| 90 |
+
|
| 91 |
+
if not completed:
|
| 92 |
+
return {'error': 'No completed evaluations'}
|
| 93 |
+
|
| 94 |
+
times = [e.wall_clock_time_seconds for e in completed]
|
| 95 |
+
rounds = [e.total_agent_rounds for e in completed]
|
| 96 |
+
|
| 97 |
+
alignment_scores = [e.expert_alignment_score for e in completed
|
| 98 |
+
if e.expert_alignment_score is not None]
|
| 99 |
+
overall_scores = [e.overall_score for e in completed
|
| 100 |
+
if e.overall_score is not None]
|
| 101 |
+
|
| 102 |
+
import numpy as np
|
| 103 |
+
|
| 104 |
+
return {
|
| 105 |
+
'total_evaluations': len(completed),
|
| 106 |
+
'timing': {
|
| 107 |
+
'mean_seconds': np.mean(times),
|
| 108 |
+
'std_seconds': np.std(times),
|
| 109 |
+
'min_seconds': np.min(times),
|
| 110 |
+
'max_seconds': np.max(times)
|
| 111 |
+
},
|
| 112 |
+
'agent_rounds': {
|
| 113 |
+
'mean': np.mean(rounds),
|
| 114 |
+
'std': np.std(rounds),
|
| 115 |
+
'min': np.min(rounds),
|
| 116 |
+
'max': np.max(rounds)
|
| 117 |
+
},
|
| 118 |
+
'expert_alignment': {
|
| 119 |
+
'mean': np.mean(alignment_scores) if alignment_scores else None,
|
| 120 |
+
'n_rated': len(alignment_scores)
|
| 121 |
+
},
|
| 122 |
+
'overall_scores': {
|
| 123 |
+
'mean': np.mean(overall_scores) if overall_scores else None,
|
| 124 |
+
'std': np.std(overall_scores) if overall_scores else None
|
| 125 |
+
}
|
| 126 |
+
}
|
| 127 |
+
|
| 128 |
+
|
| 129 |
+
# Ground truth for validation against literature consensus
|
| 130 |
+
LITERATURE_CONSENSUS = {
|
| 131 |
+
'portfolio_optimization_qaoa': {
|
| 132 |
+
'quantum_advantage_near_term': False,
|
| 133 |
+
'feasible_on_nisq': True, # Can run, but no advantage
|
| 134 |
+
'bottleneck': 'noise_and_classical_competition',
|
| 135 |
+
'recommended_approach': 'hybrid',
|
| 136 |
+
'references': [
|
| 137 |
+
'Egger et al. (2020) - Quantum Computing for Finance',
|
| 138 |
+
'Herman et al. (2022) - Portfolio Optimization Survey'
|
| 139 |
+
]
|
| 140 |
+
},
|
| 141 |
+
'option_pricing_amplitude_estimation': {
|
| 142 |
+
'quantum_advantage_near_term': False,
|
| 143 |
+
'feasible_on_nisq': False, # Requires error correction
|
| 144 |
+
'bottleneck': 'circuit_depth_and_error_correction',
|
| 145 |
+
'recommended_approach': 'classical_monte_carlo',
|
| 146 |
+
'references': [
|
| 147 |
+
'Stamatopoulos et al. (2020) - Option Pricing using QC',
|
| 148 |
+
'Chakrabarti et al. (2021) - Threshold for Quantum Speedup'
|
| 149 |
+
]
|
| 150 |
+
},
|
| 151 |
+
'fraud_detection_quantum_ml': {
|
| 152 |
+
'quantum_advantage_near_term': False,
|
| 153 |
+
'feasible_on_nisq': True, # Can run, limited scale
|
| 154 |
+
'bottleneck': 'data_loading_and_classical_ml_strength',
|
| 155 |
+
'recommended_approach': 'classical_ml',
|
| 156 |
+
'references': [
|
| 157 |
+
'Schuld & Petruccione (2021) - ML with Quantum Computers',
|
| 158 |
+
'Tang (2019) - Quantum-inspired classical algorithms'
|
| 159 |
+
]
|
| 160 |
+
},
|
| 161 |
+
'risk_analysis_quantum_monte_carlo': {
|
| 162 |
+
'quantum_advantage_near_term': False,
|
| 163 |
+
'feasible_on_nisq': False,
|
| 164 |
+
'bottleneck': 'quadratic_speedup_insufficient_with_noise',
|
| 165 |
+
'recommended_approach': 'gpu_accelerated_classical',
|
| 166 |
+
'references': [
|
| 167 |
+
'Woerner & Egger (2019) - Quantum Risk Analysis',
|
| 168 |
+
'Miyamoto & Shiohara (2022) - Bermudan Option Pricing'
|
| 169 |
+
]
|
| 170 |
+
},
|
| 171 |
+
'credit_scoring_vqc': {
|
| 172 |
+
'quantum_advantage_near_term': False,
|
| 173 |
+
'feasible_on_nisq': True,
|
| 174 |
+
'bottleneck': 'barren_plateaus_and_expressibility',
|
| 175 |
+
'recommended_approach': 'classical_ensemble_methods',
|
| 176 |
+
'references': [
|
| 177 |
+
'McClean et al. (2018) - Barren Plateaus',
|
| 178 |
+
'Cerezo et al. (2021) - Variational Quantum Algorithms'
|
| 179 |
+
]
|
| 180 |
+
}
|
| 181 |
+
}
|
| 182 |
+
|
| 183 |
+
|
| 184 |
+
def calculate_expert_alignment(
|
| 185 |
+
agent_output: dict,
|
| 186 |
+
use_case_key: str
|
| 187 |
+
) -> dict:
|
| 188 |
+
"""
|
| 189 |
+
Calculate alignment between agent output and literature consensus.
|
| 190 |
+
|
| 191 |
+
Args:
|
| 192 |
+
agent_output: Structured output from the agent crew
|
| 193 |
+
use_case_key: Key into LITERATURE_CONSENSUS dict
|
| 194 |
+
|
| 195 |
+
Returns:
|
| 196 |
+
Alignment analysis with score
|
| 197 |
+
"""
|
| 198 |
+
if use_case_key not in LITERATURE_CONSENSUS:
|
| 199 |
+
return {
|
| 200 |
+
'error': f'Unknown use case: {use_case_key}',
|
| 201 |
+
'available_cases': list(LITERATURE_CONSENSUS.keys())
|
| 202 |
+
}
|
| 203 |
+
|
| 204 |
+
consensus = LITERATURE_CONSENSUS[use_case_key]
|
| 205 |
+
alignment_checks = []
|
| 206 |
+
|
| 207 |
+
# Check quantum advantage assessment
|
| 208 |
+
if 'quantum_advantage' in agent_output:
|
| 209 |
+
agent_says_advantage = agent_output.get('quantum_advantage', False)
|
| 210 |
+
consensus_advantage = consensus['quantum_advantage_near_term']
|
| 211 |
+
alignment_checks.append({
|
| 212 |
+
'criterion': 'quantum_advantage_assessment',
|
| 213 |
+
'agent': agent_says_advantage,
|
| 214 |
+
'consensus': consensus_advantage,
|
| 215 |
+
'aligned': agent_says_advantage == consensus_advantage
|
| 216 |
+
})
|
| 217 |
+
|
| 218 |
+
# Check feasibility assessment
|
| 219 |
+
if 'feasible_on_nisq' in agent_output:
|
| 220 |
+
agent_feasible = agent_output.get('feasible_on_nisq', False)
|
| 221 |
+
consensus_feasible = consensus['feasible_on_nisq']
|
| 222 |
+
alignment_checks.append({
|
| 223 |
+
'criterion': 'nisq_feasibility',
|
| 224 |
+
'agent': agent_feasible,
|
| 225 |
+
'consensus': consensus_feasible,
|
| 226 |
+
'aligned': agent_feasible == consensus_feasible
|
| 227 |
+
})
|
| 228 |
+
|
| 229 |
+
# Calculate alignment score
|
| 230 |
+
if alignment_checks:
|
| 231 |
+
aligned_count = sum(1 for c in alignment_checks if c['aligned'])
|
| 232 |
+
alignment_score = aligned_count / len(alignment_checks)
|
| 233 |
+
else:
|
| 234 |
+
alignment_score = None
|
| 235 |
+
|
| 236 |
+
return {
|
| 237 |
+
'use_case': use_case_key,
|
| 238 |
+
'alignment_checks': alignment_checks,
|
| 239 |
+
'alignment_score': alignment_score,
|
| 240 |
+
'consensus_references': consensus['references']
|
| 241 |
+
}
|
| 242 |
+
|
| 243 |
+
|
| 244 |
+
def extract_scores_from_text(text: str) -> dict:
|
| 245 |
+
"""
|
| 246 |
+
Extract numerical scores from agent output text.
|
| 247 |
+
|
| 248 |
+
Looks for patterns like:
|
| 249 |
+
- "score: 0.7"
|
| 250 |
+
- "feasibility score (0-1): 0.65"
|
| 251 |
+
- "Rating: 7/10"
|
| 252 |
+
"""
|
| 253 |
+
scores = {}
|
| 254 |
+
|
| 255 |
+
# Pattern: "X score: 0.Y" or "X score (0-1): 0.Y"
|
| 256 |
+
score_pattern = r'(\w+(?:\s+\w+)?)\s+score\s*(?:\([^)]+\))?\s*[:=]\s*([\d.]+)'
|
| 257 |
+
for match in re.finditer(score_pattern, text, re.IGNORECASE):
|
| 258 |
+
label = match.group(1).lower().replace(' ', '_')
|
| 259 |
+
value = float(match.group(2))
|
| 260 |
+
if 0 <= value <= 1:
|
| 261 |
+
scores[f'{label}_score'] = value
|
| 262 |
+
elif 0 <= value <= 10:
|
| 263 |
+
scores[f'{label}_score'] = value / 10
|
| 264 |
+
|
| 265 |
+
# Pattern: "Rating: X/10"
|
| 266 |
+
rating_pattern = r'rating\s*[:=]\s*([\d.]+)\s*/\s*10'
|
| 267 |
+
for match in re.finditer(rating_pattern, text, re.IGNORECASE):
|
| 268 |
+
value = float(match.group(1))
|
| 269 |
+
scores['rating'] = value / 10
|
| 270 |
+
|
| 271 |
+
return scores
|
| 272 |
+
|
| 273 |
+
|
| 274 |
+
class HallucinationChecker:
|
| 275 |
+
"""
|
| 276 |
+
Check agent outputs for potential hallucinations.
|
| 277 |
+
|
| 278 |
+
Compares claims against known facts about quantum computing
|
| 279 |
+
and finance applications.
|
| 280 |
+
"""
|
| 281 |
+
|
| 282 |
+
# Known facts for validation
|
| 283 |
+
KNOWN_FACTS = {
|
| 284 |
+
# Hardware facts (2024-2026)
|
| 285 |
+
'ibm_qubit_count': (433, 1121), # Range: Osprey to Condor
|
| 286 |
+
'ionq_qubit_count': (32, 36),
|
| 287 |
+
'google_qubit_count': (72, 100),
|
| 288 |
+
|
| 289 |
+
# Algorithm facts
|
| 290 |
+
'grover_speedup': 'quadratic', # sqrt(N)
|
| 291 |
+
'shor_speedup': 'exponential',
|
| 292 |
+
'qaoa_proven_advantage': False,
|
| 293 |
+
'vqe_proven_advantage': False,
|
| 294 |
+
|
| 295 |
+
# Finance facts
|
| 296 |
+
'hft_latency_requirement_us': 1, # microseconds
|
| 297 |
+
'typical_portfolio_size': (10, 10000),
|
| 298 |
+
}
|
| 299 |
+
|
| 300 |
+
HALLUCINATION_PATTERNS = [
|
| 301 |
+
# Claims of proven quantum advantage for NISQ
|
| 302 |
+
r'proven\s+quantum\s+advantage\s+(?:for|in|on)\s+(?:NISQ|near-term)',
|
| 303 |
+
r'demonstrat(?:ed|es)\s+quantum\s+supremacy\s+(?:for|in)\s+finance',
|
| 304 |
+
|
| 305 |
+
# Unrealistic hardware claims
|
| 306 |
+
r'(?:current|available)\s+(?:quantum\s+)?computers?\s+(?:with|have)\s+(?:\d{4,}|\d+,\d{3,})\s+qubits',
|
| 307 |
+
|
| 308 |
+
# Impossible speedup claims
|
| 309 |
+
r'exponential\s+speedup\s+(?:for|in|using)\s+(?:QAOA|VQE)',
|
| 310 |
+
]
|
| 311 |
+
|
| 312 |
+
def check_output(self, text: str) -> dict:
|
| 313 |
+
"""
|
| 314 |
+
Check text for potential hallucinations.
|
| 315 |
+
|
| 316 |
+
Args:
|
| 317 |
+
text: Agent output text to check
|
| 318 |
+
|
| 319 |
+
Returns:
|
| 320 |
+
Dictionary with hallucination analysis
|
| 321 |
+
"""
|
| 322 |
+
findings = []
|
| 323 |
+
|
| 324 |
+
# Check against hallucination patterns
|
| 325 |
+
for pattern in self.HALLUCINATION_PATTERNS:
|
| 326 |
+
matches = re.findall(pattern, text, re.IGNORECASE)
|
| 327 |
+
if matches:
|
| 328 |
+
findings.append({
|
| 329 |
+
'type': 'suspicious_claim',
|
| 330 |
+
'pattern': pattern,
|
| 331 |
+
'matches': matches
|
| 332 |
+
})
|
| 333 |
+
|
| 334 |
+
# Check qubit count claims
|
| 335 |
+
qubit_claims = re.findall(r'(\d+)\s*qubits?', text, re.IGNORECASE)
|
| 336 |
+
for claim in qubit_claims:
|
| 337 |
+
count = int(claim)
|
| 338 |
+
if count > 2000: # No current hardware has this many
|
| 339 |
+
findings.append({
|
| 340 |
+
'type': 'unrealistic_qubit_count',
|
| 341 |
+
'claimed': count,
|
| 342 |
+
'realistic_max': 1121
|
| 343 |
+
})
|
| 344 |
+
|
| 345 |
+
return {
|
| 346 |
+
'potential_hallucinations': len(findings),
|
| 347 |
+
'findings': findings,
|
| 348 |
+
'text_length': len(text)
|
| 349 |
+
}
|
| 350 |
+
|
| 351 |
+
|
| 352 |
+
if __name__ == "__main__":
|
| 353 |
+
# Demo metrics collection
|
| 354 |
+
collector = MetricsCollector()
|
| 355 |
+
|
| 356 |
+
# Simulate an evaluation
|
| 357 |
+
metrics = collector.start_evaluation(
|
| 358 |
+
"Quantum portfolio optimization using QAOA"
|
| 359 |
+
)
|
| 360 |
+
metrics.total_agent_rounds = 5
|
| 361 |
+
metrics.quantum_feasibility_score = 0.6
|
| 362 |
+
metrics.hardware_readiness_score = 0.4
|
| 363 |
+
metrics.classical_competitiveness_score = 0.8
|
| 364 |
+
metrics.business_viability_score = 0.5
|
| 365 |
+
metrics.overall_score = 0.3
|
| 366 |
+
metrics.expert_alignment_score = 0.85
|
| 367 |
+
|
| 368 |
+
import time
|
| 369 |
+
time.sleep(0.1) # Simulate some work
|
| 370 |
+
metrics.complete()
|
| 371 |
+
|
| 372 |
+
print("Evaluation Metrics Demo")
|
| 373 |
+
print("=" * 50)
|
| 374 |
+
print(metrics.to_dict())
|
| 375 |
+
|
| 376 |
+
print("\nSummary Statistics:")
|
| 377 |
+
print(collector.get_summary_statistics())
|