Skip to content
This repository was archived by the owner on Jan 12, 2024. It is now read-only.
This repository was archived by the owner on Jan 12, 2024. It is now read-only.

Multidimensional arrays #39

@cgranade

Description

@cgranade

Suggestion

Currently, for any Q# type 'T, the array type 'T[] represents an immutable collection of values of type 'T indexed by a single integer. It would be really helpful to add a new collection type that is indexed by tuples of integers instead, so as to allow for a more natural representation of concepts like matrices and tensors.

Considerations

While nested arrays can be used to do so (e.g.: Complex[][]), this can presents a number of disadvantages compared to a multidimensional array:

  • Nested arrays can in general be jagged; having multidimensional arrays as a type can help enforce that arrays are rectangular at the type level.
  • Performance: because nested arrays can be jagged, element lookup cannot in general be done as efficiently as with linear indexing.
  • Copy-and-update expressions: Using the w/ operator to modify elements of nested arrays can be a bit awkward.
    mutable matrix = [[1, 0, 0], [0, 1, 0], [0, 0, 1]];
    set matrix w/ 2 <- (matrix[2] w/ 1 <- 20);
    // matrix is now [[1, 0, 0], [0, 1, 0], [0, 20, 1]]

Building on the utility of 1-D array notation, this suggestion proposes modifying Q# to include new multidimensional array types 'T[,], 'T[,,], and so forth. Like values of type 'T[], these new multidimensional would also be immutable, and could be manipulated by using the subscript ([]) and copy-and-update (w/) operators.

As a possible alternative, we could instead consider providing syntactic sugar for manipulating nested (ragged) arrays; for example, copy-and-update expressions could be extended to include tuple indices:

mutable matrix = [[1, 0, 0], [0, 1, 0], [0, 0, 1]];
set matrix w/ 2 <- (matrix[2] w/ 1 <- 20);
// syntactic sugar for the above:
set matrix w/ (2, 1) <- 20;

While this would address the ergonomics of using values of type 'T[][], 'T[][][], and so forth, this syntactic sugar does not represent the compile-time guarantee that nested arrays are rectangular, necessitating potentially expensive shape checks (e.g. Microsoft.Quantum.Arrays.RectangularArrayFact). Similarly, providing syntactic sugar for nested arrays would not fundamentally change performance concerns with using nested arrays to represent matrices and tensors. For instance, by modifying the formula used to map multidimensional indices to linear indices, matrix and tensor transposition can be implemented in time that scales with the number of dimensions rather than the number of elements.

Context

This suggestion would require adding new functions and operations to the Microsoft.Quantum.Arrays namespace in the Q# standard library to support the feature; as Q# does not currently allow for a function or operation to act on multiple input types except as unbounded type parameters (see #149), these functions or operations would require distinct names from their 1D counterparts (e.g.: ConstantArray2, ConstantArray3, and so forth). Adding these functions and operations may require breaking changes to Microsoft.Quantum.Arrays in order to accommodate a naming scheme that includes suffixes for dimensionality.

Currently, array types in Q# can be indexed by values of type Int or Range, but current array indexing could be extended to allow "fancy" slicing by values of type Int[] (similar to the functionality offered by Microsoft.Quantum.Arrays.Subarray). In the same way, this suggestion could be extended to allow indexing 2D arrays by values of type (Int[], Int[]) as well as (Int, Range), (Range, Int), (Int, Int), and so forth. For example:

let data = [
    (0, 0), (0, 1), (0, 2);
    (1, 0), (1, 1), (1, 2);
    (2, 0), (2, 1), (2, 2)
];
let corners = data[[0, 2], [0, 2]];     // ← [(0, 0), (0, 2); (2, 0), (2, 2)]
let rightHandCorners = data[[0, 2], 2]; // ← [(2, 0), (2, 2)]
let swapMatrix = (IdentityMatrix(4))[[0, 2, 1, 3], [0, 2, 1, 3]];

Examples

Example 1:
Declaring a literal array representing a matrix over 𝐹₂.

// Bool[,] literals differentiated from Bool[][] by having only one level of [ ], corresponding
// to only one pair of [ ] used to subscript and in the type signature.
let bellTableau = [
    true, true, false, false; // ← "rows" are separated by ; rather than comma.
    false, false, true, true
];

Example 2:
Declaring and updating a 3×3 array of Double values.

namespace Microsoft.Quantum.Arrays {
    function IdentityMatrix(nDimensions : Int) : Double[,] { ... }
}

mutable matrix = IdentityMatrix(3);
set matrix w/ (2, 1) <- 20;
// matrix is now [1, 0, 0; 0, 1, 0; 0, 20, 1]

Example 3:
Indexing into a stabilizer tableau using ranges and integers.

let perfect = [
    PauliI, PauliX, PauliZ, PauliZ, PauliX;
    PauliX, PauliZ, PauliZ, PauliX, PauliI;
    PauliZ, PauliZ, PauliX, PauliI, PauliX;
    PauliZ, PauliX, PauliI, PauliX, PauliZ
];
Message($"{perfect[0, 2]}"); // ← Prints PauliZ.
let firstQubit = perfect[(..., 0)]; // ← [PauliI, PauliX, PauliZ, PauliZ]
let firstRow = perfect[(0, ...)]; // ← [PauliI, PauliX, PauliZ, PauliZ, PauliX]
let subblock = perfect[(1...2, 0...3)]; //  ← [PauliX, PauliZ, PauliZ; PauliZ, PauliZ, PauliX]

Example 4:
Compatibility with nested array types.

let identityMatrices = MappedOverRange(IdentityMatrix, 1..5); // type: Double[,][] (array of 2D arrays)
let contrived = [
    [0], [0, 1];
    [0, 1, 2], [0, 1, 2, 3]
]; // type: Int[][,] (2D array of arrays)

Affidavit (please fill out)

Please add ticks by placing a cross in the box:

  • I have searched both open and closed suggestions and proposals on this site and believe this is not a duplicate.
  • I believe that the spirit of this suggestion is aligned with the design principles and general vision for Q#.

Please tick all that apply:

  • This is not a breaking change to the Q# language design
  • I or my organization would be willing to help implement and/or test this

Metadata

Metadata

Assignees

Labels

UnderReviewSuggestion for which a full proposal is being worked out

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions