qiskit-community / qiskit-nature

Qiskit Nature is an open-source, quantum computing, framework for solving quantum mechanical natural science problems.
https://qiskit-community.github.io/qiskit-nature/
Apache License 2.0
306 stars 207 forks source link

Question on UCCSD with VQEClient/VQEProgram runtime #449

Closed Contextualist closed 2 years ago

Contextualist commented 2 years ago

Environment

What is happening?

I tried to set up UCCSD ansatz to for VQEProgram, but the ansatz failed to be transpiled in the remote. In particular, I am seeing the following exception being returned:

qiskit.exceptions.QiskitError: "Cannot unroll the circuit to the given basis, [...]. 
Instruction circuit-36_dg not found in equivalence library and no rule found to expand."
Full traceback from the remote runtime ``` Unable to retrieve job result. Job c6kq1hmgkavn0ge2re20 has failed: 2021-12-03T04:45:09.200181663Z /usr/local/lib/python3.8/site-packages/sympy/core/expr.py:2451: SymPyDeprecationWarning: 2021-12-03T04:45:09.200348792Z 2021-12-03T04:45:09.200524237Z expr_free_symbols method has been deprecated since SymPy 1.9. See 2021-12-03T04:45:09.200682015Z https://github.com/sympy/sympy/issues/21494 for more info. 2021-12-03T04:45:09.200831012Z 2021-12-03T04:45:09.200966077Z SymPyDeprecationWarning(feature="expr_free_symbols method", 2021-12-03T04:45:09.594976991Z concurrent.futures.process._RemoteTraceback: 2021-12-03T04:45:09.595027186Z """ 2021-12-03T04:45:09.595041516Z Traceback (most recent call last): 2021-12-03T04:45:09.595041516Z File "/usr/local/lib/python3.8/concurrent/futures/process.py", line 239, in _process_worker 2021-12-03T04:45:09.595041516Z r = call_item.fn(*call_item.args, **call_item.kwargs) 2021-12-03T04:45:09.595041516Z File "/usr/local/lib/python3.8/concurrent/futures/process.py", line 198, in _process_chunk 2021-12-03T04:45:09.595041516Z return [fn(*args) for args in chunk] 2021-12-03T04:45:09.595041516Z File "/usr/local/lib/python3.8/concurrent/futures/process.py", line 198, in 2021-12-03T04:45:09.595041516Z return [fn(*args) for args in chunk] 2021-12-03T04:45:09.595041516Z File "/usr/local/lib/python3.8/site-packages/qiskit/tools/parallel.py", line 93, in _task_wrapper 2021-12-03T04:45:09.595041516Z return task(value, *task_args, **task_kwargs) 2021-12-03T04:45:09.595041516Z File "/usr/local/lib/python3.8/site-packages/qiskit/compiler/transpiler.py", line 380, in _transpile_circuit 2021-12-03T04:45:09.595041516Z result = pass_manager.run( 2021-12-03T04:45:09.595041516Z File "/usr/local/lib/python3.8/site-packages/qiskit/transpiler/passmanager.py", line 216, in run 2021-12-03T04:45:09.595041516Z return self._run_single_circuit(circuits, output_name, callback) 2021-12-03T04:45:09.595041516Z File "/usr/local/lib/python3.8/site-packages/qiskit/transpiler/passmanager.py", line 272, in _run_single_circuit 2021-12-03T04:45:09.595041516Z result = running_passmanager.run(circuit, output_name=output_name, callback=callback) 2021-12-03T04:45:09.595041516Z File "/usr/local/lib/python3.8/site-packages/qiskit/transpiler/runningpassmanager.py", line 123, in run 2021-12-03T04:45:09.595045032Z dag = self._do_pass(pass_, dag, passset.options) 2021-12-03T04:45:09.595052061Z File "/usr/local/lib/python3.8/site-packages/qiskit/transpiler/runningpassmanager.py", line 154, in _do_pass 2021-12-03T04:45:09.595058972Z dag = self._run_this_pass(pass_, dag) 2021-12-03T04:45:09.595065567Z File "/usr/local/lib/python3.8/site-packages/qiskit/transpiler/runningpassmanager.py", line 166, in _run_this_pass 2021-12-03T04:45:09.595072169Z new_dag = pass_.run(dag) 2021-12-03T04:45:09.595078798Z File "/usr/local/lib/python3.8/site-packages/qiskit/transpiler/passes/basis/unroll_custom_definitions.py", line 86, in run 2021-12-03T04:45:09.595086892Z raise QiskitError( 2021-12-03T04:45:09.595094816Z qiskit.exceptions.QiskitError: "Cannot unroll the circuit to the given basis, ['ccx', 'cp', 'cswap', 'csx', 'cu', 'cu1', 'cu2', 'cu3', 'cx', 'cy', 'cz', 'delay', 'diagonal', 'h', 'id', 'initialize', 'mcp', 'mcphase', 'mcr', 'mcrx', 'mcry', 'mcrz', 'mcswap', 'mcsx', 'mcu', 'mcu1', 'mcu2', 'mcu3', 'mcx', 'mcx_gray', 'mcy', 'mcz', 'multiplexer', 'p', 'pauli', 'r', 'rx', 'rxx', 'ry', 'ryy', 'rz', 'rzx', 'rzz', 's', 'sdg', 'swap', 'sx', 'sxdg', 't', 'tdg', 'u', 'u1', 'u2', 'u3', 'unitary', 'x', 'y', 'z', 'kraus', 'roerror', 'save_amplitudes', 'save_amplitudes_sq', 'save_density_matrix', 'save_expval', 'save_expval_var', 'save_probabilities', 'save_probabilities_dict', 'save_stabilizer', 'save_state', 'save_statevector', 'save_statevector_dict', 'set_density_matrix', 'set_stabilizer', 'set_statevector', 'snapshot']. Instruction circuit-36_dg not found in equivalence library and no rule found to expand." 2021-12-03T04:45:09.595118810Z """ 2021-12-03T04:45:09.595125597Z 2021-12-03T04:45:09.595148382Z The above exception was the direct cause of the following exception: 2021-12-03T04:45:09.595159003Z 2021-12-03T04:45:09.595170745Z Traceback (most recent call last): 2021-12-03T04:45:09.595182298Z File "/code/program_starter.py", line 78, in 2021-12-03T04:45:09.595192361Z final_result = main(backend, messenger, **user_params) 2021-12-03T04:45:09.595203801Z File "/code/program.py", line 1072, in main 2021-12-03T04:45:09.595374269Z result, history = vqe.compute_minimum_eigenvalue(operator, aux_operators) 2021-12-03T04:45:09.595385749Z File "/code/program.py", line 904, in compute_minimum_eigenvalue 2021-12-03T04:45:09.595395474Z opt_params, opt_value, nfev = optimizer.optimize( 2021-12-03T04:45:09.595401207Z File "/code/program.py", line 646, in optimize 2021-12-03T04:45:09.595407494Z return self._minimize(objective_function, initial_point) 2021-12-03T04:45:09.595413165Z File "/code/program.py", line 525, in _minimize 2021-12-03T04:45:09.595417922Z get_learning_rate, get_perturbation = self.calibrate(loss_callable, initial_point) 2021-12-03T04:45:09.595424860Z File "/code/program.py", line 325, in calibrate 2021-12-03T04:45:09.595434722Z delta = loss(initial_point + c * pert) - \ 2021-12-03T04:45:09.595436303Z File "/code/program.py", line 511, in loss_callable 2021-12-03T04:45:09.595451383Z return self._sampler.convert(loss, params=value_dict).eval().real 2021-12-03T04:45:09.595461759Z File "/usr/local/lib/python3.8/site-packages/qiskit/opflow/converters/circuit_sampler.py", line 218, in convert 2021-12-03T04:45:09.595474656Z sampled_statefn_dicts = self.sample_circuits(circuit_sfns=circs, param_bindings=p_b) 2021-12-03T04:45:09.595516125Z File "/usr/local/lib/python3.8/site-packages/qiskit/opflow/converters/circuit_sampler.py", line 329, in sample_circuits 2021-12-03T04:45:09.595528665Z results = self.quantum_instance.execute( 2021-12-03T04:45:09.595541801Z File "/usr/local/lib/python3.8/site-packages/qiskit/utils/quantum_instance.py", line 398, in execute 2021-12-03T04:45:09.595546844Z circuits = self.transpile(circuits) 2021-12-03T04:45:09.595546844Z File "/usr/local/lib/python3.8/site-packages/qiskit/utils/quantum_instance.py", line 345, in transpile 2021-12-03T04:45:09.595605722Z transpiled_circuits = compiler.transpile( 2021-12-03T04:45:09.595622338Z File "/usr/local/lib/python3.8/site-packages/qiskit/compiler/transpiler.py", line 293, in transpile 2021-12-03T04:45:09.595640749Z circuits = parallel_map(_transpile_circuit, list(zip(circuits, transpile_args))) 2021-12-03T04:45:09.595654453Z File "/usr/local/lib/python3.8/site-packages/qiskit/tools/parallel.py", line 164, in parallel_map 2021-12-03T04:45:09.595654453Z raise error 2021-12-03T04:45:09.595696117Z File "/usr/local/lib/python3.8/site-packages/qiskit/tools/parallel.py", line 154, in parallel_map 2021-12-03T04:45:09.595709633Z results = list(future) 2021-12-03T04:45:09.595715634Z File "/usr/local/lib/python3.8/concurrent/futures/process.py", line 484, in _chain_from_iterable_of_lists 2021-12-03T04:45:09.595724927Z for element in iterable: 2021-12-03T04:45:09.595732138Z File "/usr/local/lib/python3.8/concurrent/futures/_base.py", line 619, in result_iterator 2021-12-03T04:45:09.595740561Z yield fs.pop().result() 2021-12-03T04:45:09.595740561Z File "/usr/local/lib/python3.8/concurrent/futures/_base.py", line 437, in result 2021-12-03T04:45:09.595740561Z return self.__get_result() 2021-12-03T04:45:09.595740561Z File "/usr/local/lib/python3.8/concurrent/futures/_base.py", line 389, in __get_result 2021-12-03T04:45:09.595740561Z raise self._exception 2021-12-03T04:45:09.595740561Z qiskit.exceptions.QiskitError: "Cannot unroll the circuit to the given basis, ['ccx', 'cp', 'cswap', 'csx', 'cu', 'cu1', 'cu2', 'cu3', 'cx', 'cy', 'cz', 'delay', 'diagonal', 'h', 'id', 'initialize', 'mcp', 'mcphase', 'mcr', 'mcrx', 'mcry', 'mcrz', 'mcswap', 'mcsx', 'mcu', 'mcu1', 'mcu2', 'mcu3', 'mcx', 'mcx_gray', 'mcy', 'mcz', 'multiplexer', 'p', 'pauli', 'r', 'rx', 'rxx', 'ry', 'ryy', 'rz', 'rzx', 'rzz', 's', 'sdg', 'swap', 'sx', 'sxdg', 't', 'tdg', 'u', 'u1', 'u2', 'u3', 'unitary', 'x', 'y', 'z', 'kraus', 'roerror', 'save_amplitudes', 'save_amplitudes_sq', 'save_density_matrix', 'save_expval', 'save_expval_var', 'save_probabilities', 'save_probabilities_dict', 'save_stabilizer', 'save_state', 'save_statevector', 'save_statevector_dict', 'set_density_matrix', 'set_stabilizer', 'set_statevector', 'snapshot']. Instruction circuit-36_dg not found in equivalence library and no rule found to expand." ```

How can we reproduce the issue?

Here's my main setup (click to expand) ```python from qiskit_nature.drivers import Molecule from qiskit_nature.drivers.second_quantization import PSI4Driver molecule = Molecule(geometry= [['H', [0., 0., 0.]], ['H', [0., 0., 0.735]]], charge=0, multiplicity=1) basis = "sto-3g" driver = PSI4Driver.from_molecule(molecule=molecule, basis=basis) from qiskit.utils import QuantumInstance from qiskit import IBMQ IBMQ.load_account() provider = IBMQ.get_provider(group='open') backend = provider.get_backend("ibmq_qasm_simulator") qins = QuantumInstance( backend=backend, shots=1024, optimization_level=2, ) # VQEClientUCCFactory is adapted from VQEUCCFactory; see below solver = VQEClientUCCFactory( quantum_instance=qins, provider=provider, optimizer=dict( name="QN-SPSA", maxiter=100, resamplings={1: 100}, ), measurement_error_mitigation=True, ) def solve(driver, solver): from qiskit_nature.problems.second_quantization.electronic import ElectronicStructureProblem problem = ElectronicStructureProblem(driver) from qiskit_nature.mappers.second_quantization import ParityMapper from qiskit_nature.converters.second_quantization import QubitConverter mapper = ParityMapper() converter = QubitConverter(mapper=mapper, two_qubit_reduction=True) from qiskit_nature.algorithms import GroundStateEigensolver calc = GroundStateEigensolver(converter, solver) r = calc.solve(problem) return r.total_energies[0], if __name__ == "__main__": print(solve(driver, solver)) ```

The VQEClientUCCFactory mentioned in the code above is a copy of VQEUCCFactory with method get_solver modified

https://github.com/Qiskit/qiskit-nature/blob/8d2b0eb1606620ed45211653ed20ab78335a39bc/qiskit_nature/algorithms/ground_state_solvers/minimum_eigensolver_factories/vqe_ucc_factory.py#L187-L233

the VQE constructor part of VQEUCCFactory.get_solver is changed to:

        vqe = VQEProgram(
            ansatz=ansatz,
            optimizer=self.optimizer,
            initial_point=self.initial_point,
            backend=self.quantum_instance.backend,
            #gradient=self.gradient,
            #expectation=self.expectation,
            #include_custom=self.include_custom,
            callback=self.callback,
            shots=self.quantum_instance._run_config.shots,
            **self._kwargs, # provider, measurement_error_mitigation
        )

        return vqe

What should happen?

It should run and return the final total energy.

Any suggestions?

Not sure why there is a gate named circuit-36_dg found during the transpilation (see the exception above).

mrossinek commented 2 years ago

Hi @Contextualist! I have also seen this error before, thanks for raising it! You can get it to work be calling .decompose() on your final ansatz before returning from your custom VQECientUCCFactory.

I will leave this issue open as this is likely something we should fix internally but the above workaround should make things work for you in the meantime. Let me know if this still does not help :+1:

Contextualist commented 2 years ago

Thanks for your prompt response, @mrossinek ! I tried to do the following edit for the VQEUCCFactory.get_solver:

+       ansatz = ansatz.decompose()
        vqe = VQEProgram(
            ansatz=ansatz,
            optimizer=self.optimizer,

However, I am still seeing the same error. Here is what the decomposed circuit looks like:

          ┌───┐           ┌─────┐         ┌───┐    ┌──────────────┐┌───┐      ┌───┐      ┌───────────────┐┌───────────────┐  ┌────────────┐ ┌─────┐┌───┐┌───┐┌──────────────┐┌───┐┌───┐    ┌───┐     »
q_0: ─────┤ X ├───────────┤ Sdg ├─────────┤ H ├────┤ Rz(2.0*t[0]) ├┤ H ├──────┤ S ├──────┤ circuit-36_dg ├┤ circuit-45_dg ├──┤ circuit-36 ├─┤ Sdg ├┤ H ├┤ X ├┤ Rz(1.0*t[2]) ├┤ X ├┤ H ├────┤ S ├─────»
     ┌────┴───┴─────┐┌────┴─────┴────┐┌───┴───┴───┐└───┬─────┬────┘├───┤┌─────┴───┴─────┐└─────┬───┬─────┘└─────┬───┬─────┘┌─┴────────────┴┐└┬───┬┘└───┘└─┬─┘└──────────────┘└─┬─┘├───┤┌───┴───┴────┐»
q_1: ┤ circuit-9_dg ├┤ circuit-18_dg ├┤ circuit-9 ├────┤ Sdg ├─────┤ H ├┤ Rz(-2.0*t[1]) ├──────┤ H ├────────────┤ S ├──────┤ circuit-89_dg ├─┤ H ├────────■────────────────────■──┤ H ├┤ circuit-89 ├»
     └──────────────┘└───────────────┘└───────────┘    └─────┘     └───┘└───────────────┘      └───┘            └───┘      └───────────────┘ └───┘                                └───┘└────────────┘»
«     ┌───────────────┐┌───┐┌───┐┌───────────────┐┌───┐┌───┐┌────────────┐
«q_0: ┤ circuit-63_dg ├┤ H ├┤ X ├┤ Rz(-1.0*t[2]) ├┤ X ├┤ H ├┤ circuit-63 ├
«     └────┬─────┬────┘├───┤└─┬─┘└───────────────┘└─┬─┘├───┤└───┬───┬────┘
«q_1: ─────┤ Sdg ├─────┤ H ├──■─────────────────────■──┤ H ├────┤ S ├─────
«          └─────┘     └───┘                           └───┘    └───┘  
mrossinek commented 2 years ago

Right, sorry about that! What you actually need to do is to transpile the circuit with a subset of supported basis gates. I did something similar in a workshop whose notebook I posted as a Gist, here (cell 26). Basically you can try the following:

from qiskit import transpile

basis_gates = ["rx", "ry", "rz", "sx", "cx"]
transpiled_ansatz = transpile(ansatz, basis_gates=basis_gates, optimization_level=0)
Contextualist commented 2 years ago

I just tried it out. I can confirm that the basis gate transpilation workaround works. Thanks!

Cryoris commented 2 years ago

The source of it was Qiskit/qiskit-terra#7429, which still persists, but since Qiskit 0.33 the UCCSD ansatz uses the new PauliEvolutionGate which doesn't construct a circuit with empty gates anymore. So in brief, this bug shouldn't exist anymore.

I tried it myself but, @Contextualist, would you mind trying with the latest Qiskit versions as well?

Contextualist commented 2 years ago

Thank you, @Cryoris ! I just tested with the following settings:

and the bug cannot be reproduced with the original setup