Mixed binary, integer, and real optimisation¶
QQA's typed mixed-domain API solves bounded nonlinear models containing any combination of:
Binary(name, size)for values in{0, 1};Integer(name, lower, upper, size)for bounded integers;Real(name, lower, upper, size)for bounded reals.
All variables use a common normalised latent coordinate internally. Binary variables receive the standard QQA discrete penalty, integer variables receive a periodic grid penalty whose minima are the integer points, and real variables remain continuous. The objective and constraints are evaluated in the physical units declared by the user.
Minimal real-valued problem¶
User functions must preserve the leading population dimension:
import qqa
problem = qqa.MixedProblem(
[qqa.Real("x", -5, 5), qqa.Real("y", -5, 5)],
lambda v: (v["x"] - 1.25).square() + (v["y"] + 2.5).square(),
name="convex-real",
)
result = problem.solve(num_epochs=300, verbose=False)
print(problem.unpack(result.best_sol))
Pure integer problem¶
problem = qqa.MixedProblem(
[qqa.Integer("quantity", lower=-10, upper=10)],
lambda v: (v["quantity"] - 3).square(),
)
result = problem.solve(verbose=False)
assert result.best_sol.item() == 3
Constraints¶
Each Constraint has a direction, right-hand side, weight, unit scale, and
reporting tolerance:
qqa.Constraint(
lambda v: v["production"].sum(-1),
sense=">=",
rhs=100,
weight=250,
scale=100,
tolerance=1e-3,
name="demand",
)
The optimisation loss adds
weight * (raw_violation / scale) ** 2. Choose scale near the typical
magnitude of the constraint so weights remain interpretable. result.best_obj
is this penalised selection loss; result.score["value"] is the original
unpenalised objective and result.score["feasible"] reports whether every
constraint meets its tolerance.
problem.solve() also calibrates one global penalty multiplier from Sobol
samples so a large currency-valued objective cannot silently overwhelm a
small normalised constraint. Explicit weights still express the relative
importance of the constraint rows. For exact mixed-integer/nonlinear
refinement of a safe ModelSpec, install qqa[scip] and use
qqa.solve_spec_scip.
Warm starts in physical units¶
Use problem.pack() to create a validated solution and pass it directly:
seed = problem.pack({"quantity": 3})
result = qqa.anneal(problem, initial_state=seed, verbose=False)
The mixed relaxation automatically encodes the physical values into its normalised latent space.
Large integer bounds and numerical precision¶
Models use torch.float32 by default. If integer magnitudes exceed float32's
exact-integer range, request float64 explicitly so packing, projection, and
objective evaluation preserve every grid point:
import torch
problem = qqa.MixedProblem(
[qqa.Integer("identifier", 100_000_000, 100_000_010)],
lambda v: (v["identifier"] - 100_000_003).square(),
dtype=torch.float64,
)
Float64 is slower on many consumer GPUs, so use it only when the domain requires the additional precision.
Diagnostics and portable reports¶
from qqa import visualization as viz
viz.plot_result_dashboard(result, problem, backend="plotly")
viz.plot_variable_solution(result, problem, backend="plotly")
viz.plot_constraint_diagnostics(result, problem, backend="plotly")
qqa.save_html_report(result, problem, "report.html")
The HTML report embeds Plotly and a JSON result payload. It opens offline and can be archived or shared as a single file.
GPU execution¶
Objectives and constraints should use PyTorch operations and reduce only over
variable axes (normally dim=-1). QQA then evaluates all replicas in one
vectorised CUDA graph:
result = problem.solve(
sol_size=4096,
num_epochs=2000,
mixed_precision="bf16",
device="auto",
verbose=False,
)
The mixed solver defaults to gradient clipping and adaptive basin recovery.
Recovery always keeps the incumbent and divides weak replicas between global
reinitialisation and local incumbent-centred jitter. The result records
diagnostics["restart_events"] and history["restart_epochs"]. Pass
restart_patience=None when reproducing the original uninterrupted dynamics.
The dedicated
09_mixed_integer_real_optimization.ipynb
notebook includes real, integer, and factory-planning examples plus brute-force
verification of the mixed optimum.