Qiskit / qiskit-ibm-runtime

IBM Client for Qiskit Runtime
https://docs.quantum.ibm.com/api/qiskit-ibm-runtime
Apache License 2.0
148 stars 155 forks source link

Transpile using `ibmq_qasm_simulator` works with qiskit-ibmq-provider but not qiskit-ibm-runtime #254

Closed HuangJunye closed 2 years ago

HuangJunye commented 2 years ago

Describe the bug

Transpile using ibmq_qasm_simulator works with qiskit-ibmq-provider but not qiskit-ibm-runtime

Steps to reproduce

from qiskit import IBMQ
from qiskit import transpile

provider = IBMQ.load_account()
iqx_sim = provider.get_backend('ibmq_qasm_simulator')
grovers_circuits_transpiled = transpile(grover_circuits, iqx_sim)

works as expected, but the following produces erorr

from qiskit_ibm_runtime import IBMRuntimeService
from qiskit import transpile

service = IBMRuntimeService()
cloud_sim = service.backend('ibmq_qasm_simulator')
grovers_circuits_transpiled = transpile(grover_circuits, cloud_sim)
---------------------------------------------------------------------------
HTTPError                                 Traceback (most recent call last)
File /usr/local/anaconda3/envs/primitives/lib/python3.9/site-packages/qiskit_ibm_runtime/api/session.py:265, in RetrySession.request(self, method, url, bare, **kwargs)
    264     response = super().request(method, final_url, headers=headers, **kwargs)
--> 265     response.raise_for_status()
    266 except RequestException as ex:
    267     # Wrap the requests exceptions into a IBM Q custom one, for
    268     # compatibility.

File /usr/local/anaconda3/envs/primitives/lib/python3.9/site-packages/requests/models.py:960, in Response.raise_for_status(self)
    959 if http_error_msg:
--> 960     raise HTTPError(http_error_msg, response=self)

HTTPError: 404 Client Error: Not Found for url: https://us-east.quantum-computing.cloud.ibm.com/devices/ibmq_qasm_simulator/defaults

The above exception was the direct cause of the following exception:

RequestsApiError                          Traceback (most recent call last)
Input In [7], in <cell line: 4>()
      3 grovers_circuits_transpiled = []
      4 for qc in grover_circuits:
----> 5     t_qc = transpile(grover_circuits, backend)
      6     grovers_circuits_transpiled.append(t_qc)

File /usr/local/anaconda3/envs/primitives/lib/python3.9/site-packages/qiskit/compiler/transpiler.py:307, in transpile(circuits, backend, basis_gates, inst_map, coupling_map, backend_properties, initial_layout, layout_method, routing_method, translation_method, scheduling_method, instruction_durations, dt, approximation_degree, timing_constraints, seed_transpiler, optimization_level, pass_manager, callback, output_name, unitary_synthesis_method, unitary_synthesis_plugin_config, target)
    300     warnings.warn(
    301         "When scheduling circuits without backend,"
    302         " 'instruction_durations' should be usually provided.",
    303         UserWarning,
    304     )
    306 # Get transpile_args to configure the circuit transpilation job(s)
--> 307 transpile_args = _parse_transpile_args(
    308     circuits,
    309     backend,
    310     basis_gates,
    311     inst_map,
    312     coupling_map,
    313     backend_properties,
    314     initial_layout,
    315     layout_method,
    316     routing_method,
    317     translation_method,
    318     scheduling_method,
    319     instruction_durations,
    320     dt,
    321     approximation_degree,
    322     seed_transpiler,
    323     optimization_level,
    324     callback,
    325     output_name,
    326     timing_constraints,
    327     unitary_synthesis_method,
    328     unitary_synthesis_plugin_config,
    329     target,
    330 )
    332 _check_circuits_coupling_map(circuits, transpile_args, backend)
    334 # Transpile circuits in parallel

File /usr/local/anaconda3/envs/primitives/lib/python3.9/site-packages/qiskit/compiler/transpiler.py:562, in _parse_transpile_args(circuits, backend, basis_gates, inst_map, coupling_map, backend_properties, initial_layout, layout_method, routing_method, translation_method, scheduling_method, instruction_durations, dt, approximation_degree, seed_transpiler, optimization_level, callback, output_name, timing_constraints, unitary_synthesis_method, unitary_synthesis_plugin_config, target)
    559         backend_properties = _target_to_backend_properties(target)
    561 basis_gates = _parse_basis_gates(basis_gates, backend, circuits)
--> 562 inst_map = _parse_inst_map(inst_map, backend, num_circuits)
    563 faulty_qubits_map = _parse_faulty_qubits_map(backend, num_circuits)
    564 coupling_map = _parse_coupling_map(coupling_map, backend, num_circuits)

File /usr/local/anaconda3/envs/primitives/lib/python3.9/site-packages/qiskit/compiler/transpiler.py:710, in _parse_inst_map(inst_map, backend, num_circuits)
    708 if inst_map is None:
    709     if hasattr(backend, "defaults"):
--> 710         inst_map = getattr(backend.defaults(), "instruction_schedule_map", None)
    712 # inst_maps could be None, or single entry
    713 if inst_map is None or isinstance(inst_map, InstructionScheduleMap):

File /usr/local/anaconda3/envs/primitives/lib/python3.9/site-packages/qiskit_ibm_runtime/ibm_backend.py:418, in IBMBackend.defaults(self, refresh)
    404 """Return the pulse defaults for the backend.
    405 
    406 The schema for default pulse configuration can be found in
   (...)
    415     The backend pulse defaults or ``None`` if the backend does not support pulse.
    416 """
    417 if refresh or self._defaults is None:
--> 418     api_defaults = self._api_client.backend_pulse_defaults(self.name)
    419     if api_defaults:
    420         self._defaults = defaults_from_server_data(api_defaults)

File /usr/local/anaconda3/envs/primitives/lib/python3.9/site-packages/qiskit_ibm_runtime/api/clients/runtime.py:349, in RuntimeClient.backend_pulse_defaults(self, backend_name)
    340 def backend_pulse_defaults(self, backend_name: str) -> Dict:
    341     """Return the pulse defaults of the IBM Cloud backend.
    342 
    343     Args:
   (...)
    347         Backend pulse defaults.
    348     """
--> 349     return self._api.backend(backend_name).pulse_defaults()

File /usr/local/anaconda3/envs/primitives/lib/python3.9/site-packages/qiskit_ibm_runtime/api/rest/cloud_backend.py:73, in CloudBackend.pulse_defaults(self)
     67 """Return backend pulse defaults.
     68 
     69 Returns:
     70     JSON response of pulse defaults.
     71 """
     72 url = self.get_url("pulse_defaults")
---> 73 return self.session.get(url).json()

File /usr/local/anaconda3/envs/primitives/lib/python3.9/site-packages/requests/sessions.py:542, in Session.get(self, url, **kwargs)
    534 r"""Sends a GET request. Returns :class:`Response` object.
    535 
    536 :param url: URL for the new :class:`Request` object.
    537 :param \*\*kwargs: Optional arguments that ``request`` takes.
    538 :rtype: requests.Response
    539 """
    541 kwargs.setdefault('allow_redirects', True)
--> 542 return self.request('GET', url, **kwargs)

File /usr/local/anaconda3/envs/primitives/lib/python3.9/site-packages/qiskit_ibm_runtime/api/session.py:286, in RetrySession.request(self, method, url, bare, **kwargs)
    282         except Exception:  # pylint: disable=broad-except
    283             # the response did not contain the expected json.
    284             message += f". {ex.response.text}"
--> 286     raise RequestsApiError(message, status_code) from ex
    288 return response

RequestsApiError: '404 Client Error: Not Found for url: https://us-east.quantum-computing.cloud.ibm.com/devices/ibmq_qasm_simulator/defaults. {"errors":[{"code":"not_found","message":"device not found","more_info":"https://cloud.ibm.com/apidocs/quantum-computing#error-handling"}],"trace":"c92o333ahk6r9e4jr82g"}'

Expected behavior transpile should work with ibmq_qasm_simulator backend from qiskit-ibm-runtime provider

Suggested solutions

Additional Information

HuangJunye commented 2 years ago

transpile with real systems have no issues.

from qiskit_ibm_runtime import IBMRuntimeService
from qiskit import transpile

service = IBMRuntimeService(instance='Qiskit Runtime-Real System') # change to standard plan
backend = service.backend('ibm_algiers')
grovers_circuits_transpiled = transpile(grover_circuits, backend)
jyu00 commented 2 years ago

ibmq_qasm_simulator doesn't have pulse defaults. The backend_pulse_defaults() should catch the 404 and return None instead.

Looks like the old IQX was nicer and just return an empty dictionary instead of raising 404.

rathishcholarajan commented 2 years ago

@HuangJunye I see this below error in your logs, which says that "ibmq_qasm_simulator" itself is not available.

{"errors":[{"code":"not_found","message":"device not found","more_info":"https://cloud.ibm.com/apidocs/quantum-computing#error-handling"}]

I think it is connecting to the standard plan which has access to only real devices. Try connecting with a lite plan and make sure you are using service.backends() and you see ibmq_qasm_simulator exists.

@jyu00 When the simulator exists in the plan the properties API does return 200 with empty response for simulators as expected.

HuangJunye commented 2 years ago

@rathishcholarajan I see that was the reason. I can verify that the lite plan works as expected. But I think the error message should be more explicit. If the backend is not available for a certain account, shouldn't it raise a specific error for that? It's strange that the error occur not in this line:

iqx_sim = provider.get_backend('ibmq_qasm_simulator')

I don't have access to standard plan any more so I can't verify that.

rathishcholarajan commented 2 years ago

Yes I will make a note to throw an explicit error when working on this enhancement https://github.com/Qiskit/qiskit-ibm-runtime/issues/200