Repository: microsoft/qsharp
Pull request #2185 (2025-02-15 12:35:02)

Multi-target gate circuit art improvement
This PR has a proposed fix for issue https://github.com/microsoft/qsharp/issues/2184, but it mainly includes refactoring of the circuit-art code based on comments from PR https://github.com/microsoft/qsharp/pull/2126.

The only real functionality change in this code is that multi-target gates get extra lines that behave in the same way as measurement lines, in order to better convey the qubits involved.

For example, a circuit like this one:
```
use q0 = Qubit();
use q1 = Qubit();
Rxx(1.0, q0, q1);

use q2 = Qubit();
use q3 = Qubit();
Rxx(1.0, q2, q3);
```
instead of rendering as
```
q_0    ─ rxx(1.0000) ─
q_1    ─ rxx(1.0000) ─
q_2    ─ rxx(1.0000) ─
q_3    ─ rxx(1.0000) ─
```
will instead render as 
```
q_0    ─ rxx(1.0000) ─
              ┆
q_1    ─ rxx(1.0000) ─
q_2    ─ rxx(1.0000) ─
              ┆
q_3    ─ rxx(1.0000) ─
```

This is very similar to what we get if we measure the first qubit of each of these two-qubit gate, i.e.
```
q_0    ─ rxx(1.0000) ─── M ──
              ┆          ╘═══
q_1    ─ rxx(1.0000) ────────
q_2    ─ rxx(1.0000) ─── M ──
              ┆          ╘═══
q_3    ─ rxx(1.0000) ────────
```

On top of this change in rendering, the first few commits in this PR are actually just code refactoring. As such, it's probably best to review this PR commit by commit, for two reason - a. it's going to be much easier to follow, and b. any of these commits can be reverted if you think they make the code more complicated instead of making it easier to read.

The commits are as follows:
1. [a400655](https://github.com/microsoft/qsharp/pull/2185/commits/a4006557b4b0fcd0bacd14c5c1142eeecefbaa76) A rework of PR https://github.com/microsoft/qsharp/pull/2126, which, to be honest, is how I think I should have implemented it in the first place.
2. [c141799](https://github.com/microsoft/qsharp/pull/2185/commits/c14179907ed45ebd02e07199db85a401edaf61b1) A cleanup based on [this comment](https://github.com/microsoft/qsharp/pull/2126#pullrequestreview-2579485021). It makes the code significantly better, in my opinion.
3. [4012ee8](https://github.com/microsoft/qsharp/pull/2185/commits/4012ee8378f0080cf79b2220dead041ccc964edf) A small simplification to have the ColumnRenderer have a `new` method which is in charge of making sure that the column width is an odd number, and also a `Default` trait implementation for the case where we don't need a specific width.
4. [cfa7382](https://github.com/microsoft/qsharp/pull/2185/commits/cfa7382630b83ee0aefd64ee414ca6b5b600f2d2) This is the actual enhancement - it makes sure there is a classical line (same as what you get from a measurement) if there are two consecutive qubits for the same operation. If you think there is a better solution to make the rendering clearer, let me know. But of the ones I could think of, I found this one to be the least disruptive one (to both the existing code, and the existing circuits).

minestarks: Heads up to @ScottCarda-MS who I think has been working near this code.

Patch:
diff --git a/compiler/qsc_circuit/src/circuit.rs b/compiler/qsc_circuit/src/circuit.rs
index 47bd66fa..da101293 100644
--- a/compiler/qsc_circuit/src/circuit.rs
+++ b/compiler/qsc_circuit/src/circuit.rs
@@ -4,9 +4,9 @@
 #[cfg(test)]
 mod tests;
 
-use rustc_hash::FxHashMap;
+use rustc_hash::{FxHashMap, FxHashSet};
 use serde::Serialize;
-use std::{fmt::Display, fmt::Write, ops::Not, vec};
+use std::{cmp, fmt::Display, fmt::Write, ops::Not, vec};
 
 /// Representation of a quantum circuit.
 /// Implementation of `CircuitData` type from `qsharp-lang` npm package.
@@ -96,7 +96,6 @@ impl Config {
 }
 
 type ObjectsByColumn = FxHashMap<usize, CircuitObject>;
-type ColumnWidthsByColumn = FxHashMap<usize, usize>;
 
 struct Row {
     wire: Wire,
@@ -110,6 +109,8 @@ enum Wire {
 }
 
 enum CircuitObject {
+    Blank,
+    Wire,
     WireCross,
     WireStart,
     DashedCross,
@@ -178,38 +179,30 @@ impl Row {
         self.next_column = column + 1;
     }
 
-    fn fmt(
-        &self,
-        f: &mut std::fmt::Formatter<'_>,
-        column_widths: &ColumnWidthsByColumn,
-        end_column: usize,
-    ) -> std::fmt::Result {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>, columns: &[Column]) -> std::fmt::Result {
         // Temporary string so we can trim whitespace at the end
         let mut s = String::new();
         match &self.wire {
             Wire::Qubit { q_id: label } => {
                 s.write_str(&fmt_qubit_label(*label))?;
-                for column in 1..end_column {
-                    let val = self.objects.get(&column);
-                    let column_width = *column_widths.get(&column).unwrap_or(&MIN_COLUMN_WIDTH);
-                    if let Some(v) = val {
-                        s.write_str(&fmt_qubit_circuit_object(v, column_width))?;
-                    } else {
-                        s.write_str(&get_qubit_wire(column_width))?;
-                    }
+                for (column_index, column) in columns.iter().enumerate().skip(1) {
+                    let val = self.objects.get(&column_index);
+                    let object = val.unwrap_or(&CircuitObject::Wire);
+
+                    s.write_str(&column.fmt_qubit_circuit_object(object))?;
                 }
             }
             Wire::Classical { start_column } => {
-                for column in 0..end_column {
-                    let val = self.objects.get(&column);
-                    let column_width = *column_widths.get(&column).unwrap_or(&MIN_COLUMN_WIDTH);
-                    if let Some(v) = val {
-                        s.write_str(&fmt_classical_circuit_object(v, column_width))?;
-                    } else if start_column.map_or(false, |s| column > s) {
-                        s.write_str(&get_classical_wire(column_width))?;
-                    } else {
-                        s.write_str(&get_blank(column_width))?;
-                    }
+                for (column_index, column) in columns.iter().enumerate() {
+                    let val = self.objects.get(&column_index);
+
+                    let object = match (val, start_column) {
+                        (Some(v), _) => v,
+                        (None, Some(s)) if column_index > *s => &CircuitObject::Wire,
+                        _ => &CircuitObject::Blank,
+                    };
+
+                    s.write_str(&column.fmt_classical_circuit_object(object))?;
                 }
             }
         }
@@ -220,100 +213,101 @@ impl Row {
 
 const MIN_COLUMN_WIDTH: usize = 7;
 
-/// "───────"
-fn get_qubit_wire(column_width: usize) -> String {
-    "─".repeat(column_width)
-}
-
-/// "═══════"
-fn get_classical_wire(column_width: usize) -> String {
-    "═".repeat(column_width)
-}
-
-/// "───┼───"
-fn get_qubit_wire_cross(column_width: usize) -> String {
-    let half_width = "─".repeat(column_width / 2);
-    format!("{}┼{}", half_width, half_width)
-}
-
-/// "═══╪═══"
-fn get_classical_wire_cross(column_width: usize) -> String {
-    let half_width = "═".repeat(column_width / 2);
-    format!("{}╪{}", half_width, half_width)
-}
+const QUBIT_WIRE: [char; 3] = ['─', '─', '─']; // "───────"
+const CLASSICAL_WIRE: [char; 3] = ['═', '═', '═']; // "═══════"
+const QUBIT_WIRE_CROSS: [char; 3] = ['─', '┼', '─']; // "───┼───"
+const CLASSICAL_WIRE_CROSS: [char; 3] = ['═', '╪', '═']; // "═══╪═══"
+const CLASSICAL_WIRE_START: [char; 3] = [' ', '╘', '═']; // "   ╘═══"
+const QUBIT_WIRE_DASHED_CROSS: [char; 3] = ['─', '┆', '─']; // "───┆───"
+const CLASSICAL_WIRE_DASHED_CROSS: [char; 3] = ['═', '┆', '═']; // "═══┆═══"
+const VERTICAL_DASHED: [char; 3] = [' ', '┆', ' ']; // "   │   "
+const VERTICAL: [char; 3] = [' ', '│', ' ']; // "   ┆   "
+const BLANK: [char; 3] = [' ', ' ', ' ']; // "       "
 
-/// "   ╘═══"
-fn get_classical_wire_start(column_width: usize) -> String {
-    let first_half_width = " ".repeat(column_width / 2);
-    let second_half_width = "═".repeat(column_width / 2);
-    format!("{}╘{}", first_half_width, second_half_width)
+/// "q_0  "
+#[allow(clippy::doc_markdown)]
+fn fmt_qubit_label(id: usize) -> String {
+    let rest = MIN_COLUMN_WIDTH - 2;
+    format!("q_{id: <rest$}")
 }
 
-/// "───┆───"
-fn get_qubit_wire_dashed_cross(column_width: usize) -> String {
-    let half_width = "─".repeat(column_width / 2);
-    format!("{}┆{}", half_width, half_width)
+struct Column {
+    column_width: usize,
 }
 
-/// "═══┆═══"
-fn get_classical_wire_dashed_cross(column_width: usize) -> String {
-    let half_width = "═".repeat(column_width / 2);
-    format!("{}┆{}", half_width, half_width)
+impl Default for Column {
+    fn default() -> Self {
+        Self {
+            column_width: MIN_COLUMN_WIDTH,
+        }
+    }
 }
 
-/// "   │   "
-fn get_vertical(column_width: usize) -> String {
-    let half_width = " ".repeat(column_width / 2);
-    format!("{}│{}", half_width, half_width)
-}
+impl Column {
+    fn new(column_width: usize) -> Self {
+        // Column widths should be odd numbers for this struct to work well
+        let odd_column_width = column_width | 1;
+        Self {
+            column_width: odd_column_width,
+        }
+    }
 
-/// "   ┆   "
-fn get_vertical_dashed(column_width: usize) -> String {
-    let half_width = " ".repeat(column_width / 2);
-    format!("{}┆{}", half_width, half_width)
-}
+    /// "── A ──"
+    fn fmt_on_qubit_wire(&self, obj: &str) -> String {
+        let column_width = self.column_width;
+        format!("{:─^column_width$}", format!(" {obj} "))
+    }
 
-/// "       "
-fn get_blank(column_width: usize) -> String {
-    " ".repeat(column_width)
-}
+    /// "══ A ══"
+    fn fmt_on_classical_wire(&self, obj: &str) -> String {
+        let column_width = self.column_width;
+        format!("{:═^column_width$}", format!(" {obj} "))
+    }
 
-/// "q_0  "
-#[allow(clippy::doc_markdown)]
-fn fmt_qubit_label(id: usize) -> String {
-    let rest = MIN_COLUMN_WIDTH - 2;
-    format!("q_{id: <rest$}")
-}
+    fn expand_template(&self, template: &[char; 3]) -> String {
+        let half_width = self.column_width / 2;
+        let left = template[0].to_string().repeat(half_width);
+        let right = template[2].to_string().repeat(half_width);
 
-/// "── A ──"
-fn fmt_on_qubit_wire(obj: &str, column_width: usize) -> String {
-    format!("{:─^column_width$}", format!(" {obj} "))
-}
+        format!("{left}{}{right}", template[1])
+    }
 
-/// "══ A ══"
-fn fmt_on_classical_wire(obj: &str, column_width: usize) -> String {
-    format!("{:═^column_width$}", format!(" {obj} "))
-}
+    fn fmt_classical_circuit_object(&self, circuit_object: &CircuitObject) -> String {
+        if let CircuitObject::Object(label) = circuit_object {
+            return self.fmt_on_classical_wire(label.as_str());
+        }
 
-fn fmt_classical_circuit_object(circuit_object: &CircuitObject, column_width: usize) -> String {
-    match circuit_object {
-        CircuitObject::WireCross => get_classical_wire_cross(column_width),
-        CircuitObject::WireStart => get_classical_wire_start(column_width),
-        CircuitObject::DashedCross => get_classical_wire_dashed_cross(column_width),
-        CircuitObject::Vertical => get_vertical(column_width),
-        CircuitObject::VerticalDashed => get_vertical_dashed(column_width),
-        CircuitObject::Object(label) => fmt_on_classical_wire(label.as_str(), column_width),
+        let template = match circuit_object {
+            CircuitObject::Blank => BLANK,
+            CircuitObject::Wire => CLASSICAL_WIRE,
+            CircuitObject::WireCross => CLASSICAL_WIRE_CROSS,
+            CircuitObject::WireStart => CLASSICAL_WIRE_START,
+            CircuitObject::DashedCross => CLASSICAL_WIRE_DASHED_CROSS,
+            CircuitObject::Vertical => VERTICAL,
+            CircuitObject::VerticalDashed => VERTICAL_DASHED,
+            CircuitObject::Object(_) => unreachable!("This case is covered in the early return."),
+        };
+
+        self.expand_template(&template)
     }
-}
 
-fn fmt_qubit_circuit_object(circuit_object: &CircuitObject, column_width: usize) -> String {
-    match circuit_object {
-        CircuitObject::WireCross => get_qubit_wire_cross(column_width),
-        CircuitObject::WireStart => get_blank(column_width), // This should never happen
-        CircuitObject::DashedCross => get_qubit_wire_dashed_cross(column_width),
-        CircuitObject::Vertical => get_vertical(column_width),
-        CircuitObject::VerticalDashed => get_vertical_dashed(column_width),
-        CircuitObject::Object(label) => fmt_on_qubit_wire(label.as_str(), column_width),
+    fn fmt_qubit_circuit_object(&self, circuit_object: &CircuitObject) -> String {
+        if let CircuitObject::Object(label) = circuit_object {
+            return self.fmt_on_qubit_wire(label.as_str());
+        }
+
+        let template = match circuit_object {
+            CircuitObject::Blank => BLANK,
+            CircuitObject::Wire => QUBIT_WIRE,
+            CircuitObject::WireCross => QUBIT_WIRE_CROSS,
+            CircuitObject::WireStart => BLANK, // This should never happen
+            CircuitObject::DashedCross => QUBIT_WIRE_DASHED_CROSS,
+            CircuitObject::Vertical => VERTICAL,
+            CircuitObject::VerticalDashed => VERTICAL_DASHED,
+            CircuitObject::Object(_) => unreachable!("This case is covered in the early return."),
+        };
+
+        self.expand_template(&template)
     }
 }
 
@@ -325,6 +319,27 @@ impl Display for Circuit {
         // to row in the diagram
         let mut register_to_row = FxHashMap::default();
 
+        // Keep track of which qubits have the qubit after them in the same multi-qubit operation,
+        // because those qubits need to get a gap row below them.
+        let mut qubits_with_gap_row_below = FxHashSet::default();
+
+        for operation in self.operations.iter() {
+            for target in operation.targets.iter() {
+                let qubit = target.q_id;
+
+                if qubits_with_gap_row_below.contains(&qubit) {
+                    continue;
+                }
+
+                let next_qubit = qubit + 1;
+
+                // Check if the next qubit is also in this operation.
+                if operation.targets.iter().any(|t| t.q_id == next_qubit) {
+                    qubits_with_gap_row_below.insert(qubit);
+                }
+            }
+        }
+
         // Initialize all qubit and classical wires
         for q in &self.qubits {
             rows.push(Row {
@@ -335,7 +350,16 @@ impl Display for Circuit {
 
             register_to_row.insert((q.id, None), rows.len() - 1);
 
-            for i in 0..q.num_children {
+            // If this qubit has no children, but it is in a multi-qubit operation with
+            // the next qubit, we add an empty row to make room for the vertical connector.
+            // We can just use a classical wire type for this row since the wire won't actually be rendered.
+            let extra_rows = if qubits_with_gap_row_below.contains(&q.id) {
+                cmp::max(1, q.num_children)
+            } else {
+                q.num_children
+            };
+
+            for i in 0..extra_rows {
                 rows.push(Row {
                     wire: Wire::Classical { start_column: None },
                     objects: FxHashMap::default(),
@@ -431,14 +455,13 @@ impl Display for Circuit {
 
         // To be able to fit long-named operations, we calculate the required width for each column,
         // based on the maximum length needed for gates, where a gate X is printed as "- X -".
-        let column_widths = (0..end_column)
+        let columns = (0..end_column)
             .map(|column| {
-                (
-                    column,
+                Column::new(
                     rows.iter()
                         .filter_map(|row| row.objects.get(&column))
                         .filter_map(|object| match object {
-                            CircuitObject::Object(string) => Some((string.len() + 4) | 1), // Column lengths need to be odd numbers
+                            CircuitObject::Object(string) => Some(string.len() + 4),
                             _ => None,
                         })
                         .chain(std::iter::once(MIN_COLUMN_WIDTH))
@@ -446,11 +469,11 @@ impl Display for Circuit {
                         .unwrap(),
                 )
             })
-            .collect::<ColumnWidthsByColumn>();
+            .collect::<Vec<_>>();
 
         // Draw the diagram
         for row in rows {
-            row.fmt(f, &column_widths, end_column)?;
+            row.fmt(f, &columns)?;
         }
 
         Ok(())
diff --git a/compiler/qsc_frontend/src/typeck/rules.rs b/compiler/qsc_frontend/src/typeck/rules.rs
index 2afeaaf8..4e4c906c 100644
--- a/compiler/qsc_frontend/src/typeck/rules.rs
+++ b/compiler/qsc_frontend/src/typeck/rules.rs
@@ -399,12 +399,8 @@ impl<'a> Context<'a> {
                     .take()
                     .expect("return type should be present");
                 self.return_ty = prev_ret_ty;
-                if !body_partial.diverges {
-                    // Only when the type of the body converges do we need to unify with the inferred output type.
-                    // Otherwise we'd get spurious errors from lambdas that use explicit return-expr rather than implicit.
-                    self.inferrer
-                        .eq(body.span, output_ty.clone(), body_partial.ty);
-                }
+                self.inferrer
+                    .eq(body.span, body_partial.ty, output_ty.clone());
                 converge(Ty::Arrow(Box::new(Arrow {
                     kind: convert::callable_kind_from_ast(*kind),
                     input: Box::new(input),
diff --git a/katas/content/complex_arithmetic/powers_of_i/index.md b/katas/content/complex_arithmetic/powers_of_i/index.md
index d83ca757..5a3e7dbc 100644
--- a/katas/content/complex_arithmetic/powers_of_i/index.md
+++ b/katas/content/complex_arithmetic/powers_of_i/index.md
@@ -1,3 +1,3 @@
 **Input:** An even integer $n$ (can be negative).
 
-**Goal:** Return the $n$-th power of $i$ ($i^n$).
+**Goal:** Return $i^n$, that is, the $n$-th power of $i$.
diff --git a/library/chemistry/src/JordanWigner/JordanWignerOptimizedBlockEncoding.qs b/library/chemistry/src/JordanWigner/JordanWignerOptimizedBlockEncoding.qs
index 545e5998..0f1da5fb 100644
--- a/library/chemistry/src/JordanWigner/JordanWignerOptimizedBlockEncoding.qs
+++ b/library/chemistry/src/JordanWigner/JordanWignerOptimizedBlockEncoding.qs
@@ -8,9 +8,6 @@ export
     MixedStatePreparation,
     MixedStatePreparationRequirements,
     PurifiedMixedState,
-    ObliviousAmplitudeAmplificationFromStatePreparation,
-    ObliviousAmplitudeAmplificationFromPartialReflections,
-    ApplyObliviousAmplitudeAmplification,
     PurifiedMixedStateRequirements,
     BlockEncodingByLCU,
     QuantumWalkByQubitization,
@@ -27,6 +24,7 @@ import Std.Math.*;
 import Std.Convert.IntAsDouble;
 import Std.Arithmetic.ApplyIfGreaterLE;
 import Std.StatePreparation.PreparePureStateD;
+import Std.StatePreparation.PrepareUniformSuperposition;
 import Std.Diagnostics.Fact;
 import Utils.GeneratorIndex;
 import Utils.GeneratorSystem;
@@ -628,207 +626,6 @@ operation PrepareQuantumROMState(
     }
 }
 
-/// # Summary
-/// Creates a uniform superposition over states that encode 0 through `nIndices - 1`.
-///
-/// # Description
-///
-/// This operation can be described by a unitary matrix $U$ that creates
-/// a uniform superposition over all number states
-/// $0$ to $M-1$, given an input state $\ket{0\cdots 0}$. In other words,
-/// $$
-/// \begin{align}
-///     U \ket{0} = \frac{1}{\sqrt{M}} \sum_{j=0}^{M - 1} \ket{j}.
-/// \end{align}
-/// $$.
-///
-/// # Input
-/// ## nIndices
-/// The desired number of states $M$ in the uniform superposition.
-/// ## indexRegister
-/// The qubit register that stores the number states in `LittleEndian` format.
-/// This register must be able to store the number $M-1$, and is assumed to be
-/// initialized in the state $\ket{0\cdots 0}$.
-///
-/// # Remarks
-/// The operation is adjointable, but requires that `indexRegister` is in a uniform
-/// superposition over the first `nIndices` basis states in that case.
-///
-/// # Example
-/// The following example prepares the state $\frac{1}{\sqrt{6}}\sum_{j=0}^{5}\ket{j}$
-/// on $3$ qubits.
-/// ``` Q#
-/// let nIndices = 6;
-/// using(indexRegister = Qubit[3]) {
-///     PrepareUniformSuperposition(nIndices, LittleEndian(indexRegister));
-///     // ...
-/// }
-/// ```
-operation PrepareUniformSuperposition(nIndices : Int, indexRegister : Qubit[]) : Unit is Adj + Ctl {
-    if nIndices == 0 {
-        fail "Cannot prepare uniform superposition over 0 basis states.";
-    } elif nIndices == 1 {
-        // Superposition over one state, so do nothing.
-    } elif nIndices == 2 {
-        H(indexRegister[0]);
-    } else {
-        let nQubits = BitSizeI(nIndices - 1);
-        if nQubits > Length(indexRegister) {
-            fail $"Cannot prepare uniform superposition over {nIndices} states as it is larger than the qubit register.";
-        }
-
-        use flagQubit = Qubit[3];
-        let targetQubits = indexRegister[0..nQubits - 1];
-        let qubits = flagQubit + targetQubits;
-        let stateOracle = PrepareUniformSuperpositionOracle(nIndices, nQubits, 0, _);
-
-        let phases = ([0.0, PI()], [PI(), 0.0]);
-
-        ObliviousAmplitudeAmplificationFromStatePreparation(
-            phases,
-            stateOracle,
-            (qs0, qs1) => I(qs0[0]),
-            0
-        )(qubits, []);
-
-
-        ApplyToEachCA(X, flagQubit);
-    }
-}
-
-function ObliviousAmplitudeAmplificationFromStatePreparation(
-    phases : (Double[], Double[]),
-    startStateOracle : Qubit[] => Unit is Adj + Ctl,
-    signalOracle : (Qubit[], Qubit[]) => Unit is Adj + Ctl,
-    idxFlagQubit : Int
-) : (Qubit[], Qubit[]) => Unit is Adj + Ctl {
-    let startStateReflection = (phase, qs) => {
-        within {
-            ApplyToEachCA(X, qs);
-        } apply {
-            Controlled R1(Rest(qs), (phase, qs[0]));
-        }
-    };
-    let targetStateReflection = (phase, qs) => R1(phase, qs[idxFlagQubit]);
-    let obliviousSignalOracle = (qs0, qs1) => { startStateOracle(qs0); signalOracle(qs0, qs1); };
-    return ObliviousAmplitudeAmplificationFromPartialReflections(
-        phases,
-        startStateReflection,
-        targetStateReflection,
-        obliviousSignalOracle
-    );
-}
-
-function ObliviousAmplitudeAmplificationFromPartialReflections(
-    phases : (Double[], Double[]),
-    startStateReflection : (Double, Qubit[]) => Unit is Adj + Ctl,
-    targetStateReflection : (Double, Qubit[]) => Unit is Adj + Ctl,
-    signalOracle : (Qubit[], Qubit[]) => Unit is Adj + Ctl
-) : (Qubit[], Qubit[]) => Unit is Adj + Ctl {
-    return ApplyObliviousAmplitudeAmplification(
-        phases,
-        startStateReflection,
-        targetStateReflection,
-        signalOracle,
-        _,
-        _
-    );
-}
-
-/// # Summary
-/// Oblivious amplitude amplification by specifying partial reflections.
-///
-/// # Input
-/// ## phases
-/// Phases of partial reflections
-/// ## startStateReflection
-/// Reflection operator about start state of auxiliary register
-/// ## targetStateReflection
-/// Reflection operator about target state of auxiliary register
-/// ## signalOracle
-/// Unitary oracle $O$ of type `ObliviousOracle` that acts jointly on the
-/// auxiliary and system registers.
-/// ## auxiliaryRegister
-/// Auxiliary register
-/// ## systemRegister
-/// System register
-///
-/// # Remarks
-/// Given a particular auxiliary start state $\ket{\text{start}}\_a$, a
-/// particular auxiliary target state $\ket{\text{target}}\_a$, and any
-/// system state $\ket{\psi}\_s$, suppose that
-/// \begin{align}
-/// O\ket{\text{start}}\_a\ket{\psi}\_s= \lambda\ket{\text{target}}\_a U \ket{\psi}\_s + \sqrt{1-|\lambda|^2}\ket{\text{target}^\perp}\_a\cdots
-/// \end{align}
-/// for some unitary $U$.
-/// By a sequence of reflections about the start and target states on the
-/// auxiliary register interleaved by applications of `signalOracle` and its
-/// adjoint, the success probability of applying $U$ may be altered.
-///
-/// In most cases, `auxiliaryRegister` is initialized in the state $\ket{\text{start}}\_a$.
-///
-/// # References
-/// - See [*D.W. Berry, A.M. Childs, R. Cleve, R. Kothari, R.D. Somma*](https://arxiv.org/abs/1312.1414)
-/// for the standard version.
-/// - See [*G.H. Low, I.L. Chuang*](https://arxiv.org/abs/1610.06546)
-/// for a generalization to partial reflections.
-operation ApplyObliviousAmplitudeAmplification(
-    phases : (Double[], Double[]),
-    startStateReflection : (Double, Qubit[]) => Unit is Adj + Ctl,
-    targetStateReflection : (Double, Qubit[]) => Unit is Adj + Ctl,
-    signalOracle : (Qubit[], Qubit[]) => Unit is Adj + Ctl,
-    auxiliaryRegister : Qubit[],
-    systemRegister : Qubit[]
-) : Unit is Adj + Ctl {
-    let (aboutStart, aboutTarget) = phases;
-    Fact(Length(aboutStart) == Length(aboutTarget), "number of phases about start and target state must be equal");
-    let numPhases = Length(aboutStart);
-
-    for idx in 0..numPhases-1 {
-        if aboutStart[idx] != 0.0 {
-            startStateReflection(aboutStart[idx], auxiliaryRegister);
-        }
-
-        if aboutTarget[idx] != 0.0 {
-            // In the last iteration we do not need to apply `Adjoint signalOracle`
-            if idx == numPhases - 1 {
-                signalOracle(auxiliaryRegister, systemRegister);
-                targetStateReflection(aboutTarget[idx], auxiliaryRegister);
-            } else {
-                within {
-                    signalOracle(auxiliaryRegister, systemRegister);
-                } apply {
-                    targetStateReflection(aboutTarget[idx], auxiliaryRegister);
-                }
-            }
-        }
-    }
-
-    // We do need one more `signalOracle` call, if the last phase about the target state was 0.0
-    if numPhases == 0 or aboutTarget[numPhases - 1] == 0.0 {
-        signalOracle(auxiliaryRegister, systemRegister);
-    }
-}
-
-operation PrepareUniformSuperpositionOracle(nIndices : Int, nQubits : Int, idxFlag : Int, qubits : Qubit[]) : Unit is Adj + Ctl {
-    let targetQubits = qubits[3...];
-    let flagQubit = qubits[0];
-    let auxillaryQubits = qubits[1..2];
-    let theta = ArcSin(Sqrt(IntAsDouble(2^nQubits) / IntAsDouble(nIndices)) * Sin(PI() / 6.0));
-
-    ApplyToEachCA(H, targetQubits);
-    use compareQubits = Qubit[nQubits] {
-        within {
-            ApplyXorInPlace(nIndices - 1, compareQubits);
-        } apply {
-            ApplyIfGreaterLE(X, targetQubits, compareQubits, auxillaryQubits[0]);
-            X(auxillaryQubits[0]);
-        }
-    }
-    Ry(2.0 * theta, auxillaryQubits[1]);
-    (Controlled X)(auxillaryQubits, flagQubit);
-}
-
 // Classical processing
 // This discretizes the coefficients such that
 // |coefficient[i] * oneNorm - discretizedCoefficient[i] * discretizedOneNorm| * nCoeffs <= 2^{1-bitsPrecision}.
diff --git a/library/std/src/Std/StatePreparation.qs b/library/std/src/Std/StatePreparation.qs
index 1b67ab7d..ecf1a57a 100644
--- a/library/std/src/Std/StatePreparation.qs
+++ b/library/std/src/Std/StatePreparation.qs
@@ -1,10 +1,19 @@
 // Copyright (c) Microsoft Corporation.
 // Licensed under the MIT License.
 
+export
+    PreparePureStateD,
+    ApproximatelyPreparePureStateCP,
+    PrepareUniformSuperposition;
 
 import
     Std.Diagnostics.Fact,
     Std.Convert.ComplexAsComplexPolar,
+    Std.Convert.IntAsDouble,
+    Std.Arithmetic.ApplyIfGreaterLE,
+    Std.Arithmetic.ApplyIfGreaterL,
+    Std.Arithmetic.ReflectAboutInteger,
+    Std.Convert.IntAsBigInt,
     Std.Math.*,
     Std.Arrays.*;
 
@@ -385,4 +394,64 @@ function AnyOutsideToleranceD(tolerance : Double, coefficients : Double[]) : Boo
     Any(coefficient -> AbsD(coefficient) >= tolerance, coefficients)
 }
 
-export PreparePureStateD, ApproximatelyPreparePureStateCP;
+/// # Summary
+/// Prepares a uniform superposition of states that represent integers 0 through
+/// `nStates - 1` in a little-endian `qubits` register.
+///
+/// # Description
+/// Given an input state $\ket{0\cdots 0}$ this operation prepares
+/// a uniform superposition of all number states $0$ to $M-1$. In other words,
+/// $$
+/// \begin{align}
+///     \ket{0} \mapsto \frac{1}{\sqrt{M}} \sum_{j=0}^{M - 1} \ket{j}
+/// \end{align}
+/// $$
+///
+/// The operation is adjointable, but requires that `qubits` register is in a
+/// uniform superposition over the first `nStates` basis states in that case.
+///
+/// # Input
+/// ## nStates
+/// The number of states in the uniform superposition to be prepared.
+/// ## register
+/// The little-endian qubit register to store the prepared state.
+/// It is assumed to be initialized in the zero state $\ket{0\cdots 0}$.
+/// This register must be long enough to store the number $M-1$, meaning that
+/// $2^{Length(qubits)} >= M$.
+///
+/// # Example
+/// ```qsharp
+///    use qs = Qubit[4];
+///    PrepareUniformSuperposition(3, qs);
+///    DumpRegister(qs); // The state is (|0000>+|0100>+|1000>)/√3
+///    ResetAll(qs);
+/// ```
+operation PrepareUniformSuperposition(nStates : Int, qubits : Qubit[]) : Unit is Adj + Ctl {
+    Fact(nStates > 0, "Number of basis states must be positive.");
+    let nQubits = BitSizeI(nStates-1);
+    Fact(nQubits <= Length(qubits), $"Qubit register is too short to prepare {nStates} states.");
+    let relevantQubits = qubits[...nQubits - 1];
+    let nTrailingZeroes = TrailingZeroCountI(nStates);
+
+    ApplyToEachCA(H, relevantQubits);
+
+    if nTrailingZeroes != nQubits {
+        // Not a superposition of all relevant states so adjustment is needed.
+        use tgt = Qubit();
+
+        let nRelevantStates = 2^nQubits;
+        let sqrt = Sqrt(IntAsDouble(nRelevantStates) / IntAsDouble(nStates));
+        let angle = 2.0 * ArcSin(0.5 * sqrt);
+
+        ApplyIfGreaterL(Ry(2.0 * angle, _), IntAsBigInt(nStates), relevantQubits, tgt);
+
+        within {
+            ApplyToEachA(H, relevantQubits[nTrailingZeroes...]);
+        } apply {
+            ReflectAboutInteger(0, relevantQubits[nTrailingZeroes...] + [tgt]);
+            Ry(-angle, tgt);
+        }
+
+        X(tgt);
+    }
+}
diff --git a/package-lock.json b/package-lock.json
index 0587373d..2e8fec50 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -27,7 +27,7 @@
         "@vscode/markdown-it-katex": "^1.0.0",
         "@vscode/test-web": "^0.0.61",
         "chai": "^4.3.10",
-        "esbuild": "^0.23.1",
+        "esbuild": "^0.25.0",
         "eslint": "^9.17.0",
         "events": "^3.3.0",
         "github-markdown-css": "^5.3.0",
@@ -232,13 +232,14 @@
       }
     },
     "node_modules/@esbuild/aix-ppc64": {
-      "version": "0.23.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.23.1.tgz",
-      "integrity": "sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ==",
+      "version": "0.25.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.0.tgz",
+      "integrity": "sha512-O7vun9Sf8DFjH2UtqK8Ku3LkquL9SZL8OLY1T5NZkA34+wG3OQF7cl4Ql8vdNzM6fzBbYfLaiRLIOZ+2FOCgBQ==",
       "cpu": [
         "ppc64"
       ],
       "dev": true,
+      "license": "MIT",
       "optional": true,
       "os": [
         "aix"
@@ -248,13 +249,14 @@
       }
     },
     "node_modules/@esbuild/android-arm": {
-      "version": "0.23.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.23.1.tgz",
-      "integrity": "sha512-uz6/tEy2IFm9RYOyvKl88zdzZfwEfKZmnX9Cj1BHjeSGNuGLuMD1kR8y5bteYmwqKm1tj8m4cb/aKEorr6fHWQ==",
+      "version": "0.25.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.0.tgz",
+      "integrity": "sha512-PTyWCYYiU0+1eJKmw21lWtC+d08JDZPQ5g+kFyxP0V+es6VPPSUhM6zk8iImp2jbV6GwjX4pap0JFbUQN65X1g==",
       "cpu": [
         "arm"
       ],
       "dev": true,
+      "license": "MIT",
       "optional": true,
       "os": [
         "android"
@@ -264,13 +266,14 @@
       }
     },
     "node_modules/@esbuild/android-arm64": {
-      "version": "0.23.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.23.1.tgz",
-      "integrity": "sha512-xw50ipykXcLstLeWH7WRdQuysJqejuAGPd30vd1i5zSyKK3WE+ijzHmLKxdiCMtH1pHz78rOg0BKSYOSB/2Khw==",
+      "version": "0.25.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.0.tgz",
+      "integrity": "sha512-grvv8WncGjDSyUBjN9yHXNt+cq0snxXbDxy5pJtzMKGmmpPxeAmAhWxXI+01lU5rwZomDgD3kJwulEnhTRUd6g==",
       "cpu": [
         "arm64"
       ],
       "dev": true,
+      "license": "MIT",
       "optional": true,
       "os": [
         "android"
@@ -280,13 +283,14 @@
       }
     },
     "node_modules/@esbuild/android-x64": {
-      "version": "0.23.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.23.1.tgz",
-      "integrity": "sha512-nlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlReg==",
+      "version": "0.25.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.0.tgz",
+      "integrity": "sha512-m/ix7SfKG5buCnxasr52+LI78SQ+wgdENi9CqyCXwjVR2X4Jkz+BpC3le3AoBPYTC9NHklwngVXvbJ9/Akhrfg==",
       "cpu": [
         "x64"
       ],
       "dev": true,
+      "license": "MIT",
       "optional": true,
       "os": [
         "android"
@@ -296,13 +300,14 @@
       }
     },
     "node_modules/@esbuild/darwin-arm64": {
-      "version": "0.23.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.23.1.tgz",
-      "integrity": "sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q==",
+      "version": "0.25.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.0.tgz",
+      "integrity": "sha512-mVwdUb5SRkPayVadIOI78K7aAnPamoeFR2bT5nszFUZ9P8UpK4ratOdYbZZXYSqPKMHfS1wdHCJk1P1EZpRdvw==",
       "cpu": [
         "arm64"
       ],
       "dev": true,
+      "license": "MIT",
       "optional": true,
       "os": [
         "darwin"
@@ -312,13 +317,14 @@
       }
     },
     "node_modules/@esbuild/darwin-x64": {
-      "version": "0.23.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.23.1.tgz",
-      "integrity": "sha512-aClqdgTDVPSEGgoCS8QDG37Gu8yc9lTHNAQlsztQ6ENetKEO//b8y31MMu2ZaPbn4kVsIABzVLXYLhCGekGDqw==",
+      "version": "0.25.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.0.tgz",
+      "integrity": "sha512-DgDaYsPWFTS4S3nWpFcMn/33ZZwAAeAFKNHNa1QN0rI4pUjgqf0f7ONmXf6d22tqTY+H9FNdgeaAa+YIFUn2Rg==",
       "cpu": [
         "x64"
       ],
       "dev": true,
+      "license": "MIT",
       "optional": true,
       "os": [
         "darwin"
@@ -328,13 +334,14 @@
       }
     },
     "node_modules/@esbuild/freebsd-arm64": {
-      "version": "0.23.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.23.1.tgz",
-      "integrity": "sha512-h1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhA==",
+      "version": "0.25.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.0.tgz",
+      "integrity": "sha512-VN4ocxy6dxefN1MepBx/iD1dH5K8qNtNe227I0mnTRjry8tj5MRk4zprLEdG8WPyAPb93/e4pSgi1SoHdgOa4w==",
       "cpu": [
         "arm64"
       ],
       "dev": true,
+      "license": "MIT",
       "optional": true,
       "os": [
         "freebsd"
@@ -344,13 +351,14 @@
       }
     },
     "node_modules/@esbuild/freebsd-x64": {
-      "version": "0.23.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.23.1.tgz",
-      "integrity": "sha512-lK1eJeyk1ZX8UklqFd/3A60UuZ/6UVfGT2LuGo3Wp4/z7eRTRYY+0xOu2kpClP+vMTi9wKOfXi2vjUpO1Ro76g==",
+      "version": "0.25.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.0.tgz",
+      "integrity": "sha512-mrSgt7lCh07FY+hDD1TxiTyIHyttn6vnjesnPoVDNmDfOmggTLXRv8Id5fNZey1gl/V2dyVK1VXXqVsQIiAk+A==",
       "cpu": [
         "x64"
       ],
       "dev": true,
+      "license": "MIT",
       "optional": true,
       "os": [
         "freebsd"
@@ -360,13 +368,14 @@
       }
     },
     "node_modules/@esbuild/linux-arm": {
-      "version": "0.23.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.23.1.tgz",
-      "integrity": "sha512-CXXkzgn+dXAPs3WBwE+Kvnrf4WECwBdfjfeYHpMeVxWE0EceB6vhWGShs6wi0IYEqMSIzdOF1XjQ/Mkm5d7ZdQ==",
+      "version": "0.25.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.0.tgz",
+      "integrity": "sha512-vkB3IYj2IDo3g9xX7HqhPYxVkNQe8qTK55fraQyTzTX/fxaDtXiEnavv9geOsonh2Fd2RMB+i5cbhu2zMNWJwg==",
       "cpu": [
         "arm"
       ],
       "dev": true,
+      "license": "MIT",
       "optional": true,
       "os": [
         "linux"
@@ -376,13 +385,14 @@
       }
     },
     "node_modules/@esbuild/linux-arm64": {
-      "version": "0.23.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.23.1.tgz",
-      "integrity": "sha512-/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754g==",
+      "version": "0.25.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.0.tgz",
+      "integrity": "sha512-9QAQjTWNDM/Vk2bgBl17yWuZxZNQIF0OUUuPZRKoDtqF2k4EtYbpyiG5/Dk7nqeK6kIJWPYldkOcBqjXjrUlmg==",
       "cpu": [
         "arm64"
       ],
       "dev": true,
+      "license": "MIT",
       "optional": true,
       "os": [
         "linux"
@@ -392,13 +402,14 @@
       }
     },
     "node_modules/@esbuild/linux-ia32": {
-      "version": "0.23.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.23.1.tgz",
-      "integrity": "sha512-VTN4EuOHwXEkXzX5nTvVY4s7E/Krz7COC8xkftbbKRYAl96vPiUssGkeMELQMOnLOJ8k3BY1+ZY52tttZnHcXQ==",
+      "version": "0.25.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.0.tgz",
+      "integrity": "sha512-43ET5bHbphBegyeqLb7I1eYn2P/JYGNmzzdidq/w0T8E2SsYL1U6un2NFROFRg1JZLTzdCoRomg8Rvf9M6W6Gg==",
       "cpu": [
         "ia32"
       ],
       "dev": true,
+      "license": "MIT",
       "optional": true,
       "os": [
         "linux"
@@ -408,13 +419,14 @@
       }
     },
     "node_modules/@esbuild/linux-loong64": {
-      "version": "0.23.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.23.1.tgz",
-      "integrity": "sha512-Vx09LzEoBa5zDnieH8LSMRToj7ir/Jeq0Gu6qJ/1GcBq9GkfoEAoXvLiW1U9J1qE/Y/Oyaq33w5p2ZWrNNHNEw==",
+      "version": "0.25.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.0.tgz",
+      "integrity": "sha512-fC95c/xyNFueMhClxJmeRIj2yrSMdDfmqJnyOY4ZqsALkDrrKJfIg5NTMSzVBr5YW1jf+l7/cndBfP3MSDpoHw==",
       "cpu": [
         "loong64"
       ],
       "dev": true,
+      "license": "MIT",
       "optional": true,
       "os": [
         "linux"
@@ -424,13 +436,14 @@
       }
     },
     "node_modules/@esbuild/linux-mips64el": {
-      "version": "0.23.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.23.1.tgz",
-      "integrity": "sha512-nrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3Q==",
+      "version": "0.25.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.0.tgz",
+      "integrity": "sha512-nkAMFju7KDW73T1DdH7glcyIptm95a7Le8irTQNO/qtkoyypZAnjchQgooFUDQhNAy4iu08N79W4T4pMBwhPwQ==",
       "cpu": [
         "mips64el"
       ],
       "dev": true,
+      "license": "MIT",
       "optional": true,
       "os": [
         "linux"
@@ -440,13 +453,14 @@
       }
     },
     "node_modules/@esbuild/linux-ppc64": {
-      "version": "0.23.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.23.1.tgz",
-      "integrity": "sha512-dKN8fgVqd0vUIjxuJI6P/9SSSe/mB9rvA98CSH2sJnlZ/OCZWO1DJvxj8jvKTfYUdGfcq2dDxoKaC6bHuTlgcw==",
+      "version": "0.25.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.0.tgz",
+      "integrity": "sha512-NhyOejdhRGS8Iwv+KKR2zTq2PpysF9XqY+Zk77vQHqNbo/PwZCzB5/h7VGuREZm1fixhs4Q/qWRSi5zmAiO4Fw==",
       "cpu": [
         "ppc64"
       ],
       "dev": true,
+      "license": "MIT",
       "optional": true,
       "os": [
         "linux"
@@ -456,13 +470,14 @@
       }
     },
     "node_modules/@esbuild/linux-riscv64": {
-      "version": "0.23.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.23.1.tgz",
-      "integrity": "sha512-5AV4Pzp80fhHL83JM6LoA6pTQVWgB1HovMBsLQ9OZWLDqVY8MVobBXNSmAJi//Csh6tcY7e7Lny2Hg1tElMjIA==",
+      "version": "0.25.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.0.tgz",
+      "integrity": "sha512-5S/rbP5OY+GHLC5qXp1y/Mx//e92L1YDqkiBbO9TQOvuFXM+iDqUNG5XopAnXoRH3FjIUDkeGcY1cgNvnXp/kA==",
       "cpu": [
         "riscv64"
       ],
       "dev": true,
+      "license": "MIT",
       "optional": true,
       "os": [
         "linux"
@@ -472,13 +487,14 @@
       }
     },
     "node_modules/@esbuild/linux-s390x": {
-      "version": "0.23.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.23.1.tgz",
-      "integrity": "sha512-9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDw==",
+      "version": "0.25.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.0.tgz",
+      "integrity": "sha512-XM2BFsEBz0Fw37V0zU4CXfcfuACMrppsMFKdYY2WuTS3yi8O1nFOhil/xhKTmE1nPmVyvQJjJivgDT+xh8pXJA==",
       "cpu": [
         "s390x"
       ],
       "dev": true,
+      "license": "MIT",
       "optional": true,
       "os": [
         "linux"
@@ -488,13 +504,14 @@
       }
     },
     "node_modules/@esbuild/linux-x64": {
-      "version": "0.23.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.23.1.tgz",
-      "integrity": "sha512-EV6+ovTsEXCPAp58g2dD68LxoP/wK5pRvgy0J/HxPGB009omFPv3Yet0HiaqvrIrgPTBuC6wCH1LTOY91EO5hQ==",
+      "version": "0.25.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.0.tgz",
+      "integrity": "sha512-9yl91rHw/cpwMCNytUDxwj2XjFpxML0y9HAOH9pNVQDpQrBxHy01Dx+vaMu0N1CKa/RzBD2hB4u//nfc+Sd3Cw==",
       "cpu": [
         "x64"
       ],
       "dev": true,
+      "license": "MIT",
       "optional": true,
       "os": [
         "linux"
@@ -503,14 +520,32 @@
         "node": ">=18"
       }
     },
+    "node_modules/@esbuild/netbsd-arm64": {
+      "version": "0.25.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.0.tgz",
+      "integrity": "sha512-RuG4PSMPFfrkH6UwCAqBzauBWTygTvb1nxWasEJooGSJ/NwRw7b2HOwyRTQIU97Hq37l3npXoZGYMy3b3xYvPw==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "netbsd"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
     "node_modules/@esbuild/netbsd-x64": {
-      "version": "0.23.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.23.1.tgz",
-      "integrity": "sha512-aevEkCNu7KlPRpYLjwmdcuNz6bDFiE7Z8XC4CPqExjTvrHugh28QzUXVOZtiYghciKUacNktqxdpymplil1beA==",
+      "version": "0.25.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.0.tgz",
+      "integrity": "sha512-jl+qisSB5jk01N5f7sPCsBENCOlPiS/xptD5yxOx2oqQfyourJwIKLRA2yqWdifj3owQZCL2sn6o08dBzZGQzA==",
       "cpu": [
         "x64"
       ],
       "dev": true,
+      "license": "MIT",
       "optional": true,
       "os": [
         "netbsd"
@@ -520,13 +555,14 @@
       }
     },
     "node_modules/@esbuild/openbsd-arm64": {
-      "version": "0.23.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.23.1.tgz",
-      "integrity": "sha512-3x37szhLexNA4bXhLrCC/LImN/YtWis6WXr1VESlfVtVeoFJBRINPJ3f0a/6LV8zpikqoUg4hyXw0sFBt5Cr+Q==",
+      "version": "0.25.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.0.tgz",
+      "integrity": "sha512-21sUNbq2r84YE+SJDfaQRvdgznTD8Xc0oc3p3iW/a1EVWeNj/SdUCbm5U0itZPQYRuRTW20fPMWMpcrciH2EJw==",
       "cpu": [
         "arm64"
       ],
       "dev": true,
+      "license": "MIT",
       "optional": true,
       "os": [
         "openbsd"
@@ -536,13 +572,14 @@
       }
     },
     "node_modules/@esbuild/openbsd-x64": {
-      "version": "0.23.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.23.1.tgz",
-      "integrity": "sha512-aY2gMmKmPhxfU+0EdnN+XNtGbjfQgwZj43k8G3fyrDM/UdZww6xrWxmDkuz2eCZchqVeABjV5BpildOrUbBTqA==",
+      "version": "0.25.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.0.tgz",
+      "integrity": "sha512-2gwwriSMPcCFRlPlKx3zLQhfN/2WjJ2NSlg5TKLQOJdV0mSxIcYNTMhk3H3ulL/cak+Xj0lY1Ym9ysDV1igceg==",
       "cpu": [
         "x64"
       ],
       "dev": true,
+      "license": "MIT",
       "optional": true,
       "os": [
         "openbsd"
@@ -552,13 +589,14 @@
       }
     },
     "node_modules/@esbuild/sunos-x64": {
-      "version": "0.23.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.23.1.tgz",
-      "integrity": "sha512-RBRT2gqEl0IKQABT4XTj78tpk9v7ehp+mazn2HbUeZl1YMdaGAQqhapjGTCe7uw7y0frDi4gS0uHzhvpFuI1sA==",
+      "version": "0.25.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.0.tgz",
+      "integrity": "sha512-bxI7ThgLzPrPz484/S9jLlvUAHYMzy6I0XiU1ZMeAEOBcS0VePBFxh1JjTQt3Xiat5b6Oh4x7UC7IwKQKIJRIg==",
       "cpu": [
         "x64"
       ],
       "dev": true,
+      "license": "MIT",
       "optional": true,
       "os": [
         "sunos"
@@ -568,13 +606,14 @@
       }
     },
     "node_modules/@esbuild/win32-arm64": {
-      "version": "0.23.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.23.1.tgz",
-      "integrity": "sha512-4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6A==",
+      "version": "0.25.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.0.tgz",
+      "integrity": "sha512-ZUAc2YK6JW89xTbXvftxdnYy3m4iHIkDtK3CLce8wg8M2L+YZhIvO1DKpxrd0Yr59AeNNkTiic9YLf6FTtXWMw==",
       "cpu": [
         "arm64"
       ],
       "dev": true,
+      "license": "MIT",
       "optional": true,
       "os": [
         "win32"
@@ -584,13 +623,14 @@
       }
     },
     "node_modules/@esbuild/win32-ia32": {
-      "version": "0.23.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.23.1.tgz",
-      "integrity": "sha512-BcaL0Vn6QwCwre3Y717nVHZbAa4UBEigzFm6VdsVdT/MbZ38xoj1X9HPkZhbmaBGUD1W8vxAfffbDe8bA6AKnQ==",
+      "version": "0.25.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.0.tgz",
+      "integrity": "sha512-eSNxISBu8XweVEWG31/JzjkIGbGIJN/TrRoiSVZwZ6pkC6VX4Im/WV2cz559/TXLcYbcrDN8JtKgd9DJVIo8GA==",
       "cpu": [
         "ia32"
       ],
       "dev": true,
+      "license": "MIT",
       "optional": true,
       "os": [
         "win32"
@@ -600,13 +640,14 @@
       }
     },
     "node_modules/@esbuild/win32-x64": {
-      "version": "0.23.1",
-      "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.23.1.tgz",
-      "integrity": "sha512-BHpFFeslkWrXWyUPnbKm+xYYVYruCinGcftSBaa8zoF9hZO4BcSCFUvHVTtzpIY6YzUnYtuEhZ+C9iEXjxnasg==",
+      "version": "0.25.0",
+      "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.0.tgz",
+      "integrity": "sha512-ZENoHJBxA20C2zFzh6AI4fT6RraMzjYw4xKWemRTRmRVtN9c5DcH9r/f2ihEkMjOW5eGgrwCslG/+Y/3bL+DHQ==",
       "cpu": [
         "x64"
       ],
       "dev": true,
+      "license": "MIT",
       "optional": true,
       "os": [
         "win32"
@@ -3204,11 +3245,12 @@
       }
     },
     "node_modules/esbuild": {
-      "version": "0.23.1",
-      "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.23.1.tgz",
-      "integrity": "sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg==",
+      "version": "0.25.0",
+      "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.0.tgz",
+      "integrity": "sha512-BXq5mqc8ltbaN34cDqWuYKyNhX8D/Z0J1xdtdQ8UcIIIyJyz+ZMKUt58tF3SrZ85jcfN/PZYhjR5uDQAYNVbuw==",
       "dev": true,
       "hasInstallScript": true,
+      "license": "MIT",
       "bin": {
         "esbuild": "bin/esbuild"
       },
@@ -3216,30 +3258,31 @@
         "node": ">=18"
       },
       "optionalDependencies": {
-        "@esbuild/aix-ppc64": "0.23.1",
-        "@esbuild/android-arm": "0.23.1",
-        "@esbuild/android-arm64": "0.23.1",
-        "@esbuild/android-x64": "0.23.1",
-        "@esbuild/darwin-arm64": "0.23.1",
-        "@esbuild/darwin-x64": "0.23.1",
-        "@esbuild/freebsd-arm64": "0.23.1",
-        "@esbuild/freebsd-x64": "0.23.1",
-        "@esbuild/linux-arm": "0.23.1",
-        "@esbuild/linux-arm64": "0.23.1",
-        "@esbuild/linux-ia32": "0.23.1",
-        "@esbuild/linux-loong64": "0.23.1",
-        "@esbuild/linux-mips64el": "0.23.1",
-        "@esbuild/linux-ppc64": "0.23.1",
-        "@esbuild/linux-riscv64": "0.23.1",
-        "@esbuild/linux-s390x": "0.23.1",
-        "@esbuild/linux-x64": "0.23.1",
-        "@esbuild/netbsd-x64": "0.23.1",
-        "@esbuild/openbsd-arm64": "0.23.1",
-        "@esbuild/openbsd-x64": "0.23.1",
-        "@esbuild/sunos-x64": "0.23.1",
-        "@esbuild/win32-arm64": "0.23.1",
-        "@esbuild/win32-ia32": "0.23.1",
-        "@esbuild/win32-x64": "0.23.1"
+        "@esbuild/aix-ppc64": "0.25.0",
+        "@esbuild/android-arm": "0.25.0",
+        "@esbuild/android-arm64": "0.25.0",
+        "@esbuild/android-x64": "0.25.0",
+        "@esbuild/darwin-arm64": "0.25.0",
+        "@esbuild/darwin-x64": "0.25.0",
+        "@esbuild/freebsd-arm64": "0.25.0",
+        "@esbuild/freebsd-x64": "0.25.0",
+        "@esbuild/linux-arm": "0.25.0",
+        "@esbuild/linux-arm64": "0.25.0",
+        "@esbuild/linux-ia32": "0.25.0",
+        "@esbuild/linux-loong64": "0.25.0",
+        "@esbuild/linux-mips64el": "0.25.0",
+        "@esbuild/linux-ppc64": "0.25.0",
+        "@esbuild/linux-riscv64": "0.25.0",
+        "@esbuild/linux-s390x": "0.25.0",
+        "@esbuild/linux-x64": "0.25.0",
+        "@esbuild/netbsd-arm64": "0.25.0",
+        "@esbuild/netbsd-x64": "0.25.0",
+        "@esbuild/openbsd-arm64": "0.25.0",
+        "@esbuild/openbsd-x64": "0.25.0",
+        "@esbuild/sunos-x64": "0.25.0",
+        "@esbuild/win32-arm64": "0.25.0",
+        "@esbuild/win32-ia32": "0.25.0",
+        "@esbuild/win32-x64": "0.25.0"
       }
     },
     "node_modules/escalade": {
diff --git a/package.json b/package.json
index 86ecd521..a6e6a7d0 100644
--- a/package.json
+++ b/package.json
@@ -32,7 +32,7 @@
     "@vscode/markdown-it-katex": "^1.0.0",
     "@vscode/test-web": "^0.0.61",
     "chai": "^4.3.10",
-    "esbuild": "^0.23.1",
+    "esbuild": "^0.25.0",
     "eslint": "^9.17.0",
     "events": "^3.3.0",
     "github-markdown-css": "^5.3.0",
diff --git a/samples/estimation/df-chemistry/src/Prepare.qs b/samples/estimation/df-chemistry/src/Prepare.qs
index 504b5652..3ae7de04 100644
--- a/samples/estimation/df-chemistry/src/Prepare.qs
+++ b/samples/estimation/df-chemistry/src/Prepare.qs
@@ -7,6 +7,7 @@ import Std.Intrinsic.*;
 import Std.Math.*;
 import Std.Arithmetic.*;
 import Std.TableLookup.*;
+import Std.StatePreparation.PrepareUniformSuperposition;
 
 // ------------------------------------- //
 // State preparation (public operations) //
@@ -19,37 +20,6 @@ operation PrepareSingleQubit(p0 : Double, p1 : Double, target : Qubit) : Unit is
     Ry(2.0 * alpha, target);
 }
 
-operation PrepareUniformSuperposition(numStates : Int, qs : Qubit[]) : Unit is Adj + Ctl {
-    Fact(numStates >= 1, "numStates must be positive");
-    Fact(numStates <= 2^Length(qs), $"numStates must be smaller or equal to {2^Length(qs)}");
-
-    let qsAdjusted = qs[...Ceiling(Lg(IntAsDouble(numStates))) - 1];
-
-    let (factor, pow) = DecomposePowerOf2(numStates);
-
-    if factor == 1 {
-        ApplyToEachCA(H, qsAdjusted[0..pow - 1]);
-    } else {
-        use tgt = Qubit();
-
-        let sqrt = Sqrt(IntAsDouble(1 <<< Length(qsAdjusted)) / IntAsDouble(numStates));
-        let angle = 2.0 * ArcSin(0.5 * sqrt);
-
-        ApplyToEachCA(H, qsAdjusted);
-
-        ApplyIfGreaterL(Ry(2.0 * angle, _), IntAsBigInt(numStates), qsAdjusted, tgt);
-
-        within {
-            ApplyToEachA(H, qsAdjusted[pow...]);
-        } apply {
-            ReflectAboutInteger(0, qsAdjusted[pow...] + [tgt]);
-            Ry(-angle, tgt);
-        }
-
-        X(tgt);
-    }
-}
-
 struct PrepareArbitrarySuperposition {
     NIndexQubits : Int,
     NGarbageQubits : Int,
@@ -87,18 +57,6 @@ function MakePrepareArbitrarySuperpositionWithData(targetError : Double, coeffic
 // State preparation (private operations) //
 // -------------------------------------- //
 
-internal function DecomposePowerOf2(number : Int) : (Int, Int) {
-    mutable pow = 0;
-    mutable factor = number;
-
-    while factor % 2 == 0 {
-        set factor /= 2;
-        set pow += 1;
-    }
-
-    (factor, pow)
-}
-
 internal function ArbitrarySuperpositionRegisterLengths(targetError : Double, nCoefficients : Int) : (Int, Int) {
     Fact(targetError > 0.0, "targetError must be positive");
     Fact(nCoefficients > 0, "nCoefficients must be positive");
diff --git a/vscode/src/debugger/activate.ts b/vscode/src/debugger/activate.ts
index f5603c6e..ee0bd4c0 100644
--- a/vscode/src/debugger/activate.ts
+++ b/vscode/src/debugger/activate.ts
@@ -45,21 +45,33 @@ function registerCommands(context: vscode.ExtensionContext) {
   context.subscriptions.push(
     vscode.commands.registerCommand(
       `${qsharpExtensionId}.runEditorContents`,
-      (resource: vscode.Uri, expr?: string) =>
+      (resource: vscode.Uri, expr?: string) => {
+        // if expr is not a string, ignore it. VS Code can sometimes
+        // pass other types when this command is invoked via UI buttons.
+        if (typeof expr !== "string") {
+          expr = undefined;
+        }
         startDebugging(
           resource,
           { name: "Run Q# File", stopOnEntry: false, entry: expr },
           { noDebug: true },
-        ),
+        );
+      },
     ),
     vscode.commands.registerCommand(
       `${qsharpExtensionId}.debugEditorContents`,
-      (resource: vscode.Uri, expr?: string) =>
+      (resource: vscode.Uri, expr?: string) => {
+        // if expr is not a string, ignore it. VS Code can sometimes
+        // pass other types when this command is invoked via UI buttons.
+        if (typeof expr !== "string") {
+          expr = undefined;
+        }
         startDebugging(resource, {
           name: "Debug Q# File",
           stopOnEntry: true,
           entry: expr,
-        }),
+        });
+      },
     ),
     vscode.commands.registerCommand(
       `${qsharpExtensionId}.runEditorContentsWithCircuit`,
diff --git a/vscode/src/webviewPanel.ts b/vscode/src/webviewPanel.ts
index d30e8fdf..e1adf6a3 100644
--- a/vscode/src/webviewPanel.ts
+++ b/vscode/src/webviewPanel.ts
@@ -391,7 +391,7 @@ export function registerWebViewCommands(context: ExtensionContext) {
   context.subscriptions.push(
     commands.registerCommand(
       `${qsharpExtensionId}.showCircuit`,
-      async (operation?: IOperationInfo) => {
+      async (resource?: vscode.Uri, operation?: IOperationInfo) => {
         await showCircuitCommand(context.extensionUri, operation);
       },
     ),


Test patch:
diff --git a/compiler/qsc/src/interpret/circuit_tests.rs b/compiler/qsc/src/interpret/circuit_tests.rs
index f3188cba..53bb19d4 100644
--- a/compiler/qsc/src/interpret/circuit_tests.rs
+++ b/compiler/qsc/src/interpret/circuit_tests.rs
@@ -490,18 +490,25 @@ fn custom_intrinsic_mixed_args() {
         .circuit(CircuitEntryPoint::EntryPoint, false)
         .expect("circuit generation should succeed");
 
-    // This is one gate that spans ten target wires, even though the
-    // text visualization doesn't convey that clearly.
     expect![[r"
         q_0    ─ AccountForEstimatesInternal([(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)], 1) ──
+                                                         ┆
         q_1    ─ AccountForEstimatesInternal([(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)], 1) ──
+                                                         ┆
         q_2    ─ AccountForEstimatesInternal([(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)], 1) ──
+                                                         ┆
         q_3    ─ AccountForEstimatesInternal([(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)], 1) ──
+                                                         ┆
         q_4    ─ AccountForEstimatesInternal([(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)], 1) ──
+                                                         ┆
         q_5    ─ AccountForEstimatesInternal([(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)], 1) ──
+                                                         ┆
         q_6    ─ AccountForEstimatesInternal([(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)], 1) ──
+                                                         ┆
         q_7    ─ AccountForEstimatesInternal([(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)], 1) ──
+                                                         ┆
         q_8    ─ AccountForEstimatesInternal([(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)], 1) ──
+                                                         ┆
         q_9    ─ AccountForEstimatesInternal([(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)], 1) ──
     "]]
     .assert_eq(&circ.to_string());
@@ -887,6 +894,113 @@ fn operation_with_long_gates_properly_aligned() {
     .assert_eq(&circ.to_string());
 }
 
+#[test]
+fn operation_with_subsequent_qubits_gets_horizontal_lines() {
+    let mut interpreter = interpreter(
+        r"
+            namespace Test {
+                import Std.Measurement.*;
+
+                @EntryPoint()
+                operation Main() : Unit {
+                    use q0 = Qubit();
+                    use q1 = Qubit();
+                    Rxx(1.0, q0, q1);
+
+                    use q2 = Qubit();
+                    use q3 = Qubit();
+                    Rxx(1.0, q2, q3);
+                }
+            }
+        ",
+        Profile::Unrestricted,
+    );
+
+    let circ = interpreter
+        .circuit(CircuitEntryPoint::EntryPoint, false)
+        .expect("circuit generation should succeed");
+
+    expect![[r#"
+        q_0    ─ rxx(1.0000) ─
+                      ┆
+        q_1    ─ rxx(1.0000) ─
+        q_2    ─ rxx(1.0000) ─
+                      ┆
+        q_3    ─ rxx(1.0000) ─
+    "#]]
+    .assert_eq(&circ.to_string());
+}
+
+#[test]
+fn operation_with_subsequent_qubits_no_double_rows() {
+    let mut interpreter = interpreter(
+        r"
+            namespace Test {
+                import Std.Measurement.*;
+
+                @EntryPoint()
+                operation Main() : Unit {
+                    use q0 = Qubit();
+                    use q1 = Qubit();
+                    Rxx(1.0, q0, q1);
+                    Rxx(1.0, q0, q1);
+                }
+            }
+        ",
+        Profile::Unrestricted,
+    );
+
+    let circ = interpreter
+        .circuit(CircuitEntryPoint::EntryPoint, false)
+        .expect("circuit generation should succeed");
+
+    expect![[r#"
+        q_0    ─ rxx(1.0000) ── rxx(1.0000) ─
+                      ┆              ┆
+        q_1    ─ rxx(1.0000) ── rxx(1.0000) ─
+    "#]]
+    .assert_eq(&circ.to_string());
+}
+
+#[test]
+fn operation_with_subsequent_qubits_no_added_rows() {
+    let mut interpreter = interpreter(
+        r"
+            namespace Test {
+                import Std.Measurement.*;
+
+                @EntryPoint()
+                operation Main() : Result[] {
+                    use q0 = Qubit();
+                    use q1 = Qubit();
+                    Rxx(1.0, q0, q1);
+
+                    use q2 = Qubit();
+                    use q3 = Qubit();
+                    Rxx(1.0, q2, q3);
+
+                    [M(q0), M(q2)]
+                }
+            }
+        ",
+        Profile::Unrestricted,
+    );
+
+    let circ = interpreter
+        .circuit(CircuitEntryPoint::EntryPoint, false)
+        .expect("circuit generation should succeed");
+
+    expect![[r#"
+        q_0    ─ rxx(1.0000) ─── M ──
+                      ┆          ╘═══
+        q_1    ─ rxx(1.0000) ────────
+        q_2    ─ rxx(1.0000) ─── M ──
+                      ┆          ╘═══
+        q_3    ─ rxx(1.0000) ────────
+    "#]]
+    .assert_eq(&circ.to_string());
+}
+
 /// Tests that invoke circuit generation throught the debugger.
 mod debugger_stepping {
     use super::Debugger;
diff --git a/compiler/qsc_frontend/src/lower/tests.rs b/compiler/qsc_frontend/src/lower/tests.rs
index f69873a7..02d3e2c0 100644
--- a/compiler/qsc_frontend/src/lower/tests.rs
+++ b/compiler/qsc_frontend/src/lower/tests.rs
@@ -2380,6 +2380,90 @@ fn lambda_with_invalid_free_variable() {
     );
 }
 
+#[test]
+fn lambda_with_explicit_return_should_have_non_unit_output_type() {
+    check_hir(
+        "function Foo(): Unit { let f = i -> return i + 1;}",
+        &expect![[r#"
+            Package:
+                Item 0 [0-50] (Public):
+                    Namespace (Ident 21 [0-50] "test"): Item 1
+                Item 1 [0-50] (Internal):
+                    Parent: 0
+                    Callable 0 [0-50] (function):
+                        name: Ident 1 [9-12] "Foo"
+                        input: Pat 2 [12-14] [Type Unit]: Unit
+                        output: Unit
+                        functors: empty set
+                        body: SpecDecl 3 [0-50]: Impl:
+                            Block 4 [21-50] [Type Unit]:
+                                Stmt 5 [23-49]: Local (Immutable):
+                                    Pat 6 [27-28] [Type (Int -> Int)]: Bind: Ident 7 [27-28] "f"
+                                    Expr 8 [31-48] [Type (Int -> Int)]: Closure([], 2)
+                        adj: <none>
+                        ctl: <none>
+                        ctl-adj: <none>
+                Item 2 [31-48] (Internal):
+                    Parent: 1
+                    Callable 16 [31-48] (function):
+                        name: Ident 17 [31-48] "<lambda>"
+                        input: Pat 15 [31-48] [Type (Int,)]: Tuple:
+                            Pat 9 [31-32] [Type Int]: Bind: Ident 10 [31-32] "i"
+                        output: Int
+                        functors: empty set
+                        body: SpecDecl 18 [36-48]: Impl:
+                            Block 19 [36-48] [Type Int]:
+                                Stmt 20 [36-48]: Expr: Expr 11 [36-48] [Type Int]: Return: Expr 12 [43-48] [Type Int]: BinOp (Add):
+                                    Expr 13 [43-44] [Type Int]: Var: Local 10
+                                    Expr 14 [47-48] [Type Int]: Lit: Int(1)
+                        adj: <none>
+                        ctl: <none>
+                        ctl-adj: <none>"#]],
+    );
+}
+
+#[test]
+fn lambda_with_implicit_return_should_have_non_unit_output_type() {
+    check_hir(
+        "function Foo(): Unit { let f = i -> i + 1}",
+        &expect![[r#"
+            Package:
+                Item 0 [0-42] (Public):
+                    Namespace (Ident 20 [0-42] "test"): Item 1
+                Item 1 [0-42] (Internal):
+                    Parent: 0
+                    Callable 0 [0-42] (function):
+                        name: Ident 1 [9-12] "Foo"
+                        input: Pat 2 [12-14] [Type Unit]: Unit
+                        output: Unit
+                        functors: empty set
+                        body: SpecDecl 3 [0-42]: Impl:
+                            Block 4 [21-42] [Type Unit]:
+                                Stmt 5 [23-41]: Local (Immutable):
+                                    Pat 6 [27-28] [Type (Int -> Int)]: Bind: Ident 7 [27-28] "f"
+                                    Expr 8 [31-41] [Type (Int -> Int)]: Closure([], 2)
+                        adj: <none>
+                        ctl: <none>
+                        ctl-adj: <none>
+                Item 2 [31-41] (Internal):
+                    Parent: 1
+                    Callable 15 [31-41] (function):
+                        name: Ident 16 [31-41] "<lambda>"
+                        input: Pat 14 [31-41] [Type (Int,)]: Tuple:
+                            Pat 9 [31-32] [Type Int]: Bind: Ident 10 [31-32] "i"
+                        output: Int
+                        functors: empty set
+                        body: SpecDecl 17 [36-41]: Impl:
+                            Block 18 [36-41] [Type Int]:
+                                Stmt 19 [36-41]: Expr: Expr 11 [36-41] [Type Int]: BinOp (Add):
+                                    Expr 12 [36-37] [Type Int]: Var: Local 10
+                                    Expr 13 [40-41] [Type Int]: Lit: Int(1)
+                        adj: <none>
+                        ctl: <none>
+                        ctl-adj: <none>"#]],
+    );
+}
+
 #[test]
 fn duplicate_commas_in_tydef() {
     check_hir(
diff --git a/compiler/qsc_frontend/src/typeck/tests.rs b/compiler/qsc_frontend/src/typeck/tests.rs
index 1933bdc0..c8f02411 100644
--- a/compiler/qsc_frontend/src/typeck/tests.rs
+++ b/compiler/qsc_frontend/src/typeck/tests.rs
@@ -3164,8 +3164,8 @@ fn lambda_inner_return() {
             #12 54-55 "f" : (Unit -> Int)
             #14 58-98 "() -> {\n            return 42;\n        }" : (Unit -> Int)
             #15 58-60 "()" : Unit
-            #16 64-98 "{\n            return 42;\n        }" : Unit
-            #17 64-98 "{\n            return 42;\n        }" : Unit
+            #16 64-98 "{\n            return 42;\n        }" : Int
+            #17 64-98 "{\n            return 42;\n        }" : Int
             #19 78-87 "return 42" : Unit
             #20 85-87 "42" : Int
             #22 112-113 "r" : Int
@@ -3197,8 +3197,8 @@ fn lambda_inner_return_without_call_ambiguous() {
             #15 58-64 "(a, b)" : (?2, ?2)
             #16 59-60 "a" : ?2
             #18 62-63 "b" : ?2
-            #20 68-105 "{\n            return a + b;\n        }" : Unit
-            #21 68-105 "{\n            return a + b;\n        }" : Unit
+            #20 68-105 "{\n            return a + b;\n        }" : ?2
+            #21 68-105 "{\n            return a + b;\n        }" : ?2
             #23 82-94 "return a + b" : Unit
             #24 89-94 "a + b" : ?2
             #25 89-90 "a" : ?2
@@ -3224,17 +3224,17 @@ fn lambda_implicit_return_without_call_ambiguous() {
         &expect![[r#"
             #6 30-32 "()" : Unit
             #10 40-104 "{\n        let f = (a, b) -> {\n            a + b\n        };\n    }" : Unit
-            #12 54-55 "f" : ((?2, ?2) -> ?2)
-            #14 58-97 "(a, b) -> {\n            a + b\n        }" : ((?2, ?2) -> ?2)
-            #15 58-64 "(a, b)" : (?2, ?2)
-            #16 59-60 "a" : ?2
-            #18 62-63 "b" : ?2
-            #20 68-97 "{\n            a + b\n        }" : ?2
-            #21 68-97 "{\n            a + b\n        }" : ?2
-            #23 82-87 "a + b" : ?2
-            #24 82-83 "a" : ?2
-            #27 86-87 "b" : ?2
-            Error(Type(Error(AmbiguousTy(Span { lo: 62, hi: 63 }))))
+            #12 54-55 "f" : ((?3, ?3) -> ?3)
+            #14 58-97 "(a, b) -> {\n            a + b\n        }" : ((?3, ?3) -> ?3)
+            #15 58-64 "(a, b)" : (?3, ?3)
+            #16 59-60 "a" : ?3
+            #18 62-63 "b" : ?3
+            #20 68-97 "{\n            a + b\n        }" : ?3
+            #21 68-97 "{\n            a + b\n        }" : ?3
+            #23 82-87 "a + b" : ?3
+            #24 82-83 "a" : ?3
+            #27 86-87 "b" : ?3
+            Error(Type(Error(AmbiguousTy(Span { lo: 68, hi: 97 }))))
         "#]],
     );
 }
diff --git a/compiler/qsc_rca/src/tests/lambdas.rs b/compiler/qsc_rca/src/tests/lambdas.rs
index 35baefde..17ffc572 100644
--- a/compiler/qsc_rca/src/tests/lambdas.rs
+++ b/compiler/qsc_rca/src/tests/lambdas.rs
@@ -217,3 +217,41 @@ fn check_rca_for_operation_lambda_two_parameters_with_controls() {
                 dynamic_param_applications: <empty>"#]],
     );
 }
+
+#[test]
+fn check_rca_for_function_lambda_using_array_slicing_with_explicit_return() {
+    let mut compilation_context = CompilationContext::default();
+    compilation_context.update(
+        r#"
+        let lambda = (a, n) -> { return a[...n - 1] };
+        lambda([1, 2, 3], 2)
+        "#,
+    );
+    let package_store_compute_properties = compilation_context.get_compute_properties();
+    check_last_statement_compute_properties(
+        package_store_compute_properties,
+        &expect![[r#"
+            ApplicationsGeneratorSet:
+                inherent: Classical
+                dynamic_param_applications: <empty>"#]],
+    );
+}
+
+#[test]
+fn check_rca_for_function_lambda_using_array_slicing_with_implicit_return() {
+    let mut compilation_context = CompilationContext::default();
+    compilation_context.update(
+        r#"
+        let lambda = (a, n) -> { a[...n - 1] };
+        lambda([1, 2, 3], 2)
+        "#,
+    );
+    let package_store_compute_properties = compilation_context.get_compute_properties();
+    check_last_statement_compute_properties(
+        package_store_compute_properties,
+        &expect![[r#"
+            ApplicationsGeneratorSet:
+                inherent: Classical
+                dynamic_param_applications: <empty>"#]],
+    );
+}
diff --git a/library/chemistry/src/Tests.qs b/library/chemistry/src/Tests.qs
index 2b44b292..2a6cfdf2 100644
--- a/library/chemistry/src/Tests.qs
+++ b/library/chemistry/src/Tests.qs
@@ -2,7 +2,6 @@ import Std.StatePreparation.ApproximatelyPreparePureStateCP;
 // Copyright (c) Microsoft Corporation. All rights reserved.
 // Licensed under the MIT License.
 
-import JordanWigner.JordanWignerOptimizedBlockEncoding.PrepareUniformSuperposition;
 import JordanWigner.JordanWignerClusterOperatorEvolutionSet.JordanWignerClusterOperatorPQRSTermSigns;
 import JordanWigner.OptimizedBEOperator.OptimizedBEXY;
 import JordanWigner.OptimizedBEOperator.SelectZ;
@@ -23,20 +22,6 @@ import Std.Math.Lg;
 import Std.Arrays.Reversed;
 import Std.Math.Sqrt;
 
-@Config(Unrestricted)
-@Test()
-operation PrepareUniformSuperpositionTest() : Unit {
-    let NBits = 4;
-    use qs = Qubit[NBits];
-    for NStates in 1..2^NBits-1 {
-        PrepareUniformSuperposition(NStates, qs);
-        let t = Std.Math.Sqrt(1.0 / IntAsDouble(NStates));
-        Adjoint Std.StatePreparation.PreparePureStateD(Repeated(t, NStates), Reversed(qs));
-        Fact(CheckAllZero(qs), "All Z");
-        ResetAll(qs);
-    }
-}
-
 @Config(Unrestricted)
 @Test()
 operation PrepareSparseMultiConfigurationalState0Test() : Unit {
diff --git a/library/src/tests/resources/src/state_preparation.qs b/library/src/tests/resources/src/state_preparation.qs
index 9b2e30d0..3e4ae311 100644
--- a/library/src/tests/resources/src/state_preparation.qs
+++ b/library/src/tests/resources/src/state_preparation.qs
@@ -106,4 +106,22 @@ namespace Test {
         }
     }
 
+    operation TestPrepareUniformSuperposition(nStates : Int) : Unit {
+        use qs = Qubit[10];
+        PrepareUniformSuperposition(nStates, qs);
+        DumpMachine();
+        ResetAll(qs);
+    }
+
+    operation TestPrepareUniformSuperpositionExhaustive() : Unit {
+        let NBits = 4;
+        for NStates in 1..2^NBits-1 {
+            use qs = Qubit[NBits];
+            PrepareUniformSuperposition(NStates, qs);
+            let t = Std.Math.Sqrt(1.0 / IntAsDouble(NStates));
+            Adjoint Std.StatePreparation.PreparePureStateD(Repeated(t, NStates), Reversed(qs));
+            Fact(CheckAllZero(qs), "All qubits must be in zero state.");
+        }
+    }
+
 }
diff --git a/library/src/tests/state_preparation.rs b/library/src/tests/state_preparation.rs
index c6575eca..c48e2ace 100644
--- a/library/src/tests/state_preparation.rs
+++ b/library/src/tests/state_preparation.rs
@@ -2,6 +2,7 @@
 // Licensed under the MIT License.
 
 use super::test_expression;
+use super::test_expression_fails;
 use super::test_expression_with_lib;
 use expect_test::expect;
 use qsc::interpret::Value;
@@ -254,3 +255,55 @@ fn check_preparation_doc_sample() {
     "#]]
     .assert_eq(&out);
 }
+
+#[test]
+fn check_uniform_superposition_preparation() {
+    let out = test_expression_with_lib(
+        "Test.TestPrepareUniformSuperposition(5)",
+        STATE_PREPARATION_TEST_LIB,
+        &Value::Tuple(vec![].into()),
+    );
+
+    expect![[r#"
+        STATE:
+        |0000000000⟩: 0.4472+0.0000𝑖
+        |0010000000⟩: 0.4472+0.0000𝑖
+        |0100000000⟩: 0.4472+0.0000𝑖
+        |1000000000⟩: 0.4472+0.0000𝑖
+        |1100000000⟩: 0.4472+0.0000𝑖
+    "#]]
+    .assert_eq(&out);
+}
+
+#[test]
+fn check_uniform_superposition_preparation_exhaustive() {
+    let _ = test_expression_with_lib(
+        "Test.TestPrepareUniformSuperpositionExhaustive()",
+        STATE_PREPARATION_TEST_LIB,
+        &Value::Tuple(vec![].into()),
+    );
+}
+
+#[test]
+fn check_uniform_superposition_short_array() {
+    let out = test_expression_fails(
+        "{
+            use qs=Qubit[2];
+            Std.StatePreparation.PrepareUniformSuperposition(5, qs);
+        }",
+    );
+
+    expect!["program failed: Qubit register is too short to prepare 5 states."].assert_eq(&out);
+}
+
+#[test]
+fn check_uniform_superposition_invalid_state_count() {
+    let out = test_expression_fails(
+        "{
+            use qs=Qubit[2];
+            Std.StatePreparation.PrepareUniformSuperposition(0, qs);
+        }",
+    );
+
+    expect!["program failed: Number of basis states must be positive."].assert_eq(&out);
+}