F# library for Azure Quantum with quantum-first optimization (Graph Coloring, TSP, MaxCut, Knapsack, Network Flow, Portfolio), Azure Quantum backend integration (IonQ, Rigetti, Quantinuum, Atom Computing), extensible circuit validation, local quantum simulation, QAOA with automatic parameter optimization (Nelder-Mead), OpenQASM 2.0 support, error mitigation techniques (ZNE, PEC, REM), Quantum Random Number Generation (QRNG), and educational quantum algorithms (Grover, QFT, Amplitude Amplification) with cloud backend execution. Multi-provider architecture supports IonQ, Rigetti, Quantinuum, Atom Computing, IBM, Amazon Braket, and Google Cirq.
$ dotnet add package FSharp.Azure.QuantumHybrid Quantum-Classical F# Library - Intelligently routes optimization problems between classical algorithms (fast, cheap) and quantum backends (scalable, powerful) based on problem size and structure.
Features:
open FSharp.Azure.Quantum.Classical
// Solve a TSP problem with named cities
let cities = [
("Seattle", 47.6, -122.3)
("Portland", 45.5, -122.7)
("San Francisco", 37.8, -122.4)
]
match TSP.solveDirectly cities None with
| Ok tour ->
printfn "Best route: %A" tour.Cities
printfn "Distance: %.2f miles" tour.TotalDistance
| Error msg -> printfn "Error: %s" msg
NuGet Package: FSharp.Azure.Quantum
dotnet add package FSharp.Azure.Quantum --prereleaseAutomatically chooses the best solver (quantum or classical) based on problem characteristics:
// Let the solver decide automatically
match HybridSolver.solveTsp distances None None None with
| Ok solution ->
printfn "Method used: %A" solution.Method // Classical or Quantum
printfn "Reasoning: %s" solution.Reasoning
printfn "Solution: %A" solution.Result
| Error msg -> printfn "Error: %s" msgSolve routing problems with named cities:
let cities = [("NYC", 40.7, -74.0); ("LA", 34.0, -118.2); ("Chicago", 41.9, -87.6)]
// Option 1: Direct solve (easiest)
let tour = TSP.solveDirectly cities None
// Option 2: Build problem first (for customization)
let problem = TSP.createProblem cities
let tour = TSP.solve problem (Some customConfig)Features:
Optimize investment portfolios with risk/return constraints:
let assets = [
("AAPL", 0.12, 0.18, 150.0) // symbol, return, risk, price
("MSFT", 0.10, 0.15, 300.0)
("GOOGL", 0.15, 0.20, 2800.0)
]
let allocation = Portfolio.solveDirectly assets 10000.0 None
match allocation with
| Ok result ->
printfn "Total Value: $%.2f" result.TotalValue
printfn "Expected Return: %.2f%%" (result.ExpectedReturn * 100.0)
printfn "Risk: %.2f" result.Risk
| Error msg -> printfn "Error: %s" msgFeatures:
Get recommendations on when to use quantum vs classical:
match QuantumAdvisor.getRecommendation distances with
| Ok recommendation ->
printfn "Recommendation: %A" recommendation.RecommendationType
printfn "Problem size: %d" recommendation.ProblemSize
printfn "Reasoning: %s" recommendation.Reasoning
| Error msg -> printfn "Error: %s" msgDirect access to classical optimization algorithms:
// TSP Solver
let tspSolution = TspSolver.solveWithDistances distances TspSolver.defaultConfig
// Portfolio Solver
let portfolio = PortfolioSolver.solveGreedyByRatio assets constraints PortfolioSolver.defaultConfigTest quantum algorithms offline without Azure credentials:
open FSharp.Azure.Quantum.Core
open FSharp.Azure.Quantum.Core.QuantumBackend
open FSharp.Azure.Quantum.Core.QaoaCircuit
// Create a QAOA circuit (example: 3-qubit MaxCut)
let quboMatrix = array2D [[0.0; 0.5; 0.5]; [0.5; 0.0; 0.5]; [0.5; 0.5; 0.0]]
let circuit = {
NumQubits = 3
InitialStateGates = [| H(0); H(1); H(2) |]
Layers = [|
{
CostGates = [| RZZ(0, 1, 0.5); RZZ(1, 2, 0.5); RZZ(0, 2, 0.5) |]
MixerGates = [| RX(0, 1.0); RX(1, 1.0); RX(2, 1.0) |]
Gamma = 0.25
Beta = 0.5
}
|]
ProblemHamiltonian = ProblemHamiltonian.fromQubo quboMatrix
MixerHamiltonian = MixerHamiltonian.create 3
}
// Execute on local simulator
match Local.simulate circuit 1000 with
| Ok result ->
printfn "Backend: %s" result.Backend
printfn "Time: %.2f ms" result.ExecutionTimeMs
result.Counts
|> Map.toList
|> List.sortByDescending snd
|> List.take 3
|> List.iter (fun (bitstring, count) ->
printfn " %s: %d shots" bitstring count)
| Error msg ->
eprintfn "Error: %s" msgFeatures:
QAOA Multi-Provider Support:
QAOA circuits use OpenQASM 2.0 format, making them compatible with all major quantum providers:
open FSharp.Azure.Quantum.Core.QaoaCircuit
// Build QAOA circuit (provider-agnostic)
let quboMatrix = array2D [[1.0; -2.0]; [-2.0; 1.0]]
let problemHam = ProblemHamiltonian.fromQubo quboMatrix
let mixerHam = MixerHamiltonian.create 2
let circuit = QaoaCircuit.build problemHam mixerHam [|(0.5, 0.3)|]
// Export to OpenQASM 2.0 (universal format)
let qasm = QaoaCircuit.toOpenQasm circuit
printfn "%s" qasm
// Output:
// OPENQASM 2.0;
// include "qelib1.inc";
// qreg q[2];
// // Initial state preparation
// h q[0];
// h q[1];
// ...Provider Compatibility:
Why QAOA is Provider-Agnostic:
Execute quantum circuits on Azure Quantum backends (IonQ, Rigetti):
open FSharp.Azure.Quantum.Core
open FSharp.Azure.Quantum.Core.Authentication
open FSharp.Azure.Quantum.Core.IonQBackend
// Step 1: Create authenticated HTTP client
let credential = CredentialProviders.createDefaultCredential() // Uses Azure CLI, Managed Identity, etc.
let httpClient = Authentication.createAuthenticatedClient credential
// Step 2: Build workspace URL
let subscriptionId = "your-subscription-id"
let resourceGroup = "your-resource-group"
let workspaceName = "your-workspace-name"
let location = "eastus"
let workspaceUrl =
$"https://management.azure.com/subscriptions/{subscriptionId}/resourceGroups/{resourceGroup}/providers/Microsoft.Quantum/Workspaces/{workspaceName}"
// Step 3: Create IonQ circuit (Bell state example)
let circuit: IonQCircuit = {
Qubits = 2
Circuit = [
SingleQubit("h", 0) // Hadamard on qubit 0
TwoQubit("cnot", 0, 1) // CNOT with control=0, target=1
Measure([|0; 1|]) // Measure both qubits
]
}
// Step 4: Submit and execute
async {
let! result = IonQBackend.submitAndWaitForResultsAsync httpClient workspaceUrl circuit 100 "ionq.simulator"
match result with
| Ok histogram ->
printfn "✅ Job completed!"
histogram
|> Map.iter (fun bitstring count ->
printfn " %s: %d shots" bitstring count)
| Error err ->
eprintfn "❌ Error: %A" err
} |> Async.RunSynchronouslySupported Backends:
ionq.simulator - IonQ cloud simulatorionq.qpu.aria-1 - IonQ Aria-1 QPU (requires credits)rigetti.sim.qvm - Rigetti QVM simulatorrigetti.qpu.aspen-m-3 - Rigetti Aspen-M-3 QPU (requires credits)Authentication Methods:
DefaultAzureCredential() - Tries Azure CLI, Managed Identity, Environment VariablesAzureCliCredential() - Uses az login credentialsManagedIdentityCredential() - For Azure VMs/App ServicesFeatures:
Validate circuits against backend constraints before submission to catch errors early and avoid costly failed API calls:
open FSharp.Azure.Quantum.Core.CircuitValidator
// Example: Validate circuit for IonQ simulator
let circuit = {
NumQubits = 5
GateCount = 50
UsedGates = Set.ofList ["H"; "CNOT"; "RX"]
TwoQubitGates = [(0, 1); (1, 2)]
}
let constraints = BackendConstraints.ionqSimulator()
match validateCircuit constraints circuit with
| Ok () ->
printfn "✅ Circuit valid for IonQ simulator"
| Error errors ->
printfn "❌ Validation failed:"
errors |> List.iter (fun err ->
printfn " - %s" (formatValidationError err))Built-in Backend Constraints:
// Local simulator (1-10 qubits, all gates, no depth limit)
let local = BackendConstraints.localSimulator()
// IonQ simulator (29 qubits, all-to-all connectivity, 100 gate limit)
let ionqSim = BackendConstraints.ionqSimulator()
// IonQ hardware (11 qubits, all-to-all connectivity, 100 gate limit)
let ionqHw = BackendConstraints.ionqHardware()
// Rigetti Aspen-M-3 (79 qubits, limited connectivity, 50 gate limit)
let rigetti = BackendConstraints.rigettiAspenM3()Auto-Detection from Target String:
// Automatically detect constraints from Azure Quantum target
match KnownTargets.getConstraints "ionq.simulator" with
| Some constraints ->
// Validate circuit...
validateCircuit constraints myCircuit
| None ->
printfn "Unknown target - provide custom constraints"Integrated Validation (IonQ):
// IonQ backend validates automatically before submission
async {
let! result = IonQBackend.submitAndWaitForResultsWithValidationAsync
httpClient
workspaceUrl
circuit
1000 // shots
"ionq.simulator"
None // Auto-detect constraints from target string
match result with
| Ok histogram -> printfn "Success!"
| Error (InvalidCircuit errors) ->
printfn "Circuit validation failed before submission:"
errors |> List.iter (printfn " %s")
| Error otherError ->
printfn "Execution error: %A" otherError
} |> Async.RunSynchronouslyCustom Backend Constraints:
// Define constraints for a new quantum provider
let ibmConstraints = BackendConstraints.create
"IBM Quantum Eagle" // Name
127 // Max qubits
["H"; "X"; "CX"; "RZ"] // Supported gates
(Some 1000) // Max circuit depth
false // Limited connectivity
[(0,1); (1,2); (2,3)] // Connected qubit pairs
// Use custom constraints
match validateCircuit ibmConstraints myCircuit with
| Ok () -> printfn "Valid for IBM Quantum!"
| Error errors -> printfn "Validation errors: %A" errorsValidation Checks:
Analyze problem complexity and characteristics:
match ProblemAnalysis.classifyProblem distances with
| Ok info ->
printfn "Type: %A" info.ProblemType
printfn "Size: %d" info.Size
printfn "Complexity: %s" info.Complexity
| Error msg -> printfn "Error: %s" msgEstimate quantum execution costs before running:
let estimate = CostEstimation.estimateQuantumCost problemSize shots tier
printfn "Estimated cost: $%.2f %s" estimate.EstimatedCost estimate.CurrencyHybrid Design: Classical algorithms for small problems, quantum for large. Detailed architecture →
Three Layers:
HybridSolver routes to classical or quantumKey Difference:
TspSolver - Classical algorithm, NO backend parameter, CPU executionQuantumTspSolver - Quantum algorithm, REQUIRES backend parameter// Classical - fast, free
TspSolver.solve distances config
// Quantum - scalable, ~$10-100 per run
QuantumTspSolver.solve rigettiBackend distances 1000
// Hybrid - automatic routing
HybridSolver.solveTsp distances None None None| Component | Description |
|---|---|
| Classical Solvers | TSP, Portfolio optimization with CPU algorithms |
| Quantum Solvers | TSP (QAOA), Quantum Chemistry (VQE) |
| HybridSolver | Automatic routing based on problem size |
| Azure Quantum | IonQ and Rigetti backend integration |
| Local Simulator | Offline testing (≤10 qubits) |
| Problem Builders | Graph, Subset, Scheduling, CSP |
| Error Mitigation | ZNE, PEC, readout error correction |
Fluent APIs for encoding optimization problems:
| Builder | Domains |
|---|---|
| GraphOptimization | TSP, Graph Coloring, MaxCut |
| SubsetSelection | Knapsack, Portfolio, Set Cover |
| Scheduling | Task Scheduling, Resource Allocation |
| ConstraintSatisfaction | N-Queens, Sudoku |
| CircuitBuilder | Low-level quantum circuits |
All builders support both classical and quantum solvers.
The library automatically recommends quantum vs classical based on:
Use HybridSolver to decide automatically!
dotnet builddotnet testAll 548 tests passing ✅ (including local simulation, Azure Quantum backends, and validation tests)
cd examples
dotnet runClassical Solvers (Local Execution):
| Problem | Size | Time | Quality |
|---|---|---|---|
| TSP | 10 cities | ~20ms | Optimal |
| TSP | 50 cities | ~500ms | Within 5% of optimal |
| TSP | 100 cities | ~2s | Within 10% of optimal |
| Portfolio | 20 assets | ~10ms | Optimal |
| Portfolio | 50 assets | ~50ms | Near-optimal |
Contributions welcome! This is an alpha release and we're actively improving.
docs-for-mulder/AI-DEVELOPMENT-GUIDE.md)dev branchUnlicense - Public domain. Use freely for any purpose.
Built with:
Developed using AI-assisted TDD methodology.
Status: Alpha (v0.1.0) - Classical solvers production-ready, quantum integration coming soon.
Last Updated: 2025-11-24