Skip to content

Commit

Permalink
Make parallel case fully deterministic
Browse files Browse the repository at this point in the history
The parallel trial code was potentially non-deterministic in it's
execution because the way the parallel trials were compared was
dependent on execution speed of the pass. This could result in a
different output if results with equal number of swaps finished
executing in differing amounts of time between runs. This commit
addresses this by first collecting the results into an ordered Vec
first which is then iterated over serially to find the minimum swap
count. This will make the output independent of execution speed of the
individual trials.
  • Loading branch information
mtreinish committed Aug 18, 2022
1 parent 914b22a commit 3d0429a
Showing 1 changed file with 32 additions and 18 deletions.
50 changes: 32 additions & 18 deletions src/sabre_swap/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,12 @@ pub enum Heuristic {
Decay,
}

struct TrialResult {
out_map: HashMap<usize, Vec<[usize; 2]>>,
gate_order: Vec<usize>,
layout: NLayout,
}

/// Return a set of candidate swaps that affect qubits in front_layer.
///
/// For each virtual qubit in front_layer, find its current location
Expand Down Expand Up @@ -164,46 +170,50 @@ pub fn build_swap_map(
.sample_iter(&rand::distributions::Standard)
.take(num_trials)
.collect();
let (out_map, gate_order, best_layout) = if run_in_parallel {
(0..num_trials)
let result = if run_in_parallel {
let trial_results: Vec<TrialResult> = seed_vec
.into_par_iter()
.map(|trial_num| {
.map(|seed_trial| {
swap_map_trial(
num_qubits,
dag,
neighbor_table,
&dist,
&coupling_graph,
heuristic,
seed_vec[trial_num],
seed_trial,
layout.clone(),
)
})
.min_by_key(|(out_map, _gate_order, _layout)| {
out_map.values().map(|x| x.len()).sum::<usize>()
})
.collect();
trial_results
.into_iter()
.min_by_key(|result| result.out_map.values().map(|x| x.len()).sum::<usize>())
} else {
(0..num_trials)
seed_vec
.into_iter()
.map(|trial_num| {
.map(|seed_trial| {
swap_map_trial(
num_qubits,
dag,
neighbor_table,
&dist,
&coupling_graph,
heuristic,
seed_vec[trial_num],
seed_trial,
layout.clone(),
)
})
.min_by_key(|(out_map, _gate_order, _layout)| {
out_map.values().map(|x| x.len()).sum::<usize>()
})
.min_by_key(|result| result.out_map.values().map(|x| x.len()).sum::<usize>())
}
.unwrap();
*layout = best_layout;
(SwapMap { map: out_map }, gate_order.into_pyarray(py).into())
*layout = result.layout;
(
SwapMap {
map: result.out_map,
},
result.gate_order.into_pyarray(py).into(),
)
}

fn swap_map_trial(
Expand All @@ -215,7 +225,7 @@ fn swap_map_trial(
heuristic: &Heuristic,
seed: u64,
mut layout: NLayout,
) -> (HashMap<usize, Vec<[usize; 2]>>, Vec<usize>, NLayout) {
) -> TrialResult {
let max_iterations_without_progress = 10 * neighbor_table.neighbors.len();
let mut gate_order: Vec<usize> = Vec::with_capacity(dag.dag.node_count());
let mut ops_since_progress: Vec<[usize; 2]> = Vec::new();
Expand Down Expand Up @@ -384,10 +394,14 @@ fn swap_map_trial(
}
ops_since_progress.push(best_swap);
}
(out_map, gate_order, layout)
TrialResult {
out_map,
gate_order,
layout,
}
}

pub fn sabre_score_heuristic(
fn sabre_score_heuristic(
layer: &[[usize; 2]],
layout: &mut NLayout,
neighbor_table: &NeighborTable,
Expand Down

0 comments on commit 3d0429a

Please sign in to comment.