Skip to content

Add star to linear pre-routing pass #11387

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

Merged
merged 14 commits into from
May 2, 2024
Merged

Conversation

mtreinish
Copy link
Member

@mtreinish mtreinish commented Dec 8, 2023

Summary

This commit adds a new transpiler pass StarPreRouting that adds a dedicated transformation that finds a star graph connectivity subcircuit and replaces it with a linear routing equivalent. This makes the circuit easier for a routing pass to work with.

Details and comments

TODO:

  • Add more testing
  • Add final layout tracking and composition with routing.

Co-Authored-By: Sebastian Brandhofer 148463728+sbrandhsn@users.noreply.github.com

This commit adds a new transpiler pass StarPreRouting that adds a
dedicated transformation that finds a star graph connectivity subcircuit
and replaces it with a linear routing equivalent. This makes the circuit
easier for a routing pass to work with.
@mtreinish mtreinish added Changelog: New Feature Include in the "Added" section of the changelog mod: transpiler Issues and PRs related to Transpiler labels Dec 8, 2023
@mtreinish mtreinish added this to the 1.0.0 milestone Dec 8, 2023
@coveralls
Copy link

coveralls commented Dec 8, 2023

Pull Request Test Coverage Report for Build 8926693870

Warning: This coverage report may be inaccurate.

This pull request's base commit is no longer the HEAD commit of its target branch. This means it includes changes from outside the original pull request, including, potentially, unrelated coverage changes.

Details

  • 175 of 180 (97.22%) changed or added relevant lines in 3 files are covered.
  • 7 unchanged lines in 2 files lost coverage.
  • Overall coverage increased (+0.04%) to 89.619%

Changes Missing Coverage Covered Lines Changed/Added Lines %
qiskit/transpiler/passes/routing/star_prerouting.py 173 178 97.19%
Files with Coverage Reduction New Missed Lines %
qiskit/transpiler/passes/synthesis/unitary_synthesis.py 2 88.02%
crates/qasm2/src/lex.rs 5 92.62%
Totals Coverage Status
Change from base Build 8926203943: 0.04%
Covered Lines: 62012
Relevant Lines: 69195

💛 - Coveralls

mtreinish added a commit to mtreinish/qiskit-core that referenced this pull request Dec 11, 2023
This commit adds functionality to the built-in routing passes for
composing an existing final layout with the routing permutation. In
PRs Qiskit#9523 and Qiskit#11387 we're adding new passes that introduce a
permutation prior to routing that needs to be tracked for the final
output layout to be valid. To faciliate this a new method compose() is
added to the Layout class which will combine the two layouts. Then the
built-in routing passes are updated to call compose when a layout has
already been set.
Copy link
Member

@alexanderivrii alexanderivrii left a comment

Choose a reason for hiding this comment

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

I was playing a bit with this code, so decided to write a few high-level comments.

This is a very cool pass that will greatly improve the quality of compiled circuits for various sparsely connected architectures.

The main question that I have (and this is more general than this PR) is that (if I understand correctly) this star-to-line pass will run before routing, with the intuition that for sparsely connected architectures we will find better layout + routing when the circuit consists of linear pieces rather than star pieces. If the circuit consists of a single star and the coupling graph contains a line of the right size, then VF2 will even find a perfect layout and no routing would be needed. However if there are two or more stars (or there are more 2-qubit gates), then even if the first star is mapped perfectly, Sabre might need to do many swaps before the second star, and it's not clear that the line connectivity of the second star will help. What do you think?

Comment on lines 52 to 90
for node in dag.topological_op_nodes():
if (
len(node.qargs) == 2
and len(node.cargs) == 0
and getattr(node.op, "condition", None) is None
):
if center_node is None:
center_node = set(node.qargs)
star_sequence.append(node)
elif isinstance(center_node, set):
if node.qargs[0] in center_node:
center_node = node.qargs[0]
star_sequence.append(node)
elif node.qargs[1] in center_node:
center_node = node.qargs[1]
star_sequence.append(node)
else:
center_node = None
star_sequence = []
else:
if center_node in node.qargs:
star_sequence.append(node)
else:
saved_center = center_node
center_node = None
elif len(node.qargs) > 2:
saved_center = center_node
center_node = None

# If center_node is None after we've processed the node that
# means we've broken star connectivity
if center_node is None and len(star_sequence) > 1:
star_sequences.append((star_sequence, saved_center))
star_sequence = []
if len(node.qargs) == 2:
center_node = set(node.qargs)
star_sequence.append(node)
if len(star_sequence) > 1 and center_node:
star_sequences.append((star_sequence, center_node))
Copy link
Member

Choose a reason for hiding this comment

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

I was thinking that we have multiple passes that collect blocks of nodes according to the following general strategy:

  • if the current node matches a certain condition C1 and the current node can be added to the current block while satisfying a certain other condition C2, add the current node to the current block (and continue to the next node)
  • else if the current block is empty, skip the current node (and continue to the next node)
  • otherwise, add the current block to the list of collected blocks, set the current block to be empty, and repeat the first step with the empty current block

This is more general than what BlockCollector can currently do since it only collects nodes matches a given filter function (corresponding to C1), while now we want to say something like this: a node can be added to a partially constructed block either when the block is empty or one of the node's qubits is equal to the center_qubit (i.e. this is what the condition C2 would look like).
If you think that having this more general set of block collection strategies would be useful, I will write a PR (I actually have code somewhere that does something similar already)

Copy link
Member Author

Choose a reason for hiding this comment

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

There might be similar applications for block collection strategies like this, I'm not entirely sure though. But I can't imagine it would hurt to have the BlockCollector support this use case. I wouldn't mind having the block collection done in this pass be a bit more robust, it only works because of our default lexicographical topological sorting based on the qubit indices.

Comment on lines 121 to 130
if swap_source is None:
swap_source = center_node
new_dag.apply_operation_back(
inner_node.op,
_apply_mapping(inner_node.qargs, qubit_mapping, dag.qubits),
inner_node.cargs,
)
prev = inner_node.qargs
processed_nodes.add(inner_node)
continue
Copy link
Member

Choose a reason for hiding this comment

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

Oh, I see, not including the swap gate after the very first gate is ok because it's the previous optimization all over again. At first I was surprised that applying the pass to the circuit

q_0: ──■────■────■────■──
     ┌─┴─┐  │    │    │  
q_1: ┤ X ├──┼────┼────┼──
     └───┘┌─┴─┐  │    │  
q_2: ─────┤ X ├──┼────┼──
          └───┘┌─┴─┐  │  
q_3: ──────────┤ X ├──┼──
               └───┘┌─┴─┐
q_4: ───────────────┤ X ├
                    └───┘

we get

q_0: ──■────■───X─────────────────
     ┌─┴─┐  │   │                 
q_1: ┤ X ├──┼───┼─────────────────
     └───┘┌─┴─┐ │                 
q_2: ─────┤ X ├─X───■───X─────────
          └───┘   ┌─┴─┐ │         
q_3: ─────────────┤ X ├─X───■───X─
                  └───┘   ┌─┴─┐ │ 
q_4: ─────────────────────┤ X ├─X─
                          └───┘   

but I see now that the line consists of qubits 1 -- 0 -- 2 -- 3 -- 4.

And you can drop the very last swap gate, since this already synthesizes the star up to a permutation gate, so the last swap can be absorbed into it.

Comment on lines 149 to 152
continue
else:
new_dag.apply_operation_back(node.op, node.qargs, node.cargs)
return new_dag
Copy link
Member

Choose a reason for hiding this comment

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

To account for the induced permutation of qubits, would it make sense to add a PermutationGate at the end of the star rather than modifying the layout directly? And we already have the ElidePermutations pass that would be able to process these permutations.

Copy link
Member Author

Choose a reason for hiding this comment

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

Well ElidePermutations hasn't merged yet, I'm still trying to figure out the layout issues there. But yeah we could in theory combine them, but yeah I like the idea of pairing them. I do wonder if there is a use case for this without adding the permutation, but doing this would work well. Maybe have it as a flag, like reverse_permutation=True, in the constructor to control whether we insert the PermutationGate or not?

@mtreinish
Copy link
Member Author

The main question that I have (and this is more general than this PR) is that (if I understand correctly) this star-to-line pass will run before routing, with the intuition that for sparsely connected architectures we will find better layout + routing when the circuit consists of linear pieces rather than star pieces. If the circuit consists of a single star and the coupling graph contains a line of the right size, then VF2 will even find a perfect layout and no routing would be needed. However if there are two or more stars (or there are more 2-qubit gates), then even if the first star is mapped perfectly, Sabre might need to do many swaps before the second star, and it's not clear that the line connectivity of the second star will help. What do you think?

I was thinking we would run this before the layout stage as part of init stage. In my local full path testing I was using the pre_layout stage but if we were to add it to the preset pass managers I'd use init. I called it prerouting but in my head I was thinking like you and we'd definitely want to do this before VF2Layout in case vf2 can find a line in the connectivity graph. Prerouting to me at the time I wrote this was a initial lighter routing pass, not intended to be right before the routing stage (like what was done in sabre pre-layout), but yeah it's a poor name choice as it's meaning is ambiguous and overloaded.

@alexanderivrii
Copy link
Member

alexanderivrii commented Jan 22, 2024

There might be some problems with treating single-qubit gates. For example, the following circuit

     ┌───┐     ┌───┐     ┌───┐     ┌───┐     
q_0: ┤ H ├──■──┤ H ├──■──┤ H ├──■──┤ H ├──■──
     └───┘┌─┴─┐└───┘  │  └───┘  │  └───┘  │  
q_1: ─────┤ X ├───────┼─────────┼─────────┼──
          └───┘     ┌─┴─┐       │         │  
q_2: ───────────────┤ X ├───────┼─────────┼──
                    └───┘     ┌─┴─┐       │  
q_3: ─────────────────────────┤ X ├───────┼──
                              └───┘     ┌─┴─┐
q_4: ───────────────────────────────────┤ X ├
                                        └───┘
q_5: ────────────────────────────────────────                                          

gets transformed into

     ┌───┐             ┌───┐┌───┐┌───┐   
q_0: ┤ H ├──■────■───X─┤ H ├┤ H ├┤ H ├───
     └───┘┌─┴─┐  │   │ └───┘└───┘└───┘   
q_1: ─────┤ X ├──┼───┼───────────────────
          └───┘┌─┴─┐ │                   
q_2: ──────────┤ X ├─X───■────X──────────
               └───┘   ┌─┴─┐  │          
q_3: ──────────────────┤ X ├──X────■───X─
                       └───┘     ┌─┴─┐ │ 
q_4: ────────────────────────────┤ X ├─X─
                                 └───┘   
q_5: ────────────────────────────────────

Intuitively, this is because the pass only collects sequences of 2-qubit gates while ignoring 1-qubit gates (which is probably fine, since 1-qubit gates pose no problems for routing), but then forgets to take these 1-qubit gates into account (see how all of the Hadamard gates got pushed out to the end of the circuit).

@alexanderivrii
Copy link
Member

Another random thought is that star-to-line translation may create gate cancellation opportunities, i.e. we may want to rerun passes like inverse cancellation after star-to-line but before layout or routing.

@mtreinish
Copy link
Member Author

Another random thought is that star-to-line translation may create gate cancellation opportunities, i.e. we may want to rerun passes like inverse cancellation after star-to-line but before layout or routing.

Yeah, that's a good point. I think when we're adding the pass to the preset pass managers we can determine the best place to add this. I'm wondering if we'll want to have a do while loop for initial optimization like we do for final optimization

This commit fixes two related issues. The first is that it fixed the
handling of 1q gates in the middle of a star sequence. The sequence
collection was correctly skipping the 1q gates, but when we reassembled
the circuit and applied the linear routing it would incorrectly build
the routing without the 1q gates. This would result in the 1q gates
being pushed after the star. At the same time the other related issue
was that the permutations caused by the swap insertions were not taken
into account for subsequent gates. This would result in gates being
placed on the wrong bits and incorrect results being returned.
@mtreinish
Copy link
Member Author

Intuitively, this is because the pass only collects sequences of 2-qubit gates while ignoring 1-qubit gates (which is probably fine, since 1-qubit gates pose no problems for routing), but then forgets to take these 1-qubit gates into account (see how all of the Hadamard gates got pushed out to the end of the circuit).

This was a good catch, I've pushed up a fix for this here: 8cc0587

github-merge-queue bot pushed a commit that referenced this pull request Mar 27, 2024
* Compose multiple final_layout attributes in routing

This commit adds functionality to the built-in routing passes for
composing an existing final layout with the routing permutation. In
PRs #9523 and #11387 we're adding new passes that introduce a
permutation prior to routing that needs to be tracked for the final
output layout to be valid. To faciliate this a new method compose() is
added to the Layout class which will combine the two layouts. Then the
built-in routing passes are updated to call compose when a layout has
already been set.

* adding inverse and to_permutation methods, tests, updating release notes

---------

Co-authored-by: AlexanderIvrii <alexi@il.ibm.com>
@CLAassistant
Copy link

CLAassistant commented Apr 2, 2024

CLA assistant check
All committers have signed the CLA.

@sbrandhsn
Copy link
Contributor

sbrandhsn commented Apr 8, 2024

StarPreRouting works now but depends on #12057 and FinalizeLayouts in #9523 being merged (parts of this pass are adapted from #11614 ). If you have any suggestions/comments - I would love to hear them even before these two items are merged. :-)

Executed on a 6-qubit QFT quantum circuit, StarPreRouting yields the following mapped circuit:

                                                                          ░ ┌───┐                                                  ░ ┌───┐                                     ░ ┌───┐                         ░ ┌───┐          ░       ░ 
q_4 -> 0 ──────■──────────────────────────────────────────────────────────░─┤ H ├─■────────X───────────────────────────────────────░─┤ H ├─■────────X──────────────────────────░─┤ H ├─■────────X──────────────░─┤ H ├─■────────░───────░─
         ┌───┐ │P(π/2)                                                    ░ └───┘ │P(π/2)  │                                       ░ └───┘ │P(π/2)  │                          ░ └───┘ │P(π/2)  │              ░ └───┘ │P(π/2)  ░ ┌───┐ ░ 
q_5 -> 1 ┤ H ├─■────────■────────X────────────────────────────────────────░───────■────────X──■────────X───────────────────────────░───────■────────X──■────────X──────────────░───────■────────X──■────────X──░───────■────────░─┤ H ├─░─
         └───┘          │P(π/4)  │                                        ░                   │P(π/4)  │                           ░                   │P(π/4)  │              ░                   │P(π/4)  │  ░                ░ └───┘ ░ 
q_3 -> 2 ───────────────■────────X──■────────X────────────────────────────░───────────────────■────────X──■────────X───────────────░───────────────────■────────X──■────────X──░───────────────────■────────X──░────────────────░───────░─
                                    │P(π/8)  │                            ░                               │P(π/8)  │               ░                               │P(π/8)  │  ░                               ░                ░       ░ 
q_2 -> 3 ───────────────────────────■────────X──■─────────X───────────────░───────────────────────────────■────────X──■─────────X──░───────────────────────────────■────────X──░───────────────────────────────░────────────────░───────░─
                                                │P(π/16)  │               ░                                           │P(π/16)  │  ░                                           ░                               ░                ░       ░ 
q_1 -> 4 ───────────────────────────────────────■─────────X──■─────────X──░───────────────────────────────────────────■─────────X──░───────────────────────────────────────────░───────────────────────────────░────────────────░───────░─
                                                             │P(π/32)  │  ░                                                        ░                                           ░                               ░                ░       ░ 
q_0 -> 5 ────────────────────────────────────────────────────■─────────X──░────────────────────────────────────────────────────────░───────────────────────────────────────────░───────────────────────────────░────────────────░───────░─
                                                                          ░                                                        ░                                           ░                               ░                ░       ░ 

whereas SabreLayout yields:

                                                                    ░ ┌───┐                                               ░                                     ░ ┌───┐                         ░                   ░       ░ 
q_2 -> 0 ──────────────────X────────────────────────────────────────░─┤ H ├─X───────────■─────────────────────────────────░───────■─────────────────────────────░─┤ H ├─X───────────────────────░───────────────────░───────░─
                           │                                        ░ └───┘ │           │P(π/4)                           ░ ┌───┐ │P(π/2)                       ░ └───┘ │                       ░                   ░ ┌───┐ ░ 
q_4 -> 1 ──────■───────────X─────■──────────────────────────────────░───────X──■────────■────────X────────────────────────░─┤ H ├─■────────■───────────■────────░───────X──X───────────■────────░──────────■────────░─┤ H ├─░─
         ┌───┐ │P(π/2)           │P(π/8)                            ░          │P(π/2)           │                        ░ └───┘          │P(π/4)     │P(π/8)  ░          │           │P(π/4)  ░          │P(π/2)  ░ └───┘ ░ 
q_5 -> 2 ┤ H ├─■────────■────────■────────X─────────────────────────░──────────■─────────────────X──■────────X────────────░────────────────■────────X──■────────░──────────X──■────────■────────░───────X──■────────░───────░─
         └───┘          │P(π/4)           │                         ░                               │P(π/8)  │            ░                         │           ░             │P(π/2)           ░ ┌───┐ │           ░       ░ 
q_3 -> 3 ───────────────■─────────────────X──■─────────X────────────░───────────────────────────────■────────X──■─────────░───X─────────────────────X───────────░─────────────■─────────────────░─┤ H ├─X───────────░───────░─
                                             │P(π/16)  │            ░                                           │P(π/16)  ░   │                                 ░                               ░ └───┘             ░       ░ 
q_1 -> 4 ────────────────────────────────────■─────────X──■─────────░───X───────────────────────────────────────■─────────░───X─────────────────────────────────░───────────────────────────────░───────────────────░───────░─
                                                          │P(π/32)  ░   │                                                 ░                                     ░                               ░                   ░       ░ 
q_0 -> 5 ─────────────────────────────────────────────────■─────────░───X─────────────────────────────────────────────────░─────────────────────────────────────░───────────────────────────────░───────────────────░───────░─
                                                                    ░                                                     ░                                     ░                               ░                   ░       ░ 

A comparison on a 100-qubit QFT was done by running:

qc = qft(100)
cm = CouplingMap.from_line(100)

pm = generate_preset_pass_manager(optimization_level=3, coupling_map=cm, basis_gates=['rz', 'sx', 'cx'])
pm.pre_layout = PassManager([StarPreRouting()])
pm.post_scheduling = PassManager([FinalizeLayouts()])
start_ts = time()
result_star_prerouting = pm.run(qc)
end_ts = time()
print('star pre-routing done in {}s.'.format(end_ts-start_ts))
print('star pre-routing ops:', result_star_prerouting.count_ops())
print('star pre-routing depth:', result_star_prerouting.depth())

pm = generate_preset_pass_manager(optimization_level=3, coupling_map=cm, basis_gates=['rz', 'sx', 'cx'])
start_ts = time()
result_sabre = pm.run(qc)
end_ts = time()
print('sabre done in {}s.'.format(end_ts-start_ts))
print('sabre ops:', result_sabre.count_ops())
print('sabre depth:', result_sabre.depth())

This yielded the following data when barriers are included between the different 'stars' of a QFT instance:

star pre-routing done in 23.116374969482422s.
star pre-routing ops: OrderedDict([('cx', 14848), ('sx', 28635), ('rz', 26707), ('barrier', 100)])
star pre-routing depth: 39790

sabre done in 142.27110981941223s.
sabre ops: OrderedDict([('cx', 26635), ('sx', 6362), ('rz', 11522), ('barrier', 100)])
sabre depth: 27714

- quite a larger decrease in cx gates! - and without barriers:

star pre-routing done in 23.750023126602173s.
star pre-routing ops: OrderedDict([('cx', 14848), ('sx', 20084), ('rz', 29150)])
star pre-routing depth: 1573

sabre done in 37.29286193847656s.
sabre ops: OrderedDict([('cx', 17510), ('sx', 4064), ('rz', 9848)])
sabre depth: 1764

which yields a 16% decrease in cx gates. These comparison are on a line graph.

@mtreinish mtreinish changed the title [WIP] Add star to linear pre-routing pass Add star to linear pre-routing pass Apr 15, 2024
@mtreinish mtreinish added the on hold Can not fix yet label Apr 15, 2024
@mtreinish mtreinish marked this pull request as ready for review April 15, 2024 18:06
@mtreinish mtreinish requested a review from a team as a code owner April 15, 2024 18:06
@qiskit-bot
Copy link
Collaborator

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

  • @Qiskit/terra-core

@mtreinish
Copy link
Member Author

I've moved this out of draft since @sbrandhsn finished this up! But it still has dependencies on open PRs and will need to be rebased so I've marked this as on hold to indicate this.

Copy link
Member Author

@mtreinish mtreinish left a comment

Choose a reason for hiding this comment

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

Overall this looks great to me, thanks @sbrandhsn for taking this over and getting it across the finish line! I left a few inline comments, most of them are just questions or pretty minor.

Comment on lines 145 to 150
if not isinstance(self.dag, DAGDependency):
return [pred for pred in self.dag.predecessors(node) if isinstance(pred, DAGOpNode)]
else:
return [
self.dag.get_node(pred_id) for pred_id in self.dag.direct_predecessors(node.node_id)
]
Copy link
Member Author

Choose a reason for hiding this comment

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

I realize this was likely ported from #11614 but were you thinking we'd want to run this with a DAGDependency? I guess there is the potential to find a bigger star if we factor in potential commutations.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yup, @alexanderivrii realized we could run this pass while considering commutations in #11614 so I just left it in. Should I remove the paths corresponding to DAGDependency?

Copy link
Member

Choose a reason for hiding this comment

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

I would suggest to remove the DAGDependency path for now, and this will get optimized automatically when we finalize #11614. Thanks!

Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think the paths on DAGDependency are fully functional as of now - at least I have not verified it...

Copy link
Member Author

Choose a reason for hiding this comment

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

No it's fine, we don't have a great story about how to use DAGDependency via the pass managers yet. But I guess it's an option for someone running things manually and doesn't hurt at all.

@alexanderivrii
Copy link
Member

Thanks @mtreinish and @sbrandhsn for getting this completed, this is definitely going to be a super-useful pass. And thanks @jakelishman for doing this review (somehow I forgot that I was assigned to review this PR). I also looked at the code, and it looks great. In the future, we should probably refactor the star collection part of the pass into the more general block collection (i.e. finalize #11614) and replace the virtual_permutation_layout/FinalizeLayouts by final_permutation.

@mtreinish mtreinish removed the on hold Can not fix yet label May 2, 2024
@sbrandhsn sbrandhsn enabled auto-merge May 2, 2024 15:47
@sbrandhsn
Copy link
Contributor

Thanks @mtreinish and @sbrandhsn for getting this completed, this is definitely going to be a super-useful pass. And thanks @jakelishman for doing this review (somehow I forgot that I was assigned to review this PR). I also looked at the code, and it looks great. In the future, we should probably refactor the star collection part of the pass into the more general block collection (i.e. finalize #11614) and replace the virtual_permutation_layout/FinalizeLayouts by final_permutation.

Makes sense, thanks Jake, Matthew and Sasha for reviewing this! :-)

Copy link
Member

@alexanderivrii alexanderivrii left a comment

Choose a reason for hiding this comment

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

Thanks for all the last-minute fixes. LGTM!

@sbrandhsn sbrandhsn added this pull request to the merge queue May 2, 2024
Merged via the queue into Qiskit:main with commit f34fb21 May 2, 2024
ElePT pushed a commit to ElePT/qiskit that referenced this pull request May 31, 2024
* Add Star to linear pre-routing pass

This commit adds a new transpiler pass StarPreRouting that adds a
dedicated transformation that finds a star graph connectivity subcircuit
and replaces it with a linear routing equivalent. This makes the circuit
easier for a routing pass to work with.

* Add missing doc imports

* Fix handling of 1q gates and swap tracking

This commit fixes two related issues. The first is that it fixed the
handling of 1q gates in the middle of a star sequence. The sequence
collection was correctly skipping the 1q gates, but when we reassembled
the circuit and applied the linear routing it would incorrectly build
the routing without the 1q gates. This would result in the 1q gates
being pushed after the star. At the same time the other related issue
was that the permutations caused by the swap insertions were not taken
into account for subsequent gates. This would result in gates being
placed on the wrong bits and incorrect results being returned.

* fixed/tested star-prerouting

* Apply suggestions from code review

* changed moved self.dag to a function parameter

* Removing the usage of FinalizeLayout in star prerouting tests

* format

---------

Co-authored-by: Sebastian Brandhofer <148463728+sbrandhsn@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Changelog: New Feature Include in the "Added" section of the changelog mod: transpiler Issues and PRs related to Transpiler priority: high
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants