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

[NFM] Integration testing for CF in O2 and O3 #10390

Closed
wants to merge 69 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
69 commits
Select commit Hold shift + click to select a range
760fbfc
add initial tests
ewinston Nov 13, 2022
aeb571e
tests passing
ewinston Nov 16, 2022
dfb8d31
Merge branch 'main' into controlflow/commutative_cancellation
ewinston Feb 8, 2023
450e678
remove debug code
ewinston Apr 19, 2023
935d787
Merge branch 'main' into controlflow/commutative_cancellation
ewinston Apr 19, 2023
ad93783
fix test for clbits
ewinston Apr 20, 2023
292b0d7
formatting
ewinston Apr 20, 2023
a7c2bec
Initial commit.
kevinhartman Jun 19, 2023
2482d7a
Downgrade hashbrown to 0.12.3 for compat with Rustworkx.
kevinhartman Jun 21, 2023
8c0d926
Implement gen_swap_epilogue.
kevinhartman Jun 21, 2023
141b2ff
Add Python wrappers for structs.
kevinhartman Jun 21, 2023
b2c2001
Implement DAG -> SabreDAG.
kevinhartman Jun 21, 2023
02036f0
Merge branch 'main' into controlflow/commutative_cancellation
jlapeyre Jun 22, 2023
ccba78c
Apply block results in sabre_swap.py.
kevinhartman Jun 22, 2023
6f30dcf
Merge branch 'main' into controlflow/commutative_cancellation
jlapeyre Jun 23, 2023
f8a6d17
Fix node ID lookup issue.
kevinhartman Jun 23, 2023
893c2c1
Lift creation of PassManager out of loop
jlapeyre Jun 23, 2023
28124c7
Fix bug where block circuits started out non-empty!
kevinhartman Jun 23, 2023
68a8fce
Test commutative cancellation does not cross block boundaries
jlapeyre Jun 23, 2023
517833a
Move DAG building and result application to functions.
kevinhartman Jun 23, 2023
b6cdab4
Add release note for commutative cancellation in control flow blocks
jlapeyre Jun 23, 2023
5661409
Implement control flow handling for Sabre layout.
kevinhartman Jun 26, 2023
10d83fe
Fix qreg indexing bug for new swaps versus routed gates.
kevinhartman Jun 27, 2023
e6cbc19
Run Python formatting.
kevinhartman Jun 27, 2023
0616274
Include CommutativeAnalysis pass explicitly when doing control flow b…
jlapeyre Jun 28, 2023
413aa02
Support control flow in ConsolidateBlocks
jlapeyre Jun 28, 2023
c882c6a
Add release note for support control flow in ConsolidateBlocks
jlapeyre Jun 28, 2023
5848f94
Fix bug where root_dag was used instead of mapped_dag.
kevinhartman Jun 28, 2023
eb6f58c
Fix bug where swap_epilogue was in terms of physical bits instead of …
kevinhartman Jun 28, 2023
bc3991d
Add more tests from stochastic swap.
kevinhartman Jun 28, 2023
d269db5
Move imports from inside function to top level
jlapeyre Jun 29, 2023
c32d69c
Make construction of ConsolidateBlocks for control flow ops more effi…
jlapeyre Jun 29, 2023
b1eb08f
Fix bug mapping inner block qubits to outer circuit qubits.
kevinhartman Jun 29, 2023
7ad1ed3
Update sabre swap testing.
kevinhartman Jun 30, 2023
cddadf0
Update TODOs.
kevinhartman Jun 30, 2023
40e0cbc
Fix bug where a 2Q CF nodes would be mistakenly added to the extended…
kevinhartman Jun 30, 2023
e227da4
Port more testing from stochastic swap.
kevinhartman Jun 30, 2023
dc03e56
Run formatting.
kevinhartman Jun 30, 2023
d90cec1
Port remaining stochastic swap tests.
kevinhartman Jul 1, 2023
bdffd78
Mark Sabre routing and layout as known good for CF.
kevinhartman Jul 1, 2023
998951e
Add random circuit valid output testing for Sabre.
kevinhartman Jul 1, 2023
71d024a
Run cargo fmt.
kevinhartman Jul 1, 2023
f3054cd
Fix lint issues.
kevinhartman Jul 1, 2023
86f643a
Fix lint issues.
kevinhartman Jul 1, 2023
c946f89
Update 'test_invalid_methods_raise_on_control_flow'
kevinhartman Jul 1, 2023
01d4d01
Make gen_swap_epilogue consume 'from_layout'.
kevinhartman Jul 1, 2023
b4e3ad1
Add release note.
kevinhartman Jul 1, 2023
0093477
Allow control flow in opt levels 2 and 3.
kevinhartman Jul 3, 2023
e3a07a0
Add release note.
kevinhartman Jul 3, 2023
9844449
Merge branch 'sabre-swap-ctrl-flow' of github.com:kevinhartman/qiskit…
kevinhartman Jul 5, 2023
985bbf7
Merge branch 'controlflow/consolidate_blocks' of github.com:jlapeyre/…
kevinhartman Jul 5, 2023
bca7305
Merge branch 'controlflow/commutative_cancellation' of github.com:ewi…
kevinhartman Jul 5, 2023
74fd38a
Merge branch 'ctrl-flow-o2-o3' of github.com:kevinhartman/qiskit-terr…
kevinhartman Jul 5, 2023
b2e303e
Enable testing for opt 2 and 3.
kevinhartman Jul 5, 2023
45dc1e2
Merge branch 'main' of github.com:Qiskit/qiskit-terra into integratio…
kevinhartman Jul 6, 2023
e471c58
Fix inner qubit mapping in UnitarySynthesis pass.
kevinhartman Jul 6, 2023
9ba85c2
Merge branch 'fix-unitary-synthesis-cf' of github.com:kevinhartman/qi…
kevinhartman Jul 7, 2023
0c6bd48
Merge branch 'main' of github.com:Qiskit/qiskit-terra into integratio…
kevinhartman Jul 7, 2023
f7b68cd
Make bit copy return self.
kevinhartman Jul 10, 2023
270533a
Add release note.
kevinhartman Jul 10, 2023
fc9d243
Merge branch 'fix-bit-copy' of github.com:kevinhartman/qiskit-terra i…
kevinhartman Jul 10, 2023
d4bc8bd
Do IfElseOp test without builder interface
jlapeyre Jul 10, 2023
d210512
Linting
jlapeyre Jul 10, 2023
9b552d4
Preserve existing deepcopy behavior for old bits.
kevinhartman Jul 10, 2023
eabaee5
Avoid cyclic import
jlapeyre Jul 10, 2023
0943608
Add tests to validate copy behaviors.
kevinhartman Jul 10, 2023
6b0875e
Merge branch 'fix-bit-copy' of github.com:kevinhartman/qiskit-terra i…
kevinhartman Jul 10, 2023
c567d0d
Try to fix cyclic import (in lint tool only)
jlapeyre Jul 10, 2023
ba49398
Merge branch 'controlflow/consolidate_blocks' of github.com:jlapeyre/…
kevinhartman Jul 11, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 5 additions & 15 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion crates/accelerate/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ version = "^0.15.6"
features = ["rayon"]

[dependencies.hashbrown]
version = "0.13.2"
version = "0.12.3"
features = ["rayon"]

[dependencies.indexmap]
Expand Down
100 changes: 57 additions & 43 deletions crates/accelerate/src/sabre_layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,7 @@
// that they have been altered from the originals.
#![allow(clippy::too_many_arguments)]

use hashbrown::HashSet;
use ndarray::prelude::*;
use numpy::IntoPyArray;
use numpy::PyReadonlyArray2;
use pyo3::prelude::*;
use pyo3::wrap_pyfunction;
Expand All @@ -26,22 +24,19 @@ use crate::getenv_use_multiple_threads;
use crate::nlayout::NLayout;
use crate::sabre_swap::neighbor_table::NeighborTable;
use crate::sabre_swap::sabre_dag::SabreDAG;
use crate::sabre_swap::swap_map::SwapMap;
use crate::sabre_swap::{build_swap_map_inner, Heuristic};
use crate::sabre_swap::{build_swap_map_inner, Heuristic, SabreResult};

#[pyfunction]
pub fn sabre_layout_and_routing(
py: Python,
num_clbits: usize,
mut dag_nodes: Vec<(usize, Vec<usize>, HashSet<usize>)>,
dag: &SabreDAG,
neighbor_table: &NeighborTable,
distance_matrix: PyReadonlyArray2<f64>,
heuristic: &Heuristic,
max_iterations: usize,
num_swap_trials: usize,
num_layout_trials: usize,
seed: Option<u64>,
) -> ([NLayout; 2], SwapMap, PyObject) {
) -> ([NLayout; 2], SabreResult) {
let run_in_parallel = getenv_use_multiple_threads();
let outer_rng = match seed {
Some(seed) => Pcg64Mcg::seed_from_u64(seed),
Expand All @@ -52,16 +47,15 @@ pub fn sabre_layout_and_routing(
.take(num_layout_trials)
.collect();
let dist = distance_matrix.as_array();
let result = if run_in_parallel && num_layout_trials > 1 {
if run_in_parallel && num_layout_trials > 1 {
seed_vec
.into_par_iter()
.enumerate()
.map(|(index, seed_trial)| {
(
index,
layout_trial(
num_clbits,
&mut dag_nodes.clone(),
dag,
neighbor_table,
&dist,
heuristic,
Expand All @@ -72,9 +66,9 @@ pub fn sabre_layout_and_routing(
),
)
})
.min_by_key(|(index, result)| {
.min_by_key(|(index, (_, result))| {
(
result.1.map.values().map(|x| x.len()).sum::<usize>(),
result.map.map.values().map(|x| x.len()).sum::<usize>(),
*index,
)
})
Expand All @@ -85,8 +79,7 @@ pub fn sabre_layout_and_routing(
.into_iter()
.map(|seed_trial| {
layout_trial(
num_clbits,
&mut dag_nodes,
dag,
neighbor_table,
&dist,
heuristic,
Expand All @@ -96,39 +89,56 @@ pub fn sabre_layout_and_routing(
run_in_parallel,
)
})
.min_by_key(|result| result.1.map.values().map(|x| x.len()).sum::<usize>())
.min_by_key(|(_, result)| result.map.map.values().map(|x| x.len()).sum::<usize>())
.unwrap()
};
(result.0, result.1, result.2.into_pyarray(py).into())
}
}

fn layout_trial(
num_clbits: usize,
dag_nodes: &mut Vec<(usize, Vec<usize>, HashSet<usize>)>,
dag: &SabreDAG,
neighbor_table: &NeighborTable,
distance_matrix: &ArrayView2<f64>,
heuristic: &Heuristic,
seed: u64,
max_iterations: usize,
num_swap_trials: usize,
run_swap_in_parallel: bool,
) -> ([NLayout; 2], SwapMap, Vec<usize>) {
) -> ([NLayout; 2], SabreResult) {
// Pick a random initial layout and fully populate ancillas in that layout too
let num_physical_qubits = distance_matrix.shape()[0];
let mut rng = Pcg64Mcg::seed_from_u64(seed);
let mut physical_qubits: Vec<usize> = (0..num_physical_qubits).collect();
physical_qubits.shuffle(&mut rng);
let mut initial_layout = NLayout::from_logical_to_physical(physical_qubits);
let mut rev_dag_nodes: Vec<(usize, Vec<usize>, HashSet<usize>)> =
dag_nodes.iter().rev().cloned().collect();
let new_dag_fn = |nodes| {
// Because the current implementation of Sabre swap doesn't permute
// the layout when placing control flow ops, there's no need to
// recurse into blocks. We remove them here, but still map control
// flow node IDs to an empty block list so Sabre treats these ops
// as control flow nodes, but doesn't route their blocks.
let node_blocks_empty = dag
.node_blocks
.iter()
.map(|(node_index, _)| (*node_index, Vec::with_capacity(0)));
SabreDAG::new(
dag.num_qubits,
dag.num_clbits,
nodes,
node_blocks_empty.collect(),
)
.unwrap()
};

let mut dag_forward: SabreDAG = new_dag_fn(dag.nodes.clone());
let mut dag_reverse: SabreDAG = new_dag_fn(dag.nodes.iter().rev().cloned().collect());
for _iter in 0..max_iterations {
// forward and reverse
for _direction in 0..2 {
let dag = apply_layout(dag_nodes, &initial_layout, num_physical_qubits, num_clbits);
let layout_dag = apply_layout(&dag_forward, &initial_layout);
let mut pass_final_layout = NLayout::generate_trivial_layout(num_physical_qubits);
build_swap_map_inner(
num_physical_qubits,
&dag,
&layout_dag,
neighbor_table,
distance_matrix,
heuristic,
Expand All @@ -139,12 +149,12 @@ fn layout_trial(
);
let final_layout = compose_layout(&initial_layout, &pass_final_layout);
initial_layout = final_layout;
std::mem::swap(dag_nodes, &mut rev_dag_nodes);
std::mem::swap(&mut dag_forward, &mut dag_reverse);
}
}
let layout_dag = apply_layout(dag_nodes, &initial_layout, num_physical_qubits, num_clbits);
let layout_dag = apply_layout(dag, &initial_layout);
let mut final_layout = NLayout::generate_trivial_layout(num_physical_qubits);
let (swap_map, gate_order) = build_swap_map_inner(
let sabre_result = build_swap_map_inner(
num_physical_qubits,
&layout_dag,
neighbor_table,
Expand All @@ -155,23 +165,27 @@ fn layout_trial(
num_swap_trials,
Some(run_swap_in_parallel),
);
([initial_layout, final_layout], swap_map, gate_order)
([initial_layout, final_layout], sabre_result)
}

fn apply_layout(
dag_nodes: &[(usize, Vec<usize>, HashSet<usize>)],
layout: &NLayout,
num_qubits: usize,
num_clbits: usize,
) -> SabreDAG {
let layout_dag_nodes: Vec<(usize, Vec<usize>, HashSet<usize>)> = dag_nodes
.iter()
.map(|(node_index, qargs, cargs)| {
let new_qargs: Vec<usize> = qargs.iter().map(|n| layout.logic_to_phys[*n]).collect();
(*node_index, new_qargs, cargs.clone())
})
.collect();
SabreDAG::new(num_qubits, num_clbits, layout_dag_nodes).unwrap()
fn apply_layout(dag: &SabreDAG, layout: &NLayout) -> SabreDAG {
let layout_nodes = dag.nodes.iter().map(|(node_index, qargs, cargs)| {
let new_qargs: Vec<usize> = qargs.iter().map(|n| layout.logic_to_phys[*n]).collect();
(*node_index, new_qargs, cargs.clone())
});
let node_blocks = dag.node_blocks.iter().map(|(node_index, blocks)| {
(
*node_index,
blocks.iter().map(|d| apply_layout(d, layout)).collect(),
)
});
SabreDAG::new(
dag.num_qubits,
dag.num_clbits,
layout_nodes.collect(),
node_blocks.collect(),
)
.unwrap()
}

fn compose_layout(initial_layout: &NLayout, final_layout: &NLayout) -> NLayout {
Expand Down
Loading