Skip to the content.

API Reference

Complete reference for FSharp.Azure.Quantum quantum optimization APIs.

Table of Contents

Business Optimization APIs:

Quantum Algorithm APIs (Research & Education):

Infrastructure:


Error Handling

All FSharp.Azure.Quantum APIs use QuantumResult<T> with structured QuantumError types:

// Type alias for clarity
type QuantumResult<'T> = Result<'T, QuantumError>

Basic Error Handling

All solver APIs return QuantumResult<T> for consistent, type-safe error handling:

open FSharp.Azure.Quantum
open FSharp.Azure.Quantum.GraphColoring

match GraphColoring.solve problem 3 None with
| Ok solution -> 
    printfn "Success! Colors used: %d" solution.ColorsUsed
| Error err -> 
    printfn "Error: %s" err.Message  // Human-readable message

QuantumError Types

Errors are categorized for precise handling:

type QuantumError =
    | ValidationError of field: string * reason: string
    | OperationError of operation: string * context: string
    | BackendError of backend: string * reason: string
    | IOError of operation: string * path: string * reason: string
    | NotImplemented of feature: string * hint: string option
    | Other of message: string

Advanced Error Handling

Pattern match on error types for custom handling:

match TSP.solve cities None with
| Ok tour -> processTour tour
| Error (QuantumError.ValidationError (field, reason)) ->
    printfn "Invalid %s: %s" field reason
| Error (QuantumError.BackendError (backend, reason)) ->
    printfn "Backend %s failed: %s" backend reason
    // Retry with different backend
| Error err ->
    printfn "Unexpected error: %s" err.Message

Use the quantumResult builder to avoid nested match clauses:

let processWorkflow input backend = quantumResult {
    do! validateInput input
    let! encoded = encodeToQubo input
    let! result = executeQuantum encoded backend
    return result
}

See QuantumResult Builder Guide for complete details.


Quick Start Patterns

open FSharp.Azure.Quantum
open FSharp.Azure.Quantum.GraphColoring

// Graph Coloring: Uses LocalBackend automatically
let problem = graphColoring {
    node "R1" ["R2"; "R3"]
    node "R2" ["R1"]
    node "R3" ["R1"]
    colors ["Red"; "Blue"; "Green"]
}

match GraphColoring.solve problem 3 None with
| Ok solution -> 
    printfn "Colors used: %d" solution.ColorsUsed
    printfn "Valid: %b" solution.IsValid
| Error err -> 
    printfn "Error: %s" err.Message

Pattern 2: Cloud Backend (Large Problems)

// Create Azure Quantum backend
let backend = // Cloud backend - requires Azure Quantum workspace
// BackendAbstraction.createIonQBackend(
    connectionString = "YOUR_CONNECTION_STRING",
    targetId = "ionq.simulator"
)

// Solve on cloud quantum hardware
match GraphColoring.solve problem 3 (Some backend) with
| Ok solution -> 
    printfn "Colors used: %d" solution.ColorsUsed
    printfn "Valid: %b" solution.IsValid
| Error err -> 
    printfn "Error: %s" err.Message

Pattern 3: Inspect Solution Details

// Solve and inspect detailed results
match GraphColoring.solve problem 3 None with
| Ok solution -> 
    printfn "Solution found!"
    printfn "  Colors used: %d" solution.ColorsUsed
    printfn "  Conflicts: %d" solution.ConflictCount
    printfn "  Valid: %b" solution.IsValid
    
    // Print color assignments
    solution.Assignments
    |> Map.iter (fun node color ->
        printfn "  %s -> %s" node color
    )
| Error err -> printfn "Error: %s" err.Message

Graph Coloring Builder

Module: FSharp.Azure.Quantum.GraphColoring

Use Cases:

Computation Expression API

let problem_scheduling = graphColoring {
    // Define nodes with conflicts
    node "Task1" ["Task2"; "Task3"]
    node "Task2" ["Task1"; "Task4"]
    node "Task3" ["Task1"]
    node "Task4" ["Task2"]
    
    // Available colors/resources
    colors ["Slot A"; "Slot B"; "Slot C"]
    
    // Optimization objective
    objective MinimizeColors  // or MinimizeConflicts, BalanceColors
}

Types

type ColoredNode = {
    Id: string
    ConflictsWith: string list
    FixedColor: string option         // Pre-assigned color
    Priority: float                   // Tie-breaking priority
    AvoidColors: string list          // Soft constraints
    Properties: Map<string, obj>      // Custom metadata
}

type ColoringObjective =
    | MinimizeColors      // Minimize chromatic number
    | MinimizeConflicts   // Allow invalid colorings, minimize violations
    | BalanceColors       // Load balancing

type ColoringSolution = {
    Assignments: Map<string, string>   // Node → Color mapping
    ColorsUsed: int
    ConflictCount: int
    IsValid: bool
    ColorDistribution: Map<string, int>
    Cost: float
    BackendName: string
    IsQuantum: bool
}

Functions

val validate : GraphColoringProblem → QuantumResult<unit>
val solve : GraphColoringProblem → int → IQuantumBackend option → QuantumResult<ColoringSolution>

Parameters:

Example

// Register allocation for compiler
let registers = graphColoring {
    // Variables that interfere (live at same time)
    node "x" ["y"; "z"]
    node "y" ["x"; "w"]
    node "z" ["x"; "w"]
    node "w" ["y"; "z"]
    
    // Available CPU registers
    colors ["EAX"; "EBX"; "ECX"; "EDX"]
    
    objective MinimizeColors
}

match GraphColoring.solve registers 4 None with
| Ok solution ->
    printfn "Registers needed: %d" solution.ColorsUsed
    solution.Assignments 
    |> Map.iter (fun var reg -> printfn "%s → %s" var reg)
| Error err ->
    printfn "Allocation failed: %s" err.Message

MaxCut Builder

Module: FSharp.Azure.Quantum.MaxCut

Use Cases:

Functions

val createProblem : string list → (string * string * float) list → MaxCutProblem
val completeGraph : string list → float → MaxCutProblem
val cycleGraph : string list → float → MaxCutProblem
val solve : MaxCutProblem → IQuantumBackend option → QuantumResult<Solution>

Types

type MaxCutProblem = {
    Vertices: string list
    Edges: Edge<float> list
    VertexCount: int
    EdgeCount: int
}

type Solution = {
    PartitionS: string list         // First partition
    PartitionT: string list         // Second partition
    CutValue: float                 // Total edge weight crossing partition
    CutEdges: Edge<float> list      // Edges in the cut
    BackendName: string
    IsQuantum: bool
}

Example

// Network partitioning
let vertices = ["Server1"; "Server2"; "Server3"; "Server4"]
let edges = [
    ("Server1", "Server2", 10.0)  // communication cost
    ("Server2", "Server3", 5.0)
    ("Server3", "Server4", 8.0)
    ("Server4", "Server1", 3.0)
    ("Server1", "Server3", 12.0)
]

let problem_maxcut = MaxCut.createProblem vertices edges

match MaxCut.solve problem_maxcut None with
| Ok solution ->
    printfn "Partition 1: %A" solution.PartitionS
    printfn "Partition 2: %A" solution.PartitionT
    printfn "Inter-partition traffic: %.2f" solution.CutValue
| Error err ->
    printfn "Partitioning failed: %s" err.Message

Knapsack Builder

Module: FSharp.Azure.Quantum.Knapsack

Use Cases:

Functions

val createProblem : (string * float * float) list → float → Problem
val solve : Problem → IQuantumBackend option → QuantumResult<Solution>

Parameters:

Types

type Item = {
    Id: string
    Weight: float
    Value: float
}

type Problem = {
    Items: Item list
    Capacity: float
    ItemCount: int
    TotalValue: float
    TotalWeight: float
}

type Solution = {
    SelectedItems: Item list
    TotalWeight: float
    TotalValue: float
    IsFeasible: bool
    Efficiency: float                // Value per unit weight
    CapacityUtilization: float       // Percentage used
    BackendName: string
    IsQuantum: bool
}

Example

// Cargo loading optimization
let cargo = [
    ("Electronics", 50.0, 10000.0)
    ("Furniture", 200.0, 5000.0)
    ("Textiles", 30.0, 3000.0)
    ("Machinery", 150.0, 8000.0)
    ("Food", 80.0, 2000.0)
]

let problem_knapsack = Knapsack.createProblem cargo 300.0  // 300kg capacity

match Knapsack.solve problem_knapsack None with
| Ok solution ->
    printfn "Total value: $%.2f" solution.TotalValue
    printfn "Weight: %.2f/%.2f kg" solution.TotalWeight problem_knapsack.Capacity
    printfn "Efficiency: $%.2f/kg" solution.Efficiency
    
    solution.SelectedItems 
    |> List.iter (fun item -> 
        printfn "  Load: %s (%.2f kg, $%.2f)" item.Id item.Weight item.Value)
| Error err ->
    printfn "Optimization failed: %s" err.Message

TSP Builder

Module: FSharp.Azure.Quantum.TSP

Use Cases:

Functions

val createProblem : (string * float * float) list → TspProblem
val solve : TspProblem → IQuantumBackend option → QuantumResult<Tour>

Parameters:

Types

type TspProblem = {
    Cities: City array
    CityCount: int
    DistanceMatrix: float[,]
}

type Tour = {
    Cities: string list             // City names in tour order
    TotalDistance: float
    IsValid: bool
}

Example

// Delivery route optimization
let cities = [
    ("Warehouse", 0.0, 0.0)
    ("Customer A", 5.0, 3.0)
    ("Customer B", 2.0, 7.0)
    ("Customer C", 8.0, 4.0)
    ("Customer D", 3.0, 6.0)
]

let problem_tsp = TSP.createProblem cities

match TSP.solve problem_tsp None with
| Ok tour ->
    printfn "Optimal route: %s" (String.concat " → " tour.Cities)
    printfn "Total distance: %.2f km" tour.TotalDistance
| Error err ->
    printfn "Route optimization failed: %s" err.Message

Portfolio Builder

Module: FSharp.Azure.Quantum.Portfolio

Use Cases:

Functions

val createProblem : (string * float * float * float) list → float → PortfolioProblem
val solve : PortfolioProblem → IQuantumBackend option → QuantumResult<PortfolioAllocation>

Parameters:

Types

type PortfolioProblem = {
    Assets: Asset array
    AssetCount: int
    Budget: float
    Constraints: Constraints option
}

type PortfolioAllocation = {
    Allocations: (string * float * float) list  // (symbol, shares, value)
    TotalValue: float
    ExpectedReturn: float
    Risk: float
    IsValid: bool
}

Example

// Investment allocation
let assets = [
    ("AAPL", 0.12, 0.15, 150.0)      // return, risk, price
    ("GOOGL", 0.10, 0.12, 2800.0)
    ("MSFT", 0.11, 0.14, 350.0)
    ("BONDS", 0.05, 0.03, 100.0)
]

let problem_portfolio = Portfolio.createProblem assets 50000.0  // $50k budget

match Portfolio.solve problem_portfolio None with
| Ok allocation ->
    printfn "Portfolio value: $%.2f" allocation.TotalValue
    printfn "Expected return: %.2f%%" (allocation.ExpectedReturn * 100.0)
    printfn "Portfolio risk: %.2f" allocation.Risk
    
    allocation.Allocations 
    |> List.iter (fun (symbol, shares, value) ->
        printfn "  %s: %.2f shares = $%.2f" symbol shares value)
| Error err ->
    printfn "Allocation failed: %s" err.Message

Network Flow Builder

Module: FSharp.Azure.Quantum.NetworkFlow

Use Cases:

Types

type NodeType =
    | Source        // Supplier, factory
    | Sink          // Customer, demand point
    | Intermediate  // Warehouse, distribution center

type Node = {
    Id: string
    NodeType: NodeType
    Capacity: int
    Demand: int option      // Sinks only
    Supply: int option      // Sources only
}

type Route = {
    From: string
    To: string
    Cost: float
}

type FlowSolution = {
    SelectedRoutes: (string * string * float) list
    TotalCost: float
    DemandSatisfied: float
    TotalDemand: float
    FillRate: float
    IsValid: bool
    BackendName: string
}

Helper Functions

val SourceNode : string → int → Node
val SinkNode : string → int → Node
val IntermediateNode : string → int → Node
val Route : string → string → float → Route
val solve : NetworkFlowProblem → IQuantumBackend option → QuantumResult<FlowSolution>

Example

// Supply chain optimization
let nodes = [
    NetworkFlow.SourceNode("Factory A", 1000)
    NetworkFlow.SourceNode("Factory B", 800)
    NetworkFlow.IntermediateNode("Warehouse", 1500)
    NetworkFlow.SinkNode("Store 1", 400)
    NetworkFlow.SinkNode("Store 2", 600)
    NetworkFlow.SinkNode("Store 3", 300)
]

let routes = [
    NetworkFlow.Route("Factory A", "Warehouse", 5.0)
    NetworkFlow.Route("Factory B", "Warehouse", 4.0)
    NetworkFlow.Route("Warehouse", "Store 1", 3.0)
    NetworkFlow.Route("Warehouse", "Store 2", 2.5)
    NetworkFlow.Route("Warehouse", "Store 3", 4.5)
]

let problem = { NetworkFlow.Nodes = nodes; Routes = routes }

match NetworkFlow.solve problem None with
| Ok flow ->
    printfn "Total cost: $%.2f" flow.TotalCost
    printfn "Fill rate: %.1f%%" (flow.FillRate * 100.0)
    
    flow.SelectedRoutes 
    |> List.iter (fun (from, to_, amount) ->
        printfn "  %s → %s: %.2f units" from to_ amount)
| Error err ->
    printfn "Optimization failed: %s" err.Message

Quantum Backends

Module: FSharp.Azure.Quantum.Core.BackendAbstraction

LocalBackend

Characteristics:

let backend = LocalBackendFactory.createUnified()

// Use with any solver
match GraphColoring.solve problem 3 (Some backend) with
| Ok solution -> printfn "Colors used: %d" solution.ColorsUsed

IonQBackend (Azure Quantum)

Characteristics:

let backend = // Cloud backend - requires Azure Quantum workspace
// BackendAbstraction.createIonQBackend(
    connectionString = "Endpoint=https://...",
    targetId = "ionq.simulator"  // or "ionq.qpu"
)

match GraphColoring.solve problem 3 (Some backend) with
| Ok solution -> 
    printfn "Executed on: %s" solution.BackendName

RigettiBackend (Azure Quantum)

let backend = // Cloud backend - requires Azure Quantum workspace
// BackendAbstraction.createRigettiBackend(
    connectionString = "Endpoint=https://...",
    targetId = "rigetti.sim.qvm"  // or QPU target
)

Backend Selection Guide

Problem Size Recommended Backend Rationale
≤20 qubits LocalBackend Free, fast, sufficient
17-20 qubits IonQ/Rigetti Simulator Scalable, still affordable
20+ qubits IonQ/Rigetti QPU Real quantum hardware needed

C# Interop

Module: FSharp.Azure.Quantum.CSharpBuilders

All problem builders have C#-friendly static methods:

using FSharp.Azure.Quantum;
using static FSharp.Azure.Quantum.CSharpBuilders;

// MaxCut
var vertices = new[] { "A", "B", "C" };
var edges = new[] {
    (source: "A", target: "B", weight: 1.0),
    (source: "B", target: "C", weight: 2.0)
};
var problem = MaxCutProblem(vertices, edges);
var result = MaxCut.solve(problem, null);

// Knapsack
var items = new[] {
    (id: "laptop", weight: 3.0, value: 1000.0)
};
var problem = KnapsackProblem(items, capacity: 5.0);

// TSP
var cities = new[] {
    (name: "Seattle", x: 0.0, y: 0.0)
};
var problem = TspProblem(cities);

// Portfolio
var assets = new[] {
    (symbol: "AAPL", expectedReturn: 0.12, risk: 0.15, price: 150.0)
};
var problem = PortfolioProblem(assets, budget: 10000.0);

See: C# interoperability examples above for complete usage


Core Types

Result Type

All solvers return QuantumResult<'T>:

match solver.solve problem with
| Ok solution -> 
    // Success case
    printfn "Solution: %A" solution
| Error errorMessage -> 
    // Failure case
    printfn "Error: %s" errorMessage

IQuantumBackend Interface

type IQuantumBackend =
    abstract Execute : Circuit -> int -> ExecutionResult
    abstract Name : string

Circuit Types

type Gate =
    | H of int                       // Hadamard
    | RX of int * float              // Rotation-X
    | RY of int * float              // Rotation-Y
    | RZ of int * float              // Rotation-Z
    | CNOT of int * int              // Controlled-NOT
    | RZZ of int * int * float       // Two-qubit rotation

type QaoaLayer = {
    CostGates: Gate array
    MixerGates: Gate array
    Gamma: float
    Beta: float
}

type Circuit = {
    NumQubits: int
    InitialStateGates: Gate array
    Layers: QaoaLayer array
}

Quantum Linear System Solver (HHL Algorithm)

Module: FSharp.Azure.Quantum.QuantumLinearSystemSolver

Use Cases (Scientific & Engineering):

Algorithm: HHL (Harrow-Hassidim-Lloyd) - solves Ax = b exponentially faster than classical methods

What is HHL?

HHL solves linear systems Ax = b where:

Quantum Advantage:

Computation Expression API

open FSharp.Azure.Quantum
open FSharp.Azure.Quantum.QuantumLinearSystemSolver

// Simple 2×2 system: [[3,1],[1,3]] * x = [1,0]
let problem = linearSystemSolver {
    matrix [[3.0, 1.0]; [1.0, 3.0]]
    vector [1.0; 0.0]
    precision 4  // 4 eigenvalue qubits = 16 bins
}

match solve problem with
| Ok solution ->
    printfn "Success probability: %.4f" solution.SuccessProbability
    printfn "Condition number: %A" solution.ConditionNumber
    printfn "Gates used: %d" solution.GateCount
| Error err ->
    printfn "Error: %s" err.Message

Advanced Configuration

// Diagonal system (faster, more accurate)
let problem = linearSystemSolver {
    diagonalMatrix [2.0; 4.0; 8.0; 16.0]  // Eigenvalues
    vector [1.0; 1.0; 1.0; 1.0]
    precision 8
    eigenvalueQubits 6                     // Override precision
    inversionMethod (ExactRotation 1.0)   // Exact vs linear approximation
    minEigenvalue 0.001                    // Stability threshold
    postSelection true                     // Higher accuracy, lower success rate
    backend ionQBackend                    // Cloud quantum hardware
    shots 2000                             // Measurement samples
}

Types

type LinearSystemProblem = {
    Matrix: HermitianMatrix
    InputVector: QuantumVector
    EigenvalueQubits: int
    InversionMethod: EigenvalueInversionMethod
    MinEigenvalue: float
    UsePostSelection: bool
    Backend: IQuantumBackend option
    Shots: int option
}

type EigenvalueInversionMethod =
    | ExactRotation of normalizationConstant: float
    | LinearApproximation of normalizationConstant: float
    | PiecewiseLinear of segments: (float * float * float)[]

type LinearSystemSolution = {
    SuccessProbability: float
    EstimatedEigenvalues: float[]
    ConditionNumber: float option
    GateCount: int
    PostSelectionSuccess: bool
    SolutionAmplitudes: Map<int, Complex> option
    BackendName: string
    IsQuantum: bool
    Success: bool
    Message: string
}

Functions

val solve : LinearSystemProblem → QuantumResult<LinearSystemSolution>
val solve2x2 : float → float → float → float → float → float → QuantumResult<LinearSystemSolution>
val solveDiagonal : float list → float list → QuantumResult<LinearSystemSolution>

Example: Engineering Simulation

// Solve heat equation discretization: Ax = b
// A = tridiagonal matrix (heat diffusion operator)
// b = boundary conditions

let heatDiffusion = linearSystemSolver {
    matrix [
        [2.0, -1.0,  0.0,  0.0]
        [-1.0, 2.0, -1.0,  0.0]
        [0.0, -1.0,  2.0, -1.0]
        [0.0,  0.0, -1.0,  2.0]
    ]
    vector [100.0; 0.0; 0.0; 50.0]  // Boundary temps
    precision 6
    minEigenvalue 0.01  // Avoid small eigenvalues
}

match solve heatDiffusion with
| Ok solution ->
    printfn "Temperature distribution computed!"
    printfn "Condition number: %.2f" (defaultArg solution.ConditionNumber 0.0)
    
    match solution.SolutionAmplitudes with
    | Some amplitudes ->
        amplitudes 
        |> Map.iter (fun idx amp -> 
            printfn "  Point %d: %.4f" idx amp.Magnitude)
    | None ->
        printfn "Use measurement statistics for cloud backends"
| Error err ->
    printfn "Simulation failed: %s" err.Message

Example: Machine Learning (Least Squares)

// Solve normal equations: (X^T X) w = X^T y
// For linear regression: find weights w

let leastSquares = linearSystemSolver {
    // Covariance matrix X^T X (must be symmetric positive definite)
    matrix [
        [10.0,  5.0,  2.0]
        [ 5.0, 12.0,  3.0]
        [ 2.0,  3.0,  8.0]
    ]
    // Right-hand side X^T y
    vector [15.0; 20.0; 10.0]
    precision 8
    postSelection true  // Higher accuracy for ML
}

match solve leastSquares with
| Ok solution ->
    printfn "Model weights found!"
    printfn "Success rate: %.2f%%" (solution.SuccessProbability * 100.0)
| Error err ->
    printfn "Training failed: %s" err.Message

Important Limitations

⚠️ Matrix Requirements:

⚠️ Solution Format:

⚠️ Performance Considerations:

When to Use HHL vs Classical

Problem Size Condition Number Sparsity Recommendation
N ≤ 100 Any Any Classical (Gaussian elimination faster)
100 < N ≤ 1000 κ < 10 Sparse HHL (modest speedup)
N > 1000 κ < 100 Sparse HHL (exponential speedup!)
Any N κ > 1000 Any Classical (HHL success rate too low)

Advanced Topics

Custom QAOA Parameters

open FSharp.Azure.Quantum.Quantum

// Configure optimization behavior
let config : QuantumMaxCutSolver.QuantumMaxCutConfig = {
    OptimizationShots = 50           // Shots per optimization iteration
    FinalShots = 500                 // Shots for final measurement
    EnableOptimization = true        // Enable parameter search
    InitialParameters = (0.5, 0.5)   // Starting (gamma, beta)
}

// Use with quantum solver directly
let backend = LocalBackendFactory.createUnified()
match QuantumMaxCutSolver.solve backend problem config with
| Ok result -> 
    let (gamma, beta) = result.OptimizedParameters
    printfn "Optimal parameters: γ=%.3f, β=%.3f" gamma beta

Error Handling Patterns

// Pattern 1: Match on Result
match solver.solve problem with
| Ok solution -> processSuccess solution
| Error err -> handleError msg

// Pattern 2: Result.map
problem
|> solver.solve
|> Result.map (fun solution -> solution.Cost)
|> Result.defaultValue infinity

// Pattern 3: Railway-oriented programming
let workflow problem =
    problem
    |> validate
    |> Result.bind solve
    |> Result.map postProcess

Performance Tips

1. Start Small

// Test with LocalBackend first
let testProblem = MaxCut.createProblem ["A"; "B"; "C"] []
match MaxCut.solve testProblem None with
| Ok _ -> 
    // Works! Now scale up
    let largeProblem = MaxCut.createProblem largeVertices largeEdges
    printfn "Created large problem with %d vertices" largeVertices.Length

2. Use Problem Validation

// Validate before solving
match GraphColoring.validate problem with
| Ok () -> 
    GraphColoring.solve problem 3 None
| Error err -> 
    Error (sprintf "Invalid problem: %s" err.Message)

3. Cache Backends

// Create once, reuse many times
let backend = LocalBackendFactory.createUnified()

problems 
|> List.map (fun p -> GraphColoring.solve p 3 (Some backend))
|> List.choose Result.toOption


Last Updated: 2025-11-29