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

Remove list argument broadcasting and simplify transpile() #10291

Merged
merged 21 commits into from
Jul 19, 2023

Conversation

mtreinish
Copy link
Member

@mtreinish mtreinish commented Jun 15, 2023

Summary

This commit updates the transpile() function to no longer support broadcast of lists of arguments. This functionality was deprecated in the 0.23.0 release. As part of this removal the internals of the transpile() function are simplified so we don't need to handle broadcasting, building preset pass managers, parallel dispatch, etc anymore as this functionality (without broadcasting) already exists through the transpiler API. Besides greatly simplifying the transpile() code and using more aspects of the public APIs that exist in the qiskit.transpiler module, this commit also should fix the overhead we have around parallel execution due to the complexity of supporting broadcasting. This overhead was partially addressed before in #7789 which leveraged shared memory to minimize the serialization time necessary for IPC but by using PassManager.run() internally now all of that overhead is removed as the initial fork will have all the necessary context in each process from the start.

Three seemingly unrelated changes made here were necessary to support our current transpile() API without relying on custom pass manager construction.

The first is the handling of layout from intlist. The current Layout class is dependent on a circuit because it maps Qubit
objects to a physical qubit index. Ideally the layout structure would just map virtual indices to physical indices (see #8060
for a similar issue, also it's worth noting this is how the internal NLayout and QPY represent layout), but because of the
existing API the construction of a Layout is dependent on a circuit. For the initial_layout argument when running with
multiple circuits to avoid the need to broadcasting the layout construction for supported input types that need the circuit
to lookup the Qubit objects the SetLayout pass now supports taking in an int list and will construct a Layout object at run
time. This effectively defers the Layout object creation for initial_layout to run time so it can be built as a function of the
circuit as the API demands. (this was handled separately in #10344)

The second is the FakeBackend class used in some tests was constructing invalid backends in some cases. This wasn't caught in the previous structure because the backends were not actually being parsed by transpile() previously which masked this issue. This commit fixes that issue because PassManagerConfig.from_backend() was failing because of the invalid backend construction.

The third issue is a new _skip_target private argument to generate_preset_pass_manager() and PassManagerConfig. This was necessary to recreate the behavior of transpile() when a user provides a BackendV2 and either basis_gates or coupling_map arguments. In general the internals of the transpiler treat a target as higher priority because it has more complete and restrictive constraints than the basis_gates/coupling map objects. However, for transpile() if a backendv2 is passed in for backend paired with coupling_map and/or basis_gates the expected workflow is that the basis_gates and coupling_map arguments take priority and override the equivalent attributes from the backend. To facilitate this we need to block pulling the target from the backend This should only be needed for a short period of time as when #9256 is implemented we'll just build a single target from the arguments as needed.

Details and comments

Fixes #7741
Fix #7883

TODO:

  • Fix last failing tests (dt handling for scheduling)

This commit updates the transpile() function to no longer support
broadcast of lists of arguments. This functionality was deprecated in
the 0.23.0 release. As part of this removal the internals of the
transpile() function are simplified so we don't need to handle
broadcasting, building preset pass managers, parallel dispatch, etc
anymore as this functionality (without broadcasting) already exists
through the transpiler API. Besides greatly simplifying the transpile()
code and using more aspects of the public APIs that exist in the
qiskit.transpiler module, this commit also should fix the overhead we
have around parallel execution due to the complexity of supporting
broadcasting. This overhead was partially addressed before in Qiskit#7789
which leveraged shared memory to minimize the serialization time
necessary for IPC but by using `PassManager.run()` internally now all of
that overhead is removed as the initial fork will have all the necessary
context in each process from the start.

Three seemingly unrelated changes made here were necessary to support our
current transpile() API without building custom pass manager
construction.

The first is the handling of layout from intlist. The
current Layout class is dependent on a circuit because it maps Qubit
objects to a physical qubit index. Ideally the layout structure would
just map virtual indices to physical indices (see Qiskit#8060 for a similar
issue, also it's worth noting this is how the internal NLayout and QPY
represent layout), but because of the existing API the construction of
a Layout is dependent on a circuit. For the initial_layout argument when
running with multiple circuits to avoid the need to broadcasting the
layout construction for supported input types that need the circuit to
lookup the Qubit objects the SetLayout pass now supports taking in an
int list and will construct a Layout object at run time. This
effectively defers the Layout object creation for initial_layout to
run time so it can be built as a function of the circuit as the API
demands.

The second is the FakeBackend class used in some tests was constructing
invalid backends in some cases. This wasn't caught in the previous
structure because the backends were not actually being parsed by
transpile() previously which masked this issue. This commit fixes that
issue because PassManagerConfig.from_backend() was failing because of
the invalid backend construction.

The third issue is a new _skip_target private argument to
generate_preset_pass_manager() and PassManagerConfig. This was necessary
to recreate the behavior of transpile() when a user provides a BackendV2
and either `basis_gates` or `coupling_map` arguments. In general the
internals of the transpiler treat a target as higher priority because it
has more complete and restrictive constraints than the
basis_gates/coupling map objects. However, for transpile() if a
backendv2 is passed in for backend paired with coupling_map and/or
basis_gates the expected workflow is that the basis_gates and
coupling_map arguments take priority and override the equivalent
attributes from the backend. To facilitate this we need to block pulling
the target from the backend This should only be needed for a short
period of time as when Qiskit#9256 is implemented we'll just build a single
target from the arguments as needed.

Fixes Qiskit#7741
@mtreinish mtreinish requested review from a team and jyu00 as code owners June 15, 2023 16:05
@qiskit-bot
Copy link
Collaborator

One or more of the the following people are requested to review this:

  • @Qiskit/terra-core

@mtreinish mtreinish added the Changelog: Removal Include in the Removed section of the changelog label Jun 15, 2023
@mtreinish mtreinish added this to the 0.25.0 milestone Jun 15, 2023
@jlapeyre jlapeyre self-requested a review June 17, 2023 00:09
@jlapeyre jlapeyre self-assigned this Jun 17, 2023
@mtreinish mtreinish changed the title [WIP] Remove list argument broadcasting and simplify transpile() Remove list argument broadcasting and simplify transpile() Jun 19, 2023
@coveralls
Copy link

coveralls commented Jun 19, 2023

Pull Request Test Coverage Report for Build 5587396079

  • 76 of 81 (93.83%) changed or added relevant lines in 4 files are covered.
  • 10 unchanged lines in 4 files lost coverage.
  • Overall coverage increased (+0.03%) to 86.054%

Changes Missing Coverage Covered Lines Changed/Added Lines %
qiskit/compiler/transpiler.py 71 76 93.42%
Files with Coverage Reduction New Missed Lines %
qiskit/compiler/transpiler.py 1 92.89%
qiskit/transpiler/instruction_durations.py 1 92.96%
crates/qasm2/src/lex.rs 2 91.39%
crates/qasm2/src/parse.rs 6 97.58%
Totals Coverage Status
Change from base Build 5582955280: 0.03%
Covered Lines: 72302
Relevant Lines: 84019

💛 - Coveralls

A duplicate import slipped through in the most recent rebase.
This commit fixes that oversight and removes the duplicate.
Copy link
Contributor

@danielleodigie danielleodigie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From what I can see, it LGTM, other than that failing test I guess. I think it's a Linux test, and I can't recreate the issue on my end.

@jakelishman
Copy link
Member

The test failure was a flakiness in the CI suite that I've made #10439 to address.

Copy link
Member

@jakelishman jakelishman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks a jillion times better than the old code. Given that this PR claims to close #7741, do you have approximate timings for the type of thing in that issue?

Comment on lines -638 to 639
with self.assertRaisesRegex(TranspilerError, "different numbers of qubits"):
with self.assertRaises(TranspilerError):
transpile(qc, backend, initial_layout=bad_initial_layout)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the new error message significantly worse?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was when I modified this test, but @1ucian0 added a real error message in SetLayout as part of #10344 so it'll say:

The length of the layout is different than the size of the circuit 1024 <> 2

now. (I glossed over <> in my review we should change that to actually say 1024 qubits in the layout != 2 qubits in the circuit or something more explicit instead)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or just stick from __future__ import barry_as_FLUFL at the top of the file lol

qiskit/compiler/transpiler.py Outdated Show resolved Hide resolved
qiskit/compiler/transpiler.py Show resolved Hide resolved
approximation_degree = _parse_approximation_degree(approximation_degree)

output_name = _parse_output_name(output_name, circuits)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

output_name still broadcasts in _parse_output_name, but that at least doesn't get passed to the PassManager, so I guess we're ok with keeping that? I honestly had no idea we even had that option.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah it shouldn't matter for this, it felt like if we're taking an output name argument it needs to support broadcasting. Since if you did transpile([qc1, qc2, qc3, qc4], output_name='foo') I'm not sure what the expected behavior for that would be (or why we'd force it on people). Since the broadcasting doesn't effect the PassManager object or the parallel dispatch I figured it was fine to keep it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm fine with keeping it broadcasting, since it doesn't affect the PassManager. If the option wasn't already in transpile, I wouldn't have been in favour of adding it, haha - turns out that the initial use-case was to distinguish the same circuit transpiled with broadcast arguments (#2745).

qiskit/compiler/transpiler.py Outdated Show resolved Hide resolved
Comment on lines +351 to +353
# If durations are provided and there is more than one circuit
# we need to serialize the execution because the full durations
# is dependent on the circuit calibrations which are per circuit
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To me, this seems to be indicating a problem with the passes that interpret this data; they should read it from the circuit during their run methods. It's the same problem that we had with SetLayout until just recently.

Ideally we'd fix that before this PR, but there's no time before 0.25 now. Can we check with the people who might be using these options within IBM that they're not going to be hamstrung by the decay to serial transpile, at least?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is definitely a problem. My concern with doing the same fix as with SetLayout was I didn't think it was used in a single place like the input layout and that InstructionDurations would have to be updated in an instance variable in multiple passes. So I went with this approach instead to avoid doing this in multiple places.

@nkanazawa1989 or @itoko do you have any idea/thoughts here regarding the potential impact of serializing the execution with a custom instruction durations or dt input? I expect you've got the best handle on the impact of setting custom instruction durations (or dt) on the argument inputs to transpile().

My thinking is for most users it won't be noticeable because my feeling is most of them are on macOS anyway and we disable multiprocessing by default on macOS.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with Jake. Ideally we should fix passes to check circuit calibrations directly without updating the instruction durations here. In addition, duration values are already reported in the InstructionProperties, and we no longer need to create this object.

Just reusing the same custom instruction durations object is likely problematic. For example, we have two set of circuits generated by different experiments, and we may want to batch them together in a single job. When one is with the custom cal and the other is a reference with no custom cal, reusing the same durations object may impact the scheduling of second experiment circuits. When durations object is created for each circuit groups (this is impossible because circuits don't have context, because it's just a list, and thus we need to prepare durations object for each entry), we can avoid this kind of problem.

I prefer removing this option in future since duration values may conflict with one in the Target.

Copy link
Contributor

@itoko itoko Jul 19, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the potential impact of serializing the execution with a custom instruction durations or dt input would be little (at least for noisy simulation users). I didn't know until now that instruction durations were being used for pulse gates. I've been thinking InstructionDurations is for custom gates without calibrations used for noisy simulation and pulse gates are separately handled here. @naoki, do you think the case you mentioned above is covered by the code in the link? If so, maybe we could drop the updates with circuits in _parse_instruction_durations.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given the comments I'm going to go ahead and add this to merge queue. I think we can revisit the exact structure of how the passes deal with instruction durations in a followup as that isn't blocked by this change, and the risk of this becoming a performance issue is low. I do wonder if an implementation of #9256 would alleviate some of those concerns. Because then the passes will only get a target and we're not using InstructionDurations anywhere (except for the plugin interface). But I'll convert this comment into an issue for 0.26 and we can track it there.

Comment on lines -913 to -918
def _zip_dict(mapping: Dict[Any, Iterable]) -> Iterable[Dict]:
"""Zip a dictionary where all the values are iterables of the same length into an iterable of
dictionaries with the same keys. This has the same semantics as zip with regard to laziness
(over the iterables; there must be a finite number of keys!) and unequal lengths."""
keys, iterables = zip(*mapping.items())
return (dict(zip(keys, values)) for values in zip(*iterables))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Noooo, my first non-trivial merged PR to Terra D: (#6814, haha)

@mtreinish
Copy link
Member Author

This looks a jillion times better than the old code. Given that this PR claims to close #7741, do you have approximate timings for the type of thing in that issue?

I don't have the timings handy. I think that I tried to run the recreate from the issue when I wrote this a month ago and I was having trouble reproducing the issue locally. I'll give it a try again in a bit and see if I can get real numbers.

Copy link
Member

@jakelishman jakelishman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm happy with this and ready to merge, pending an answer from one of the potentially affected people about #10291 (comment). In general, I think that's probably a trade-off we're going to need to make; the parallel overhead for pulse jobs was already (I think?) high enough that parallel transpile probably wasn't helping a great amount already, and the behaviour is still achievable with explicit parallelisation with built-in Python tools.

I'll hold off on tagging for merge until there's a resolution in that comment thread.

@mtreinish mtreinish added this pull request to the merge queue Jul 19, 2023
Merged via the queue into Qiskit:main with commit 346ca77 Jul 19, 2023
13 checks passed
@mtreinish mtreinish deleted the better-transpile branch July 20, 2023 00:49
to24toro pushed a commit to to24toro/qiskit-terra that referenced this pull request Aug 3, 2023
)

* Remove list argument broadcasting and simplify transpile()

This commit updates the transpile() function to no longer support
broadcast of lists of arguments. This functionality was deprecated in
the 0.23.0 release. As part of this removal the internals of the
transpile() function are simplified so we don't need to handle
broadcasting, building preset pass managers, parallel dispatch, etc
anymore as this functionality (without broadcasting) already exists
through the transpiler API. Besides greatly simplifying the transpile()
code and using more aspects of the public APIs that exist in the
qiskit.transpiler module, this commit also should fix the overhead we
have around parallel execution due to the complexity of supporting
broadcasting. This overhead was partially addressed before in Qiskit#7789
which leveraged shared memory to minimize the serialization time
necessary for IPC but by using `PassManager.run()` internally now all of
that overhead is removed as the initial fork will have all the necessary
context in each process from the start.

Three seemingly unrelated changes made here were necessary to support our
current transpile() API without building custom pass manager
construction.

The first is the handling of layout from intlist. The
current Layout class is dependent on a circuit because it maps Qubit
objects to a physical qubit index. Ideally the layout structure would
just map virtual indices to physical indices (see Qiskit#8060 for a similar
issue, also it's worth noting this is how the internal NLayout and QPY
represent layout), but because of the existing API the construction of
a Layout is dependent on a circuit. For the initial_layout argument when
running with multiple circuits to avoid the need to broadcasting the
layout construction for supported input types that need the circuit to
lookup the Qubit objects the SetLayout pass now supports taking in an
int list and will construct a Layout object at run time. This
effectively defers the Layout object creation for initial_layout to
run time so it can be built as a function of the circuit as the API
demands.

The second is the FakeBackend class used in some tests was constructing
invalid backends in some cases. This wasn't caught in the previous
structure because the backends were not actually being parsed by
transpile() previously which masked this issue. This commit fixes that
issue because PassManagerConfig.from_backend() was failing because of
the invalid backend construction.

The third issue is a new _skip_target private argument to
generate_preset_pass_manager() and PassManagerConfig. This was necessary
to recreate the behavior of transpile() when a user provides a BackendV2
and either `basis_gates` or `coupling_map` arguments. In general the
internals of the transpiler treat a target as higher priority because it
has more complete and restrictive constraints than the
basis_gates/coupling map objects. However, for transpile() if a
backendv2 is passed in for backend paired with coupling_map and/or
basis_gates the expected workflow is that the basis_gates and
coupling_map arguments take priority and override the equivalent
attributes from the backend. To facilitate this we need to block pulling
the target from the backend This should only be needed for a short
period of time as when Qiskit#9256 is implemented we'll just build a single
target from the arguments as needed.

Fixes Qiskit#7741

* Fix _skip_target logic

* Fix InstructionScheduleMap handling with backendv2

* Fix test failure caused by exception being raised later

* Fix indentation error

* Update qiskit/providers/fake_provider/fake_backend.py

Co-authored-by: John Lapeyre <jlapeyre@users.noreply.github.com>

* Fix standalone dt argument handling

* Remove unused code

* Fix lint

* Remove duplicate import in set_layout.py

A duplicate import slipped through in the most recent rebase.
This commit fixes that oversight and removes the duplicate.

* Update release notes

Co-authored-by: Jake Lishman <jake.lishman@ibm.com>

* Adjust logic for _skip_transpile to check if None

* Simplify check cmap code

* Only check backend if it exists

---------

Co-authored-by: John Lapeyre <jlapeyre@users.noreply.github.com>
Co-authored-by: Jake Lishman <jake.lishman@ibm.com>
ElePT pushed a commit to ElePT/qiskit-ibm-provider that referenced this pull request Oct 4, 2023
…skit#10291)

* Remove list argument broadcasting and simplify transpile()

This commit updates the transpile() function to no longer support
broadcast of lists of arguments. This functionality was deprecated in
the 0.23.0 release. As part of this removal the internals of the
transpile() function are simplified so we don't need to handle
broadcasting, building preset pass managers, parallel dispatch, etc
anymore as this functionality (without broadcasting) already exists
through the transpiler API. Besides greatly simplifying the transpile()
code and using more aspects of the public APIs that exist in the
qiskit.transpiler module, this commit also should fix the overhead we
have around parallel execution due to the complexity of supporting
broadcasting. This overhead was partially addressed before in Qiskit/qiskit#7789
which leveraged shared memory to minimize the serialization time
necessary for IPC but by using `PassManager.run()` internally now all of
that overhead is removed as the initial fork will have all the necessary
context in each process from the start.

Three seemingly unrelated changes made here were necessary to support our
current transpile() API without building custom pass manager
construction.

The first is the handling of layout from intlist. The
current Layout class is dependent on a circuit because it maps Qubit
objects to a physical qubit index. Ideally the layout structure would
just map virtual indices to physical indices (see Qiskit/qiskit#8060 for a similar
issue, also it's worth noting this is how the internal NLayout and QPY
represent layout), but because of the existing API the construction of
a Layout is dependent on a circuit. For the initial_layout argument when
running with multiple circuits to avoid the need to broadcasting the
layout construction for supported input types that need the circuit to
lookup the Qubit objects the SetLayout pass now supports taking in an
int list and will construct a Layout object at run time. This
effectively defers the Layout object creation for initial_layout to
run time so it can be built as a function of the circuit as the API
demands.

The second is the FakeBackend class used in some tests was constructing
invalid backends in some cases. This wasn't caught in the previous
structure because the backends were not actually being parsed by
transpile() previously which masked this issue. This commit fixes that
issue because PassManagerConfig.from_backend() was failing because of
the invalid backend construction.

The third issue is a new _skip_target private argument to
generate_preset_pass_manager() and PassManagerConfig. This was necessary
to recreate the behavior of transpile() when a user provides a BackendV2
and either `basis_gates` or `coupling_map` arguments. In general the
internals of the transpiler treat a target as higher priority because it
has more complete and restrictive constraints than the
basis_gates/coupling map objects. However, for transpile() if a
backendv2 is passed in for backend paired with coupling_map and/or
basis_gates the expected workflow is that the basis_gates and
coupling_map arguments take priority and override the equivalent
attributes from the backend. To facilitate this we need to block pulling
the target from the backend This should only be needed for a short
period of time as when Qiskit/qiskit#9256 is implemented we'll just build a single
target from the arguments as needed.

Fixes Qiskit/qiskit#7741

* Fix _skip_target logic

* Fix InstructionScheduleMap handling with backendv2

* Fix test failure caused by exception being raised later

* Fix indentation error

* Update qiskit/providers/fake_provider/fake_backend.py

Co-authored-by: John Lapeyre <jlapeyre@users.noreply.github.com>

* Fix standalone dt argument handling

* Remove unused code

* Fix lint

* Remove duplicate import in set_layout.py

A duplicate import slipped through in the most recent rebase.
This commit fixes that oversight and removes the duplicate.

* Update release notes

Co-authored-by: Jake Lishman <jake.lishman@ibm.com>

* Adjust logic for _skip_transpile to check if None

* Simplify check cmap code

* Only check backend if it exists

---------

Co-authored-by: John Lapeyre <jlapeyre@users.noreply.github.com>
Co-authored-by: Jake Lishman <jake.lishman@ibm.com>
ElePT pushed a commit to ElePT/qiskit-ibm-runtime that referenced this pull request Oct 10, 2023
…skit#10291)

* Remove list argument broadcasting and simplify transpile()

This commit updates the transpile() function to no longer support
broadcast of lists of arguments. This functionality was deprecated in
the 0.23.0 release. As part of this removal the internals of the
transpile() function are simplified so we don't need to handle
broadcasting, building preset pass managers, parallel dispatch, etc
anymore as this functionality (without broadcasting) already exists
through the transpiler API. Besides greatly simplifying the transpile()
code and using more aspects of the public APIs that exist in the
qiskit.transpiler module, this commit also should fix the overhead we
have around parallel execution due to the complexity of supporting
broadcasting. This overhead was partially addressed before in Qiskit/qiskit#7789
which leveraged shared memory to minimize the serialization time
necessary for IPC but by using `PassManager.run()` internally now all of
that overhead is removed as the initial fork will have all the necessary
context in each process from the start.

Three seemingly unrelated changes made here were necessary to support our
current transpile() API without building custom pass manager
construction.

The first is the handling of layout from intlist. The
current Layout class is dependent on a circuit because it maps Qubit
objects to a physical qubit index. Ideally the layout structure would
just map virtual indices to physical indices (see Qiskit/qiskit#8060 for a similar
issue, also it's worth noting this is how the internal NLayout and QPY
represent layout), but because of the existing API the construction of
a Layout is dependent on a circuit. For the initial_layout argument when
running with multiple circuits to avoid the need to broadcasting the
layout construction for supported input types that need the circuit to
lookup the Qubit objects the SetLayout pass now supports taking in an
int list and will construct a Layout object at run time. This
effectively defers the Layout object creation for initial_layout to
run time so it can be built as a function of the circuit as the API
demands.

The second is the FakeBackend class used in some tests was constructing
invalid backends in some cases. This wasn't caught in the previous
structure because the backends were not actually being parsed by
transpile() previously which masked this issue. This commit fixes that
issue because PassManagerConfig.from_backend() was failing because of
the invalid backend construction.

The third issue is a new _skip_target private argument to
generate_preset_pass_manager() and PassManagerConfig. This was necessary
to recreate the behavior of transpile() when a user provides a BackendV2
and either `basis_gates` or `coupling_map` arguments. In general the
internals of the transpiler treat a target as higher priority because it
has more complete and restrictive constraints than the
basis_gates/coupling map objects. However, for transpile() if a
backendv2 is passed in for backend paired with coupling_map and/or
basis_gates the expected workflow is that the basis_gates and
coupling_map arguments take priority and override the equivalent
attributes from the backend. To facilitate this we need to block pulling
the target from the backend This should only be needed for a short
period of time as when Qiskit/qiskit#9256 is implemented we'll just build a single
target from the arguments as needed.

Fixes Qiskit/qiskit#7741

* Fix _skip_target logic

* Fix InstructionScheduleMap handling with backendv2

* Fix test failure caused by exception being raised later

* Fix indentation error

* Update qiskit/providers/fake_provider/fake_backend.py

Co-authored-by: John Lapeyre <jlapeyre@users.noreply.github.com>

* Fix standalone dt argument handling

* Remove unused code

* Fix lint

* Remove duplicate import in set_layout.py

A duplicate import slipped through in the most recent rebase.
This commit fixes that oversight and removes the duplicate.

* Update release notes

Co-authored-by: Jake Lishman <jake.lishman@ibm.com>

* Adjust logic for _skip_transpile to check if None

* Simplify check cmap code

* Only check backend if it exists

---------

Co-authored-by: John Lapeyre <jlapeyre@users.noreply.github.com>
Co-authored-by: Jake Lishman <jake.lishman@ibm.com>
ElePT pushed a commit to ElePT/qiskit that referenced this pull request Oct 12, 2023
)

* Remove list argument broadcasting and simplify transpile()

This commit updates the transpile() function to no longer support
broadcast of lists of arguments. This functionality was deprecated in
the 0.23.0 release. As part of this removal the internals of the
transpile() function are simplified so we don't need to handle
broadcasting, building preset pass managers, parallel dispatch, etc
anymore as this functionality (without broadcasting) already exists
through the transpiler API. Besides greatly simplifying the transpile()
code and using more aspects of the public APIs that exist in the
qiskit.transpiler module, this commit also should fix the overhead we
have around parallel execution due to the complexity of supporting
broadcasting. This overhead was partially addressed before in Qiskit#7789
which leveraged shared memory to minimize the serialization time
necessary for IPC but by using `PassManager.run()` internally now all of
that overhead is removed as the initial fork will have all the necessary
context in each process from the start.

Three seemingly unrelated changes made here were necessary to support our
current transpile() API without building custom pass manager
construction.

The first is the handling of layout from intlist. The
current Layout class is dependent on a circuit because it maps Qubit
objects to a physical qubit index. Ideally the layout structure would
just map virtual indices to physical indices (see Qiskit#8060 for a similar
issue, also it's worth noting this is how the internal NLayout and QPY
represent layout), but because of the existing API the construction of
a Layout is dependent on a circuit. For the initial_layout argument when
running with multiple circuits to avoid the need to broadcasting the
layout construction for supported input types that need the circuit to
lookup the Qubit objects the SetLayout pass now supports taking in an
int list and will construct a Layout object at run time. This
effectively defers the Layout object creation for initial_layout to
run time so it can be built as a function of the circuit as the API
demands.

The second is the FakeBackend class used in some tests was constructing
invalid backends in some cases. This wasn't caught in the previous
structure because the backends were not actually being parsed by
transpile() previously which masked this issue. This commit fixes that
issue because PassManagerConfig.from_backend() was failing because of
the invalid backend construction.

The third issue is a new _skip_target private argument to
generate_preset_pass_manager() and PassManagerConfig. This was necessary
to recreate the behavior of transpile() when a user provides a BackendV2
and either `basis_gates` or `coupling_map` arguments. In general the
internals of the transpiler treat a target as higher priority because it
has more complete and restrictive constraints than the
basis_gates/coupling map objects. However, for transpile() if a
backendv2 is passed in for backend paired with coupling_map and/or
basis_gates the expected workflow is that the basis_gates and
coupling_map arguments take priority and override the equivalent
attributes from the backend. To facilitate this we need to block pulling
the target from the backend This should only be needed for a short
period of time as when Qiskit#9256 is implemented we'll just build a single
target from the arguments as needed.

Fixes Qiskit#7741

* Fix _skip_target logic

* Fix InstructionScheduleMap handling with backendv2

* Fix test failure caused by exception being raised later

* Fix indentation error

* Update qiskit/providers/fake_provider/fake_backend.py

Co-authored-by: John Lapeyre <jlapeyre@users.noreply.github.com>

* Fix standalone dt argument handling

* Remove unused code

* Fix lint

* Remove duplicate import in set_layout.py

A duplicate import slipped through in the most recent rebase.
This commit fixes that oversight and removes the duplicate.

* Update release notes

Co-authored-by: Jake Lishman <jake.lishman@ibm.com>

* Adjust logic for _skip_transpile to check if None

* Simplify check cmap code

* Only check backend if it exists

---------

Co-authored-by: John Lapeyre <jlapeyre@users.noreply.github.com>
Co-authored-by: Jake Lishman <jake.lishman@ibm.com>
ElePT pushed a commit to ElePT/qiskit-ibm-runtime that referenced this pull request Dec 8, 2023
…skit#10291)

* Remove list argument broadcasting and simplify transpile()

This commit updates the transpile() function to no longer support
broadcast of lists of arguments. This functionality was deprecated in
the 0.23.0 release. As part of this removal the internals of the
transpile() function are simplified so we don't need to handle
broadcasting, building preset pass managers, parallel dispatch, etc
anymore as this functionality (without broadcasting) already exists
through the transpiler API. Besides greatly simplifying the transpile()
code and using more aspects of the public APIs that exist in the
qiskit.transpiler module, this commit also should fix the overhead we
have around parallel execution due to the complexity of supporting
broadcasting. This overhead was partially addressed before in Qiskit/qiskit#7789
which leveraged shared memory to minimize the serialization time
necessary for IPC but by using `PassManager.run()` internally now all of
that overhead is removed as the initial fork will have all the necessary
context in each process from the start.

Three seemingly unrelated changes made here were necessary to support our
current transpile() API without building custom pass manager
construction.

The first is the handling of layout from intlist. The
current Layout class is dependent on a circuit because it maps Qubit
objects to a physical qubit index. Ideally the layout structure would
just map virtual indices to physical indices (see Qiskit/qiskit#8060 for a similar
issue, also it's worth noting this is how the internal NLayout and QPY
represent layout), but because of the existing API the construction of
a Layout is dependent on a circuit. For the initial_layout argument when
running with multiple circuits to avoid the need to broadcasting the
layout construction for supported input types that need the circuit to
lookup the Qubit objects the SetLayout pass now supports taking in an
int list and will construct a Layout object at run time. This
effectively defers the Layout object creation for initial_layout to
run time so it can be built as a function of the circuit as the API
demands.

The second is the FakeBackend class used in some tests was constructing
invalid backends in some cases. This wasn't caught in the previous
structure because the backends were not actually being parsed by
transpile() previously which masked this issue. This commit fixes that
issue because PassManagerConfig.from_backend() was failing because of
the invalid backend construction.

The third issue is a new _skip_target private argument to
generate_preset_pass_manager() and PassManagerConfig. This was necessary
to recreate the behavior of transpile() when a user provides a BackendV2
and either `basis_gates` or `coupling_map` arguments. In general the
internals of the transpiler treat a target as higher priority because it
has more complete and restrictive constraints than the
basis_gates/coupling map objects. However, for transpile() if a
backendv2 is passed in for backend paired with coupling_map and/or
basis_gates the expected workflow is that the basis_gates and
coupling_map arguments take priority and override the equivalent
attributes from the backend. To facilitate this we need to block pulling
the target from the backend This should only be needed for a short
period of time as when Qiskit/qiskit#9256 is implemented we'll just build a single
target from the arguments as needed.

Fixes Qiskit/qiskit#7741

* Fix _skip_target logic

* Fix InstructionScheduleMap handling with backendv2

* Fix test failure caused by exception being raised later

* Fix indentation error

* Update qiskit/providers/fake_provider/fake_backend.py

Co-authored-by: John Lapeyre <jlapeyre@users.noreply.github.com>

* Fix standalone dt argument handling

* Remove unused code

* Fix lint

* Remove duplicate import in set_layout.py

A duplicate import slipped through in the most recent rebase.
This commit fixes that oversight and removes the duplicate.

* Update release notes

Co-authored-by: Jake Lishman <jake.lishman@ibm.com>

* Adjust logic for _skip_transpile to check if None

* Simplify check cmap code

* Only check backend if it exists

---------

Co-authored-by: John Lapeyre <jlapeyre@users.noreply.github.com>
Co-authored-by: Jake Lishman <jake.lishman@ibm.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Changelog: Removal Include in the Removed section of the changelog
Projects
None yet
8 participants