Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

qiskit.execute() does not use the scheduling_method argument #7640

Closed
CharlieDerby opened this issue Feb 9, 2022 · 12 comments · Fixed by #11044
Closed

qiskit.execute() does not use the scheduling_method argument #7640

CharlieDerby opened this issue Feb 9, 2022 · 12 comments · Fixed by #11044
Labels
bug Something isn't working

Comments

@CharlieDerby
Copy link

Environment

  • Qiskit version: 0.34.1
  • Qiskit Terra version: 0.19.1
  • Python version: 3.8.2
  • Operating system: Ubuntu 20.04 (via Windows WSL)

What is happening?

I'm attempting to queue circuits to run on the devices that involve delays before the measurements. If I send a circuit with a delay then I may receive the error message:

TranspilerError: "This circuit None may involve a delay instruction violating the pulse controller alignment. To adjust instructions to right timing, you should call one of scheduling passes first. This is usually done by calling transpiler with scheduling_method='alap'."

If I try running qiskit.execute with the argument scheduling_method='alap' as suggested then I receive the same error. Furthermore if I try to pre-transpile the circuit with qiskit.transpile with the same scheduling method argument and try to execute the transpiled circuit I get the same error.

How can we reproduce the issue?

IN

from qiskit import QuantumCircuit, execute, IBMQ, transpile

backend = reservation_provider.backend.ibmq_casablanca

test_circ = QuantumCircuit(1)
test_circ.x(0)
test_circ.delay(20, unit="dt")
test_circ.measure_all()

test_circ.draw()

OUT

        ┌───┐┌───────────────┐ ░ ┌─┐
     q: ┤ X ├┤ Delay(20[dt]) ├─░─┤M├
        └───┘└───────────────┘ ░ └╥┘
meas: 1/══════════════════════════╩═
                                  0 

IN

test_job = execute(test_circ, backend=backend, shots=10000)

OUT

Above error

IN

test_job = execute(test_circ, backend=backend, shots=10000, scheduling_method='alap')

OUT

Above error

IN

# pre-transpile the circuit
test_circ_transpiled = transpile(test_circ,backend=backend, scheduling_method='alap')
test_circ_transpiled.draw()

OUT

                      ┌───┐        ┌───────────────┐ ░ ┌───────────────┐┌─┐
      q_0 -> 0 ───────┤ X ├────────┤ Delay(20[dt]) ├─░─┤ Delay(12[dt]) ├┤M├
               ┌──────┴───┴───────┐└───────────────┘ ░ └───────────────┘└╥┘
ancilla_0 -> 1 ┤ Delay(26704[dt]) ├──────────────────────────────────────╫─
               ├──────────────────┤                                      ║ 
ancilla_1 -> 2 ┤ Delay(26704[dt]) ├──────────────────────────────────────╫─
               ├──────────────────┤                                      ║ 
ancilla_2 -> 3 ┤ Delay(26704[dt]) ├──────────────────────────────────────╫─
               ├──────────────────┤                                      ║ 
ancilla_3 -> 4 ┤ Delay(26704[dt]) ├──────────────────────────────────────╫─
               ├──────────────────┤                                      ║ 
ancilla_4 -> 5 ┤ Delay(26704[dt]) ├──────────────────────────────────────╫─
               ├──────────────────┤                                      ║ 
ancilla_5 -> 6 ┤ Delay(26704[dt]) ├──────────────────────────────────────╫─
               └──────────────────┘                                      ║ 
       meas: 1/══════════════════════════════════════════════════════════╩═
                                                                         0 

IN

test_job = execute(test_circ_transpiled, backend=backend, shots=10000)

OUT

Above error

IN

test_job = execute(test_circ_transpiled, backend=backend, shots=10000, scheduling_method='alap')

OUT

Above error

What should happen?

I expect the execute functions to finish running in a few seconds and for the job to be queued up to run on the device.

Any suggestions?

I noticed in the traceback that when the execute function transpiles a circuit to run on the device it doesn't seem to use the scheduling_method argument, see lines 292-303 of qiskit/execute_function.py in my installation

    else:
        # transpiling the circuits using given transpile options
        experiments = transpile(
            experiments,
            basis_gates=basis_gates,
            coupling_map=coupling_map,
            backend_properties=backend_properties,
            initial_layout=initial_layout,
            seed_transpiler=seed_transpiler,
            optimization_level=optimization_level,
            backend=backend
        )

I tried making this edit to my local installation

    else:
        # transpiling the circuits using given transpile options
        experiments = transpile(
            experiments,
            basis_gates=basis_gates,
            coupling_map=coupling_map,
            backend_properties=backend_properties,
            initial_layout=initial_layout,
            seed_transpiler=seed_transpiler,
            optimization_level=optimization_level,
            backend=backend,
            scheduling_method=scheduling_method # <-----Added by me
        )

and the code in the MWE above ran without errors, with my jobs getting queued and running with the expected results.

I'm hesitant to make a pull request with this change in case this causes problems elsewhere but it definitely solves my problem.

@CharlieDerby CharlieDerby added the bug Something isn't working label Feb 9, 2022
@corbett5
Copy link

+1, I've also encountered this error.

@corbett5
Copy link

Actually the following works for me with Qiskit Terra version 0.19.2

test_circ_transpiled = transpile(test_circ,backend=backend, scheduling_method='alap')
backend.run(circuits, shots=NUM_SHOTS)

I tried a bunch of combinations and this was the only one that worked.

@mtreinish
Copy link
Member

So this behavior is actually by design. The execute() function is not meant to expose every option of transpile() it's a higher level abstraction that is there primarily to provide a simpler experience for users that don't care about the internal operation of the transpiler and just want to take their circuits and run them on a backend. The options to the transpiler which are exposed via execute() are limited to just high level ones like optimization_level (there are options there which were added before we made this distinction clear which really should be deprecated and removed). If you're looking to control the scheduling of your circuits that's already a layer deeper than what execute() is intended for and calling transpile() directly is the intended path there.

I don't think this behavior of exeucte() is something we are going to change (we used to try and have execute() proxy everything in transpile() and assemble() a long time ago but that didn't scale and is why we made the separation of concerns clearer. However, I think we can make this distinction clearer in the documentation. So I'll leave this issue open and we can close it with a docstring update to explain the purpose of execute better.

@yaelbh
Copy link
Contributor

yaelbh commented Mar 3, 2022

@mtreinish How about raising an error for calls to execute with an unsupported transpile option, rather than ignoring it?

@mtreinish
Copy link
Member

mtreinish commented Mar 3, 2022

The problem there is we pass through all kwargs as run options to backend.run(). Since all backends have a unique set of runtime options they offer we made the decision a long time ago to pass kwargs to the backend.run() (or assemble() before BackendV1) and warn if an option is passed in the backend doesn't support but not ignore it: https://github.com/Qiskit/qiskit-terra/blob/main/qiskit/execute_function.py#L386-L396 (with the old pre-backendv1 approach no warning would be emitted the unsupported options were silently ignored by the backend).

@jakelishman
Copy link
Member

In this case, scheduling_method is a correct parameter to execute, it's just gated behind passing schedule_circuit=True, and it's never passed to transpile, it's just used in the separate function schedule (a few lines below your change). If you pass schedule_circuit=True as well, I think your example should work.

@yaelbh: it's a bit tricky to handle this, because execute collects up all its unknown keyword arguments to pass them to backend.run.

@yaelbh
Copy link
Contributor

yaelbh commented Mar 3, 2022

According to @mtreinish and @jakelishman's explanations, I'd expect the backend to warn about an unknown run option.

@mtreinish
Copy link
Member

Ah I missed that, but it's bit weird because of the overloaded terminology. the schedule_circuit flag is to indicate that the circuit should be lowered to a pulse schedule prior to executing it. The scheduling_method arg there is for the schedule() not the transpile() call before it. These options actually predate the scheduler in the transpiler for scheduling gates. I feel like we should deprecate the support in execute() to schedule a circuit to a pulse schedule prior to calling run.

@CharlieDerby
Copy link
Author

@mtreinish

If you're looking to control the scheduling of your circuits that's already a layer deeper than what execute() is intended for and calling transpile() directly is the intended path there.

In my example I attempted this method and got the same error. The transpiler outputs a circuit with (presumably) the correct extra delay to realign measurement but running that circuit leads to the same problem. I'm not sure why this is the case because it seems like the misalignment problem should be solved by pre-transpiling.

@jakelishman
Copy link
Member

jakelishman commented Mar 3, 2022

When you manually transpile something, are you then passing it to execute or to your backend.run? After manual transpilation, you should do the latter, otherwise execute will re-transpile the circuit which will most likely invalidate its scheduling. You should hopefully be able to do backend.run(transpiled_circuit, shots=10_000) without issue, which is the expected path for people who want finer-grained control over the transpilation process.

@yaelbh: that's a fair point. At the moment, it looks like there should be a notice emitted by execute, but it's as a log message at level INFO, which isn't super visible. Any incorrect options that actually get passed to a backend should be reported by the backend (in this case the qiskit-ibm ones). In this case, scheduling_method was interpreted as a correct but inert option for execute so it wouldn't have triggered any logging or warnings.

@CharlieDerby
Copy link
Author

@jakelishman that makes a good deal of sense, thanks.

mtreinish added a commit to mtreinish/qiskit-core that referenced this issue Apr 4, 2022
This commit updates the documentation of the execute() function to
clarify its purpose and intent. The execute() function is provided as a
higher level abstraction and convenience function for use cases where
you just want to execute a circuit and not worry about how it gets
compiled for a particular backend. The set of options the function is
minimal by design because it should just be about running circuits with
no options needed and if you need to exert more control over the
compilation you should use transpile() and backend.run() together
instead. As part of this a large number of legacy kwargs defined on the
function are deprecated as they are mostly holdovers from before the
purpose of the function was clear and really are just needless
duplication of transpile(), schedule(), and assemble() (even though this
isn't used anymore after Qiskit#7886).

Closes Qiskit#7640
@1ucian0
Copy link
Member

1ucian0 commented Mar 8, 2024

Closing because:

  • The behavior is expected
  • There is a "workaround"
  • execute exists in 0.* series and it was removed in 1.*

@1ucian0 1ucian0 closed this as not planned Won't fix, can't repro, duplicate, stale Mar 8, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
6 participants