QAOA with Amazon Braket
Overview
# --- Setup cell added by QCR (not part of the original tutorial) ---
# Source: amazon-braket/amazon-braket-examples @ 0c0818f315479aab9deebed7e7ed7533ac581923, Apache License 2.0.
# Installs the example's dependencies. If a later cell still reports a missing
# package, restart the runtime/kernel and run again from the top.
%pip install -q amazon-braket-sdk==1.117.3 matplotlib seaborn networkx
# Use Braket SDK Cost Tracking to estimate the cost to run this example
from braket.tracking import Tracker
t = Tracker().start()QUANTUM APPROXIMATE OPTIMIZATION ALGORITHM (QAOA)
In this tutorial we show how to (approximately) solve binary combinatorial optimization problems, using the Quantum Approximate Optimization Algorithm (QAOA), as introduced in Ref.[1]. The QAOA algorithm belongs to the class of hybrid quantum algorithms (leveraging both classical as well as quantum compute), that are widely believed to be the working horse for the current NISQ (noisy intermediate-scale quantum) era. In this NISQ era QAOA is also an emerging approach for benchmarking quantum devices and is a prime candidate for demonstrating a practical quantum speed-up on near-term NISQ device [1,4]. To validate our approach we benchmark our results with exact results as obtained from classical QUBO solvers.
We provide a step-by-step walkthrough explaining the QAOA quantum algorithm and show how to build the corresponding parametrized quantum circuit ansatz using the Braket SDK, with simple modular building blocks (that can be re-used for other purposes).
We use open-source off-the-shelf scipy optimizers for classical numerical optimization.
While we demonstrate our proof-of-concept approach using classical simulators for circuit execution, our code could in principle be run on actual quantum hardware by simply changing the definition of the device object (provided that the gate set used in the ansatz is supported by the device, as is the case here for IonQ; for Rigetti we need to apply one more extra trick as shown below).
BACKGROUND: HYBRID QUANTUM ALGORITHMS
Quantum computers hold the promise to outperform even the most-powerful classical computers on a range of computational problems in (for example) optimization, chemistry, material science and cryptography. The canonical set of quantum algorithms (such as Shor's or Grover's quantum algorithms), however, comes with hardware requirements (such as a large number of quantum gates) that are currently not available with state-of-the-art technology. Specifically, these algorithms are typically believed to be feasible only with fault-tolerance as provided by quantum error correction. In the current noisy intermediate-scale (NISQ) era, near-term quantum computers do not have a large enough number of physical qubits for the implementation of error correction protocols, making this canonical set of quantum algorithms unsuitable for near-term devices. Against this background, the near-term focus has widely shifted to the class of hybrid quantum algorithms that do not require quantum error correction. In these hybrid quantum algorithms, the noisy near-term quantum computers are used as co-processors only, within a larger classical optimization loop, as sketched in the schematic figure below. Here, the undesired effects of noise are suppressed by deliberately limiting the quantum circuits on the quantum processing unit (QPU) to short bursts of the calculation, and the need for long coherence times (as required for the standard set of quantum algorithms) is traded for a classical overhead due to (possibly many) measurement repetitions and (essentially error-free) classical processing.

Variational Quantum Algorithms: Specifically, variational quantum algorithms such as the Quantum Approximate Optimization Algorithm (QAOA) [1] belong to this emerging class of hybrid quantum algorithms. These are widely believed to be promising candidates for the demonstration of a quantum advantage, already with near-term (NISQ) devices in areas such as quantum chemistry [2], condensed matter simulations [3], and discrete optimization tasks [4].
Variational Quantum Computing vs. Deep Learning: The working principle of variational quantum computing is very much reminiscent of training deep neural networks: when you train a neural network, you have an objective function that you want to minimize, typically characterized by the error on your training set. To minimize that error, typically you start out with an initial guess for the weights in your network. The coprocessor, in that case a GPU, takes these weights which define the exact operation to execute and the output of the neural network is computed. This output is then used to calculate the value of your objective function, which in turn is used by the CPU to make an educated guess to update the weights and the cycle continues. Variational quantum algorithms, a specific form of hybrid algorithms, work in the very same way, using parametrized quantum circuits rather than parametrized neural networks and replacing the GPU with a QPU. Here, you start with an initial guess for the parameters that define your circuit, have the QPU execute that circuit, perform measurements to calculate an objective function, pass this value (together with the current values of the parameters) back to the CPU and have this classical CPU update the parameters based on that information.
Of course, coordinating that workflow for quantum computers is much more challenging than in the previous case. Quantum computers are located in specialized laboratory facilities, are typically single threaded, and have special latency requirements. This is exactly the undifferentiated heavy-lifting that Amazon Braket handles for us, such that we can focus on our scientific problem. For the sake of this introductory tutorial, we simply use a classical circuit simulator (that mimic the behavior of a quantum machine) as the device to execute our quantum circuits. Within Amazon Braket, the workflow, however, is exactly the same.
BACKGROUND: QUADRATIC BINARY OPTIMIZATION PROBLEMS
Combinatorial optimization: Combinatorial optimization problems are ubiquitous across many areas of science and application areas. Applications can be found (for example) in logistics, scheduling, planning, and portfolio optimization. In a nutshell combinatorial optimization problems are problems involving a large number of yes/no decisions with each set of decisions yielding a corresponding objective function value, like a cost or profit value. Because of the combinatorial explosion of the solution space with the number of variables, finding good solutions is a daunting task and extremely difficult.
QUBO problems: The QUBO (Quadratic Unconstrained Binary Optimization) model unifies a rich variety of NP-hard combinatorial optimization problems: Famous examples include Quadratic Assignment Problems, Capital Budgeting Problems, Task Allocation Problems and Maximum-Cut Problems. For more details we refer to the excellent review and tutorial on QUBO problems presented in Ref.[5].
Maximum Cut: Among the class of QUBO problems, Maximum Cut (MaxCut) is paradigm combinatorial optimization problem.
Given a graph
Ising Hamiltonian: Importantly, there is a fundamental correspondence between QUBO problems and Ising problems in physics. Specifically, we can encode the Maximum Cut problem as a minimization problem of an Ising Hamiltonian, where the (classical) cost function reads
with Ising variables
BACKGROUND: THE QUANTUM APPROXIMATE OPTIMIZATION ALGORITHM
In this tutorial we will try to solve for the optimal classical bitstring
which can be written as a matrix of size
QAOA ansatz: Finding this ground state is generically hard.
To approximate this groundstate, QAOA prepares a parametrized ansatz state (corresponding to a parameterized gate sequence), whose parameters are iteratively updated by a classical optimizer in a closed loop.
Specifically, QAOA involves a specific ansatz wavefunction parametrized by a parameter family
with single qubit rotations induced by
Optimization: Since we are primarily interested in solving the classical optimization problem, within this routine it is sufficient to keep track of the best classical bitstring.
This means that the wavefunction prepared by the quantum circuit
where
since the term
Let us illustrate this results as follows:
If we do not know anything and just resort to a uniform superposition
Objective function: Finally, some more details on the definition of the cost function are in order.
Following the standard approach [1, 4], QAOA tries to minimize the expectation value
IMPORTS and SETUP
For classical benchmarking we will be using the python library pyqubo, as used in our helper script utils_classical. If not already present in your virtual environment, you can install this library simply with pip install pyqubo. Similarly, as seaborn are not expected to be present in the virtual environment by default, we will install them via pip install seaborn. Note the -q to suppress install updates from pip.
# If these have already been installed, this cell can be commented out.
!pip install pyqubo -q
!pip install seaborn -q# general imports
import pickle
import random
import time
from datetime import datetime
import matplotlib.pyplot as plt
import networkx as nx
import numpy as np
import seaborn as sns
# magic line for producing visualizations in notebook
%matplotlib inline# fix random seed for reproducibility
seed = 42
np.random.seed(seed)
random.seed(a=seed)
# switch to trigger writing training results to disk
store_results = False
# switch to trigger printing results of each optimization cycle
verbose = False# AWS imports: Import Braket SDK modules
from braket.circuits import FreeParameter
from braket.devices import LocalSimulatorfrom utils_classical import plot_colored_graph_simple, solve_classical_ising
# auto reload external files, so that we can edit the external .py file and immediately see the changes here
%load_ext autoreload
%autoreload 2# Set up device: Local Simulator
device = LocalSimulator()# example code for other backends
# from braket.aws import AwsDevice
# from braket.devices import Devices
# choose the on-demand simulator to run your circuit
# device = AwsDevice(Devices.Amazon.SV1)
# choose the Ionq device to run your circuit
# device = AwsDevice(Devices.IonQ.ForteEnterprise1)
# choose the IQM device to run your circuit
# device = AwsDevice(Devices.IQM.Garnet)
# choose the Rigetti device to run your circuit
# device = AwsDevice(Devices.Rigetti.Cepheus1108Q)PROBLEM SETUP
We consider a graph coloring problem.
Given a graph networkx library to visualize the problem graph.
Feel free to play with the parameters
# setup Erdos Renyi graph
n = 10 # number of nodes/vertices
m = 20 # number of edges
# define graph object
G = nx.gnm_random_graph(n, m, seed=seed)
# positions for all nodes
pos = nx.spring_layout(G)
# choose random weights
for u, v in G.edges():
G.edges[u, v]["weight"] = random.uniform(0, 1)
# draw graph
nx.draw(G, pos)
plt.show()# set Ising matrix
Jfull = nx.to_numpy_array(G)
# get off-diagonal upper triangular matrix
J = np.triu(Jfull, k=1).astype(np.float64)# plot Ising matrix
plt.figure(1, figsize=[7, 5])
sns.heatmap(J, annot=True, linewidths=0.5, cmap="YlGnBu", annot_kws={"alpha": 1})
plt.title("Ising distance matrix")
plt.tight_layout();IMPLEMENTATION OF QAOA WITH BRAKET
In this section we load a set of useful helper functions that we will explain in detail below.
Specifically in utils_qaoa.py we provide simple building blocks for the core modules of our QAOA algorithm, that is (i) a function called circuit that defines the parametrized ansatz, (ii) a function called objective_function that takes a list of variational parameters as input, and returns the cost associated with those parameters and finally (iii) a function train to run the entire QAOA algorithm for given ansatz.
This way we can solve the problem in a clean and modular approach.
Here, we show in markdown the definition of the parametrized QAOA circuit.
For more details, see the corresponding file utils_qaoa.py.
from utils_qaoa import circuit, train
# auto reload external files, so that we can edit the external .py file and immediately see the changes here
%load_ext autoreload
%autoreload 2The autoreload extension is already loaded. To reload it, use: %reload_ext autoreload
# function to implement evolution with driver Hamiltonian
def driver(beta, n_qubits):
"""
Returns circuit for driver Hamiltonian U(Hb, beta)
"""
# instantiate circuit object
circ = Circuit()
for qubit in range(n_qubits):
gate = Circuit().rx(qubit, 2*beta)
circ.add(gate)
return circ
# helper function for evolution with cost Hamiltonian
def cost_circuit(gamma, n_qubits, ising):
"""
returns circuit for evolution with cost Hamiltonian
"""
# instantiate circuit object
circ = Circuit()
# get all non-zero entries (edges) from Ising matrix
idx = ising.nonzero()
edges = list(zip(idx[0], idx[1]))
for qubit_pair in edges:
# get interaction strength
int_strength = ising[qubit_pair[0], qubit_pair[1]]
gate = Circuit().zz(qubit_pair[0], qubit_pair[1], angle=2*gamma*int_strength)
circ.add(gate)
return circ
# function to build the QAOA circuit with depth p
def circuit(params, n_qubits, ising):
"""
function to return full QAOA circuit
"""
# initialize qaoa circuit with first Hadamard layer: for minimization start in |->
circ = Circuit()
X_on_all = Circuit().x(range(0, n_qubits))
circ.add(X_on_all)
H_on_all = Circuit().h(range(0, n_qubits))
circ.add(H_on_all)
# setup two parameter families
circuit_length = int(len(params) / 2)
gammas = params[:circuit_length]
betas = params[circuit_length:]
# add circuit layers
for mm in range(circuit_length):
circ.add(cost_circuit(gammas[mm], n_qubits, ising))
circ.add(driver(betas[mm], n_qubits))
return circ
VISUALIZATION OF THE QAOA ANSATZ
Let us first visualize our parametrized QAOA ansatz for a small number of qubits and fixed (i.e., not optimized) parameters.
For convenience, the parameters are displayed in the circuit (up to a factor of device object, as the implementation of the ZZ gate depends on the specific gate set supported by the device.
# create parameters
gammas = [FreeParameter("gamma")]
betas = [FreeParameter("beta")]
params = gammas + betas
# for demonstration purposes use small Ising matrix
J_sub = np.array([[0, 1], [0, 0]])
N = J_sub.shape[0]
# get circuit ansatz
my_simple_circuit = circuit(params, device, N, J_sub)
# print test ansatz circuit
print("Printing test circuit:")
print(my_simple_circuit)Printing test circuit:
T : |0|1| 2 | 3 |
q0 : -X-H-ZZ(2*gamma)-Rx(2*beta)-
|
q1 : -X-H-ZZ(2*gamma)-Rx(2*beta)-
T : |0|1| 2 | 3 |
Unassigned parameters: [beta, gamma].
We see that our ansatz produces the expected result for shallow QAOA with
# set number of qubits and fix parameters
gammas = [FreeParameter("gamma_1"), FreeParameter("gamma_2")]
betas = [FreeParameter("beta_1"), FreeParameter("beta_2")]
params = gammas + betas
# for demonstration purposes use small Ising matrix
J_sub = np.array([[0, 1], [0, 0]])
N = J_sub.shape[0]
# get circuit ansatz
my_simple_circuit = circuit(params, device, N, J_sub)
# print test ansatz circuit
print("Printing test circuit:")
print(my_simple_circuit)Printing test circuit:
T : |0|1| 2 | 3 | 4 | 5 |
q0 : -X-H-ZZ(2*gamma_1)-Rx(2*beta_1)-ZZ(2*gamma_2)-Rx(2*beta_2)-
| |
q1 : -X-H-ZZ(2*gamma_1)-Rx(2*beta_1)-ZZ(2*gamma_2)-Rx(2*beta_2)-
T : |0|1| 2 | 3 | 4 | 5 |
Unassigned parameters: [beta_1, beta_2, gamma_1, gamma_2].
QAOA SIMULATION ON LOCAL SCHROEDINGER SIMULATOR
We are now all set to run some QAOA simulation experiments.
First of all, you can play and experiment yourself with the number of qubits scipy minimizer (as described in more detail here), you can simply swap between different optimizers by setting the OPT_METHOD parameter below.
Some popular options readily available within this library include Nelder-Mead, BFGS and COBYLA.
As a precautionary warning, note that the classical optimization step may get stuck in a local optimum, rather than finding the global minimum for our parametrized QAOA ansatz wavefunction.
To address this issue, we may run several optimization loops, starting from different random parameter seeds.
While this brute-force approach does not provide any guarantee to find the global optimum, from a pragmatic point of view at least it does increase the odds of finding an acceptable solution, at the expense of potentially having to run many more circuits on the simulator or QPU, respectively.
Finally, the optimization loop may require the execution of many individual quantum tasks (i.e., single circuit executions for fixed parameters).
For example, when choosing the classical Powell optimizer for the graph considered here, we find maxfev parameter to control the maximum allowed number function evaluations (compare comment in the next code block below).
##################################################################################
# set up hyperparameters
##################################################################################
# User-defined hypers
DEPTH = 3 # circuit depth for QAOA
SHOTS = 1000 # number measurements to make on circuit
OPT_METHOD = "COBYLA" # SLSQP, COBYLA, Nelder-Mead, BFGS, Powell, ...
# set up the problem
n_qubits = J.shape[0]
# initialize reference solution (simple guess)
bitstring_init = -1 * np.ones([n_qubits])
energy_init = np.dot(bitstring_init, np.dot(J, bitstring_init))
# set tracker to keep track of results
tracker = {
"count": 1, # Elapsed optimization steps
"optimal_energy": energy_init, # Global optimal energy
"opt_energies": [], # Optimal energy at each step
"global_energies": [], # Global optimal energy at each step
"optimal_bitstring": bitstring_init, # Global optimal bitstring
"opt_bitstrings": [], # Optimal bitstring at each step
"costs": [], # Cost (average energy) at each step
"res": None, # Quantum result object
"params": [], # Track parameters
}
# set options for classical optimization
options = {"disp": True, "maxiter": 50}##################################################################################
# run QAOA optimization on graph
##################################################################################
print("Circuit depth hyperparameter:", DEPTH)
print("Problem size:", n_qubits)
# kick off training
start = time.time()
result_energy, result_angle, tracker = train(
device=device,
options=options,
p=DEPTH,
ising=J,
n_qubits=n_qubits,
n_shots=SHOTS,
opt_method=OPT_METHOD,
tracker=tracker,
verbose=verbose,
)
end = time.time()
# print execution time
print("Code execution time [sec]:", end - start)
# print optimized results
print("Optimal energy:", tracker["optimal_energy"])
print("Optimal classical bitstring:", tracker["optimal_bitstring"])
##################################################################################
# Compute output and dump to pickle
##################################################################################
if store_results:
out = {
"p": DEPTH,
"N": n_qubits,
"ENERGY_OPTIMAL": tracker["optimal_energy"],
"BITSTRING": tracker["optimal_bitstring"],
"result_energy": result_energy,
"result_angle": result_angle,
}
# store results: dump output to pickle with timestamp in filename
time_now = datetime.strftime(datetime.now(), "%Y%m%d%H%M%S")
results_file = "results-" + time_now + ".pkl"
print(f"Writing results to file: {results_file}")
pickle.dump(out, open(results_file, "wb"))
# you can load results as follows
# out = pickle.load(open(results_file, "rb"))Circuit depth hyperparameter: 3
Problem size: 10
Starting the training.
====================================================================
OPTIMIZATION for circuit depth p=3
Param "verbose" set to False. Will not print intermediate steps.
====================================================================
Final average energy (cost):
Return from subroutine COBYLA because the MAXFUN limit has been reached.
-0.586455292294228
Final angles: [5.78684986 4.70523429 6.47840919 0.25681156 1.2539245 2.7942261 ]
Training complete.
Code execution time [sec]: 6.3666791915893555
Optimal energy: -6.486032631497276
Optimal classical bitstring: [-1 1 -1 -1 1 -1 1 1 -1 -1]
NFVALS = 50 F =-5.864553E-01 MAXCV = 0.000000E+00
X = 5.786850E+00 4.705234E+00 6.478409E+00 2.568116E-01 1.253925E+00
2.794226E+00
POSTPROCESSING AND COMPARISON OF OUR QAOA RESULTS WITH CLASSICAL RESULTS
In this section we visualize the results we have found with QAOA.
Specifically, we display the results found for the variational parameters pyqubo package.
Ideally, the two results should agree with each other but this is not necessarily the case for several reasons:
First of all, for the original small toy problem we have set up there are several degenerate classical solutions with the same optimal quality.
The classical and the QAOA approach may find solutions with different coloring configurations but the same quality (that is energy).
Secondly, with QAOA we are not guaranteed to find the optimal solutions.
Specifically, the deeper the circuit, the harder the classical optimization problem, and we may get stuck in a local rather than global optimum.
One brute-force approach is then to just re-run QAOA with different random initial seeds for the parameters
# visualize the optimization process
cycles = np.arange(1, tracker["count"])
optim_classical = tracker["global_energies"]
# print information
info = "Optimization on graph with n={} vertices, m={} edges, optimized with {} and {} shots per call; seed={}."
print(info.format(n, m, OPT_METHOD, SHOTS, seed))
plt.plot(cycles, optim_classical)
plt.xlabel("optimization cycle")
plt.ylabel("best classical minimum")
plt.show()Optimization on graph with n=10 vertices, m=20 edges, optimized with COBYLA and 1000 shots per call; seed=42.
# print the optimal energy found with QAOA
print("Optimal energy found with QAOA:", tracker["optimal_energy"])
# print the corresponding bitstring
print("Optimal bit-string found with QAOA:", tracker["optimal_bitstring"])Optimal energy found with QAOA: -6.486032631497276 Optimal bit-string found with QAOA: [-1 1 -1 -1 1 -1 1 1 -1 -1]
# get results for variational angles
gamma = result_angle[:DEPTH]
beta = result_angle[DEPTH:]
# get array [1, 2, ..., p]
pa = np.arange(1, DEPTH + 1)
plt.figure(2)
plt.plot(pa, gamma / np.pi, "-o", label="gamma")
plt.plot(pa, beta / np.pi, "-s", label="beta")
plt.xlabel("circuit depth (layer) p")
plt.ylabel("optimal angles [pi]")
plt.xticks(pa)
plt.legend(title="Variational QAOA angles:", loc="upper left")
plt.show()# visualize solution
colorlist = tracker["optimal_bitstring"]
colorlist[colorlist == -1] = 0
# plot_colored_graph(J, N, colorlist, pos)
plot_colored_graph_simple(G, colorlist, pos)
print("Minimal energy found with QAOA:", tracker["optimal_energy"])Minimal energy found with QAOA: -6.486032631497276
# validate quantum results with classical algorithm
solution, energy_min, colors_classical = solve_classical_ising(J, n_qubits, pos)
# plot classical solution
plot_colored_graph_simple(G, colors_classical, pos)Classical solution: {'s0': -1, 's1': 1, 's2': -1, 's3': -1, 's4': 1, 's5': -1, 's6': 1, 's7': 1, 's8': -1, 's9': -1}
Minimal energy found classically: -6.486032631497276
Note that QAOA may arrive at a different solution than our classical benchmark code.
First of all, the classical optimization routine may get stuck in a local rather than global optimum.
To avoid this, more sophisticated optimization strategies may be employed (as proposed for example in Ref.[4]), going beyond the scope of this introductory notebook tutorial.
Secondly, even if QAOA arrives at the same classical energy as our classical approach, the coloring may differ since the solution space may be degenerate for the specific example shown here (this means, two different classical bitstrings have the same energy).
At minimum, you may find an inverted coloring (by swapping red and blue colors), because of the underlying
SUMMARY
In this notebook we have gone through an end-to-end demo on QAOA and its implementation on Amazon Braket. We have built modular core building blocks that may easily adapted to other problems. The QAOA routine is tailored towards solving combinatorial optimization problems such as Maximum Cut [4] and arguably one of the most prominent examples of the emerging class of hybrid, variational algorithms and still very much a field of active research today. For example, as we increase the circuit depth of QAOA, the classical optimization step becomes increasingly difficult (because of the curse of dimensionality as well known in classical machine learning) and may easily get stuck in local sub-optimal solutions. To address this issue some heuristics have already been developed, for example in Ref.[4], but further improvements will arguably be necessary to fully unlock the potential of this approach.
REFERENCES
[1] E. Farhi, J. Goldstone, and S. Gutmann, "A Quantum Approximate Optimization Algorithm", arXiv: 1411.4028 (2014).
[2] Y. Cao, J. Romero, J. P. Olson, M. Degroote, P. D. Johnson, M. Kieferova, I. D. Kivlichan, T. Menke, B. Peropadre, N. P. Sawaya, et al., "Quantum Chemistry in the Age of Quantum Computing", Chemical reviews 119, 10856 (2019).
[3] A. Smith, M. Kim, F. Pollmann, and J. Knolle, "Simulating quantum many-body dynamics on a current digital quantum computer", npj Quantum Information 5, 1 (2019).
[4] L. Zhou, S.-T. Wang, S. Choi, H. Pichler, and M. D. Lukin, "Quantum Approximate Optimization Algorithm: Performance, Mechanism,and Implementation on Near-Term Devices", arXiv: 1812.01041 (2018).
[5] F. Glover, G. Kochenberger, "A Tutorial on Formulating and Using QUBO Models", arXiv:1811.11538 (2018).
[6] P. Vikstal, M. Groenkvist, M. Svensson, M. Andersson, G. Johansson, and G. Ferrini, "Applying the Quantum Approximate Optimization Algorithm to the Tail Assignment Problem", arXiv:1912.10499 (2019).
[7] L. Li, M. Fan, M. Coram, P. Riley, and S. Leichenauer, "Quantum optimization with a novel gibbs objective function and ansatz architecture search", arXiv:1909.07621 (2019).
APPENDIX
APPENDIX: Example for Ising Matrix Syntax
In this appendix we provide a small code example to showcase how we obtain all edges with corresponding weights.
# example Ising matrix with edges between qubit 0 and qubit 1 (weight=1) and qubit 1 and qubit 2 (weight=3)
ising = np.array([[0, 1, 0], [0, 0, 3], [0, 0, 0]])
print("Ising matrix:\n", ising)
# get all non-zero entries (edges) from Ising matrix
idx = ising.nonzero()
edges = list(zip(idx[0], idx[1]))
print("Edges:", edges)
# for every edge print interaction strength
for qubit_pair in edges:
# get interaction strength
int_strength = ising[qubit_pair[0], qubit_pair[1]]
print("Interaction strength:", int_strength)
# get all non-zero entries from Ising, with proper order
interactions = np.array([ising[q[0], q[1]] for q in edges])
print("All interactions:", interactions)Ising matrix: [[0 1 0] [0 0 3] [0 0 0]] Edges: [(0, 1), (1, 2)] Interaction strength: 1 Interaction strength: 3 All interactions: [1 3]
print("Quantum Task Summary")
print(t.quantum_tasks_statistics())
print(
f"Estimated cost to run this example with SV1: {t.qpu_tasks_cost() + t.simulator_tasks_cost()} USD",
)Task Summary
{}
Estimated cost to run this example with SV1: 0 USD
This entry was created automatically from publicly available records. QCR links to public sources and only stores repository content where the license permits redistribution.
Versions
Cite all versions? Use the base QCR ID to always reference the latest version of this entry.
Join the Discussion
Comments (0)
No comments yet. Be the first to share your thoughts!