Qiskit / qiskit

Qiskit is an open-source SDK for working with quantum computers at the level of extended quantum circuits, operators, and primitives.
https://www.ibm.com/quantum/qiskit
Apache License 2.0
5.16k stars 2.35k forks source link

Transpiling `Delay` without a scheduling_method raises `TranspilerError` #8985

Open kdk opened 1 year ago

kdk commented 1 year ago

Environment

What is happening?

For any circuit including a Delay operation, transpiling that circuit for a backend with non-null TimingConstraints will raise a TranaspilerError that is not user something the user can take action on.

How can we reproduce the issue?

>>> qc = qk.QuantumCircuit(1)
>>> qc.x(0)
>>> qc.delay(0.123, 0, 'us')
>>> qc.x(0)
>>> qc.draw()
   ┌───┐┌──────────────────┐┌───┐
q: ┤ X ├┤ Delay(0.123[us]) ├┤ X ├
   └───┘└──────────────────┘└───┘
>>> provider.get_backend('ibmq_belem').configuration().timing_constraints
{'acquire_alignment': 16, 'granularity': 16, 'min_length': 64, 'pulse_alignment': 1}
>>> qk.transpile(qc, provider.get_backend('ibmq_belem'))
/Users/kdk/q/qiskit-terra/qiskit/circuit/duration.py:40: UserWarning: Duration is rounded to 554 [dt] = 1.231111e-07 [s] from 1.230000e-07 [s]
  UserWarning,
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/kdk/q/qiskit-terra/qiskit/compiler/transpiler.py", line 389, in transpile
    transpile_config["pass_manager_config"].backend_properties,
  File "/Users/kdk/q/qiskit-terra/qiskit/compiler/transpiler.py", line 475, in _serial_transpile_circuit
    result = pass_manager.run(circuit, callback=callback, output_name=output_name)
  File "/Users/kdk/q/qiskit-terra/qiskit/transpiler/passmanager.py", line 528, in run
    return super().run(circuits, output_name, callback)
  File "/Users/kdk/q/qiskit-terra/qiskit/transpiler/passmanager.py", line 228, in run
    return self._run_single_circuit(circuits, output_name, callback)
  File "/Users/kdk/q/qiskit-terra/qiskit/transpiler/passmanager.py", line 283, in _run_single_circuit
    result = running_passmanager.run(circuit, output_name=output_name, callback=callback)
  File "/Users/kdk/q/qiskit-terra/qiskit/transpiler/runningpassmanager.py", line 125, in run
    dag = self._do_pass(pass_, dag, passset.options)
  File "/Users/kdk/q/qiskit-terra/qiskit/transpiler/runningpassmanager.py", line 172, in _do_pass
    dag = self._run_this_pass(pass_, dag)
  File "/Users/kdk/q/qiskit-terra/qiskit/transpiler/runningpassmanager.py", line 226, in _run_this_pass
    pass_.run(FencedDAGCircuit(dag))
  File "/Users/kdk/q/qiskit-terra/qiskit/transpiler/passes/scheduling/alignments/reschedule.py", line 207, in run
    f"The input circuit {dag.name} is not scheduled. Call one of scheduling passes "
qiskit.transpiler.exceptions.TranspilerError: 'The input circuit None is not scheduled. Call one of scheduling passes before running the ConstrainedReschedule pass.'

What should happen?

It's not clear to me that the ConstrainedReschedule pass needs to be called in this case. In particular, it should be possible for users to use both Delay instructions and rely on backend scheduling (so not needing to specify a scheduling_method).

Converting the Delay operations to units of dt should be sufficient for it to be executable by a backend. The TimeUnitConversion pass currently handles this conversion, but does not appear to look at timing_constraints.

If ConstrainedReschedule is decided to be needed, the error message should guide users that they need to specify a scheduling_method in order to use Delays.

Any suggestions?

No response

mtreinish commented 1 year ago

I'm not sure I agree this is a bug, the issue here is the backend's requirements are clearly saying that there are timing constraints for running on this backend and if you're passing any delay instructions we need to verify that the scheduled circuit we're outputting is conforming with the timing constraints it expresses. In this case since there is no alignment constraint it's probably ok but short of running the full scheduling analysis how can we be sure of that? Like if you added a measure to you're circuit I'm pretty sure we'd have to schedule the circuit to ensure the measurement starts on a multiple of 16*dt. I just can't think of a way we can make sure of this for every case short of requiring scheduling analysis (and potentially padding) in the presence of any delay.

nkanazawa1989 commented 1 year ago

Good question. In the case of single qubit circuit indeed we have no choice of scheduling option, i.e. ASAP and ALAP yield the same scheduled circuit. In principle we can do naive scheduling for 1Q circuit, but I'm not sure adding extra logic for 1Q really improves the user experience. They may wonder why >1Q raises an error. Alternatively, we can always do ALAP with user warning to run reschedule, because I don't think people prefer ASAP scheduling. Usually ASAP circuit is sensitive to relaxation.

kdk commented 1 year ago

Thanks both, I think this raises some interesting questions.

In the case of single qubit circuit indeed we have no choice of scheduling option

This is true, the example above is probably oversimplified, but I think the same question could be asked of >=2Q circuits, should the presence of a delay always be sufficient to trigger rescheduling?

the issue here is the backend's requirements are clearly saying that there are timing constraints for running on this backend and if you're passing any delay instructions we need to verify that the scheduled circuit we're outputting is conforming with the timing constraints it expresses.

I believe this is true if we expect delay instruction to result in an idle period of exactly some duration within the circuit, but not if they are expected to generate an idle period of at least some duration within the circuit (e.g., if they are equivalent to an 0-amplitude pulse gate of the same duration, which may be pushed around as needed by the scheduler). I haven't seen anywhere where it's specified which of these two behaviors users should expect.

The two open questions I see at the moment are:

  1. Does a delay instruction in the circuit imply an idle period of exactly the duration of that delay, or of at least the duration of that delay? (My leaning is toward the latter, because the former introduces the possibility of the user building a circuit with unresolvable constraints.)
  2. When converting delay durations into units of dt, we currently round to the nearest multiple of dt. Should we also round to the nearest multiple of timing_constraints.{pulse,aquire}_alignment so that scheduling can be avoided in these cases?
taalexander commented 1 year ago

The issue is that Qiskit's scheduling and timing model is overly restricted compared to how actual hardware is implemented, to the point where no hardware implements the current scheduling models (therefore they cannot be used). The point is that scheduling cannot work in every case so requiring it to simply transpile a circuit and convert its units of time to the nearest dt is effectively a bug.

nkanazawa1989 commented 1 year ago

Current timing constraints and rescheduling strategy come from IBM devices. AWG there requires a chunk of 16 samples per clock (i.e. 1 clock is 16 dt), thus instruction and acquisition must placed at t0 which is multiple of this chunk size (old devices can place instructions at arbitrary t0 though). This means, given IBM device,

not if they are expected to generate an idle period of at least some duration within the circuit

This will never happen, i.e. even if we use pulse gate, that instruction duration must be multiple of the chunk size and it automatically satisfies other constraints. However this model is too much tied to our architecture, and we must define some generic model for constraints (this is why it's not written in Qiskit). In IBM device, instruction with timing violation yields error, and acquisition with violation yields broken output due to frame offset. So truncating the delay duration into the LCM of all constraint values always give you executable circuit. This is what we are doing in Qiskit Experiments.

Does a delay instruction in the circuit imply an idle period of exactly the duration of that delay, or of at least the duration of that delay? (My leaning is toward the latter, because the former introduces the possibility of the user building a circuit with unresolvable constraints.)

Depends on context. If you write circuit in target-agnostic way this is exact duration. Qiskit doesn't distinguish logical/virtual/physical circuits. IMO this is where these confusions come.

When converting delay durations into units of dt, we currently round to the nearest multiple of dt. Should we also round to the nearest multiple of timing_constraints.{pulse,aquire}_alignment so that scheduling can be avoided in these cases?

I think this is the reasonable solution. Invoking schedule/reschedule pass is kind of overkill. As @taalexander mentioned, scheduled circuit doesn't ALWAYS guarantee actual instruction time across measurement and conditional operation. In your example circuit above, we can expect consistency between frontend and backend.