Digitized Counterdiabatic Quantum Optimization#

class DCQOProblem(Q, H_init, H_prob, A_lam, agp_coeffs, lam_func, g_func=None, H_control=None, qarg_prep=None)[source]#

General structure to formulate Digitized Counterdiabatic Quantum Optimization problems. This class is used to solve DCQO problems with the algorithms COLD (counterdiabatic optimized local driving) or LCD (local counterdiabatic driving). To run the COLD algorithm on the problem, you need to specify the control Hamiltonian H_control and the inverse scheduling function g_func. These are not needed for the LCD algorithm. To learn more about counterdiabatic driving, make sure to check out the tutorial.

Parameters:
Qnp.array

The QUBO matrix.

H_initQubitOperator

Hamiltonian, the system is at the time t=0.

H_probQubitOperator

Hamiltonian, the system evolves to for t=T.

A_lamQubitOperator

Operator holding an appoximation for the adiabatic gauge potential (AGP).

agp_coeffscallable

The parameters for the adiabatic gauge potential (AGP). If the COLD method is being used, they must depend on the optimization pulses in H_control.

lam_funccallable

A function \(\lambda(t, T)\) mapping \(t \in [0, T]\) to \(\lambda \in [0, 1]\). This function needs to return a sympy expression with \(t\) and \(T\) as sympy.Symbols.

g_funccallable, optional

The inverse function of \(\lambda(t, T)\). This function needs to return a sympy expression with \(\lambda\) and \(T\) as sympy.Symbols. Only needed for the COLD algorithm.

H_controlQubitOperator, optional

Hamiltonian specifying the control pulses for the COLD method. If not given, the LCD method is used automatically.

qarg_prepcallable, optional

A function receiving a QuantumVariable for preparing the inital state. By default, the groundstate of the x-operator \(\ket{-}^n\) is prepared.

Examples

For a quick demonstration we build a DCQO problem instance for a 4x4 QUBO. We choose a first order AGP ansatz with uniform coefficients and solve it with LCD.

import numpy as np
import sympy as sp
from qrisp.operators.qubit import X, Y, Z
from qrisp.algorithms.cold import DCQOProblem
from qrisp import QuantumVariable

Q = np.array([
    [-1.2,  0.40, 0.0,  0.0],
    [ 0.40,  0.30, 0.20, 0.0],
    [ 0.0,   0.20,-1.1,  0.30],
    [ 0.0,   0.0,  0.30,-0.80]
])
N = Q.shape[0]

# Define QUBO problem hamiltonian
h = -0.5 * np.diag(Q) - 0.5 * np.sum(Q, axis=1)
J = 0.5 * Q

H_init = 1 * sum([X(i) for i in range(N)])

H_prob = (sum([sum([J[i][j]*Z(i)*Z(j) for j in range(i)]) for i in range(N)])
        + sum([h[i]*Z(i) for i in range(N)]))

# Create AGP
A_lam = sum([Y(i) for i in range(N)]) # uniform

# Function for uniform AGP coefficients
def alpha(lam):
    A = lam * h
    B = 1 - lam
    nom = np.sum(A + 4*B*h)
    denom = 2 * (np.sum(A**2) + N * (B**2)) + 4 * (lam**2) * np.sum(np.tril(J, -1).sum(axis=1))
    alph = nom/denom
    alph = [alph]*N
    return alph

# Simple scheduling function 0 -> 1
def lam():
    t, T = sp.symbols("t T", real=True)
    lam_expr = t/T
    return lam_expr

# Create problem instance
lcd_problem = DCQOProblem(Q, H_init, H_prob, A_lam, alpha, lam)

# Run problem with LCD algorithm
qarg = QuantumVariable(N)
res = lcd_problem.run(qarg, N_steps=4, T=12, method="LCD")
print(res)
{'1011': [0.40630593694063055, np.float64(-2.5)], '1111': [0.16247837521624783, np.float64(-0.9999999999999999)], '0111': [0.13156868431315685, np.float64(-0.6000000000000001)], '1000': [0.06881931180688193, np.float64(-1.2)], '0011': [0.05949940500594993, np.float64(-1.3)], '1010': [0.04499955000449995, np.float64(-2.3)], '1101': [0.04084959150408495, np.float64(-0.9)], '0110': [0.019769802301976978, np.float64(-0.40000000000000013)], '1100': [0.01815981840181598, np.float64(-0.09999999999999998)], '0100': [0.013679863201367985, np.float64(0.3)], '0001': [0.010399896001039988, np.float64(-0.8)], '0000': [0.007659923400765992, np.float64(0.0)], '1110': [0.006329936700632993, np.float64(-0.7999999999999999)], '0101': [0.0052899471005289946, np.float64(-0.5)], '1001': [0.0024299757002429973, np.float64(-2.0)], '0010': [0.0017599824001759982, np.float64(-1.1)]}

We get a dictionary where the key is the quantum state and the values are lists of [probability, cost]. So our most likely result is ‘1011’ with probabilty 0.4 and the QUBO cost \(x^T Q x = -2.5\).

Methods#

DCQOProblem.run(qarg, N_steps, T, method[, ...])

Run the specific DCQO problem instance with given quantum arguments, number of timesteps and evolution time.

DCQOProblem.apply_lcd_hamiltonian(qarg, ...)

Simulate the local counterdiabatic driving (LCD) Hamiltonian on a quantum argument via trotterization.

DCQOProblem.apply_cold_hamiltonian(qarg, ...)

Simulate counterdiabatic optimized local driving (COLD) Hamiltonian on a quantumvariable via trotterization.

DCQOProblem.compile_U_cold(qarg, N_opt, ...)

Compiles the circuit that is created by the apply_cold_hamiltonian method.

DCQOProblem.optimization_routine(qarg, ...)

Subroutine for the optimization method used in COLD.

DCQOProblem.QUBO_cost(res)

Returns the cost y = x^T Q x for a given binary array x.

Quick run#

Quickly run LCD/COLD with our predefined operators and functions in QUBO.py:

solve_QUBO(Q: array, problem_args: dict, run_args: dict)[source]#

Solves a QUBO Matrix using counterdiabatic driving. This method uses the pre-defined COLD/LCD operators (hamiltonian, scheduling function, AGP parameters) as described in the tutorial. To define your own operators, create a DCQO instance and use the run method.

Parameters:
Qnp.array

QUBO Matrix to solve.

problem_argsdict

Holds arguments for DCQO problem creation (method: str (“COLD”/”LCD”), uniform: bool).

run_argsdict

Holds arguments for running the DCQO instance (N_steps, T, N_opt, CRAB). For all options, see DCQOProblem.run().

Returns:
resultdict

The dictionary holding the QUBO vector results, with their probabilitites and cost. They are ordered from most to least likely and the dictionary entries are {“state”: [prob, cost]}.

Examples

import numpy as np
from qrisp.algorithms.cold import solve_QUBO

Q = np.array([[-1.1, 0.6, 0.4, 0.0, 0.0, 0.0],
            [0.6, -0.9,  0.5, 0.0, 0.0, 0.0],
            [0.4, 0.5, -1.0, -0.6, 0.0, 0.0],
            [0.0, 0.0, -0.6, -0.5, 0.6, 0.0],
            [0.0, 0.0, 0.0, 0.6, -0.3, 0.5],
            [0.0, 0.0, 0.0, 0.0, 0.5, -0.4]])

problem_args = {"method": "COLD", "uniform": False}

run_args = {"N_steps": 4, "T": 8, "N_opt": 1, "CRAB": False,
            "objective": "agp_coeff_magnitude", "bounds": (-3, 3)}

result = solve_QUBO(Q, problem_args, run_args)

print(result)
{'101101': [0.2749327493274933, np.float64(-3.4)], '011101': [0.14747147471474714, np.float64(-3.0)], '111101': [0.10500105001050011, np.float64(-2.1)], '101100': [0.0888608886088861, np.float64(-3.0)], '011100': [0.04720047200472005, np.float64(-2.6)], '101110': [0.043830438304383046, np.float64(-2.1)], '111100': [0.035760357603576036, np.float64(-1.7000000000000002)], '011110': [0.024410244102441025, np.float64(-1.7)], '100101': [0.02137021370213702, np.float64(-2.0)], '110101': [0.016960169601696017, np.float64(-1.7000000000000002)], '111110': [0.01686016860168602, np.float64(-0.8)], '111001': [0.016390163901639016, np.float64(-0.4)], '001101': [0.014560145601456015, np.float64(-3.1)], '010101': [0.014370143701437016, np.float64(-1.7999999999999998)], '101011': [0.011320113201132012, np.float64(-1.0)], '111000': [0.008620086200862008, np.float64(0.0)], '100001': [0.007290072900729008, np.float64(-1.5)], '000101': [0.006580065800658007, np.float64(-0.9)], '110100': [0.006420064200642007, np.float64(-1.3000000000000003)], '011011': [0.006090060900609006, np.float64(-0.6)], '101000': [0.005780057800578007, np.float64(-1.3)], '100100': [0.0057700577005770064, np.float64(-1.6)], '101001': [0.005720057200572007, np.float64(-1.7000000000000002)], '101111': [0.005310053100531005, np.float64(-1.5)], '100110': [0.005230052300523006, np.float64(-0.7)], '010100': [0.004050040500405004, np.float64(-1.4)], '001100': [0.004040040400404004, np.float64(-2.7)], '011000': [0.003870038700387004, np.float64(-0.9)], '011111': [0.0032400324003240034, np.float64(-1.1)], '100000': [0.0031800318003180035, np.float64(-1.1)], '110010': [0.0029900299002990033, np.float64(-1.1)], '010001': [0.002930029300293003, np.float64(-1.3)], '011001': [0.002850028500285003, np.float64(-1.3)], '110011': [0.002770027700277003, np.float64(-0.5000000000000001)], '001110': [0.002650026500265003, np.float64(-1.8)], '010110': [0.0025900259002590025, np.float64(-0.5)], '110001': [0.0024400244002440027, np.float64(-1.2000000000000002)], '000100': [0.0022800228002280024, np.float64(-0.5)], '100011': [0.002020020200202002, np.float64(-0.8000000000000002)], '111011': [0.001770017700177002, np.float64(0.3)], '010000': [0.0015300153001530014, np.float64(-0.9)], '101010': [0.0014900149001490016, np.float64(-1.6)], '111111': [0.0014200142001420015, np.float64(-0.20000000000000007)], '000010': [0.0010500105001050011, np.float64(-0.3)], '110111': [0.0008300083000830009, np.float64(0.19999999999999984)], '010011': [0.0008200082000820009, np.float64(-0.6)], '001011': [0.0007900079000790008, np.float64(-0.7000000000000001)], '100111': [0.0007200072000720008, np.float64(-0.09999999999999998)], '001000': [0.0006300063000630007, np.float64(-1.0)], '100010': [0.0006000060000600005, np.float64(-1.4000000000000001)], '001111': [0.0005800058000580006, np.float64(-1.2000000000000002)], '010010': [0.0005700057000570006, np.float64(-1.2)], '001001': [0.0005300053000530005, np.float64(-1.4)], '011010': [0.0005200052000520005, np.float64(-1.2)], '000011': [0.0005000050000500006, np.float64(0.3)], '111010': [0.0004300043000430004, np.float64(-0.3)], '110000': [0.00026000260002600025, np.float64(-0.8000000000000002)], '000110': [0.00026000260002600025, np.float64(0.39999999999999997)], '010111': [0.00021000210002100023, np.float64(0.09999999999999998)], '000001': [0.0001700017000170002, np.float64(-0.4)], '001010': [0.00012000120001200013, np.float64(-1.3)], '000000': [9.00009000090001e-05, np.float64(0.0)], '000111': [8.000080000800009e-05, np.float64(1.0)], '110110': [2.0000200002000023e-05, np.float64(-0.4000000000000002)]}