entropicalabs / openqaoa Goto Github PK
View Code? Open in Web Editor NEWMulti-backend SDK for quantum optimisation
License: MIT License
Multi-backend SDK for quantum optimisation
License: MIT License
To remove the results returned by Scipy's minimize function.
Note: Some of the evaluations made using the scipy minimize function, for methods that use the jacobian, are not kept tracked off.
To create a way to record the number of evaluations from both the function calls to optimise_this
and the those used to compute the jacobian.
The Backend Class returns the appropriate callback function for the jacobian evaluations. We can make modifications to that callback to capture the information we need to return to the user.
To make sure every call to .expectation
of the backend class is recorded/kept track off.
For methods like BFGS, it calls the optimise_this
method. We need to make sure we are updating the log lists appropriately.
Currently in the workflow, there needs to be branching if/else statements to handle the different result outputs from the various backends in OptimizeVQA. 'vectorized' producing its results as a probability vector while shot-based backends outputing their results in counts. The results populate different entries in the results_dictionary depending on the backend used.
We should find a more unified way to combine these 2 together. Since in the current version. workflows post-processes the results as well.
Having the results from the Logger Class go directly into a Results Object that post-processes the results one more time should make the code look cleaner.
Before raising this issue, I have already checked that I am:
OpenQAOA cannot be installed currently due to conflicting package requirements. Most likely due to the usage of an older version of the pyquil package.
Steps to reproduce the behavior:
pip install openqaoa
clone openqaoa locally and use make dev-install-all
The package should be installed correctly
The current OpenQAOA version makes use of pyquil 3.5.4 to ignore breaking changes occuring with 4.X
I was trying to use OpenQAOA to run only the optimised circuit of my QAOA instance. I have used the simulator to derive the optimal variational parameters, and I wanted to run only the final circuit on the IBMQ cloud.
I used the following command (where qsim_qiskit is my QAOA() object)
qsim_qiskit.set_classical_optimizer(optimize=False)
While it worked on the local qiskit simulator, on the cloud it sent multiple jobs (I am not sure how many iterations it was considering, eventually I killed the jobs).
Steps to reproduce the behavior:
# initialize model with default configurations
qsim_qiskit = QAOA()
# optionally configure the following properties of the model
# device
qiskit_cloud = create_device(location='ibmq', name='ibmq_qasm_simulator', **qpu_credentials)
qsim_qiskit.set_device(qiskit_cloud)
#qiskit_device = create_device(location='local', name='qiskit.statevector_simulator')
#qsim_qiskit.set_device(qiskit_device)
# circuit properties
qsim_qiskit.set_circuit_properties(p=2, param_type='standard', init_type='custom', mixer_hamiltonian='x',
variational_params_dict={
"betas":variational_params.betas.tolist(),
"gammas":variational_params.gammas.tolist()
})
# backend properties (already set by default)
qsim_qiskit.set_backend_properties(prepend_state=None, append_state=None)
#qsim_qiskit.set_classical_optimizer(optimize=False) # **<--- This is the problematic line**
I want to be able to run only one circuit on the IBMQ cloud
Note that the following command works (but it's not ideal)
#qsim_qiskit.set_classical_optimizer(optimize=False) qsim_qiskit.set_classical_optimizer(method='cobyla', maxiter=0, cost_progress=True, parameter_log=True, optimization_progress=True)
I like the openQAOA ecosystem and I am trying to integrate a tensor network based backend (using cuQuantum SDK), which does not calculate the explicit wf as statevec. I can use qiskit circuits as starting point before converting them to perform TN contractions, so I adapted a backend from qiskit_sim. However the optimization fails at the first cycle without measurement_outcomes.
Here is the kernel code from the backend, is there a way to bypass measurement_outcomes?
def expectation(self,
params: QAOAVariationalBaseParams) -> float:
ckt = self.qaoa_circuit(params)
## QISKIT VERSION
# output_wf = Statevector(ckt)
# self.measurement_outcomes = output_wf.data
# cost = np.real(output_wf.expectation_value(self.qiskit_cost_hamil))
## CUQUANTUM VERSION
einsum = CircuitToEinsum(ckt, dtype='complex128', backend=cp)
cost = 0
for pauli_term_list in self.qiskit_cost_hamil:
pauli_term = str(pauli_term_list).split(' * ')
expression, operands = einsum.expectation(pauli_term[1], lightcone=True)
expec = contract(expression, *operands)
cost += np.real(expec * float(pauli_term[0]))
return cost
A qaoa or a rqaoa object can be optimized more than once without recompiling again.
The following code is now valid:
q = qaoa()
q.compile(problem)
q.optimize()
...
q.optimize()
If you run the code above, an error should be raised saying that the qaoa object is already optimized and that it should be compiled before optimizing again.
That could be done by implementing a boolean already_optimized
that is False
when the user compiles and it's True
when they optimize. If the boolean is True
then the warning is raised.
When trying to create a random instance of a number partitioning problem, I get the following error
The core issue is that random_instance()
is a static method and should be used as such:
The inconsistency is made worst by the fact that I can do the following, where the numbers I pass to the constructor are right away changed by the random_instance()
method
#Solution
I am unsure what's the best way to go about this, but we should review the way that random instances are created across the pre-defined problem settings.
Several energy calculation functions in utilities.py
will fail if Hamiltonian object contains terms that are not in the range [0, ..., n]
, returning an out-of-bounds error. Reason: in these functions, the terms of the Hamiltonian (which may be more than n
) is used directly as indices for the bitstring (which has length n
). A simple fix is to 're-zero' the terms in the Hamiltonian object so that they range from [0, ...., n]
.
Affected functions in utilities:
bitstring_energy, energy_expectation, energy_spectrum_hamiltonian
Example solution:
def bitstring_energy(terms:list,
weights:list,
bitstring:Union[List[int],str]) -> float:
"""
Computes the energy of a given bitstring with respect to the cost Hamiltonian.
Parameters
----------
terms: list
Hamiltonian terms
weights: list
Coefficients of the hamiltonian terms
bitstring : Union[list,str]
A list of integers 0 and 1 of length `n_qubits` representing a configuration
or a string of bits of length `n_qubits`.
Returns
-------
energy:
The energy of a given bitstring with respect to the cost Hamiltonian.
"""
# Re-zero terms to prevent out of range error
rezeroed_terms = rezero_terms(terms)
energy = 0
# string_rev = bitstring
for i, term in enumerate(rezeroed_terms):
if len(term) == 0:
energy += np.real(weights[i])
else:
variables_product = np.prod([(-1)**int(bitstring[k]) for k in term])
energy += weights[i]*variables_product
return energy
def rezero_terms(terms):
copied_terms = deepcopy(terms)
indices = list(set([item for sublist in copied_terms for item in sublist]))
zero_indices = list(range(len(set([item for sublist in copied_terms for item in sublist]))))
for pairs in copied_terms:
for i, item in enumerate(pairs):
pairs[i] = zero_indices[indices.index(item)]
return copied_terms
@shahidee44, I think the disable_qubit_rewiring argument is repeated. The argument `rewiring` used for the Pyquil backend does the same thing, no?
Originally posted by @vishal-ph in #69 (comment)
Function description:
The random classical hamiltonian accepts as input the qubit_register
as a List
to define a random cost hamiltonian on those qubits. The function's logic randomly either creates an edge between possible pairs of qubits in the qubit_register
or omits it.
Unexpected behavior:
For some runs, stochastically, the final hamiltonian ends up having fewer qubits in total than the specified qubit_register
. However, if, the mixer_hamiltonian is defined on the original qubit_register
it leads to a mismatch in the number of qubits in the QAOA circuit leading to index out of bounds
error.
The following is an example of the traceback messages resulting from this error:
---------------------------------------------------------------------------
IndexError Traceback (most recent call last)
File ~/.conda/envs/openqaoa_may22/lib/python3.8/site-packages/qiskit/circuit/quantumcircuit.py:4814, in _bit_argument_conversion(specifier, bit_sequence, bit_set, type_)
4813 try:
-> 4814 return [bit_sequence[specifier]]
4815 except IndexError as ex:
IndexError: list index out of range
The above exception was the direct cause of the following exception:
CircuitError Traceback (most recent call last)
Input In [1], in <cell line: 24>()
19 qaoa_circuit_params = QAOACircuitParams(
20 cost_hamiltonian, mixer_hamiltonian, p)
21 variational_params_std = QAOAVariationalStandardParams(
22 qaoa_circuit_params, betas, gammas)
---> 24 backend_qiskit_statevec = get_qaoa_backend(
25 qaoa_circuit_params, 'qiskit_statevec_simulator')
File ~/openqaoa_github/openqaoa/openqaoa/backends/qaoa_backend.py:144, in get_qaoa_backend(circuit_params, device, prepend_state, append_state, init_hadamard, cvar_alpha, **kwargs)
142 backend_class = backend_name_to_object_mapper(simulator_name)
143 backend_kwargs = _backend_arg_mapper(backend_class, **kwargs)
--> 144 backend_obj = backend_class(circuit_params=circuit_params, prepend_state=prepend_state,
145 append_state=append_state, init_hadamard=init_hadamard,
146 cvar_alpha=cvar_alpha, **backend_kwargs)
147 # except TypeError:
148 # raise TypeError(
149 # 'Please make sure the **kwargs are supported by the chosen backend')
(...)
152 # raise ValueError(
153 # f"{e} The backend {simulator_name} returned an error")
155 elif isinstance(device, AccessObjectBase):
File ~/openqaoa_github/openqaoa/openqaoa/backends/simulators/qaoa_qiskit_sim.py:239, in QAOAQiskitBackendStatevecSimulator.__init__(self, circuit_params, prepend_state, append_state, init_hadamard, cvar_alpha)
235 assert self.n_qubits >= len(prepend_state.qubits), "Cannot attach a bigger circuit " \
236 "to the QAOA routine"
238 # For parametric circuits
--> 239 self.parametric_circuit = self.parametric_qaoa_circuit
240 self.qiskit_cost_hamil = self.qiskit_cost_hamiltonian
241 self.qiskit_cost_hamil_sq = self.qiskit_cost_hamil**2
File ~/openqaoa_github/openqaoa/openqaoa/backends/simulators/qaoa_qiskit_sim.py:317, in QAOAQiskitBackendStatevecSimulator.parametric_qaoa_circuit(self)
315 # Create Circuit
316 for each_tuple in decomposition:
--> 317 parametric_circuit = each_tuple[0](*each_tuple[1]).apply_gate(parametric_circuit, 'ibm')
319 if self.append_state:
320 parametric_circuit = parametric_circuit.compose(self.append_state)
File ~/openqaoa_github/openqaoa/openqaoa/qaoa_parameters/lowlevelgate.py:30, in LowLevelGate.apply_gate(self, circuit, circuit_library)
27 def apply_gate(self, circuit, circuit_library: str):
29 if circuit_library == 'ibm':
---> 30 return self._ibm_gate(circuit)
31 elif circuit_library == 'pyquil':
32 return self._pyquil_gate(circuit)
File ~/openqaoa_github/openqaoa/openqaoa/qaoa_parameters/lowlevelgate.py:93, in RX._ibm_gate(self, circuit)
91 def _ibm_gate(self, circuit: qkQuantumCircuit) -> qkQuantumCircuit:
---> 93 circuit.rx(self.rotation_angle_obj.rotation_angle, self.qubit_1)
94 return circuit
File ~/.conda/envs/openqaoa_may22/lib/python3.8/site-packages/qiskit/circuit/quantumcircuit.py:2988, in QuantumCircuit.rx(self, theta, qubit, label)
2974 """Apply :class:`~qiskit.circuit.library.RXGate`.
2975
2976 For the full matrix form of this gate, see the underlying gate documentation.
(...)
2984 A handle to the instructions created.
2985 """
2986 from .library.standard_gates.rx import RXGate
-> 2988 return self.append(RXGate(theta, label=label), [qubit], [])
File ~/.conda/envs/openqaoa_may22/lib/python3.8/site-packages/qiskit/circuit/quantumcircuit.py:1204, in QuantumCircuit.append(self, instruction, qargs, cargs)
1201 if is_parameter:
1202 instruction = copy.deepcopy(instruction)
-> 1204 expanded_qargs = [self.qbit_argument_conversion(qarg) for qarg in qargs or []]
1205 expanded_cargs = [self.cbit_argument_conversion(carg) for carg in cargs or []]
1207 if self._control_flow_scopes:
File ~/.conda/envs/openqaoa_may22/lib/python3.8/site-packages/qiskit/circuit/quantumcircuit.py:1204, in <listcomp>(.0)
1201 if is_parameter:
1202 instruction = copy.deepcopy(instruction)
-> 1204 expanded_qargs = [self.qbit_argument_conversion(qarg) for qarg in qargs or []]
1205 expanded_cargs = [self.cbit_argument_conversion(carg) for carg in cargs or []]
1207 if self._control_flow_scopes:
File ~/.conda/envs/openqaoa_may22/lib/python3.8/site-packages/qiskit/circuit/quantumcircuit.py:1102, in QuantumCircuit.qbit_argument_conversion(self, qubit_representation)
1091 def qbit_argument_conversion(self, qubit_representation: QubitSpecifier) -> List[Qubit]:
1092 """
1093 Converts several qubit representations (such as indexes, range, etc.)
1094 into a list of qubits.
(...)
1100 List(Qubit): the resolved instances of the qubits.
1101 """
-> 1102 return _bit_argument_conversion(
1103 qubit_representation, self.qubits, self._qubit_indices, Qubit
1104 )
File ~/.conda/envs/openqaoa_may22/lib/python3.8/site-packages/qiskit/circuit/quantumcircuit.py:4816, in _bit_argument_conversion(specifier, bit_sequence, bit_set, type_)
4814 return [bit_sequence[specifier]]
4815 except IndexError as ex:
-> 4816 raise CircuitError(
4817 f"Index {specifier} out of range for size {len(bit_sequence)}."
4818 ) from ex
4819 # Slices can't raise IndexError - they just return an empty list.
4820 if isinstance(specifier, slice):
CircuitError: 'Index 5 out of range for size 5.'
Resulting from the following qaoa_circuit_params
(Notice the different number of qubits in the cost hamiltonian and mixer hamiltonian) :
Circuit Parameters:
p: 1
register: [0, 1, 2, 3, 4]
Cost Hamiltonian:
cost_qubits_singles: [PauliOp(Z,(0,)), PauliOp(Z,(4,)), PauliOp(Z,(4,))]
cost_single_qubit_coeffs: [0.2553358375172401, 0.7451256815312157, 0.19961958936046076]
cost_qubits_pairs: [PauliOp(ZZ,(0, 1)), PauliOp(ZZ,(0, 4)), PauliOp(ZZ,(2, 3)), PauliOp(ZZ,(2, 4))]
cost_pair_qubit_coeffs: [0.41784048382311567, 0.26267010544127745, 0.20272558242632943, 0.5514867726991646]
Mixer Hamiltonian:
mixer_qubits_singles: [PauliOp(X,(0,)), PauliOp(X,(1,)), PauliOp(X,(2,)), PauliOp(X,(3,)), PauliOp(X,(4,)), PauliOp(X,(5,))]
mixer_single_qubit_coeffs: [-1, -1, -1, -1, -1, -1]
mixer_qubits_pairs: []
mixer_pair_qubit_coeffs: []
qaoa_circuit_params
Before raising this issue, I have already checked that I am:
Running a QAOA problem using the OpenQAOA workflow as described in this notebook will require web authentication twice before executing the run. For reference, see the attached screenshot.
This happens because DeviceAzure, which is defined in src/openqaoa-azure/openqaoa_azure/backends/devices.py
, has a method called check_connection
, that is called twice, once from within the workflow and the other time from within the backend object.
Steps to reproduce the behavior:
qubo
for a problem of choiceq = QAOA()
q.compile(qubo)
Upon executing the above steps, the web authenticator should only prompt once for device authentication
A recent bug in the decomposition methods of some GateMaps
raised concern for the quality of QPU tests. The bug was fixed with PR #91, however, we need to update the QPU test suite.
The QAOAResult object stores information regarding the QAOA optimization routine. This result object can be accessed post optimization through the QAOA
workflow object via the following steps:
qubo
q = QAOA()
q.compile(qubo)
q.optimize()
qaoa_result = q.result
Add a method under the QAOAResult
class that computes some statistical quantities for the measurement outcomes.
The QAOA object can store measurement outcomes (i.e. counts) from each circuit evaluation in the QAOAResult
object.
mean
and standard deviation
for the optimized set of measurement outcomes.An approach adding statistical tools to understand QAOA results better
Before raising this issue, I have already checked that I am:
When compiling a QAOA circuit without having the IMBQ credentials set up, the link displayed to solve the issue leads to a 404 error on https://quantum-computing.ibm.com/
Steps to reproduce the behavior:
.compile()
functionThe link displayed should lead to a valid page.
The QAOA Results object has some dictionaries as attributes. These dictionaries use strings with white spaces as keys, see: https://github.com/entropicalabs/openqaoa/blob/main/openqaoa/optimizers/result.py#L69
That is a problem when trying to serialize the results object to a json. For good serialization, those white spaces should be removed. However, this means that older code that uses these keys will not work anymore.
Currently, the methods to calculate the derivative functions and the quantum Fisher information matrix (QFIM) (located in basebackend.py
, the methods derivative_function
and qfim
respectively) accepts a QAOAVariationalBaseParams
object and return a callable which accepts an array of parameters and output either the derivatives or QFIM. This is because the derivative/QFIM argument in scipy.minimize.optimize and our custom gradient optimisers expect a callable that takes in an array and outputs a vector/matrix.
Design wise, it might be more intuitive that these methods directly output the corresponding derivative/QFIM, given the QAOAVariationalBaseParams
object, since they already contain angles/parameters.
Some possible solutions to be discussed:
Before raising this feature request, I made sure:
OpenQAOA has a function called ground_state_hamiltonian
that takes as input the Cost Hamiltonian corresponding to the QUBO problem and outputs the degenerate solutions (or ground states of the Hamiltonian) along with the lowest energy (i.e. ground state energy). The function is defined in src/openqaoa-core/openqaoa/utilities.py
.
Expose this function as a QAOA
workflow class method so users can easily access it.
Ideal workflow
q = QAOA()
q.compile(qubo)
q.solve_brute_force()
The existing way to obtain the brute force solution of a qubo is described as follows:
qubo
prob_hamiltonian = qubo.hamiltonian
solution, energy = ground_state_hamiltonian(prob_hamiltonian)
name: Docplex converter.
about: Having an optimization problem in Docplex form transforms it into the OpenQAOA Hamiltonian.
title: 'docplex2hamiltonian'
labels: 'feature request'
assignees: @alejomonbar @MaldoAlberto
Before raising this feature request, I have made sure:
Implementing optimization problems using openQAOA is restricted to certain problems with a predefined structure ( NumberPartition, TSP, Knapsack, etc). For example, if we want to modify the Knapsack problem with a Heuristic equation, the implemented Knapsack problem would not help me to solve my problem and I must create my own Hamiltonian of this problem. Docplex a python based library used to solve optimization problems can be used to codify the optimization problem and then translate it directly into its OpenQAOA Hamiltonian.
It will be something like:
from docplex.mp.model import Model
from openqaoa.utilities import X_mixer_hamiltonian
from openqaoa.problems.helper_functions import docplex2hamiltonian #The function we want to implement
mdl = Model(name="MyOptimizationProblem") # Docplex model
z = mdl.binary_var_list(10, name="Z") #My binary optimization variables
objective = mdl.sum(z) - 2 * z[0] + z[3] * z[4] # Cost function
mdl.minimize(objective) # Adding the objective function to the model
cost_hamil = docplex2hamiltonian(mdl) # The function we want to implement
mixer_hamil = X_mixer_hamiltonian(num_assets)
circuit_params = QAOACircuitParams(cost_hamil, mixer_hamil, p=1)
variate_params = create_qaoa_variational_params(circuit_params, 'standard', 'ramp')
backend_obj_qiskit = get_qaoa_backend(circuit_params, 'qiskit_shot_simulator', n_shots=10000)
backend_obj_qiskit.expectation_w_uncertainty(variate_params)
backend_obj_qiskit.expectation(variate_params)
optimizer_dict = {'method': 'cobyla', 'maxiter': 10}
variate_params_qiskit = variate_params
optimizer_obj_qiskit = get_optimizer(backend_obj_qiskit, variate_params_qiskit, optimizer_dict)
optimizer_obj_qiskit()
optimizer_obj_qiskit.results_information()
Create a class function that translates an optimization problem into its Hamiltonian representation.
we think Numba can be used instead of Docplex. But, we should start first with Docplex.
So, I guess a general design choice could be to replace all this with ENUM... it may be worth considering for a future improvement
Originally posted by @Q-lds in #193 (comment)
Before raising this issue, I have already checked that I am:
Hello, I am trying to do some basic testing of the openqaoa module. In particular, I am simply going through the initial walkthrough for MinimumVertexCover
as described in the docs. I began by successfully cloning the OpenQAOA github file, and then using pip install .
to sucessfully install all dependencies. I verified that all dependencies were succesfully installed, including openqaoa
.
However, when I run my test file in Python, I get the error:
ModuleNotFoundError: No module named 'openqaoa.utilities'; 'openqaoa' is not a package
and the execution fails.
Steps to reproduce the behavior:
pip install .
or just manually install each required dependencytest.py
and paste the following code into it:import networkx
from openqaoa.problems import MinimumVertexCover
g = networkx.circulant_graph(6, [1])
vc = MinimumVertexCover(g, field=1.0, penalty=10)
qubo_problem = vc.qubo
python test.py
to run the fileI expect the file to run successfully, not to get the above error.
I also tried installing just the openqaoa
dependency in a new folder and then running the file there (without cloning the original file), but got the same error.
When running simple code to generate a random knapsack problem, I encounter the following error. I do not know where this is coming from or if I am doing something wrong.
Code:
q = QAOA()
problem = Knapsack.random_instance(n_items=9, quantum=True).get_pubo_problem()
q.compile(problem)
q.optimize()
Error:
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
Input In [71], in <cell line: 13>()
49 q = QAOA()
50 problem = Knapsack.random_instance(n_items=9, quantum=True).get_pubo_problem()
---> 51 q.compile(problem)
52 q.optimize()
53 ks[-1].append(q.results_information["best cost"][0])
File c:\users\owenl\documents\openqaoa-main\openqaoa\workflows\optimizer.py:345, in QAOA.compile(self, problem, verbose)
324 """
325 Initialise the trainable parameters for QAOA according to the specified
326 strategies and by passing the problem statement
(...)
339 Set True to have a summary of QAOA to displayed after compilation
340 """
341 self.mixer_hamil = get_mixer_hamiltonian(n_qubits=problem.n,
342 qubit_connectivity=self.circuit_properties.mixer_qubit_connectivity,
343 coeffs=self.circuit_properties.mixer_coeffs)
--> 345 self.cost_hamil = Hamiltonian.classical_hamiltonian(
346 terms=problem.terms, coeffs=problem.weights, constant=problem.constant)
348 self.circuit_params = QAOACircuitParams(
349 self.cost_hamil, self.mixer_hamil, p=self.circuit_properties.p)
350 self.variate_params = create_qaoa_variational_params(qaoa_circuit_params=self.circuit_params, params_type=self.circuit_properties.param_type,
351 init_type=self.circuit_properties.init_type, variational_params_dict=self.circuit_properties.variational_params_dict,
352 linear_ramp_time=self.circuit_properties.linear_ramp_time, q=self.circuit_properties.q, seed=self.circuit_properties.seed)
File c:\users\owenl\documents\openqaoa-main\openqaoa\qaoa_parameters\operators.py:610, in Hamiltonian.classical_hamiltonian(cls, terms, coeffs, constant)
608 pauli_ops.append(PauliOp('Z', term))
609 else:
--> 610 raise ValueError(
611 "Hamiltonian only supports Linear and Quadratic terms")
613 return cls(pauli_ops, coeffs, constant)
ValueError: Hamiltonian only supports Linear and Quadratic terms
Before raising this issue, I have already checked that I am:
Using local statevector/wavefunction simulators results in optimizer.log.probability.best
being empty.
The reason is probably a mismatch between the attributes probabilities
and counts
in the logger
from openqaoa.qaoa_parameters import PauliOp, Hamiltonian, QAOACircuitParams, create_qaoa_variational_params
from openqaoa.utilities import X_mixer_hamiltonian
from openqaoa.devices import DeviceQiskit, create_device
from openqaoa.backends.qaoa_backend import get_qaoa_backend
from openqaoa.optimizers import get_optimizer
from openqaoa.problems.problem import MinimumVertexCover
import networkx as nx
g = nx.circulant_graph(4, [1])
vc = MinimumVertexCover(g, field =1.0, penalty=10).get_pubo_problem()
mixer_hamil = X_mixer_hamiltonian(n_qubits=3)
circuit_params = QAOACircuitParams(vc.hamiltonian, mixer_hamil, p=2)
variate_params = create_qaoa_variational_params(circuit_params,'standard','ramp')
qiskit_sv_sim = create_device('local','qiskit.statevector_simulator')
backend_qiskit_sv = get_qaoa_backend(circuit_params, qiskit_sv_sim)
optimizer_dict = {'method': 'cobyla', 'maxiter': 10}
opti_sv = get_optimizer(backend_qiskit_sv, variate_params, optimizer_dict)
opti_sv()
The probability attribute should be populated! Note that the optimisation does happen, so the bug is at the logger's level
Probably a solution is to remove the difference between probability and count, and use the same attribute for both cases!
Code: from openqaoa.optimizers import *
Error Message:
---------------------------------------------------------------------------
ImportError Traceback (most recent call last)
<ipython-input-1-901a46c0d7dd> in <module>
----> 1 from openqaoa.optimizers import *
~/Test/openqaoa/openqaoa/optimizers/__init__.py in <module>
20 """
21
---> 22 from .training_vqa import *
23 from .qaoa_optimizer import *
~/Test/openqaoa/openqaoa/optimizers/training_vqa.py in <module>
24 from scipy.optimize import LinearConstraint, NonlinearConstraint, Bounds
25
---> 26 from ..basebackend import VQABaseBackend
27 from ..qaoa_parameters.baseparams import QAOAVariationalBaseParams
28 from . import optimization_methods as om
~/Test/openqaoa/openqaoa/basebackend.py in <module>
29 from copy import deepcopy
30
---> 31 from .backends.qpus.qpu_auth import AccessObjectBase
32 from .qaoa_parameters.pauligate import PauliGate, TwoPauliGate
33 from .qaoa_parameters.baseparams import QAOACircuitParams, QAOAVariationalBaseParams
~/Test/openqaoa/openqaoa/backends/__init__.py in <module>
30 from .qpus.qpu_auth import *
31
---> 32 from .qpus.qaoa_qiskit_qpu import *
33 from .qpus.qaoa_pyquil_qpu import *
34
~/Test/openqaoa/openqaoa/backends/qpus/qaoa_qiskit_qpu.py in <module>
22
23 from .qpu_auth import AccessObjectQiskit
---> 24 from ...basebackend import QAOABaseBackendShotBased, QAOABaseBackendCloud, QAOABaseBackendParametric
25 from ...qaoa_parameters.baseparams import QAOACircuitParams, QAOAVariationalBaseParams
26 from ...utilities import flip_counts
ImportError: cannot import name 'QAOABaseBackendShotBased' from partially initialized module 'openqaoa.basebackend' (most likely due to a circular import) (/home/shahidee/Test/openqaoa/openqaoa/basebackend.py)
The issue is partially resolved/the reason why we do not observe the error is when we call the import.
from openqaoa.backends.qpus.qpu_auth import *
The circular import error is fixed.
Before raising this issue, I have already checked that I am:
A clear and concise description of what the bug is.
Using an azure device (e.g. device = create_device(location='azure', name='rigetti.sim.qvm', resource_id=resource_id, az_location=az_location)
) lead to the following HttpResponseError
Since the exception was not caught gracefully by OQ the result of the run was lost.
OQ should always exit gracefully any error that happens during the hybrid classical-quantum loop. This is fundamental to avoid loosing QPU data.
Before raising this feature request, I have made sure:
Issues to be resolved:
vqa_optimizer.py
since the functions in this module are not specific to QAOA.)training
is more meant for ML. optimization_vqa
is more accurate. optimization_loop
is also proposed as a module name.)Workflow
ABC. Workflow is a legacy name.)WorkflowProperties
in src/openqaoa-core/algorithms/baseworkflow.py, is labelled as parameters
in the asdict method of the workflow objects. A proposal was made to change the entry that contains information from this class from ['data']['input_parameters']
to ['data']['input_properties']
.To discuss on what is a better naming scheme for the following files.
Issue raised to resolve conversations in ongoing PR #170 that needs to be merged
However, after installing the error persists.
Current fix is installing openqaoa-core only.
The optimize
function in training_vqa
(see
openqaoa/openqaoa/optimizers/training_vqa.py
Line 607 in e024f4c
minimize()
function crashes.
To reproduce the error,
params
to None
in
import networkx as nx
from openqaoa.problems.problem import MaximumCut
from openqaoa.workflows.optimizer import QAOA
g = nx.generators.fast_gnp_random_graph(n=6,p=0.6)
maxcut_prob = MaximumCut(g)
maxcut_qubo = maxcut_prob.get_qubo_problem()
q = QAOA()
q.compile(maxcut_qubo)
q.optimize()
optimize()
fails as
capi_return is NULL
Call-back cb_calcfc_in__cobyla__user__routines failed.
But the optimisation doesn't crash, and the result dictionary is still being created (see the finally
clause at the end of optimize)
We need to change the logic of optimize()
so to:
Before raising this feature request, I have made sure:
Proposal a method into the object QAOA to indicate the parameters necessaries for Mitiq and try to mitigate the error for the problem.
Add mitiq on OpenQAOA using ZNE mitigation error and implement in the QAOA class.
A clear and concise description of any alternative solutions or features you've considered.
Add any other context or screenshots about the feature request here.
Before raising this issue, I have already checked that I am:
Hello, when performing testing using the QAOA package, I find that the initial run of the program will seem to execute correctly. However, if subsequent runs are executed, the program will re-execute as if no variables had changed.
In a new folder, install the necessary dependencies, and then execute this code:
import numpy as np
import networkx as nx
from openqaoa.utilities import plot_graph
# Generating a graph of 100 nodes
n = 100 # Number of nodes in graph
G = nx.generators.fast_gnp_random_graph(n, p=0.4, seed=42)
plot_graph(G)
from openqaoa.problems import MaximumCut
maxcut_prob = MaximumCut(G)
maxcut_qubo = maxcut_prob.qubo
print(maxcut_qubo.hamiltonian.expression)
maxcut_qubo.asdict()
print('this is maxcut_qubo', maxcut_qubo.asdict())
plot_graph(G)
from openqaoa import QAOA, create_device
q = QAOA()
analytical_device = create_device(location='local', name='analytical_simulator')
q.set_device(analytical_device)
q.compile(maxcut_qubo)
q.optimize()
print('this is answer',q.result.most_probable_states)
You will get an error saying 'ValueError: Maximum allowed dimension exceeded'
Then make a slight modification to the code, setting n
to 6.
The code will run as if n
still equals to 100, and you will get the same error.
The code should run as id n
=6 on the second try.
Please note that I tested this on two separate PC laptops, in both virtual and non-virtual environments, and got the same error each time. Also, there is a follow-up question as to why the analytical machine cannot solve the initial max-cut problem at 100 nodes...?
Thank you,
Before raising this issue, I have already checked that I am:
The RQAOA Workflow is missing some form of error catching in the case where a QAOA run is incomplete/crashes midway.
Link to file
Line 385
If an error occurred during one of the QAOA runs and the error is caught, but the run is incomplete. The RQAOA should be terminated and whatever information that was obtained should be available in the final workflow object in the result
attribute.
The ability to easily use custom mixer's would be nice, currently I see only x and xy supported, but there is a work in exploring more options. The input format could either be a qiskit circuit (depending on internal conversions) or some string based representation, but I think there would be value in this.
Before raising this issue, I have already checked that I am:
Using workflows, if the QUBO problem to be compiled contains more qubits than the device chosen, running q.optimise()
will just pass, without returning an error message.
Steps to reproduce the behavior:
ibm_nairobi
with 6 qubits)q.optimise()
An error message should be thrown to inform the user that the problem and device are incompatible.
I don't think we need 4 different methods (apply_1q_rotation_gate, apply_2q_rotation_gate, apply_1q_fixed_gate, apply_1q_fixed_gate) I think they all do exactly the same.
I believe we could change all of this:
@staticmethod
def apply_1q_rotation_gate(
vectorized_gate: Callable,
qubit_1: int,
rotation_object: RotationAngle
):
vectorized_gate(
qubit_1,
rotation_object.rotation_angle
)
@staticmethod
def apply_2q_rotation_gate(
vectorized_gate: Callable,
qubit_1: int,
qubit_2: int,
rotation_object: RotationAngle
):
vectorized_gate(
qubit_1,
qubit_2,
rotation_object.rotation_angle
)
@staticmethod
def apply_1q_fixed_gate(
vectorized_gate: Callable,
qubit_1: int
):
vectorized_gate(
qubit_1
)
@staticmethod
def apply_2q_fixed_gate(
vectorized_gate: Callable,
qubit_1: int,
qubit_2: int
):
vectorized_gate(
qubit_1,
qubit_2
)
def apply_gate(self, gate: gates_core.Gate, *args):
selected_vector_gate = self.gate_selector(gate, args[-1])
# Remove argument from tuple
args=args[:-1]
if gate.n_qubits == 1:
if hasattr(gate, 'rotation_object'):
# *args must be of the following format -- (qubit_1,rotation_object)
self.apply_1q_rotation_gate(selected_vector_gate, *args)
else:
# *args must be of the following format -- (qubit_1)
self.apply_1q_fixed_gate(selected_vector_gate, *args)
elif gate.n_qubits == 2:
if hasattr(gate, 'rotation_object'):
# *args must be of the following format -- (qubit_1,qubit_2,rotation_object)
self.apply_2q_rotation_gate(selected_vector_gate, *args)
else:
# *args must be of the following format -- (qubit_1,qubit_2)
self.apply_2q_fixed_gate(selected_vector_gate, *args)
else:
raise ValueError("Error applying the requested gate. Please check in the input")
for something much more compact like:
def apply_gate(self, gate: gates_core.Gate, *args):
if not gate.n_qubits in [1, 2]:
raise ValueError("Error applying the requested gate. Please check in the input")
selected_vector_gate = self.gate_selector(gate, args[-1])
args_ = args[:-1]
for i in range(len(args_)):
if isinstance(args_[i], RotationAngle):
args_[i] = args_[i].rotation_angle
selected_vector_gate(*args_)
Originally posted by @raulconchello in #193 (comment)
src/openqaoa-core/tests/test_problems.py
into different files containing relevant tests for each problem class defined in OpenQAOAsrc/openqaoa-core/openqaoa_core/problems/
.Create a new folder in test_problems
and create scripts consisting of specific tests corresponding to that problem class.
For e.g. create test_maximumcut.py
and put all tests corresponding to maximum_cut.py in this file
NOTE: Please branch out of openqaoa/dev
and make the PR to openqaoa/dev
The method set_classical_optimizer
for the QAOA and RQAOA classes doesn't have the proper documentation. It should be the same as the documentation of the ClassicalOptimizer
class. The parameters optimization_progress
, cost_progress
, parameter_log
, and save_intermediate
are missing. Also, these names could be changed to be more descriptive.
Before raising this issue, I have already checked that I am:
Hello!
I am trying to use openqaoa to solve a maximum-cut -type question. Based on the tutorial here: (https://openqaoa.entropicalabs.com/problems/maximum-cut/#maxcut-in-openqaoa), this is the sample code given to solve a small Max Cut question:
import numpy as np
import networkx as nx
#from openqaoa.utilities import plot_graph
# Generating a graph of nodes
G = nx.generators.fast_gnp_random_graph(n=6, p=0.6, seed=42)
from openqaoa.utilities import plot_graph
plot_graph(G)
from openqaoa.problems.problem import MaximumCut
maxcut_prob = MaximumCut(G)
maxcut_qubo = maxcut_prob.qubo
maxcut_qubo.hamiltonian.expression
However, after installing all dependencies and running the code, I get the following error:
Steps to reproduce the behavior:
openqaoa
Metadata/ solution should be produced, not the error above.
When trying to generate a random problem (e.g. TSP.random_instance(n_cities=[10])
) I get the following error. I think it is because the check_kwargs function returns a tuple that is then directly fed into numpy (which doesn't like the tuple). However, I may be using the function wrong, if that is the case just let me know.
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Input In [9], in <cell line: 1>()
----> 1 i = TSP.random_instance(n_cities=[10])
File openqaoa-main\openqaoa\problems\problem.py:237, in TSP.random_instance(**kwargs)
234 n_cities = check_kwargs(['n_cities'], [None], **kwargs)
236 box_size = np.sqrt(n_cities)
--> 237 coordinates = box_size * np.random.rand(n_cities, 2)
238 return TSP(coordinates, n_cities)
File mtrand.pyx:1182, in numpy.random.mtrand.RandomState.rand()
File mtrand.pyx:425, in numpy.random.mtrand.RandomState.random_sample()
File _common.pyx:292, in numpy.random._common.double_fill()
TypeError: 'tuple' object cannot be interpreted as an integer
The documentation for the logger and results is empty (https://el-openqaoa.readthedocs.io/en/latest/logger_and_results.html). I'm not sure if it doesn't exist or isn't being generated properly, but it is valuable documentation to have available.
Should the comment in decomposition_standard2 for the Swap gate be : Decomposition of H gate ?
Before raising this issue, I have already checked that I am:
Running a QAOA computation on a QPU and attempting to dump the results fails because some QPUs return their measurement_outcome probabilities as a numpy.float
, which is not python serializable. This issue may also happen for statevector simulators, where the measurement_outcomes are wavefunctions which are complex arrays.
Steps to reproduce the behavior:
dump
the QAOA results in a JSON fileOpenQAOA should convert all non-serializable outputs to native python types, so that QPU results including measurement outcomes can be dump
ed into a JSON
Before raising this issue, I have already checked that I am:
Upon creating an instance of the NumberPartition problem with a 0
entry in the list, the problem is created with redundant qubit and terms. These terms then manifest as extra cost gates
with angle=0
.
Steps to reproduce the behavior:
from openqaoa.problems import NumberPartition
np = NumberPartition([0,2,3,5,8])
np_qubo = np.qubo()
np_qubo.hamiltonian.expression
The problem class should catch 0
in the list and raise a warning while removing the zero from the list, and create a problem with the remaining qubits.
If applicable, add screenshots to help explain your problem.
Add any other context about the problem here.
Before raising this issue, I have already checked that I am:
The IBMQ import in qiskit is going to be deprecated.
Need to change the way the module is imported. Need to check if setup needs to be changed to accomandate possible module that might not be installed with the package.
Before raising this feature request, I made sure:
The class Hamiltonian
in OpenQAOA defined in src/openqaoa-src/openqaoa/qaoa_components/ansatz_constructor/operators.py
is responsible for constructing the Cost
and Mixer
Hamiltonians in QAOA. It fundamentally describes the Hamiltonian object via list of PauliOp
s defined on a set of qubits and a corresponding list of their coefficients. Implicitly, the definition of the Hamiltonian is then assumed as follows: PauliOp
s respectively.
Implement a method in this class that returns the matrix representation of the Hamiltonian
object. This will be a
class Hamiltonian:
def as_matrix(self):
"Implements a numpy array (sparse where relevant) representation
of the Hamiltonian object."
#TODO
return mat
Currently, get_counts
in basebackend.py
assumes that the samples should be converted from binary to integers. However, the vectorised backend is already returning the samples in binary.
unique_nums, frequency = np.unique(samples, return_counts=True)
unique_shots = [np.binary_repr(num, self.n_qubits)[
::-1] for num in unique_nums]
However, it seems that unique_nums
is currently already a list of binary
values.
I get a TypeError: 'numpy.str_' object cannot be interpreted as an integer
To reproduce the error run
from openqaoa.qaoa_parameters import create_qaoa_variational_params, QAOACircuitParams, PauliOp, Hamiltonian
from openqaoa.utilities import X_mixer_hamiltonian
from openqaoa.backends.qaoa_backend import get_qaoa_backend
terms = [(1,2),(2,3),(0,3),(4,0),(1,),(3,)]
coeffs = [1,2,3,4,3,5]
cost_hamil = Hamiltonian.classical_hamiltonian(terms,coeffs,0)
mixer_hamil = X_mixer_hamiltonian(n_qubits=5)
qaoa_circuit_params = QAOACircuitParams(cost_hamil,mixer_hamil,p=1)
params1 = create_qaoa_variational_params(qaoa_circuit_params,'fourier','rand',q=1)
backend_obj_vect = get_qaoa_backend(qaoa_circuit_params, 'vectorized')
Note that currently lines 607 and 608 have already been commented out.
See:
openqaoa/openqaoa/basebackend.py
Line 607 in f42c8a2
Full traceback :
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Input In [8], in <cell line: 1>()
----> 1 backend_obj_vect.get_counts(params1, n_shots=100)
File ~/openqaoa/openqaoa-temporary/openqaoa/basebackend.py:608, in QAOABaseBackendStatevector.get_counts(self, params, n_shots)
606 unique_nums, frequency = np.unique(samples, return_counts=True)
607 print(unique_nums, frequency )
--> 608 unique_shots = [np.binary_repr(num, self.n_qubits)[
609 ::-1] for num in unique_nums]
610 counts = dict(zip(unique_nums, frequency))
612 return counts
File ~/openqaoa/openqaoa-temporary/openqaoa/basebackend.py:608, in <listcomp>(.0)
606 unique_nums, frequency = np.unique(samples, return_counts=True)
607 print(unique_nums, frequency )
--> 608 unique_shots = [np.binary_repr(num, self.n_qubits)[
609 ::-1] for num in unique_nums]
610 counts = dict(zip(unique_nums, frequency))
612 return counts
File ~/.conda/envs/openqaoa/lib/python3.8/site-packages/numpy/core/numeric.py:2021, in binary_repr(num, width)
2014 warnings.warn(
2015 "Insufficient bit width provided. This behavior "
2016 "will raise an error in the future.", DeprecationWarning,
2017 stacklevel=3)
2019 # Ensure that num is a Python integer to avoid overflow or unwanted
2020 # casts to floating point.
-> 2021 num = operator.index(num)
2023 if num == 0:
2024 return '0' * (width or 1)
TypeError: 'numpy.str_' object cannot be interpreted as an integer
Before raising this issue, I have already checked that I am:
The name of the QPU used for the unittest is hardcoded. To change to automated device name selection.
(https://github.com/entropicalabs/openqaoa/blob/main/tests/test_qpu_qiskit.py#L504)
In the scenario where ibmq_perth
gets decommissioned, the code will not work. Also this code might not work if the device is not accepting jobs. (Although technically the Device Object should already reject this device if it isn't Online
, even before the Job is sent.)
I've been exploring the openqaoa
package for solving vehicle routing problems (VRP) and encountered an issue when trying to use the from_distance_matrix
method with the VRP
class. I have run the code using colab.
Clone the repository and checkout the dev
branch:
!git clone https://github.com/entropicalabs/openqaoa
cd openqaoa
!git checkout dev
!pip install .
Run the following Python code:
from openqaoa.problems import VRP
distance_matrix = [ [0, 2, 5, 10, 9, 9], [2, 0, 17, 6, 8, 14], [5, 17, 0, 10, 4, 7], [10, 6, 10, 0, 7, 11], [9, 8, 4, 7, 0, 16], [9, 14, 7, 11, 16, 0]]
vrp = VRP.from_distance_matrix(matrix=distance_matrix, n_vehicles=2)
I expected to create a VRP
instance using the from_distance_matrix
method.
I encountered the following error:
AttributeError: type object 'VRP' has no attribute 'from_distance_matrix'
I noticed a couple of warnings regarding missing modules (azure and qiskit), but I'm not sure if they are related to this issue.
Any assistance or guidance would be greatly appreciated. Thanks!
Is there a built in way to get the actual/exact/true solution to a given problem? Obviously it doesn't scale, but I would like to evaluate how well the QAOA is performing.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.