Skip to content

quast_decisiontree.utils.qubo_conversions

quast_decisiontree.utils.qubo_conversions

Converters from QUBO matrices to Qrisp-compatible cost operators and cost functions.

qubo_to_qrisp_cost_operator

qubo_to_qrisp_cost_operator(qubo_matrix)

Create a Qrisp-compatible cost_operator from a QUBO matrix.

The cost operator applies phase separations corresponding to the Ising Hamiltonian derived from the QUBO: H = sum_{i<j} J_ij Z_i Z_j + sum_i h_i Z_i.

The QUBO-to-Ising conversion follows

Z_i = 1 - 2*x_i => x_i = (1 - Z_i) / 2

Parameters:

Name Type Description Default
qubo_matrix ndarray

Square numpy array representing the QUBO cost matrix Q.

required

Returns:

Type Description
Callable

Tuple of (cost_operator, offset) where cost_operator is a callable

float

with signature cost_operator(qv, gamma) -> None and offset is the

tuple[Callable, float]

constant energy shift from QUBO→Ising conversion.

Raises:

Type Description
ValueError

If qubo_matrix is not square.

Source code in src/quast_decisiontree/utils/qubo_conversions.py
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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
def qubo_to_qrisp_cost_operator(qubo_matrix: np.ndarray) -> tuple[Callable, float]:
    """Create a Qrisp-compatible cost_operator from a QUBO matrix.

    The cost operator applies phase separations corresponding to the Ising
    Hamiltonian derived from the QUBO: H = sum_{i<j} J_ij Z_i Z_j + sum_i h_i Z_i.

    The QUBO-to-Ising conversion follows:
        Z_i = 1 - 2*x_i  =>  x_i = (1 - Z_i) / 2

    Args:
        qubo_matrix: Square numpy array representing the QUBO cost matrix Q.

    Returns:
        Tuple of (cost_operator, offset) where cost_operator is a callable
        with signature ``cost_operator(qv, gamma) -> None`` and offset is the
        constant energy shift from QUBO→Ising conversion.

    Raises:
        ValueError: If qubo_matrix is not square.
    """
    qubo = np.asarray(qubo_matrix, dtype=float)
    if qubo.ndim != 2 or qubo.shape[0] != qubo.shape[1]:
        raise ValueError(f"QUBO matrix must be square, got shape {qubo.shape!r}.")

    n = qubo.shape[0]
    J = np.zeros((n, n))
    h = np.zeros(n)
    offset = 0.0

    for i in range(n):
        for j in range(n):
            if i == j:
                h[i] -= qubo[i, i] / 2.0
                offset += qubo[i, i] / 2.0
            elif i < j:
                coupling = (qubo[i, j] + qubo[j, i]) / 4.0
                J[i, j] = coupling
                h[i] -= coupling
                h[j] -= coupling
                offset += coupling

    def cost_operator(qv, gamma):
        for i in range(n):
            if abs(h[i]) > 1e-12:
                rz(2 * gamma * h[i], qv[i])
        for i in range(n):
            for j in range(i + 1, n):
                if abs(J[i, j]) > 1e-12:
                    rzz(2 * gamma * J[i, j], qv[i], qv[j])

    return cost_operator, offset

qubo_to_cl_cost_function

qubo_to_cl_cost_function(qubo_matrix)

Create a Qrisp-compatible cl_cost_function from a QUBO matrix.

The returned function evaluates the expected QUBO cost from measurement counts, suitable for use with QrispQAOA and QAOAProblem.

Parameters:

Name Type Description Default
qubo_matrix ndarray

Square numpy array representing the QUBO cost matrix Q.

required

Returns:

Type Description
Callable

A callable cl_cost_function(counts: dict) -> float that computes the

Callable

weighted average QUBO cost from {bitstring: count/probability}.

Raises:

Type Description
ValueError

If qubo_matrix is not square.

Source code in src/quast_decisiontree/utils/qubo_conversions.py
 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
def qubo_to_cl_cost_function(qubo_matrix: np.ndarray) -> Callable:
    """Create a Qrisp-compatible cl_cost_function from a QUBO matrix.

    The returned function evaluates the expected QUBO cost from measurement
    counts, suitable for use with QrispQAOA and QAOAProblem.

    Args:
        qubo_matrix: Square numpy array representing the QUBO cost matrix Q.

    Returns:
        A callable cl_cost_function(counts: dict) -> float that computes the
        weighted average QUBO cost from {bitstring: count/probability}.

    Raises:
        ValueError: If qubo_matrix is not square.
    """
    qubo = np.asarray(qubo_matrix, dtype=float)
    if qubo.ndim != 2 or qubo.shape[0] != qubo.shape[1]:
        raise ValueError(f"QUBO matrix must be square, got shape {qubo.shape!r}.")

    def cl_cost_function(counts: dict[str, float]) -> float:
        total_cost = 0.0
        total_weight = 0.0
        for bitstring, weight in counts.items():
            x = np.array(bitstring_to_list(bitstring), dtype=float)
            cost = float(x @ qubo @ x)
            total_cost += weight * cost
            total_weight += weight
        if total_weight == 0:
            return 0.0
        return total_cost / total_weight

    return cl_cost_function