Skip to content

QUBOProblemIR

from cascaqit import QUBOProblemIR

QUBOProblemIR

QUBOProblemIR(
    problem_id: str,
    variables: tuple[str, ...],
    linear_terms: tuple[tuple[str, float], ...] = (),
    quadratic_terms: tuple[
        tuple[str, str, float], ...
    ] = (),
    offset: float = 0.0,
    variable_positions: tuple[
        tuple[str, tuple[float, float]], ...
    ] = (),
    schema_version: str = SCHEMA_VERSION,
    metadata: dict[str, Any] = dict(),
)

Store a quadratic unconstrained binary objective: E(x) = offset + sum(a_i*x_i) + sum(b_ij*x_i*x_j), with x in {0, 1} and each stored quadratic coefficient counted once. This is a list of coefficient terms, not a Q matrix with an implicit triangular convention. If both (a,b) and (b,a) are supplied, from_terms() adds their coefficients.

variables defines variable and result-bit order. Optional variable_positions should cover all variables when present. Retain offset when comparing energies across transformations. Direct construction and dictionary restoration do not call validate() automatically. Supply finite real coefficients; structural diagnostics do not replace full numerical validation. problem_id, metadata and schema_version retain identity, additional information and format.

The example enumerates both variables and checks energy preservation for every assignment, including the constant.

from itertools import product
from math import isclose
from cascaqit import QUBOProblemIR
from cascaqit.problems import evaluate_ising_bitstring, evaluate_qubo_bitstring

qubo = QUBOProblemIR.from_terms(problem_id="pair", linear_terms={"a": -1, "b": -2},
    quadratic_terms={("a", "b"): 3}, offset=0.25)
assert not qubo.validate()
ising = qubo.to_ising_model()
for bits in product("01", repeat=2):
    bitstring = "".join(bits)
    assert isclose(evaluate_qubo_bitstring(qubo, bitstring),
                   evaluate_ising_bitstring(ising, bitstring), abs_tol=1e-12)
assert QUBOProblemIR.from_json(qubo.to_json()) == qubo

See QUBO and Hamiltonians for the derivation.

from_terms

from_terms(
    *,
    problem_id: str,
    linear_terms: dict[str, float] | None = None,
    quadratic_terms: dict[tuple[str, str], float]
    | None = None,
    offset: float = 0.0,
    variables: list[str] | tuple[str, ...] | None = None,
    positions: dict[str, tuple[float, float]] | None = None,
    metadata: dict[str, Any] | None = None,
) -> QUBOProblemIR

Build a model from linear/quadratic coefficient dictionaries. Variables are the union of all term references and explicit variables, converted to strings and sorted. Explicit variables can add coefficient-free variables. Quadratic endpoints are ordered and reversed entries added; positions are sorted by variable name and checked for two finite real coordinates. A term (x,x) is not automatically folded into the linear part; simplify with x²=x and call validate().

validate

validate() -> tuple[DiagnosticsIR, ...]

Return structural diagnostics for empty/duplicate variables, unknown references, self-quadratic terms, and duplicate, incomplete or invalid two-dimensional coordinates. This does not comprehensively check coefficients or offset for finiteness and does not solve the model. No diagnostics does not guarantee acceptance by downstream algorithms or physical encodings.

position_by_variable

position_by_variable() -> dict[str, tuple[float, float]]

Return a dictionary of saved variable positions without generating a missing layout or modifying the model.

to_ising_model

to_ising_model() -> IsingModelIR

Return IsingModelIR under x=(1+s)/2, preserving every assignment’s energy. A linear term ax contributes a/2 to offset and its field. A quadratic term bx_i*x_j contributes b/4 to offset, both fields and the coupling. The ID becomes ising.from., with source ID/digest and convention retained in metadata. Validate the input first; this method does not call validate() or generate a quantum circuit.

result_decoding_metadata

result_decoding_metadata() -> ProblemResultDecodingIR

Return decoding metadata with variable order, source digest and the convention that each bit is the binary variable x. This does not evaluate the objective or find an optimal bitstring.

objective_candidate

objective_candidate() -> ProblemCandidateIR

Return ProblemCandidateIR with variable order, term counts, coefficients, offset and notices that optimization and scheduling were not performed. Here candidate means an objective summary, not a candidate solution produced by optimization.

from_dict

from_dict(data: dict[str, Any]) -> QUBOProblemIR

Restore QUBOProblemIR from a dictionary. Restore coefficients, positions and variable order without from_terms() term merging. Call validate() explicitly after restoration. Missing required fields or invalid values can raise KeyError, TypeError or ValueError.

from_json

from_json(text: str) -> QUBOProblemIR

Parse a JSON object and call from_dict(), returning QUBOProblemIR. Invalid JSON raises a parsing error; a non-object root raises TypeError.

to_dict

to_dict() -> dict[str, Any]

Return a JSON-compatible dictionary, serializing nested objects and converting tuples to arrays. This stores the declaration, not an execution result.

to_json

to_json(*, indent: int | None = None) -> str

Return a JSON string without writing a file. indent=None uses compact formatting; supply an indentation width for readable output.

stable_hash

stable_hash() -> str

Return the SHA-256 hex digest of canonical JSON. Fields, identifiers and metadata can affect it. Use it to compare saved content, not to decide physical equivalence.