QUBO Characterization Service¶
The Qoro QUBO Characterization Service is a hosted diagnostic that analyzes a QUBO or HUBO before — or instead of — running QAOA. It returns a structural quality score, an optimal-parameter sweep, hardness metrics, and actionable recommendations, all from a single short call.
Note
Characterization runs on Qoro’s hosted cloud service via
QoroService. See Pricing below for
credit cost.
When to Use It¶
Characterization is useful whenever you would otherwise guess at a QAOA setup. Common scenarios:
Before tuning a QAOA, to find good initial
γ,βvalues via a server-side parameter sweep and skip a long optimizer warm-up.When picking a penalty multiplier for constrained problems — auto-tuning returns a recommended
λand flags whether the current value is well-tuned.To decide whether a QUBO is worth running at all — the quality score and hardness metrics surface formulations that are unlikely to succeed at shallow depth regardless of how long you optimize.
For HUBO problems, where
BinaryOptimizationProblemalready accepts higher-order terms; characterization works on the same canonical form without extra conversion.
The diagnostic itself does not execute QAOA on hardware. It runs classically on Qoro’s cloud and completes within a few seconds.
Quick Start¶
The single-call entry point is
characterize_and_validate():
import numpy as np
from divi.backends import (
CharacterizationOptions,
QoroService,
characterize_and_validate,
)
from divi.qprog.problems import BinaryOptimizationProblem
# A small QUBO (any shape BinaryOptimizationProblem accepts is fine —
# ndarray, sparse, BQM, HUBO dict).
problem = BinaryOptimizationProblem(np.array([[-1, 2], [0, -1]]))
result = characterize_and_validate(
problem,
target_states=["01", "10"], # known/expected solutions, if any
service=QoroService(),
options=CharacterizationOptions(parameter_sweep=True),
)
result.display() # rich console report
print(result.quality_score)
Viewing the Report¶
A characterization result carries two views of the same data, chosen by output medium:
Terminal —
result.display()prints a styled console report (panels, gauges, tables) usingrich. Use this from scripts or REPLs.Jupyter — evaluating
resultdirectly in a cell triggers_repr_html_and renders a server-styled HTML report inline. The HTML is fetched once when the result is created and cached on the object as thehtmlattribute.
The HTML report is self-contained — inline CSS, no external assets
— so you can serialize result.html and email, log, or embed it as
a standalone artifact:
Path("report.html").write_text(result.html)
If the HTML endpoint is unreachable at fetch time, the result is still
returned but result.html is an empty string and a warning is logged.
The structured fields (quality_score, recommendations, etc.)
remain available either way.
What You Get Back¶
characterize_and_validate() returns a
CharacterizationResult with typed properties for
the most useful fields:
Property |
What it means |
|---|---|
|
Composite metric (0–100) of how amenable the QUBO is to QAOA,
derived from spectral and concentration features. A high
|
|
Probability mass on target states relative to the uniform baseline.
|
|
The server’s estimate of the approximation ratio at the returned
|
|
The |
|
Fraction of sampled states satisfying all declared constraints. |
|
For constrained problems: a recommended |
|
Static QUBO-structure metrics — |
|
Server-generated interpretive notes (see Reading Recommendations Programmatically below). |
Every field is None when the corresponding analysis was not requested.
Configuring the Run¶
Pass a CharacterizationOptions to control which
sub-analyses run. All fields are optional; the default-constructed object
runs a basic report.
from divi.backends import CharacterizationOptions
opts = CharacterizationOptions(
parameter_sweep=True, # sweep γ, β server-side
sensitivity=True, # per-qubit fragility report
auto_tune=True, # recommend a penalty λ
ansatz={"mixer": "x", "layers": 1},
)
Setting sensitivity=True adds a per-qubit fragility breakdown to the
result’s sensitivity field, identifying which variable assignments
have the largest impact on the objective — useful for spotting brittle
encodings that small perturbations can flip.
One constructor rule is worth knowing up front:
parameter_sweep=True is mutually exclusive with fixed gamma /
beta — pick one mode. The constructor raises ValueError
immediately if you set both, so the error surfaces locally before any
API call.
Penalty Tuning for Constrained Problems¶
For QUBOs that encode constraints as quadratic penalties, you can split the formulation into the cost-only and penalty-only halves and pass them both. The service then evaluates whether the chosen multiplier dominates the cost term enough to enforce constraints — and recommends an adjustment when it does not.
opts = CharacterizationOptions(
cost_qubo=cost_problem, # BinaryOptimizationProblem
penalty_qubo=penalty_problem, # BinaryOptimizationProblem
constraints=[...], # constraint descriptors
auto_tune=True,
)
result = characterize_and_validate(
problem, target_states=[...], service=QoroService(), options=opts
)
print(result.penalty_recommendation, result.is_well_tuned)
Reading Recommendations Programmatically¶
result.recommendations is always a list (empty when no rules fired or
the job did not complete). Each entry is a dict with four keys:
Key |
Value |
|---|---|
|
|
|
Which report field drove the rule — one of |
|
Plain-text message, suitable for terminal or log output. |
|
Same message with inline |
Acting on them in code:
for rec in result.recommendations:
if rec["level"] == "action":
logger.warning("[%s] %s", rec["metric"], rec["text"])
Recommendations are deterministic given the same report — the server applies a fixed rule set (quality-score tiers, a hardness-difficulty trigger, a feasibility-rate threshold, a penalty-tuning check, and a low-concentration warning) — so they are safe to gate workflows on.
Re-fetching a Previous Result¶
Every characterization run has a job_id that you can hand back to
get_characterization_result() to retrieve the stored
result without re-running the analysis.
from divi.backends import QoroService, get_characterization_result
result = get_characterization_result(
"4d0550f5-ffb0-...",
service=QoroService(),
)
result.display()
This costs no credits and is the recommended pattern for notebooks and CI runs where you want to inspect a known result without re-billing.
Pricing¶
Characterization is priced per submission, scaling with the QUBO’s qubit
count. A balance check runs before submission, and credits are deducted
only when the job completes successfully — failed jobs are not billed.
Fetching a result by job_id does not cost anything. See the
dashboard for the current credit tiers.
See Also¶
Combinatorial Optimization with QAOA and PCE — the QAOA workflow that characterization is designed to support.
CharacterizationResult— full property list.CharacterizationOptions— every configurable field, including constraint and ansatz schemas.QoroService— the cloud client that drives the underlying API calls.