Skip to content

Commit

Permalink
[API Proposal] Array CircularlyShifted array function (#881)
Browse files Browse the repository at this point in the history
I recently needed that and was surprised that in the reach pool of
built-in array functions there was no rotation function (rotate left or
right).

This PR adds a `Rotated` function which performs just that. It follows
the pattern of `Padded` function, in that a positive step indicates
rotation right, and negative indicates a rotation left.

Hope this makes sense.
  • Loading branch information
filipw authored Jan 5, 2024
1 parent 8ace063 commit b20710c
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 0 deletions.
48 changes: 48 additions & 0 deletions library/std/arrays.qs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,54 @@ namespace Microsoft.Quantum.Arrays {
output
}

/// # Summary
/// Shift an array circularly left or right by a specific step size.
///
/// # Type Parameters
/// ## 'T
/// The type of the array elements.
///
/// # Input
/// ## stepCount
/// The amount of positions by which the array elements will be shifted.
/// If this is positive, `array` is circularly shifted to the right.
/// If this is negative, `array` is circularly shifted to the left.
/// ## array
/// Array to be circularly shifted.
///
/// # Output
/// An array `output` that is the `array` circularly shifted to the right or left
/// by the specified step size.
///
/// # Example
/// ```qsharp
/// let array = [10, 11, 12];
/// // The following line returns [11, 12, 10].
/// let output = CircularlyShifted(2, array);
/// // The following line returns [12, 10, 11].
/// let output = CircularlyShifted(-2, array);
/// ```
function CircularlyShifted<'T> (stepCount : Int, array : 'T[]) : 'T[] {
let arrayLength = Length(array);
if arrayLength <= 1 {
return array;
}

// normalize circular shift count to be within the bounds of the array length
let normalizedShift = stepCount % arrayLength;
let effectiveShift = normalizedShift >= 0 ? arrayLength - normalizedShift | -normalizedShift;

// no shift needed
if effectiveShift == 0 {
return array;
}

let leftPart = array[...effectiveShift - 1];
let rightPart = array[effectiveShift..arrayLength - 1];

rightPart + leftPart
}

/// # Summary
/// Extracts a column from a matrix.
///
Expand Down
24 changes: 24 additions & 0 deletions library/tests/src/test_arrays.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,30 @@ fn check_chunks() {
);
}

#[test]
fn check_circularly_shifted() {
test_expression(
"Microsoft.Quantum.Arrays.CircularlyShifted(0, [10, 11, 12])",
&Value::Array(vec![Value::Int(10), Value::Int(11), Value::Int(12)].into()),
);
test_expression(
"Microsoft.Quantum.Arrays.CircularlyShifted(1, [10, 11, 12])",
&Value::Array(vec![Value::Int(12), Value::Int(10), Value::Int(11)].into()),
);
test_expression(
"Microsoft.Quantum.Arrays.CircularlyShifted(-1, [10, 11, 12])",
&Value::Array(vec![Value::Int(11), Value::Int(12), Value::Int(10)].into()),
);
test_expression(
"Microsoft.Quantum.Arrays.CircularlyShifted(500, [10, 11, 12])",
&Value::Array(vec![Value::Int(11), Value::Int(12), Value::Int(10)].into()),
);
test_expression(
"Microsoft.Quantum.Arrays.CircularlyShifted(-500, [10, 11, 12])",
&Value::Array(vec![Value::Int(12), Value::Int(10), Value::Int(11)].into()),
);
}

#[test]
fn check_column_at() {
test_expression(
Expand Down

0 comments on commit b20710c

Please sign in to comment.