QUBO / Ising API¶
The quprep.qubo module provides QUBO and Ising problem formulation, QAOA circuit generation, and D-Wave export.
Classical reference solvers (solve_brute, solve_sa) are available in
quprep.qubo.solver for benchmarking quantum results against classical baselines.
They are not part of the public quprep.qubo namespace.
Core types¶
quprep.qubo.converter.QUBOResult(Q, offset=0.0, variable_map=None, n_original=None)
¶
Result of a QUBO conversion.
Attributes:
| Name | Type | Description |
|---|---|---|
Q |
(ndarray, shape(n, n))
|
Upper-triangular QUBO matrix. Q[i,i] are linear (bias) terms; Q[i,j] for i<j are quadratic couplings. Suitable for D-Wave samplers, QAOA, and OpenQAOA. |
offset |
float
|
Constant offset term (does not affect the optimal solution). |
variable_map |
dict
|
Mapping from variable names to matrix indices. Empty by default. |
n_original |
int
|
Number of original (non-slack) variables. Equals Q.shape[0] unless inequality constraints introduced slack variables. |
Functions¶
evaluate(x)
¶
Evaluate the QUBO objective for a given binary assignment.
Computes \(x^T Q x + ext{offset}\).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x
|
(array - like, shape(n))
|
Binary assignment vector with values in {0, 1}. |
required |
Returns:
| Type | Description |
|---|---|
float
|
Objective value including the constant offset. |
Examples:
from_dict(d)
classmethod
¶
Deserialize from a dict produced by to_dict().
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
d
|
dict
|
Dict with keys Q, offset, variable_map, n_original. |
required |
Returns:
| Type | Description |
|---|---|
QUBOResult
|
Reconstructed QUBO problem. |
to_dict()
¶
Serialize to a plain Python dict (JSON-compatible).
Returns:
| Type | Description |
|---|---|
dict
|
Keys: |
to_dwave()
¶
Export QUBO as a D-Wave Ocean SDK-compatible linear/quadratic dict.
Returns a dict mapping (i, j) tuples to coefficients, where:
i == jencodes linear (bias) terms (from the diagonal of Q)i < jencodes quadratic (coupling) terms (from upper triangle of Q)
Zero entries are omitted. The result can be passed directly to
dimod.BinaryQuadraticModel.from_qubo() or
dwave.system.DWaveSampler.
Returns:
| Type | Description |
|---|---|
dict
|
|
Examples:
to_ising()
¶
Convert QUBO to Ising (h, J) form.
Returns:
| Type | Description |
|---|---|
IsingResult
|
Ising model equivalent to this QUBO problem. |
quprep.qubo.ising.IsingResult(h, J, offset=0.0)
dataclass
¶
Ising model representation.
Attributes:
| Name | Type | Description |
|---|---|---|
h |
(ndarray, shape(n))
|
Linear (bias) coefficients. |
J |
(ndarray, shape(n, n))
|
Quadratic (coupling) coefficients, upper-triangular (J[i,j] for i < j). |
offset |
float
|
Constant energy offset. |
Functions¶
to_qubo()
¶
Convert Ising (h, J) back to QUBO form.
Uses the inverse transformation \(x_i = (s_i + 1) / 2\):
Returns:
| Type | Description |
|---|---|
QUBOResult
|
QUBO form of the Ising model. |
Conversion¶
quprep.qubo.converter.to_qubo(cost_matrix, constraints=None, penalty=10.0)
¶
Convert a cost matrix and optional linear equality constraints to QUBO.
The QUBO objective is: minimize \(x^T Q x\), \(x \in \{0, 1\}^n\)
The input cost_matrix can be any square real matrix. It is converted to
upper-triangular QUBO form:
Constraint penalties are added on top via the Lagrangian approach.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cost_matrix
|
(ndarray, shape(n, n))
|
Quadratic cost matrix. Diagonal entries encode linear terms. |
required |
constraints
|
list of dicts
|
Equality and inequality constraints. Each dict must have:
"A" : np.ndarray, shape (m, n) or (n,)
"b" : np.ndarray or scalar
"type" : "eq" (default) or "ineq" (Ax <= b via slack variables)
"penalty" : float (optional, falls back to global penalty)
Inequality constraints expand the variable count by adding binary
slack variables. |
None
|
penalty
|
float
|
Default Lagrange multiplier. Heuristic: 10x the largest |cost| entry. |
10.0
|
Returns:
| Type | Description |
|---|---|
QUBOResult
|
|
Source code in quprep/qubo/converter.py
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 | |
quprep.qubo.ising.qubo_to_ising(qubo)
¶
Convert a QUBOResult to Ising (h, J) form.
Uses the substitution \(x_i = (s_i + 1) / 2\):
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
qubo
|
QUBOResult
|
QUBO problem in upper-triangular form. |
required |
Returns:
| Type | Description |
|---|---|
IsingResult
|
Ising model with bias vector h and coupling matrix J. |
Source code in quprep/qubo/ising.py
quprep.qubo.ising.ising_to_qubo(ising)
¶
Convert an Ising model back to QUBO form.
Applies the inverse substitution \(x_i = (s_i + 1) / 2\):
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
ising
|
IsingResult
|
Ising model in (h, J) form. |
required |
Returns:
| Type | Description |
|---|---|
QUBOResult
|
QUBO form of the Ising model. |
Examples:
>>> import numpy as np
>>> from quprep.qubo.problems.maxcut import max_cut
>>> from quprep.qubo.ising import ising_to_qubo, qubo_to_ising
>>> adj = np.array([[0,1,1],[1,0,1],[1,1,0]], dtype=float)
>>> q = max_cut(adj)
>>> q2 = ising_to_qubo(qubo_to_ising(q))
>>> np.allclose(q.Q, q2.Q)
True
Source code in quprep/qubo/ising.py
Problem library¶
quprep.qubo.problems.max_cut(adjacency)
¶
Build the QUBO for the Max-Cut problem.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
adjacency
|
(ndarray, shape(n, n))
|
Weighted adjacency matrix of the graph. Symmetric; self-loops (diagonal) are ignored. For unweighted graphs, use a 0/1 matrix. |
required |
Returns:
| Type | Description |
|---|---|
QUBOResult
|
Variable i=0..n-1 is 1 if node i is in partition S, 0 otherwise. Minimizing the QUBO objective maximises the cut weight. |
Source code in quprep/qubo/problems/maxcut.py
quprep.qubo.problems.knapsack
¶
0/1 Knapsack QUBO formulation.
Knapsack: given n items with values v_i and weights w_i, select a subset to maximize total value without exceeding capacity W.
QUBO formulation (minimization):
The capacity constraint is enforced via a quadratic penalty \(\lambda\). The penalty coefficient should be at least \(\max(v_i)\) to ensure feasibility.
Note
This is a penalty-based (soft) formulation. Infeasible solutions have higher energy, but the exact cut-off depends on penalty strength. For hard enforcement use slack binary variables (adds ceil(log2(W+1)) ancilla qubits).
References
Lucas, A. (2014). Ising formulations of many NP problems. Frontiers in Physics, 2, 5. doi:10.3389/fphy.2014.00005
Classes¶
Functions¶
knapsack(weights, values, capacity, penalty=None)
¶
Build the QUBO for the 0/1 Knapsack problem.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
weights
|
(ndarray, shape(n))
|
Item weights. |
required |
values
|
(ndarray, shape(n))
|
Item values (non-negative). |
required |
capacity
|
float
|
Maximum total weight W. |
required |
penalty
|
float
|
Lagrange multiplier for the capacity constraint. Defaults to max(values) + 1, which is tight enough to enforce feasibility for integer-valued instances. |
None
|
Returns:
| Type | Description |
|---|---|
QUBOResult
|
Variable x_i = 1 means item i is selected. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Source code in quprep/qubo/problems/knapsack.py
quprep.qubo.problems.tsp
¶
Travelling Salesman Problem (TSP) QUBO formulation.
TSP: given n cities with distance matrix D, find the shortest Hamiltonian cycle visiting every city exactly once.
QUBO formulation uses \(n^2\) binary variables \(x_{i,t}\) where \(x_{i,t}=1\) means city \(i\) is visited at time step \(t\).
Objective (minimize total distance):
Constraints (enforced via quadratic penalties):
- \(C_1\): each city visited once: \(\sum_t x_{i,t} = 1\) for all \(i\)
- \(C_2\): one city per time slot: \(\sum_i x_{i,t} = 1\) for all \(t\)
Variable index: \(v(i, t) = i \cdot n + t\).
References
Lucas, A. (2014). Ising formulations of many NP problems. Frontiers in Physics, 2, 5. doi:10.3389/fphy.2014.00005
Classes¶
Functions¶
tsp(distance_matrix, penalty=None)
¶
Build the QUBO for the Travelling Salesman Problem.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
distance_matrix
|
(ndarray, shape(n, n))
|
Pairwise distances between cities. Asymmetric matrices are supported. Self-distances (diagonal) are ignored. |
required |
penalty
|
float
|
Lagrange multiplier for both city and time-slot constraints. Defaults to max(D) * n, which is typically large enough to enforce feasibility while keeping constraint violations expensive. |
None
|
Returns:
| Type | Description |
|---|---|
QUBOResult
|
\(n^2\) binary variables. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Source code in quprep/qubo/problems/tsp.py
quprep.qubo.problems.portfolio
¶
Markowitz Portfolio Optimization QUBO formulation.
Portfolio optimization: given n assets with expected returns mu_i and covariance matrix Sigma, select exactly K assets to maximize risk-adjusted return.
QUBO formulation (minimization):
References
Mugel et al. (2022). Dynamic portfolio optimization with real datasets using quantum processors and quantum-inspired tensor networks. Physical Review Research, 4(1), 013006. doi:10.1103/PhysRevResearch.4.013006
Classes¶
Functions¶
portfolio(returns, covariance, budget, risk_penalty=1.0, budget_penalty=None)
¶
Build the QUBO for Markowitz portfolio optimization.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
returns
|
(ndarray, shape(n))
|
Expected return for each asset. |
required |
covariance
|
(ndarray, shape(n, n))
|
Return covariance matrix (positive semi-definite). |
required |
budget
|
int
|
Number of assets to select (K). |
required |
risk_penalty
|
float
|
Lagrange multiplier for the risk (variance) term. Higher values favour lower-risk portfolios. Default is 1.0. |
1.0
|
budget_penalty
|
float
|
Lagrange multiplier enforcing the budget constraint sum(x) = K. Defaults to max(|returns|) * n, which is generally strong enough. |
None
|
Returns:
| Type | Description |
|---|---|
QUBOResult
|
Variable x_i = 1 means asset i is selected. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Source code in quprep/qubo/problems/portfolio.py
quprep.qubo.problems.graph_color
¶
Graph Coloring QUBO formulation.
Graph coloring: assign one of \(K\) colors to each node in graph \(G=(V, E)\) such that no two adjacent nodes share the same color.
QUBO uses \(n \cdot K\) binary variables \(x_{i,c}\) where \(x_{i,c}=1\) means node \(i\) is assigned color \(c\).
Constraints (both enforced as penalty terms):
- \(C_1\) (one color per node): \(\sum_c x_{i,c} = 1\) for all \(i\)
- \(C_2\) (valid coloring): \(x_{i,c} \cdot x_{j,c} = 0\) for all edges \((i,j)\), all \(c\)
Variable index: \(v(i, c) = i \cdot K + c\)
References
Lucas, A. (2014). Ising formulations of many NP problems. Frontiers in Physics, 2, 5. doi:10.3389/fphy.2014.00005
Classes¶
Functions¶
graph_color(adjacency, n_colors, penalty=10.0)
¶
Build the QUBO for the Graph Coloring problem.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
adjacency
|
(ndarray, shape(n, n))
|
Adjacency matrix of the graph (weighted or 0/1). Symmetric; diagonal is ignored. |
required |
n_colors
|
int
|
Number of colors K available for assignment. |
required |
penalty
|
float
|
Lagrange multiplier for both constraints. Should be large enough that any constraint violation costs more than the best feasible objective. Typically >= n * max_edge_weight. |
10.0
|
Returns:
| Type | Description |
|---|---|
QUBOResult
|
n * n_colors binary variables. variable_map["x_{i}{c}"] gives the index of variable x. A feasible solution has exactly n variables set to 1, one per node. |
Notes
A valid K-coloring may not exist for all graphs and K values. If the minimum energy solution has non-zero cost, the graph is not K-colorable.
Source code in quprep/qubo/problems/graph_color.py
quprep.qubo.problems.scheduling
¶
Job Scheduling QUBO formulation.
Scheduling: assign n jobs to m machines to minimize total squared load (a proxy for balanced makespan minimization).
QUBO uses \(n \cdot m\) binary variables \(x_{i,k}\) where \(x_{i,k}=1\) means job \(i\) is assigned to machine \(k\).
Objective (minimize load imbalance):
where \(p_i\) is the processing time of job \(i\).
Constraint: each job assigned to exactly one machine: \(\sum_k x_{i,k} = 1\) for all \(i\).
Variable index: \(v(i, k) = i \cdot m + k\).
Notes
This is a load-balancing formulation. It does not model job dependencies, deadlines, or preemption. For those, see the Travelling Salesman or QUBO references for richer scheduling models.
References
Lucas, A. (2014). Ising formulations of many NP problems. Frontiers in Physics, 2, 5. doi:10.3389/fphy.2014.00005
Classes¶
Functions¶
scheduling(processing_times, n_machines, penalty=None)
¶
Build the QUBO for the job scheduling (load balancing) problem.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
processing_times
|
(ndarray, shape(n))
|
Processing time of each job (non-negative). |
required |
n_machines
|
int
|
Number of machines m available. |
required |
penalty
|
float
|
Lagrange multiplier for the assignment constraint (each job assigned to exactly one machine). Defaults to sum(processing_times)^2 + 1, which is always large enough to enforce feasibility. |
None
|
Returns:
| Type | Description |
|---|---|
QUBOResult
|
n * n_machines binary variables. variable_map["x_{i}{k}"] gives the index of x. A feasible solution has exactly n variables set to 1, one per job. |
Source code in quprep/qubo/problems/scheduling.py
quprep.qubo.problems.number_partition
¶
Number Partitioning QUBO formulation.
Number partitioning: given n positive numbers v_i, split them into two subsets A and B such that the difference |sum(A) - sum(B)| is minimised (ideally zero for a perfect partition).
Let \(x_i = 1\) if value \(i\) is in subset \(A\), \(0\) if in subset \(B\). Define \(s_i = 2x_i - 1 \in \{-1, +1\}\). A perfect partition requires:
The objective to minimize is the squared difference:
Expanding (using \(x_i^2 = x_i\) for binary \(x\)), with \(S = \sum_i v_i\):
Note: the penalty argument scales the entire objective — useful when combining with other QUBO terms via add_qubo().
References
Lucas, A. (2014). Ising formulations of many NP problems. Frontiers in Physics, 2, 5. doi:10.3389/fphy.2014.00005
Classes¶
Functions¶
number_partition(values, penalty=1.0)
¶
Build the QUBO for the Number Partitioning problem.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
values
|
(ndarray, shape(n))
|
Positive numbers to partition. |
required |
penalty
|
float
|
Global scale factor. Set > 1 when combining with other QUBO objectives to ensure the partition constraint dominates. Default is 1.0. |
1.0
|
Returns:
| Type | Description |
|---|---|
QUBOResult
|
Variable x_i = 1 means value i goes into subset A. Minimum energy = 0 indicates a perfect partition exists. Minimum energy > 0 means no perfect partition; the solution with lowest energy is the most balanced achievable split. |
Examples:
>>> import numpy as np
>>> from quprep.qubo.problems.number_partition import number_partition
>>> from quprep.qubo.solver import solve_brute
>>> v = np.array([3.0, 1.0, 1.0, 2.0, 2.0, 1.0]) # sum=10, perfect split at 5
>>> sol = solve_brute(number_partition(v))
>>> sol.energy # should be 0.0 for a perfect partition
0.0
Source code in quprep/qubo/problems/number_partition.py
Classical reference solvers¶
Import from quprep.qubo.solver — not part of the quprep.qubo public namespace.
quprep.qubo.solver.SolveResult(x, energy, n_evaluated)
dataclass
¶
Result of a QUBO solve.
Attributes:
| Name | Type | Description |
|---|---|---|
x |
(ndarray, shape(n))
|
Optimal binary assignment vector (values in {0, 1}). |
energy |
float
|
Optimal objective value including the constant offset. |
n_evaluated |
int
|
Number of binary strings evaluated. |
quprep.qubo.solver.solve_brute(qubo, max_n=20)
¶
Find the exact minimum of a QUBO by exhaustive enumeration.
Evaluates all \(2^n\) binary strings and returns the one with the lowest objective value \(x^T Q x + ext{offset}\).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
qubo
|
QUBOResult
|
The QUBO problem to solve. |
required |
max_n
|
int
|
Safety limit on problem size. Raises ValueError if n > max_n. Default is 20 (2^20 = ~1M evaluations, runs in < 1s). |
20
|
Returns:
| Type | Description |
|---|---|
SolveResult
|
Best solution found, its energy, and the number of states evaluated.
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If n > max_n. |
Examples:
>>> from quprep.qubo.problems.maxcut import max_cut
>>> from quprep.qubo.solver import solve_brute
>>> import numpy as np
>>> adj = np.array([[0,1,1],[1,0,1],[1,1,0]], dtype=float)
>>> result = solve_brute(max_cut(adj))
>>> result.energy # max cut of triangle = -1 (one node vs two)
-1.0
Source code in quprep/qubo/solver.py
quprep.qubo.solver.solve_sa(qubo, n_steps=10000, T_start=None, T_end=0.01, seed=None, restarts=1)
¶
Find a near-optimal QUBO solution via simulated annealing.
Uses an incremental O(n)-per-step energy update and a geometric
cooling schedule. Suitable for problems where solve_brute is
impractical (n > 20).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
qubo
|
QUBOResult
|
The QUBO problem to solve. |
required |
n_steps
|
int
|
Number of single-bit-flip proposals per restart. Default 10 000. |
10000
|
T_start
|
float or None
|
Initial temperature. If None (default), auto-set to
|
None
|
T_end
|
float
|
Final temperature. Default 0.01. |
0.01
|
seed
|
int or None
|
Random seed for reproducibility. |
None
|
restarts
|
int
|
Number of independent restarts. The best result is returned. Default 1. |
1
|
Returns:
| Type | Description |
|---|---|
SolveResult
|
|
Examples:
>>> from quprep.qubo.problems.maxcut import max_cut
>>> from quprep.qubo.solver import solve_sa
>>> import numpy as np
>>> adj = np.array([[0,1,1],[1,0,1],[1,1,0]], dtype=float)
>>> sol = solve_sa(max_cut(adj), seed=0)
>>> sol.energy
-1.0
Source code in quprep/qubo/solver.py
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 | |
QAOA¶
quprep.qubo.qaoa.qaoa_circuit(qubo, p=1, gamma=None, beta=None)
¶
Generate a QAOA circuit for a QUBO problem as OpenQASM 3.0 string.
The QUBO is first converted to Ising form (h, J) via qubo.to_ising(),
then a p-layer QAOA ansatz is constructed.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
qubo
|
QUBOResult
|
The QUBO problem. Use any of the problem library functions (max_cut, knapsack, tsp, portfolio) or to_qubo(). |
required |
p
|
int
|
Number of QAOA layers (circuit depth). Default is 1. |
1
|
gamma
|
list of float
|
Cost unitary angles, length p. Defaults to [pi/4] * p. Optimal values depend on the problem; use a classical optimizer (e.g. scipy.optimize.minimize) to tune them. |
None
|
beta
|
list of float
|
Mixer unitary angles, length p. Defaults to [pi/8] * p. |
None
|
Returns:
| Type | Description |
|---|---|
str
|
OpenQASM 3.0 circuit string. Can be run directly on Qiskit, Cirq, or any QASM-compatible backend. |
Examples:
>>> from quprep.qubo.problems.maxcut import max_cut
>>> from quprep.qubo.qaoa import qaoa_circuit
>>> import numpy as np
>>> adj = np.array([[0,1,1],[1,0,1],[1,1,0]], dtype=float)
>>> qasm = qaoa_circuit(max_cut(adj), p=2)
>>> print(qasm[:60])
OPENQASM 3.0;
include "stdgates.inc";
Source code in quprep/qubo/qaoa.py
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 | |
Constraints¶
quprep.qubo.constraints.equality_penalty(A, b, penalty)
¶
Encode linear equality constraints \(Ax = b\) as a QUBO penalty matrix.
Each row of \(A\) defines one constraint \(a^T x = b_i\), penalised as:
Expanding and collecting QUBO terms:
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
A
|
(ndarray, shape(m, n) or (n,))
|
Constraint matrix. Each row is one constraint. A 1-D array is treated as a single constraint. |
required |
b
|
(ndarray, shape(m) or scalar)
|
RHS vector. A scalar is broadcast across all constraints. |
required |
penalty
|
float
|
Lagrange multiplier \(\lambda\). Must be large enough to enforce constraints; a common heuristic is 10x the largest cost coefficient. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
Q_penalty |
(ndarray, shape(n, n))
|
Upper-triangular QUBO penalty matrix to add to the cost matrix. |
offset |
float
|
Constant offset contributed by the penalty terms. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the number of rows in |
Source code in quprep/qubo/constraints.py
quprep.qubo.constraints.inequality_penalty(A, b, penalty)
¶
Encode linear inequality constraints \(Ax \leq b\) as a QUBO penalty matrix.
Each constraint \(a^T x \leq b_i\) is converted to an equality by introducing \(K = \lceil \log_2(\text{max\_slack}+1) \rceil\) binary slack variables \(z_0, \ldots, z_{K-1}\):
This expands the variable space from \(n\) to \(n + n_{\text{slack}}\).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
A
|
(ndarray, shape(m, n) or (n,))
|
Constraint matrix. Each row is one constraint. |
required |
b
|
(ndarray, shape(m) or scalar)
|
RHS values. Must satisfy \(b_i \geq \min(a^T x)\) for feasibility. |
required |
penalty
|
float
|
Lagrange multiplier \(\lambda\). |
required |
Returns:
| Name | Type | Description |
|---|---|---|
Q_penalty |
(ndarray, shape(n + n_slack, n + n_slack))
|
Upper-triangular QUBO penalty matrix. Rows/columns \(0 \ldots n-1\) correspond to original variables; \(n \ldots n+n_{\text{slack}}-1\) are slack variables. |
offset |
float
|
Constant offset. |
n_slack |
int
|
Number of slack binary variables added. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the number of rows in |
Notes
The slack encoding covers slack values \(0 \ldots 2^K - 1\). If \(\text{max\_slack}\) is not a power-of-two minus one, some slack assignments are infeasible but are penalised naturally by the equality term.
Source code in quprep/qubo/constraints.py
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 | |
Utilities¶
quprep.qubo.utils.add_qubo(q1, q2, weight=1.0)
¶
Add two QUBO problems of the same size.
Useful for multi-objective problems where you want to combine an objective term (e.g. max_cut) with a constraint term (e.g. equality penalty) that was built separately.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
q1
|
QUBOResult
|
First QUBO. |
required |
q2
|
QUBOResult
|
Second QUBO. Must have the same number of variables as q1. |
required |
weight
|
float
|
Scalar multiplier applied to q2 before addition. Default is 1.0. |
1.0
|
Returns:
| Type | Description |
|---|---|
QUBOResult
|
Combined QUBO with |
Raises:
| Type | Description |
|---|---|
ValueError
|
If q1 and q2 have different Q matrix shapes. |
Examples:
>>> from quprep.qubo.problems.maxcut import max_cut
>>> from quprep.qubo.constraints import equality_penalty
>>> from quprep.qubo.converter import QUBOResult
>>> from quprep.qubo.utils import add_qubo
>>> import numpy as np
>>> q_cut = max_cut(np.array([[0,1],[1,0]], dtype=float))
>>> Q_pen, off = equality_penalty(np.array([[1.0, 1.0]]), np.array([1.0]), 5.0)
>>> q_pen = QUBOResult(Q=Q_pen, offset=off)
>>> combined = add_qubo(q_cut, q_pen)
Source code in quprep/qubo/utils.py
quprep.qubo.visualize.draw_qubo(qubo, title='QUBO Matrix', cmap='RdBu_r', ax=None)
¶
Draw a heatmap of the QUBO Q matrix.
Positive entries (coupling penalties) are shown in one colour, negative entries (incentives) in another. The diagonal encodes linear terms; off-diagonal entries encode quadratic interactions.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
qubo
|
QUBOResult
|
The QUBO problem to visualize. |
required |
title
|
str
|
Plot title. Default is "QUBO Matrix". |
'QUBO Matrix'
|
cmap
|
str
|
Matplotlib colormap. Default is "RdBu_r" (blue=negative, red=positive). |
'RdBu_r'
|
ax
|
Axes
|
Existing axes to draw on. Creates a new figure if None. |
None
|
Returns:
| Type | Description |
|---|---|
Axes
|
Axes object with the Q matrix heatmap drawn on it. |
Raises:
| Type | Description |
|---|---|
ImportError
|
If matplotlib is not installed. Install with: pip install quprep[viz] |
quprep.qubo.visualize.draw_ising(ising, title='Ising Model', ax=None)
¶
Draw the Ising model as a weighted graph.
Nodes are arranged in a circle. Node colour represents the bias (h_i): blue = negative bias (prefers s=-1), red = positive (prefers s=+1). Edge colour and thickness represent coupling strength (J_ij).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
ising
|
IsingResult
|
The Ising model to visualize. |
required |
title
|
str
|
Plot title. |
'Ising Model'
|
ax
|
Axes
|
Existing axes. Creates a new figure if None. |
None
|
Returns:
| Type | Description |
|---|---|
Axes
|
Axes object with the Ising graph drawn on it. |
Raises:
| Type | Description |
|---|---|
ImportError
|
If matplotlib is not installed. |