Skip to content

Commit

Permalink
merge from main
Browse files Browse the repository at this point in the history
  • Loading branch information
sezna committed Sep 17, 2024
2 parents 8973d25 + 82e2a62 commit 411205a
Show file tree
Hide file tree
Showing 13 changed files with 209 additions and 97 deletions.
2 changes: 1 addition & 1 deletion compiler/qsc_eval/src/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ pub(crate) fn call(
Err(_) => Err(Error::OutputFail(name_span)),
}
}
"Relabel" => qubit_relabel(arg, arg_span, |q0, q1| sim.qubit_swap_id(q0, q1)),
"PermuteLabels" => qubit_relabel(arg, arg_span, |q0, q1| sim.qubit_swap_id(q0, q1)),
"Message" => match out.message(&arg.unwrap_string()) {
Ok(()) => Ok(Value::unit()),
Err(_) => Err(Error::OutputFail(name_span)),
Expand Down
4 changes: 2 additions & 2 deletions compiler/qsc_eval/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3724,7 +3724,7 @@ fn controlled_operation_with_duplicate_controls_fails() {
1,
),
item: LocalItemId(
131,
132,
),
},
caller: PackageId(
Expand Down Expand Up @@ -3774,7 +3774,7 @@ fn controlled_operation_with_target_in_controls_fails() {
1,
),
item: LocalItemId(
131,
132,
),
},
caller: PackageId(
Expand Down
2 changes: 1 addition & 1 deletion compiler/qsc_partial_eval/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1293,7 +1293,7 @@ impl<'a> PartialEvaluator<'a> {
// Qubit allocations and measurements have special handling.
"__quantum__rt__qubit_allocate" => Ok(self.allocate_qubit()),
"__quantum__rt__qubit_release" => Ok(self.release_qubit(args_value)),
"Relabel" => qubit_relabel(args_value, args_span, |q0, q1| {
"PermuteLabels" => qubit_relabel(args_value, args_span, |q0, q1| {
self.resource_manager.swap_qubit_ids(Qubit(q0), Qubit(q1));
})
.map_err(std::convert::Into::into),
Expand Down
21 changes: 21 additions & 0 deletions library/src/tests/canon.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,27 @@ fn check_relabel_four_qubit_shuffle_permutation() {
);
}

#[test]
fn check_relabel_adjoint_undoes_permutation() {
test_expression(
"{
use qs = Qubit[3];
// Prepare |01+⟩
X(qs[1]);
H(qs[2]);
Relabel([qs[0], qs[1], qs[2]], [qs[1], qs[2], qs[0]]);
// Expected state is |1+0⟩, perform part of the adjoint to correct one of the qubits.
X(qs[0]);
Adjoint Relabel([qs[0], qs[1], qs[2]], [qs[1], qs[2], qs[0]]);
// Expected state is now |00+⟩, perform the rest of the adjoint to get back to ground state,
// using the original qubit ids.
H(qs[2]);
// Qubit release will fail if the state is not |000⟩
}",
&Value::unit(),
);
}

#[test]
fn check_apply_cnot_chain_2() {
test_expression(
Expand Down
16 changes: 13 additions & 3 deletions library/std/src/Std/Canon.qs
Original file line number Diff line number Diff line change
Expand Up @@ -583,8 +583,7 @@ operation ApplyXorInPlaceL(value : BigInt, target : Qubit[]) : Unit is Adj + Ctl
}
adjoint self;
}

/// # Summary
/// # Summary
/// Relabels the qubits in the `current` array with the qubits in the `updated` array. The `updated` array
/// must be a valid permutation of the `current` array.
///
Expand Down Expand Up @@ -612,7 +611,18 @@ operation ApplyXorInPlaceL(value : BigInt, target : Qubit[]) : Unit is Adj + Ctl
/// use (q0, q1) = (Qubit(), Qubit());
/// Relabel([q0, q1], [q1, q0]);
/// ```
operation Relabel(current : Qubit[], updated : Qubit[]) : Unit {
/// Note that the adjoint of this operation effectively changes the order of arguments, such that
/// `Adjoint Relabel(qubits, newOrder)` is equivalent to `Relabel(newOrder, qubits)`.
operation Relabel(current : Qubit[], updated : Qubit[]) : Unit is Adj {
body ... {
PermuteLabels(current, updated);
}
adjoint ... {
PermuteLabels(updated, current);
}
}

operation PermuteLabels(current : Qubit[], updated : Qubit[]) : Unit {
body intrinsic;
}

Expand Down
2 changes: 1 addition & 1 deletion resource_estimator/src/estimates.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,6 @@ pub use physical_estimation::{
};
mod layout;
mod logical_qubit;
pub use layout::Overhead;
pub use layout::{Overhead, RealizedOverhead};
pub use logical_qubit::LogicalPatch;
pub mod optimization;
65 changes: 65 additions & 0 deletions resource_estimator/src/estimates/layout.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

use serde::Serialize;

use super::ErrorBudget;

/// Trait to model post-layout logical overhead
Expand All @@ -22,3 +24,66 @@ pub trait Overhead {
/// supported by available factory builders in the physical estimation.
fn num_magic_states(&self, budget: &ErrorBudget, index: usize) -> u64;
}

/// This is the realized logical overhead after applying an error budget. This
/// structure has two purposes: 1) it is used to store the realized logical
/// overhead, once the error budget partition is decided into the resource
/// estimation result; 2) it can be used to pass a logical overhead to the
/// resource estimation API, if it does not depend on the error budget, since it
/// also implements the [`Overhead`] trait.
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub struct RealizedOverhead {
logical_qubits: u64,
logical_depth: u64,
num_magic_states: Vec<u64>,
}

impl RealizedOverhead {
pub fn from_overhead(
overhead: &impl Overhead,
budget: &ErrorBudget,
num_magic_state_types: usize,
) -> Self {
let logical_qubits = overhead.logical_qubits();
let logical_depth = overhead.logical_depth(budget);
let num_magic_states = (0..num_magic_state_types)
.map(|index| overhead.num_magic_states(budget, index))
.collect();

Self {
logical_qubits,
logical_depth,
num_magic_states,
}
}

#[must_use]
pub fn logical_qubits(&self) -> u64 {
self.logical_qubits
}

#[must_use]
pub fn logical_depth(&self) -> u64 {
self.logical_depth
}

#[must_use]
pub fn num_magic_states(&self) -> &[u64] {
&self.num_magic_states
}
}

impl Overhead for RealizedOverhead {
fn logical_qubits(&self) -> u64 {
self.logical_qubits
}

fn logical_depth(&self, _budget: &ErrorBudget) -> u64 {
self.logical_depth
}

fn num_magic_states(&self, _budget: &ErrorBudget, index: usize) -> u64 {
self.num_magic_states[index]
}
}
26 changes: 16 additions & 10 deletions resource_estimator/src/estimates/physical_estimation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,10 @@ impl<
}
}

pub fn error_correction(&self) -> &E {
&self.ftp
}

pub fn layout_overhead(&self) -> &L {
&self.layout_overhead
}
Expand All @@ -274,13 +278,15 @@ impl<
self.max_physical_qubits = Some(max_physical_qubits);
}

pub fn factory_builder(&self) -> &Builder {
&self.factory_builder
}

pub fn factory_builder_mut(&mut self) -> &mut Builder {
&mut self.factory_builder
}

pub fn estimate(
&self,
) -> Result<PhysicalResourceEstimationResult<E, Builder::Factory, L>, Error> {
pub fn estimate(&self) -> Result<PhysicalResourceEstimationResult<E, Builder::Factory>, Error> {
match (self.max_duration, self.max_physical_qubits) {
(None, None) => self.estimate_without_restrictions(),
(None, Some(max_physical_qubits)) => {
Expand All @@ -294,7 +300,7 @@ impl<
#[allow(clippy::too_many_lines, clippy::type_complexity)]
pub fn build_frontier(
&self,
) -> Result<Vec<PhysicalResourceEstimationResult<E, Builder::Factory, L>>, Error> {
) -> Result<Vec<PhysicalResourceEstimationResult<E, Builder::Factory>>, Error> {
if self.factory_builder.num_magic_state_types() != 1 {
return Err(Error::MultipleMagicStatesNotSupported);
}
Expand Down Expand Up @@ -329,7 +335,7 @@ impl<
}

let mut best_estimation_results =
Population::<Point2D<PhysicalResourceEstimationResult<E, Builder::Factory, L>>>::new();
Population::<Point2D<PhysicalResourceEstimationResult<E, Builder::Factory>>>::new();

let mut last_factories = Vec::new();
let mut last_code_parameter = None;
Expand Down Expand Up @@ -455,7 +461,7 @@ impl<

pub fn estimate_without_restrictions(
&self,
) -> Result<PhysicalResourceEstimationResult<E, Builder::Factory, L>, Error> {
) -> Result<PhysicalResourceEstimationResult<E, Builder::Factory>, Error> {
let mut num_cycles = self.compute_num_cycles()?;

loop {
Expand Down Expand Up @@ -616,7 +622,7 @@ impl<
pub fn estimate_with_max_duration(
&self,
max_duration_in_nanoseconds: u64,
) -> Result<PhysicalResourceEstimationResult<E, Builder::Factory, L>, Error> {
) -> Result<PhysicalResourceEstimationResult<E, Builder::Factory>, Error> {
if self.factory_builder.num_magic_state_types() != 1 {
return Err(Error::MultipleMagicStatesNotSupported);
}
Expand Down Expand Up @@ -647,7 +653,7 @@ impl<
}

let mut best_estimation_result: Option<
PhysicalResourceEstimationResult<E, Builder::Factory, L>,
PhysicalResourceEstimationResult<E, Builder::Factory>,
> = None;

let mut last_factories = Vec::new();
Expand Down Expand Up @@ -767,7 +773,7 @@ impl<
pub fn estimate_with_max_num_qubits(
&self,
max_num_qubits: u64,
) -> Result<PhysicalResourceEstimationResult<E, Builder::Factory, L>, Error> {
) -> Result<PhysicalResourceEstimationResult<E, Builder::Factory>, Error> {
if self.factory_builder.num_magic_state_types() != 1 {
return Err(Error::MultipleMagicStatesNotSupported);
}
Expand Down Expand Up @@ -795,7 +801,7 @@ impl<
}

let mut best_estimation_result: Option<
PhysicalResourceEstimationResult<E, Builder::Factory, L>,
PhysicalResourceEstimationResult<E, Builder::Factory>,
> = None;

let mut last_factories = Vec::new();
Expand Down
41 changes: 23 additions & 18 deletions resource_estimator/src/estimates/physical_estimation/result.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

use std::rc::Rc;

use serde::Serialize;

use crate::estimates::{
ErrorBudget, ErrorCorrection, Factory, FactoryBuilder, LogicalPatch, Overhead,
PhysicalResourceEstimation,
PhysicalResourceEstimation, RealizedOverhead,
};

/// Resource estimation result
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub struct PhysicalResourceEstimationResult<E: ErrorCorrection, F, L> {
pub struct PhysicalResourceEstimationResult<E: ErrorCorrection, F> {
#[serde(bound = "E::Parameter: Serialize")]
logical_patch: LogicalPatch<E>,
num_cycles: u64,
Expand All @@ -25,19 +23,19 @@ pub struct PhysicalResourceEstimationResult<E: ErrorCorrection, F, L> {
physical_qubits: u64,
runtime: u64,
rqops: u64,
#[serde(skip)]
layout_overhead: Rc<L>,
layout_overhead: RealizedOverhead,
error_budget: ErrorBudget,
}

impl<
E: ErrorCorrection<Parameter = impl Clone>,
F: Factory<Parameter = E::Parameter> + Clone,
L: Overhead,
> PhysicalResourceEstimationResult<E, F, L>
impl<E: ErrorCorrection<Parameter = impl Clone>, F: Factory<Parameter = E::Parameter> + Clone>
PhysicalResourceEstimationResult<E, F>
{
pub fn new(
estimation: &PhysicalResourceEstimation<E, impl FactoryBuilder<E, Factory = F>, L>,
estimation: &PhysicalResourceEstimation<
E,
impl FactoryBuilder<E, Factory = F>,
impl Overhead,
>,
logical_patch: LogicalPatch<E>,
num_cycles: u64,
factory_parts: Vec<Option<FactoryPart<F>>>,
Expand Down Expand Up @@ -71,13 +69,21 @@ impl<
physical_qubits,
runtime,
rqops,
layout_overhead: estimation.layout_overhead.clone(),
layout_overhead: RealizedOverhead::from_overhead(
estimation.layout_overhead(),
estimation.error_budget(),
estimation.factory_builder().num_magic_state_types(),
),
error_budget: estimation.error_budget().clone(),
}
}

pub fn without_factories(
estimation: &PhysicalResourceEstimation<E, impl FactoryBuilder<E, Factory = F>, L>,
estimation: &PhysicalResourceEstimation<
E,
impl FactoryBuilder<E, Factory = F>,
impl Overhead,
>,
logical_patch: LogicalPatch<E>,
num_cycles: u64,
required_logical_patch_error_rate: f64,
Expand Down Expand Up @@ -136,7 +142,7 @@ impl<
self.rqops
}

pub fn layout_overhead(&self) -> &Rc<L> {
pub fn layout_overhead(&self) -> &RealizedOverhead {
&self.layout_overhead
}

Expand All @@ -145,14 +151,13 @@ impl<
}

pub fn algorithmic_logical_depth(&self) -> u64 {
self.layout_overhead.logical_depth(&self.error_budget)
self.layout_overhead.logical_depth()
}

/// The argument index indicates for which type of magic state (starting
/// from 0) the number is requested for.
pub fn num_magic_states(&self, index: usize) -> u64 {
self.layout_overhead
.num_magic_states(&self.error_budget, index)
self.layout_overhead.num_magic_states()[index]
}
}

Expand Down
Loading

0 comments on commit 411205a

Please sign in to comment.