Skip to content

Commit

Permalink
Make SpreadZ utility iterative instead of recursive (#1545)
Browse files Browse the repository at this point in the history
This updates the internal utility for `SpreadZ` as used by
`Microsoft.Quantum.Intrinsic.Exp` to use an iterative algorith rather
than recursive. This allows `Exp` to be used when generating QIR
adaptive profile code, where RCA rejects call cycles.
  • Loading branch information
swernli authored May 21, 2024
1 parent f8d344b commit 8f00e81
Show file tree
Hide file tree
Showing 2 changed files with 204 additions and 6 deletions.
183 changes: 183 additions & 0 deletions library/src/tests/intrinsic.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

#![allow(clippy::needless_raw_string_hashes, clippy::too_many_lines)]

use expect_test::expect;
use indoc::indoc;
use qsc::{interpret::Value, target::Profile, SparseSim};
Expand Down Expand Up @@ -2825,3 +2827,184 @@ fn global_phase_correct_for_triply_controlled_adjoint_r1() {
"#]]
.assert_eq(&dump);
}

#[test]
fn test_exp() {
let dump = test_expression(
indoc! {r#"
{
open Microsoft.Quantum.Math;
open Microsoft.Quantum.Diagnostics;
for p in [PauliX, PauliY, PauliZ, PauliI] {
for i in 1 .. 4 {
Message($"Exp with {p} on {i} qubits:");
use qs = Qubit[i];
for q in qs {
H(q);
}
Exp(Repeated(p, i), PI() / 7.0, qs);
DumpMachine();
ResetAll(qs);
}
}
}
"#},
&Value::unit(),
);

expect![[r#"
Exp with PauliX on 1 qubits:
STATE:
|0⟩: 0.6371+0.3068𝑖
|1⟩: 0.6371+0.3068𝑖
Exp with PauliX on 2 qubits:
STATE:
|00⟩: 0.4505+0.2169𝑖
|01⟩: 0.4505+0.2169𝑖
|10⟩: 0.4505+0.2169𝑖
|11⟩: 0.4505+0.2169𝑖
Exp with PauliX on 3 qubits:
STATE:
|000⟩: 0.3185+0.1534𝑖
|001⟩: 0.3185+0.1534𝑖
|010⟩: 0.3185+0.1534𝑖
|011⟩: 0.3185+0.1534𝑖
|100⟩: 0.3185+0.1534𝑖
|101⟩: 0.3185+0.1534𝑖
|110⟩: 0.3185+0.1534𝑖
|111⟩: 0.3185+0.1534𝑖
Exp with PauliX on 4 qubits:
STATE:
|0000⟩: 0.2252+0.1085𝑖
|0001⟩: 0.2252+0.1085𝑖
|0010⟩: 0.2252+0.1085𝑖
|0011⟩: 0.2252+0.1085𝑖
|0100⟩: 0.2252+0.1085𝑖
|0101⟩: 0.2252+0.1085𝑖
|0110⟩: 0.2252+0.1085𝑖
|0111⟩: 0.2252+0.1085𝑖
|1000⟩: 0.2252+0.1085𝑖
|1001⟩: 0.2252+0.1085𝑖
|1010⟩: 0.2252+0.1085𝑖
|1011⟩: 0.2252+0.1085𝑖
|1100⟩: 0.2252+0.1085𝑖
|1101⟩: 0.2252+0.1085𝑖
|1110⟩: 0.2252+0.1085𝑖
|1111⟩: 0.2252+0.1085𝑖
Exp with PauliY on 1 qubits:
STATE:
|0⟩: 0.9439+0.0000𝑖
|1⟩: 0.3303+0.0000𝑖
Exp with PauliY on 2 qubits:
STATE:
|00⟩: 0.4505−0.2169𝑖
|01⟩: 0.4505+0.2169𝑖
|10⟩: 0.4505+0.2169𝑖
|11⟩: 0.4505−0.2169𝑖
Exp with PauliY on 3 qubits:
STATE:
|000⟩: 0.1651+0.0000𝑖
|001⟩: 0.4719+0.0000𝑖
|010⟩: 0.4719+0.0000𝑖
|011⟩: 0.1651+0.0000𝑖
|100⟩: 0.4719+0.0000𝑖
|101⟩: 0.1651+0.0000𝑖
|110⟩: 0.1651+0.0000𝑖
|111⟩: 0.4719+0.0000𝑖
Exp with PauliY on 4 qubits:
STATE:
|0000⟩: 0.2252+0.1085𝑖
|0001⟩: 0.2252−0.1085𝑖
|0010⟩: 0.2252−0.1085𝑖
|0011⟩: 0.2252+0.1085𝑖
|0100⟩: 0.2252−0.1085𝑖
|0101⟩: 0.2252+0.1085𝑖
|0110⟩: 0.2252+0.1085𝑖
|0111⟩: 0.2252−0.1085𝑖
|1000⟩: 0.2252−0.1085𝑖
|1001⟩: 0.2252+0.1085𝑖
|1010⟩: 0.2252+0.1085𝑖
|1011⟩: 0.2252−0.1085𝑖
|1100⟩: 0.2252+0.1085𝑖
|1101⟩: 0.2252−0.1085𝑖
|1110⟩: 0.2252−0.1085𝑖
|1111⟩: 0.2252+0.1085𝑖
Exp with PauliZ on 1 qubits:
STATE:
|0⟩: 0.6371+0.3068𝑖
|1⟩: 0.6371−0.3068𝑖
Exp with PauliZ on 2 qubits:
STATE:
|00⟩: 0.4505+0.2169𝑖
|01⟩: 0.4505−0.2169𝑖
|10⟩: 0.4505−0.2169𝑖
|11⟩: 0.4505+0.2169𝑖
Exp with PauliZ on 3 qubits:
STATE:
|000⟩: 0.3185+0.1534𝑖
|001⟩: 0.3185−0.1534𝑖
|010⟩: 0.3185−0.1534𝑖
|011⟩: 0.3185+0.1534𝑖
|100⟩: 0.3185−0.1534𝑖
|101⟩: 0.3185+0.1534𝑖
|110⟩: 0.3185+0.1534𝑖
|111⟩: 0.3185−0.1534𝑖
Exp with PauliZ on 4 qubits:
STATE:
|0000⟩: 0.2252+0.1085𝑖
|0001⟩: 0.2252−0.1085𝑖
|0010⟩: 0.2252−0.1085𝑖
|0011⟩: 0.2252+0.1085𝑖
|0100⟩: 0.2252−0.1085𝑖
|0101⟩: 0.2252+0.1085𝑖
|0110⟩: 0.2252+0.1085𝑖
|0111⟩: 0.2252−0.1085𝑖
|1000⟩: 0.2252−0.1085𝑖
|1001⟩: 0.2252+0.1085𝑖
|1010⟩: 0.2252+0.1085𝑖
|1011⟩: 0.2252−0.1085𝑖
|1100⟩: 0.2252+0.1085𝑖
|1101⟩: 0.2252−0.1085𝑖
|1110⟩: 0.2252−0.1085𝑖
|1111⟩: 0.2252+0.1085𝑖
Exp with PauliI on 1 qubits:
STATE:
|0⟩: 0.6371+0.3068𝑖
|1⟩: 0.6371+0.3068𝑖
Exp with PauliI on 2 qubits:
STATE:
|00⟩: 0.4505+0.2169𝑖
|01⟩: 0.4505+0.2169𝑖
|10⟩: 0.4505+0.2169𝑖
|11⟩: 0.4505+0.2169𝑖
Exp with PauliI on 3 qubits:
STATE:
|000⟩: 0.3185+0.1534𝑖
|001⟩: 0.3185+0.1534𝑖
|010⟩: 0.3185+0.1534𝑖
|011⟩: 0.3185+0.1534𝑖
|100⟩: 0.3185+0.1534𝑖
|101⟩: 0.3185+0.1534𝑖
|110⟩: 0.3185+0.1534𝑖
|111⟩: 0.3185+0.1534𝑖
Exp with PauliI on 4 qubits:
STATE:
|0000⟩: 0.2252+0.1085𝑖
|0001⟩: 0.2252+0.1085𝑖
|0010⟩: 0.2252+0.1085𝑖
|0011⟩: 0.2252+0.1085𝑖
|0100⟩: 0.2252+0.1085𝑖
|0101⟩: 0.2252+0.1085𝑖
|0110⟩: 0.2252+0.1085𝑖
|0111⟩: 0.2252+0.1085𝑖
|1000⟩: 0.2252+0.1085𝑖
|1001⟩: 0.2252+0.1085𝑖
|1010⟩: 0.2252+0.1085𝑖
|1011⟩: 0.2252+0.1085𝑖
|1100⟩: 0.2252+0.1085𝑖
|1101⟩: 0.2252+0.1085𝑖
|1110⟩: 0.2252+0.1085𝑖
|1111⟩: 0.2252+0.1085𝑖
"#]]
.assert_eq(&dump);
}
27 changes: 21 additions & 6 deletions library/std/internal.qs
Original file line number Diff line number Diff line change
Expand Up @@ -241,13 +241,28 @@ namespace Microsoft.Quantum.Intrinsic {
}

internal operation SpreadZ(from : Qubit, to : Qubit[]) : Unit is Adj {
if (Length(to) > 0) {
if (Length(to) > 1) {
let half = Length(to) / 2;
SpreadZ(to[0], to[half + 1..Length(to) - 1]);
SpreadZ(from, to[1..half]);
let targets = GetSpread(from, to);
for (ctl, tgt) in targets {
CNOT(ctl, tgt);
}
}

internal function GetSpread(from : Qubit, to : Qubit[]) : (Qubit, Qubit)[] {
mutable queue = [(from, to)];
mutable targets = [];
while Length(queue) > 0 {
mutable (next, rest) = (queue[0], queue[1...]);
set queue = rest;
let (next_from, next_to) = next;
if Length(next_to) > 0 {
set targets = [(next_to[0], next_from)] + targets;
if Length(next_to) > 1 {
let half = Length(next_to) / 2;
set queue = [(next_from, next_to[1..half]), (next_to[0], next_to[(half + 1)...])] + rest;
}
}
CNOT(to[0], from);
}

targets
}
}

0 comments on commit 8f00e81

Please sign in to comment.