Skip to content
This repository was archived by the owner on Jan 12, 2024. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 107 additions & 0 deletions Standard/src/Arrays/Arrays.qs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@
// Licensed under the MIT License.

namespace Microsoft.Quantum.Arrays {
open Microsoft.Quantum.Convert;
open Microsoft.Quantum.Diagnostics;
open Microsoft.Quantum.Intrinsic;
open Microsoft.Quantum.Math;
open Microsoft.Quantum.Logical;

/// # Summary
/// Create an array that contains the same elements as an input array but in Reversed
Expand Down Expand Up @@ -295,5 +298,109 @@ namespace Microsoft.Quantum.Arrays {


}
function _IsPermutationPred(permutation : Int[], value : Int) : Bool {
let index = IndexOf(EqualI(value, _), permutation);
return index != -1;
}

function _IsPermutation(permuation : Int[]) : Bool {
return All(_IsPermutationPred(permuation, _), RangeAsIntArray(IndexRange(permuation)));
}

/// # Summary
/// Returns the order elements in an array need to be swapped to produce an ordered array.
/// Assumes swaps occur in place.
///
/// # Input
/// ## newOrder
/// Array with the permutation of the indices of the new array. There should be $n$ elements,
/// each being a unique integer from $0$ to $n-1$.
///
/// # Output
/// The tuple represents the two indices to be swapped. The swaps begin at the lowest index.
///
/// # Remarks
/// ## Example
/// ```qsharp
/// // The following returns [(0, 5),(0, 4),(0, 1),(0, 3)];
/// let swapOrder = _SwapOrderToPermuteArray([5, 3, 2, 0, 1, 4]);
/// ```
///
/// ## Psuedocode
/// for (index in 0..Length(newOrder) - 1)
/// {
/// while newOrder[index] != index
/// {
/// Switch newOrder[index] with newOrder[newOrder[index]]
/// }
/// }
function _SwapOrderToPermuteArray(newOrder : Int[]) : (Int, Int)[] {
// Check to verify the new ordering actually is a permutation of the indices
Fact(_IsPermutation(newOrder), $"The new ordering is not a permutation");

mutable swaps = new (Int, Int)[0];
mutable order = newOrder;

// for each value, whenever the index and value don't match, swap until it does
for (index in IndexRange(order)) {
while (not EqualI(order[index], index))
{
set swaps += [(index, order[index])];
set order = Swapped(order[index], index, order);
}
}

return swaps;
}

/// # Summary
/// Applies a swap of two elements in an array.
///
/// # Input
/// ## firstIndex
/// Index of the first element to be swapped.
///
/// ## secondIndex
/// Index of the second element to be swapped.
///
/// ## arr
/// Array with elements to be swapped.
///
/// # Output
/// The array with the in place swapp applied.
///
/// ## Example
/// ```qsharp
/// // The following returns [0, 3, 2, 1, 4]
/// Swapped(1, 3, [0, 1, 2, 3, 4]);
function Swapped<'T>(firstIndex: Int, secondIndex: Int, arr: 'T[]) : 'T[] {
return arr
w/ firstIndex <- arr[secondIndex]
w/ secondIndex <- arr[firstIndex];
}

/// # Summary
/// Turns a list of 2-tuples into a nested array.
///
/// # Input
/// ## tupleList
/// List of 2-tuples to be turned into a nested array.
///
/// # Output
/// A nested array with length matching the tupleList.
///
/// ## Example
/// ```qsharp
/// // The following returns [[2, 3], [4, 5]]
/// TupleArrayAsNestedArray([(2, 3), (4, 5)]);
/// ```
function TupleArrayAsNestedArray<'T>(tupleList : ('T, 'T)[]) : 'T[][] {
mutable newArray = new 'T[][Length(tupleList)];
for (idx in IndexRange(tupleList)) {
let (tupleLeft, tupleRight) = tupleList[idx];
set newArray w/= idx <- [tupleLeft, tupleRight];
}
return newArray;
}

}
256 changes: 256 additions & 0 deletions Standard/src/Canon/Combinators/ApplyRepeatedOver.qs
Original file line number Diff line number Diff line change
@@ -0,0 +1,256 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

namespace Microsoft.Quantum.Canon {
open Microsoft.Quantum.Diagnostics;
open Microsoft.Quantum.Arrays;
open Microsoft.Quantum.Intrinsic;

///////////////////////////////////////////////////////////////////////////////////////////////
// Helpers to repeatedly apply operations over qubit arrays
///////////////////////////////////////////////////////////////////////////////////////////////

/// # Summary
/// Applies a list of ops and their targets sequentially on an array.
///
/// # Input
/// ## listOfOps
/// List of ops, each taking a 'T array, to be applied. They are applied sequentially, lowest index first.
/// ## targets
/// Nested arrays describing the targets of the op. Each array should contain a list of ints describing
/// the indices to be used.
/// ## register
/// Qubit register to be acted upon.
///
/// ## Example
/// // The following applies Exp([PauliX, PauliY], 0.5) to qubits 0, 1
/// // then X to qubit 2
/// let ops = [Exp([PauliX, PauliY], 0.5, _), ApplyToFirstQubit(X, _)];
/// let indices = [[0, 1], [2]];
/// ApplySeriesOfOps(ops, indices, qubitArray);
///
/// # See Also
/// - Microsoft.Quantum.Canon.ApplyOpRepeatedlyOver
operation ApplySeriesOfOps<'T>(listOfOps : ('T[] => Unit)[], targets : Int[][], register : 'T[]) : Unit {
if (Length(listOfOps) != Length(targets)) {
fail "The number of ops and number of targets do not match!";
}
for ((op, targetIndices) in Zip(listOfOps, targets)) {
if (Length(targetIndices) > Length(register)) {
fail "There are too many targets!";
}
op(Subarray(targetIndices, register));
}
}

/// # Summary
/// Applies a list of ops and their targets sequentially on an array. (Adjoint)
///
/// # Input
/// ## listOfOps
/// List of ops, each taking a 'T array, to be applied. They are applied sequentially, lowest index first.
/// Each must have an adjoint functor
/// ## targets
/// Nested arrays describing the targets of the op. Each array should contain a list of ints describing
/// the indices to be used.
/// ## register
/// Qubit register to be acted upon.
///
/// ## Example
/// // The following applies Exp([PauliX, PauliY], 0.5) to qubits 0, 1
/// // then X to qubit 2
/// let ops = [Exp([PauliX, PauliY], 0.5, _), ApplyToFirstQubitA(X, _)];
/// let indices = [[0, 1], [2]];
/// ApplySeriesOfOpsA(ops, indices, qubitArray);
///
/// # See Also
/// - Microsoft.Quantum.Canon.ApplyOpRepeatedlyOver
operation ApplySeriesOfOpsA<'T>(listOfOps : ('T[] => Unit is Adj)[], targets : Int[][], register : 'T[]) : Unit is Adj{
if (Length(listOfOps) != Length(targets)) {
fail "The number of ops and number of targets do not match!";
}
for ((op, targetIndices) in Zip(listOfOps, targets)) {
if (Length(targetIndices) > Length(register)) {
fail "There are too many targets!";
}
op(Subarray(targetIndices, register));
}
}

/// # Summary
/// Applies a list of ops and their targets sequentially on an array. (Controlled)
///
/// # Input
/// ## listOfOps
/// List of ops, each taking a 'T array, to be applied. They are applied sequentially, lowest index first.
/// Each must have a Controlled functor
/// ## targets
/// Nested arrays describing the targets of the op. Each array should contain a list of ints describing
/// the indices to be used.
/// ## register
/// Qubit register to be acted upon.
///
/// ## Example
/// // The following applies Exp([PauliX, PauliY], 0.5) to qubits 0, 1
/// // then X to qubit 2
/// let ops = [Exp([PauliX, PauliY], 0.5, _), ApplyToFirstQubitC(X, _)];
/// let indices = [[0, 1], [2]];
/// ApplySeriesOfOpsC(ops, indices, qubitArray);
///
/// # See Also
/// - Microsoft.Quantum.Canon.ApplyOpRepeatedlyOver
operation ApplySeriesOfOpsC<'T>(listOfOps : ('T[] => Unit is Ctl)[], targets : Int[][], register : 'T[]) : Unit is Ctl{
if (Length(listOfOps) != Length(targets)) {
fail "The number of ops and number of targets do not match!";
}
for ((op, targetIndices) in Zip(listOfOps, targets)) {
if (Length(targetIndices) > Length(register)) {
fail "There are too many targets!";
}
op(Subarray(targetIndices, register));
}
}

/// # Summary
/// Applies a list of ops and their targets sequentially on an array. (Adjoint + Controlled)
///
/// # Input
/// ## listOfOps
/// List of ops, each taking a 'T array, to be applied. They are applied sequentially, lowest index first.
/// Each must have both an Adjoint and Controlled functor.
/// ## targets
/// Nested arrays describing the targets of the op. Each array should contain a list of ints describing
/// the indices to be used.
/// ## register
/// Qubit register to be acted upon.
///
/// ## Example
/// // The following applies Exp([PauliX, PauliY], 0.5) to qubits 0, 1
/// // then X to qubit 2
/// let ops = [Exp([PauliX, PauliY], 0.5, _), ApplyToFirstQubitCA(X, _)];
/// let indices = [[0, 1], [2]];
/// ApplySeriesOfOpsCA(ops, indices, qubitArray);
///
/// # See Also
/// - Microsoft.Quantum.Canon.ApplyOpRepeatedlyOver
operation ApplySeriesOfOpsCA<'T>(listOfOps : ('T[] => Unit is Adj + Ctl)[], targets : Int[][], register : 'T[]) : Unit is Adj + Ctl{
if (Length(listOfOps) != Length(targets)) {
fail "The number of ops and number of targets do not match!";
}
for ((op, targetIndices) in Zip(listOfOps, targets)) {
if (Length(targetIndices) > Length(register)) {
fail "There are too many targets!";
}
op(Subarray(targetIndices, register));
}
}

/// # Summary
/// Applies the same op over a qubit register multiple times.
///
/// # Input
/// ## op
/// An operation to be applied multiple times on the qubit register
/// ## targets
/// Nested arrays describing the targets of the op. Each array should contain a list of ints describing
/// the qubits to be used.
/// ## register
/// Qubit register to be acted upon.
///
/// # See Also
/// - Microsoft.Quantum.Canon.ApplySeriesOfOps
operation ApplyOpRepeatedlyOver(op : (Qubit[] => Unit), targets : Int[][], register : Qubit[]) : Unit
{
for (target in targets)
{
if (Length(target) > Length(register))
{
fail "Too many targets!";
}
let opTargets = Subarray(target, register);
op(opTargets);
}
}

/// # Summary
/// Applies the same op over a qubit register multiple times.
///
/// # Input
/// ## op
/// An operation to be applied multiple times on the qubit register
/// ## targets
/// Nested arrays describing the targets of the op. Each array should contain a list of ints describing
/// the qubits to be used.
/// ## register
/// Qubit register to be acted upon.
///
/// # See Also
/// - Microsoft.Quantum.Canon.ApplySeriesOfOps
operation ApplyOpRepeatedlyOverA(op : (Qubit[] => Unit is Adj), targets : Int[][], register : Qubit[]) : Unit is Adj
{
for (target in targets)
{
if (Length(target) > Length(register))
{
fail "Too many targets!";
}
let opTargets = Subarray(target, register);
op(opTargets);
}
}

/// # Summary
/// Applies the same op over a qubit register multiple times.
///
/// # Input
/// ## op
/// An operation to be applied multiple times on the qubit register
/// ## targets
/// Nested arrays describing the targets of the op. Each array should contain a list of ints describing
/// the qubits to be used.
/// ## register
/// Qubit register to be acted upon.
///
/// # See Also
/// - Microsoft.Quantum.Canon.ApplySeriesOfOps
operation ApplyOpRepeatedlyOverC(op : (Qubit[] => Unit is Ctl), targets : Int[][], register : Qubit[]) : Unit is Ctl
{
for (target in targets)
{
if (Length(target) > Length(register))
{
fail "Too many targets!";
}
let opTargets = Subarray(target, register);
op(opTargets);
}
}

/// # Summary
/// Applies the same op over a qubit register multiple times.
///
/// # Input
/// ## op
/// An operation to be applied multiple times on the qubit register
/// ## targets
/// Nested arrays describing the targets of the op. Each array should contain a list of ints describing
/// the qubits to be used.
/// ## register
/// Qubit register to be acted upon.
///
/// # See Also
/// - Microsoft.Quantum.Canon.ApplySeriesOfOps
operation ApplyOpRepeatedlyOverCA(op : (Qubit[] => Unit is Adj+Ctl), targets : Int[][], register : Qubit[]) : Unit is Adj+Ctl
{
for (target in targets)
{
if (Length(target) > Length(register))
{
fail "Too many targets!";
}
let opTargets = Subarray(target, register);
op(opTargets);
}
}

}
Loading