diff --git a/library/std/arrays.qs b/library/std/arrays.qs index ba11952883..b45297cbb5 100644 --- a/library/std/arrays.qs +++ b/library/std/arrays.qs @@ -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. /// diff --git a/library/tests/src/test_arrays.rs b/library/tests/src/test_arrays.rs index 0523b02a42..8e44c423ed 100644 --- a/library/tests/src/test_arrays.rs +++ b/library/tests/src/test_arrays.rs @@ -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(