From e6c7cbf4078683eb08cbcf6656817b869ebaa95b Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Thu, 17 Sep 2020 02:48:23 -0700 Subject: [PATCH 01/25] Update indexing --- spec/API_specification/indexing.md | 78 ++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/spec/API_specification/indexing.md b/spec/API_specification/indexing.md index 8a838b459..8f3dd5602 100644 --- a/spec/API_specification/indexing.md +++ b/spec/API_specification/indexing.md @@ -1 +1,79 @@ +.. _indexing: + # Indexing + +> Array API specification for indexing arrays. + +A conforming implementation of the array API standard must adhere to the following conventions. + +## Single-Axis Indexing + +To index a single array axis, an array must support standard Python indexing rules. + +1. Indices must start at `0` (i.e., zero-based indexing). Valid positive indices must reside on the interval `[0, n)`, where `n` is the axis (dimension) size. + +2. Negative indices must count backward from the last array index, starting from `-1` (where `-1` refers to the last index). Valid negative indices must reside on the interval `[-n, -1]`, where `n` is the axis (dimension) size. To convert a negative index `j` to a zero-based positive index `i`, evaluate `i = n+j`. + +3. Colons `:` must be used for slices: `start:stop:step`, where `start` is inclusive and `stop` is exclusive. + +### Slice Syntax + +The basic slice syntax is `i:j:k` where `i` is the starting index, `j` is the stopping index, and `k` is the step (`k != 0`). + +Using a slice to index a single array axis must select `m` elements with index values + +```text +i, i+k, i+2k, i+3k, ..., i+(m-1)k +``` + +where + +```text +m = q + r +``` + +and `q` and `r` (`r != 0`) are the quotient and remainder obtained by dividing `j-i` by `k` + +```text +j - i = qk + r +``` + +such that + +```text +j > i + (m-1)k +``` + +.. note:: + + The starting index `i` is **always** included, while the stopping index `j` is **always** excluded. This preserves `x[:i]+x[i:]` always being equal to `x`. + +Slice syntax must have the following defaults. Let `n` be the axis (dimension) size. + +1. If `k` is not provided (e.g., `0:10`), `k` must equal `1`. +2. If `k > 0` and `i` is not provided (e.g., `:10:2`), `i` must equal `0`. +3. If `k > 0` and `j` is not provided (e.g., `0::2`), `j` must equal `n`. +4. If `k < 0` and `i` is not provided (e.g., `:10:-2`), `i` must equal `n-1`. +5. If `k < 0` and `j` is not provided (e.g., `0::-2`), `j` must equal `-n-1`. + +Indexing via `:` and `::` must be equivalent and have defaults derived from the rules above. Both `:` and `::` indicate to select all elements along a single axis (dimension). + +## Multi-Axis Indexing + +Multi-dimensional arrays must extend the concept of single-axis indexing to multiple axes by applying single-axis indexing rules along each axis (dimension) and supporting the following additional rules. Let `N` be the number of dimensions of a multi-dimensional array `A`. + +1. Each axis may be independently indexed via single-axis indexing by providing a comma-separated sequence (selection tuple) of single-axis indexing expressions (e.g., `A[:, 2:10, :]`). + +.. note:: + + In Python, `x[(exp1, exp2, ..., expN)]` is equivalent to `x[exp1, exp2, ..., expN]`; the latter is just syntactic sugar for the former. + +2. Providing a single integer as a single-axis index must index the same elements as the slice `i:i+1`. + +3. Providing a single integer as a single-axis index must reduce the number of array dimensions by `1` (i.e., the array rank should decrease by one; `rank(A)-1 == rank(A[0, :])`). In particular, a selection tuple with the `m`th element an integer (and all other entries `:`) indexes the corresponding sub-array with rank `N-1`. + +4. Providing a slice must retain array dimensions (i.e., the array rank must remain the same; `rank(A) == rank(A[:])`). + +5. If the number of provided single-axis indexing expressions is less than `N`, then `:` must be assumed for the remaining dimensions (e.g., if `A` has rank `2`, `A[2:10] == A[2:10, :]`). + +6. Providing ellipsis must apply `:` to each dimension necessary to index all dimensions (e.g., if `A` has rank `4`, `A[1:, ..., 2:5] == A[1:, :, :, 2:5]`). Only a single ellipsis must be allowed. An exception must be raised if more than one ellipsis is provided. From ff6456d7ae29a8f01352847240d6ad062992dbbe Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Thu, 17 Sep 2020 02:50:58 -0700 Subject: [PATCH 02/25] Update example --- spec/API_specification/indexing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/API_specification/indexing.md b/spec/API_specification/indexing.md index 8f3dd5602..396bd3e0f 100644 --- a/spec/API_specification/indexing.md +++ b/spec/API_specification/indexing.md @@ -70,7 +70,7 @@ Multi-dimensional arrays must extend the concept of single-axis indexing to mult 2. Providing a single integer as a single-axis index must index the same elements as the slice `i:i+1`. -3. Providing a single integer as a single-axis index must reduce the number of array dimensions by `1` (i.e., the array rank should decrease by one; `rank(A)-1 == rank(A[0, :])`). In particular, a selection tuple with the `m`th element an integer (and all other entries `:`) indexes the corresponding sub-array with rank `N-1`. +3. Providing a single integer as a single-axis index must reduce the number of array dimensions by `1` (i.e., the array rank should decrease by one; if `A` has rank `2`, `rank(A)-1 == rank(A[0, :])`). In particular, a selection tuple with the `m`th element an integer (and all other entries `:`) indexes the corresponding sub-array with rank `N-1`. 4. Providing a slice must retain array dimensions (i.e., the array rank must remain the same; `rank(A) == rank(A[:])`). From 6480a7d012ce9e06df2e01a60d01976d630716cd Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Thu, 17 Sep 2020 13:58:13 -0700 Subject: [PATCH 03/25] Update copy --- spec/API_specification/indexing.md | 54 ++++++++++++++++++++++++------ 1 file changed, 43 insertions(+), 11 deletions(-) diff --git a/spec/API_specification/indexing.md b/spec/API_specification/indexing.md index 396bd3e0f..db7d50db2 100644 --- a/spec/API_specification/indexing.md +++ b/spec/API_specification/indexing.md @@ -8,17 +8,49 @@ A conforming implementation of the array API standard must adhere to the followi ## Single-Axis Indexing -To index a single array axis, an array must support standard Python indexing rules. +To index a single array axis, an array must support standard Python indexing rules. Let `n` be the axis (dimension) size. -1. Indices must start at `0` (i.e., zero-based indexing). Valid positive indices must reside on the interval `[0, n)`, where `n` is the axis (dimension) size. +1. Indices must be Python integers (i.e., `int`). -2. Negative indices must count backward from the last array index, starting from `-1` (where `-1` refers to the last index). Valid negative indices must reside on the interval `[-n, -1]`, where `n` is the axis (dimension) size. To convert a negative index `j` to a zero-based positive index `i`, evaluate `i = n+j`. +1. Nonnegative indices must start at `0` (i.e., zero-based indexing). -3. Colons `:` must be used for slices: `start:stop:step`, where `start` is inclusive and `stop` is exclusive. +1. Valid nonnegative indices must reside on the half-open interval `[0, n)`. + +1. Negative indices must count backward from the last array index, starting from `-1` (i.e., negative-one-based indexing, where `-1` refers to the last array index). + +.. note:: + + A negative index `j` is equivalent to `n-j`; the former is syntactic sugar for the latter, providing a shorthand for indexing elements that would otherwise need to be specified in terms of the axis (dimension) size. + +1. Valid negative indices must reside on the closed interval `[-n, -1]`. + +1. A negative index `j` is related to a zero-based nonnegative index `i` via `i = n+j`. + +1. Colons `:` must be used for [slices](https://docs.python.org/3/library/functions.html?highlight=slice#slice): `start:stop:step`, where `start` is inclusive and `stop` is exclusive. ### Slice Syntax -The basic slice syntax is `i:j:k` where `i` is the starting index, `j` is the stopping index, and `k` is the step (`k != 0`). +The basic slice syntax is `i:j:k` where `i` is the starting index, `j` is the stopping index, and `k` is the step (`k != 0`). A slice may contain either one or two colons, with either an integer value or nothing on either side of each colon. The following are valid slices. + +```text +A[:] +A[x:] +A[:y] +A[x:y] +A[::] +A[x::] +A[:y:] +A[::z] +A[x:y:] +A[x::z] +A[:y:z] +A[x::z] +A[x:y:z] +``` + +.. note:: + + Slice syntax can be equivalently achieved using the Python built-in [`slice()`](https://docs.python.org/3/library/functions.html?highlight=slice#slice) API. Using a slice to index a single array axis must select `m` elements with index values @@ -51,10 +83,10 @@ j > i + (m-1)k Slice syntax must have the following defaults. Let `n` be the axis (dimension) size. 1. If `k` is not provided (e.g., `0:10`), `k` must equal `1`. -2. If `k > 0` and `i` is not provided (e.g., `:10:2`), `i` must equal `0`. -3. If `k > 0` and `j` is not provided (e.g., `0::2`), `j` must equal `n`. -4. If `k < 0` and `i` is not provided (e.g., `:10:-2`), `i` must equal `n-1`. -5. If `k < 0` and `j` is not provided (e.g., `0::-2`), `j` must equal `-n-1`. +1. If `k > 0` and `i` is not provided (e.g., `:10:2`), `i` must equal `0`. +1. If `k > 0` and `j` is not provided (e.g., `0::2`), `j` must equal `n`. +1. If `k < 0` and `i` is not provided (e.g., `:10:-2`), `i` must equal `n-1`. +1. If `k < 0` and `j` is not provided (e.g., `0::-2`), `j` must equal `-n-1`. Indexing via `:` and `::` must be equivalent and have defaults derived from the rules above. Both `:` and `::` indicate to select all elements along a single axis (dimension). @@ -62,7 +94,7 @@ Indexing via `:` and `::` must be equivalent and have defaults derived from the Multi-dimensional arrays must extend the concept of single-axis indexing to multiple axes by applying single-axis indexing rules along each axis (dimension) and supporting the following additional rules. Let `N` be the number of dimensions of a multi-dimensional array `A`. -1. Each axis may be independently indexed via single-axis indexing by providing a comma-separated sequence (selection tuple) of single-axis indexing expressions (e.g., `A[:, 2:10, :]`). +1. Each axis may be independently indexed via single-axis indexing by providing a comma-separated sequence ("selection tuple") of single-axis indexing expressions (e.g., `A[:, 2:10, :, 5]`). .. note:: @@ -76,4 +108,4 @@ Multi-dimensional arrays must extend the concept of single-axis indexing to mult 5. If the number of provided single-axis indexing expressions is less than `N`, then `:` must be assumed for the remaining dimensions (e.g., if `A` has rank `2`, `A[2:10] == A[2:10, :]`). -6. Providing ellipsis must apply `:` to each dimension necessary to index all dimensions (e.g., if `A` has rank `4`, `A[1:, ..., 2:5] == A[1:, :, :, 2:5]`). Only a single ellipsis must be allowed. An exception must be raised if more than one ellipsis is provided. +6. Providing [ellipsis](https://docs.python.org/3/library/constants.html#Ellipsis) must apply `:` to each dimension necessary to index all dimensions (e.g., if `A` has rank `4`, `A[1:, ..., 2:5] == A[1:, :, :, 2:5]`). Only a single ellipsis must be allowed. An exception must be raised if more than one ellipsis is provided. From ab737dc194f5e883567b9b97493c7e83fd9b39e7 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Thu, 17 Sep 2020 14:00:06 -0700 Subject: [PATCH 04/25] Update variables --- spec/API_specification/indexing.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/spec/API_specification/indexing.md b/spec/API_specification/indexing.md index db7d50db2..bddb988ac 100644 --- a/spec/API_specification/indexing.md +++ b/spec/API_specification/indexing.md @@ -34,18 +34,18 @@ The basic slice syntax is `i:j:k` where `i` is the starting index, `j` is the st ```text A[:] -A[x:] -A[:y] -A[x:y] +A[i:] +A[:j] +A[i:k] A[::] -A[x::] -A[:y:] -A[::z] -A[x:y:] -A[x::z] -A[:y:z] -A[x::z] -A[x:y:z] +A[i::] +A[:j:] +A[::k] +A[i:j:] +A[i::k] +A[:j:k] +A[i::k] +A[i:j:k] ``` .. note:: From c27783ad35e2438b822b04186e459912ac4f0cbe Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Thu, 17 Sep 2020 14:01:38 -0700 Subject: [PATCH 05/25] Remove word --- spec/API_specification/indexing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/API_specification/indexing.md b/spec/API_specification/indexing.md index bddb988ac..627c2d18b 100644 --- a/spec/API_specification/indexing.md +++ b/spec/API_specification/indexing.md @@ -98,7 +98,7 @@ Multi-dimensional arrays must extend the concept of single-axis indexing to mult .. note:: - In Python, `x[(exp1, exp2, ..., expN)]` is equivalent to `x[exp1, exp2, ..., expN]`; the latter is just syntactic sugar for the former. + In Python, `x[(exp1, exp2, ..., expN)]` is equivalent to `x[exp1, exp2, ..., expN]`; the latter is syntactic sugar for the former. 2. Providing a single integer as a single-axis index must index the same elements as the slice `i:i+1`. From a736f7008892543424082e784b6eea349f6f417f Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Thu, 17 Sep 2020 14:02:30 -0700 Subject: [PATCH 06/25] Remove words --- spec/API_specification/indexing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/API_specification/indexing.md b/spec/API_specification/indexing.md index 627c2d18b..8b5fb0bfd 100644 --- a/spec/API_specification/indexing.md +++ b/spec/API_specification/indexing.md @@ -102,7 +102,7 @@ Multi-dimensional arrays must extend the concept of single-axis indexing to mult 2. Providing a single integer as a single-axis index must index the same elements as the slice `i:i+1`. -3. Providing a single integer as a single-axis index must reduce the number of array dimensions by `1` (i.e., the array rank should decrease by one; if `A` has rank `2`, `rank(A)-1 == rank(A[0, :])`). In particular, a selection tuple with the `m`th element an integer (and all other entries `:`) indexes the corresponding sub-array with rank `N-1`. +3. Providing a single integer as a single-axis index must reduce the number of array dimensions by `1` (i.e., the array rank should decrease by one; if `A` has rank `2`, `rank(A)-1 == rank(A[0, :])`). In particular, a selection tuple with the `m`th element an integer (and all other entries `:`) indexes a sub-array with rank `N-1`. 4. Providing a slice must retain array dimensions (i.e., the array rank must remain the same; `rank(A) == rank(A[:])`). From 6eaf90be4338577d96b3441bd74d785c552a427b Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Thu, 17 Sep 2020 14:04:24 -0700 Subject: [PATCH 07/25] Update markup --- spec/API_specification/indexing.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/spec/API_specification/indexing.md b/spec/API_specification/indexing.md index 8b5fb0bfd..0a6d4e43d 100644 --- a/spec/API_specification/indexing.md +++ b/spec/API_specification/indexing.md @@ -18,9 +18,9 @@ To index a single array axis, an array must support standard Python indexing rul 1. Negative indices must count backward from the last array index, starting from `-1` (i.e., negative-one-based indexing, where `-1` refers to the last array index). -.. note:: + .. note:: - A negative index `j` is equivalent to `n-j`; the former is syntactic sugar for the latter, providing a shorthand for indexing elements that would otherwise need to be specified in terms of the axis (dimension) size. + A negative index `j` is equivalent to `n-j`; the former is syntactic sugar for the latter, providing a shorthand for indexing elements that would otherwise need to be specified in terms of the axis (dimension) size. 1. Valid negative indices must reside on the closed interval `[-n, -1]`. @@ -96,16 +96,16 @@ Multi-dimensional arrays must extend the concept of single-axis indexing to mult 1. Each axis may be independently indexed via single-axis indexing by providing a comma-separated sequence ("selection tuple") of single-axis indexing expressions (e.g., `A[:, 2:10, :, 5]`). -.. note:: + .. note:: - In Python, `x[(exp1, exp2, ..., expN)]` is equivalent to `x[exp1, exp2, ..., expN]`; the latter is syntactic sugar for the former. + In Python, `x[(exp1, exp2, ..., expN)]` is equivalent to `x[exp1, exp2, ..., expN]`; the latter is syntactic sugar for the former. -2. Providing a single integer as a single-axis index must index the same elements as the slice `i:i+1`. +1. Providing a single integer as a single-axis index must index the same elements as the slice `i:i+1`. -3. Providing a single integer as a single-axis index must reduce the number of array dimensions by `1` (i.e., the array rank should decrease by one; if `A` has rank `2`, `rank(A)-1 == rank(A[0, :])`). In particular, a selection tuple with the `m`th element an integer (and all other entries `:`) indexes a sub-array with rank `N-1`. +1. Providing a single integer as a single-axis index must reduce the number of array dimensions by `1` (i.e., the array rank should decrease by one; if `A` has rank `2`, `rank(A)-1 == rank(A[0, :])`). In particular, a selection tuple with the `m`th element an integer (and all other entries `:`) indexes a sub-array with rank `N-1`. -4. Providing a slice must retain array dimensions (i.e., the array rank must remain the same; `rank(A) == rank(A[:])`). +1. Providing a slice must retain array dimensions (i.e., the array rank must remain the same; `rank(A) == rank(A[:])`). -5. If the number of provided single-axis indexing expressions is less than `N`, then `:` must be assumed for the remaining dimensions (e.g., if `A` has rank `2`, `A[2:10] == A[2:10, :]`). +1. If the number of provided single-axis indexing expressions is less than `N`, then `:` must be assumed for the remaining dimensions (e.g., if `A` has rank `2`, `A[2:10] == A[2:10, :]`). -6. Providing [ellipsis](https://docs.python.org/3/library/constants.html#Ellipsis) must apply `:` to each dimension necessary to index all dimensions (e.g., if `A` has rank `4`, `A[1:, ..., 2:5] == A[1:, :, :, 2:5]`). Only a single ellipsis must be allowed. An exception must be raised if more than one ellipsis is provided. +1. Providing [ellipsis](https://docs.python.org/3/library/constants.html#Ellipsis) must apply `:` to each dimension necessary to index all dimensions (e.g., if `A` has rank `4`, `A[1:, ..., 2:5] == A[1:, :, :, 2:5]`). Only a single ellipsis must be allowed. An exception must be raised if more than one ellipsis is provided. From 11ac37774c2965a5e68e9126ca13ebeb7954367e Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Thu, 17 Sep 2020 14:06:10 -0700 Subject: [PATCH 08/25] Update copy --- spec/API_specification/indexing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/API_specification/indexing.md b/spec/API_specification/indexing.md index 0a6d4e43d..6480859a3 100644 --- a/spec/API_specification/indexing.md +++ b/spec/API_specification/indexing.md @@ -92,7 +92,7 @@ Indexing via `:` and `::` must be equivalent and have defaults derived from the ## Multi-Axis Indexing -Multi-dimensional arrays must extend the concept of single-axis indexing to multiple axes by applying single-axis indexing rules along each axis (dimension) and supporting the following additional rules. Let `N` be the number of dimensions of a multi-dimensional array `A`. +Multi-dimensional arrays must extend the concept of single-axis indexing to multiple axes by applying single-axis indexing rules along each axis (dimension) and supporting the following additional rules. Let `N` be the number of dimensions ("rank") of a multi-dimensional array `A`. 1. Each axis may be independently indexed via single-axis indexing by providing a comma-separated sequence ("selection tuple") of single-axis indexing expressions (e.g., `A[:, 2:10, :, 5]`). From 35ef60e5f6b1015b2898b1c530e0721b6ef0ec85 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Thu, 17 Sep 2020 14:06:36 -0700 Subject: [PATCH 09/25] Update headings --- spec/API_specification/indexing.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/API_specification/indexing.md b/spec/API_specification/indexing.md index 6480859a3..3a4f60de3 100644 --- a/spec/API_specification/indexing.md +++ b/spec/API_specification/indexing.md @@ -6,7 +6,7 @@ A conforming implementation of the array API standard must adhere to the following conventions. -## Single-Axis Indexing +## Single-axis Indexing To index a single array axis, an array must support standard Python indexing rules. Let `n` be the axis (dimension) size. @@ -90,7 +90,7 @@ Slice syntax must have the following defaults. Let `n` be the axis (dimension) s Indexing via `:` and `::` must be equivalent and have defaults derived from the rules above. Both `:` and `::` indicate to select all elements along a single axis (dimension). -## Multi-Axis Indexing +## Multi-axis Indexing Multi-dimensional arrays must extend the concept of single-axis indexing to multiple axes by applying single-axis indexing rules along each axis (dimension) and supporting the following additional rules. Let `N` be the number of dimensions ("rank") of a multi-dimensional array `A`. From 702cadaa115c6147e3dc453041d408bd38014b40 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Thu, 17 Sep 2020 14:08:04 -0700 Subject: [PATCH 10/25] Use unordered lists --- spec/API_specification/indexing.md | 36 +++++++++++++++--------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/spec/API_specification/indexing.md b/spec/API_specification/indexing.md index 3a4f60de3..109539059 100644 --- a/spec/API_specification/indexing.md +++ b/spec/API_specification/indexing.md @@ -10,23 +10,23 @@ A conforming implementation of the array API standard must adhere to the followi To index a single array axis, an array must support standard Python indexing rules. Let `n` be the axis (dimension) size. -1. Indices must be Python integers (i.e., `int`). +- Indices must be Python integers (i.e., `int`). -1. Nonnegative indices must start at `0` (i.e., zero-based indexing). +- Nonnegative indices must start at `0` (i.e., zero-based indexing). -1. Valid nonnegative indices must reside on the half-open interval `[0, n)`. +- Valid nonnegative indices must reside on the half-open interval `[0, n)`. -1. Negative indices must count backward from the last array index, starting from `-1` (i.e., negative-one-based indexing, where `-1` refers to the last array index). +- Negative indices must count backward from the last array index, starting from `-1` (i.e., negative-one-based indexing, where `-1` refers to the last array index). .. note:: A negative index `j` is equivalent to `n-j`; the former is syntactic sugar for the latter, providing a shorthand for indexing elements that would otherwise need to be specified in terms of the axis (dimension) size. -1. Valid negative indices must reside on the closed interval `[-n, -1]`. +- Valid negative indices must reside on the closed interval `[-n, -1]`. -1. A negative index `j` is related to a zero-based nonnegative index `i` via `i = n+j`. +- A negative index `j` is related to a zero-based nonnegative index `i` via `i = n+j`. -1. Colons `:` must be used for [slices](https://docs.python.org/3/library/functions.html?highlight=slice#slice): `start:stop:step`, where `start` is inclusive and `stop` is exclusive. +- Colons `:` must be used for [slices](https://docs.python.org/3/library/functions.html?highlight=slice#slice): `start:stop:step`, where `start` is inclusive and `stop` is exclusive. ### Slice Syntax @@ -82,11 +82,11 @@ j > i + (m-1)k Slice syntax must have the following defaults. Let `n` be the axis (dimension) size. -1. If `k` is not provided (e.g., `0:10`), `k` must equal `1`. -1. If `k > 0` and `i` is not provided (e.g., `:10:2`), `i` must equal `0`. -1. If `k > 0` and `j` is not provided (e.g., `0::2`), `j` must equal `n`. -1. If `k < 0` and `i` is not provided (e.g., `:10:-2`), `i` must equal `n-1`. -1. If `k < 0` and `j` is not provided (e.g., `0::-2`), `j` must equal `-n-1`. +- If `k` is not provided (e.g., `0:10`), `k` must equal `1`. +- If `k > 0` and `i` is not provided (e.g., `:10:2`), `i` must equal `0`. +- If `k > 0` and `j` is not provided (e.g., `0::2`), `j` must equal `n`. +- If `k < 0` and `i` is not provided (e.g., `:10:-2`), `i` must equal `n-1`. +- If `k < 0` and `j` is not provided (e.g., `0::-2`), `j` must equal `-n-1`. Indexing via `:` and `::` must be equivalent and have defaults derived from the rules above. Both `:` and `::` indicate to select all elements along a single axis (dimension). @@ -94,18 +94,18 @@ Indexing via `:` and `::` must be equivalent and have defaults derived from the Multi-dimensional arrays must extend the concept of single-axis indexing to multiple axes by applying single-axis indexing rules along each axis (dimension) and supporting the following additional rules. Let `N` be the number of dimensions ("rank") of a multi-dimensional array `A`. -1. Each axis may be independently indexed via single-axis indexing by providing a comma-separated sequence ("selection tuple") of single-axis indexing expressions (e.g., `A[:, 2:10, :, 5]`). +- Each axis may be independently indexed via single-axis indexing by providing a comma-separated sequence ("selection tuple") of single-axis indexing expressions (e.g., `A[:, 2:10, :, 5]`). .. note:: In Python, `x[(exp1, exp2, ..., expN)]` is equivalent to `x[exp1, exp2, ..., expN]`; the latter is syntactic sugar for the former. -1. Providing a single integer as a single-axis index must index the same elements as the slice `i:i+1`. +- Providing a single integer as a single-axis index must index the same elements as the slice `i:i+1`. -1. Providing a single integer as a single-axis index must reduce the number of array dimensions by `1` (i.e., the array rank should decrease by one; if `A` has rank `2`, `rank(A)-1 == rank(A[0, :])`). In particular, a selection tuple with the `m`th element an integer (and all other entries `:`) indexes a sub-array with rank `N-1`. +- Providing a single integer as a single-axis index must reduce the number of array dimensions by `1` (i.e., the array rank should decrease by one; if `A` has rank `2`, `rank(A)-1 == rank(A[0, :])`). In particular, a selection tuple with the `m`th element an integer (and all other entries `:`) indexes a sub-array with rank `N-1`. -1. Providing a slice must retain array dimensions (i.e., the array rank must remain the same; `rank(A) == rank(A[:])`). +- Providing a slice must retain array dimensions (i.e., the array rank must remain the same; `rank(A) == rank(A[:])`). -1. If the number of provided single-axis indexing expressions is less than `N`, then `:` must be assumed for the remaining dimensions (e.g., if `A` has rank `2`, `A[2:10] == A[2:10, :]`). +- If the number of provided single-axis indexing expressions is less than `N`, then `:` must be assumed for the remaining dimensions (e.g., if `A` has rank `2`, `A[2:10] == A[2:10, :]`). -1. Providing [ellipsis](https://docs.python.org/3/library/constants.html#Ellipsis) must apply `:` to each dimension necessary to index all dimensions (e.g., if `A` has rank `4`, `A[1:, ..., 2:5] == A[1:, :, :, 2:5]`). Only a single ellipsis must be allowed. An exception must be raised if more than one ellipsis is provided. +- Providing [ellipsis](https://docs.python.org/3/library/constants.html#Ellipsis) must apply `:` to each dimension necessary to index all dimensions (e.g., if `A` has rank `4`, `A[1:, ..., 2:5] == A[1:, :, :, 2:5]`). Only a single ellipsis must be allowed. An exception must be raised if more than one ellipsis is provided. From ded8acdec9a880b90847033fb14ea13e19e7816c Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sun, 20 Sep 2020 15:43:40 -0700 Subject: [PATCH 11/25] Add notes --- spec/API_specification/indexing.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/spec/API_specification/indexing.md b/spec/API_specification/indexing.md index 109539059..47bc97912 100644 --- a/spec/API_specification/indexing.md +++ b/spec/API_specification/indexing.md @@ -10,12 +10,16 @@ A conforming implementation of the array API standard must adhere to the followi To index a single array axis, an array must support standard Python indexing rules. Let `n` be the axis (dimension) size. -- Indices must be Python integers (i.e., `int`). +- An valid index must be an object satisfying [`operator.index`](https://www.python.org/dev/peps/pep-0357/) (e.g., `int`). - Nonnegative indices must start at `0` (i.e., zero-based indexing). - Valid nonnegative indices must reside on the half-open interval `[0, n)`. + .. note:: + + This specification does not explicitly require bounds checking. The behavior for out-of-bounds integer indices is left unspecified. + - Negative indices must count backward from the last array index, starting from `-1` (i.e., negative-one-based indexing, where `-1` refers to the last array index). .. note:: @@ -24,6 +28,10 @@ To index a single array axis, an array must support standard Python indexing rul - Valid negative indices must reside on the closed interval `[-n, -1]`. + .. note:: + + This specification does not explicitly require bounds checking. The behavior for out-of-bounds integer indices is left unspecified. + - A negative index `j` is related to a zero-based nonnegative index `i` via `i = n+j`. - Colons `:` must be used for [slices](https://docs.python.org/3/library/functions.html?highlight=slice#slice): `start:stop:step`, where `start` is inclusive and `stop` is exclusive. @@ -109,3 +117,6 @@ Multi-dimensional arrays must extend the concept of single-axis indexing to mult - If the number of provided single-axis indexing expressions is less than `N`, then `:` must be assumed for the remaining dimensions (e.g., if `A` has rank `2`, `A[2:10] == A[2:10, :]`). - Providing [ellipsis](https://docs.python.org/3/library/constants.html#Ellipsis) must apply `:` to each dimension necessary to index all dimensions (e.g., if `A` has rank `4`, `A[1:, ..., 2:5] == A[1:, :, :, 2:5]`). Only a single ellipsis must be allowed. An exception must be raised if more than one ellipsis is provided. + +## Boolean Array Indexing + From 40467a8c60fcd4ed3b06bf47bb3f03400d940520 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sun, 20 Sep 2020 15:44:14 -0700 Subject: [PATCH 12/25] Fix grammar --- spec/API_specification/indexing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/API_specification/indexing.md b/spec/API_specification/indexing.md index 47bc97912..63cf91275 100644 --- a/spec/API_specification/indexing.md +++ b/spec/API_specification/indexing.md @@ -10,7 +10,7 @@ A conforming implementation of the array API standard must adhere to the followi To index a single array axis, an array must support standard Python indexing rules. Let `n` be the axis (dimension) size. -- An valid index must be an object satisfying [`operator.index`](https://www.python.org/dev/peps/pep-0357/) (e.g., `int`). +- A valid integer index must be an object satisfying [`operator.index`](https://www.python.org/dev/peps/pep-0357/) (e.g., `int`). - Nonnegative indices must start at `0` (i.e., zero-based indexing). From 50c6b1fdf57598cc396c481edbb93afabc080b83 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sun, 20 Sep 2020 15:46:15 -0700 Subject: [PATCH 13/25] Update note --- spec/API_specification/indexing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/API_specification/indexing.md b/spec/API_specification/indexing.md index 63cf91275..59f15d724 100644 --- a/spec/API_specification/indexing.md +++ b/spec/API_specification/indexing.md @@ -58,7 +58,7 @@ A[i:j:k] .. note:: - Slice syntax can be equivalently achieved using the Python built-in [`slice()`](https://docs.python.org/3/library/functions.html?highlight=slice#slice) API. + Slice syntax can be equivalently achieved using the Python built-in [`slice()`](https://docs.python.org/3/library/functions.html?highlight=slice#slice) API. From the perspective from `A`, the behavior of `A[i:j:k]` and `A[slice(i, j, k)]` are indistinguishable (i.e., both retrieve the same set of items from `__getitem__`). Using a slice to index a single array axis must select `m` elements with index values From bf16ecab8f02950a2e8593d45116272418e6da61 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sun, 20 Sep 2020 15:51:38 -0700 Subject: [PATCH 14/25] Add qualifications --- spec/API_specification/indexing.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/spec/API_specification/indexing.md b/spec/API_specification/indexing.md index 59f15d724..a9d2a6bf0 100644 --- a/spec/API_specification/indexing.md +++ b/spec/API_specification/indexing.md @@ -10,11 +10,11 @@ A conforming implementation of the array API standard must adhere to the followi To index a single array axis, an array must support standard Python indexing rules. Let `n` be the axis (dimension) size. -- A valid integer index must be an object satisfying [`operator.index`](https://www.python.org/dev/peps/pep-0357/) (e.g., `int`). +- An integer index must be an object satisfying [`operator.index`](https://www.python.org/dev/peps/pep-0357/) (e.g., `int`). - Nonnegative indices must start at `0` (i.e., zero-based indexing). -- Valid nonnegative indices must reside on the half-open interval `[0, n)`. +- **Valid** nonnegative indices must reside on the half-open interval `[0, n)`. .. note:: @@ -26,7 +26,7 @@ To index a single array axis, an array must support standard Python indexing rul A negative index `j` is equivalent to `n-j`; the former is syntactic sugar for the latter, providing a shorthand for indexing elements that would otherwise need to be specified in terms of the axis (dimension) size. -- Valid negative indices must reside on the closed interval `[-n, -1]`. +- **Valid** negative indices must reside on the closed interval `[-n, -1]`. .. note:: @@ -86,7 +86,7 @@ j > i + (m-1)k .. note:: - The starting index `i` is **always** included, while the stopping index `j` is **always** excluded. This preserves `x[:i]+x[i:]` always being equal to `x`. + For `i < j`, **valid** integer index `i`, and positive step `k`, a starting index `i` is **always** included, while the stopping index `j` is **always** excluded. This preserves `x[:i]+x[i:]` always being equal to `x`. Slice syntax must have the following defaults. Let `n` be the axis (dimension) size. From d4dcb6a5c70502dda52b206665b5777cd86ce416 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sun, 20 Sep 2020 15:53:56 -0700 Subject: [PATCH 15/25] Add additional note --- spec/API_specification/indexing.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/spec/API_specification/indexing.md b/spec/API_specification/indexing.md index a9d2a6bf0..368489dd7 100644 --- a/spec/API_specification/indexing.md +++ b/spec/API_specification/indexing.md @@ -88,6 +88,10 @@ j > i + (m-1)k For `i < j`, **valid** integer index `i`, and positive step `k`, a starting index `i` is **always** included, while the stopping index `j` is **always** excluded. This preserves `x[:i]+x[i:]` always being equal to `x`. +.. note:: + + Using a slice to index into a single array axis should select the same elements as using a slice to index a Python list of the same size. + Slice syntax must have the following defaults. Let `n` be the axis (dimension) size. - If `k` is not provided (e.g., `0:10`), `k` must equal `1`. From abcbc3147c4cb51244bd4308112aa9ed5948288b Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sun, 20 Sep 2020 15:56:59 -0700 Subject: [PATCH 16/25] Add clause for negative integer indices --- spec/API_specification/indexing.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/spec/API_specification/indexing.md b/spec/API_specification/indexing.md index 368489dd7..45ac2bc47 100644 --- a/spec/API_specification/indexing.md +++ b/spec/API_specification/indexing.md @@ -112,7 +112,9 @@ Multi-dimensional arrays must extend the concept of single-axis indexing to mult In Python, `x[(exp1, exp2, ..., expN)]` is equivalent to `x[exp1, exp2, ..., expN]`; the latter is syntactic sugar for the former. -- Providing a single integer as a single-axis index must index the same elements as the slice `i:i+1`. +- Providing a single nonnegative integer `i` as a single-axis index must index the same elements as the slice `i:i+1`. + +- Providing a single negative integer `i` as a single-axis index must index the same elements as the slice `n+i:n`, where `n` is the axis (dimension) size. - Providing a single integer as a single-axis index must reduce the number of array dimensions by `1` (i.e., the array rank should decrease by one; if `A` has rank `2`, `rank(A)-1 == rank(A[0, :])`). In particular, a selection tuple with the `m`th element an integer (and all other entries `:`) indexes a sub-array with rank `N-1`. From 7dce65aa85185808eee14a1a91b8f58fc6ff718b Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sun, 20 Sep 2020 16:01:38 -0700 Subject: [PATCH 17/25] Add clause regarding providing extra axis indexing expressions --- spec/API_specification/indexing.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/spec/API_specification/indexing.md b/spec/API_specification/indexing.md index 45ac2bc47..65c17e716 100644 --- a/spec/API_specification/indexing.md +++ b/spec/API_specification/indexing.md @@ -122,6 +122,8 @@ Multi-dimensional arrays must extend the concept of single-axis indexing to mult - If the number of provided single-axis indexing expressions is less than `N`, then `:` must be assumed for the remaining dimensions (e.g., if `A` has rank `2`, `A[2:10] == A[2:10, :]`). +- An `IndexError` exception must be raised if the number of provided single-axis indexing expressions is greater than `N`. + - Providing [ellipsis](https://docs.python.org/3/library/constants.html#Ellipsis) must apply `:` to each dimension necessary to index all dimensions (e.g., if `A` has rank `4`, `A[1:, ..., 2:5] == A[1:, :, :, 2:5]`). Only a single ellipsis must be allowed. An exception must be raised if more than one ellipsis is provided. ## Boolean Array Indexing From 9d522f147b73c5b74c8d8c6a0290b10b62381d05 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sun, 20 Sep 2020 16:02:49 -0700 Subject: [PATCH 18/25] Specify exception type --- spec/API_specification/indexing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/API_specification/indexing.md b/spec/API_specification/indexing.md index 65c17e716..cb8706799 100644 --- a/spec/API_specification/indexing.md +++ b/spec/API_specification/indexing.md @@ -124,7 +124,7 @@ Multi-dimensional arrays must extend the concept of single-axis indexing to mult - An `IndexError` exception must be raised if the number of provided single-axis indexing expressions is greater than `N`. -- Providing [ellipsis](https://docs.python.org/3/library/constants.html#Ellipsis) must apply `:` to each dimension necessary to index all dimensions (e.g., if `A` has rank `4`, `A[1:, ..., 2:5] == A[1:, :, :, 2:5]`). Only a single ellipsis must be allowed. An exception must be raised if more than one ellipsis is provided. +- Providing [ellipsis](https://docs.python.org/3/library/constants.html#Ellipsis) must apply `:` to each dimension necessary to index all dimensions (e.g., if `A` has rank `4`, `A[1:, ..., 2:5] == A[1:, :, :, 2:5]`). Only a single ellipsis must be allowed. An `IndexError` exception must be raised if more than one ellipsis is provided. ## Boolean Array Indexing From 74943fbd175f945004c76bf810ca60506ae376cf Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sun, 20 Sep 2020 18:03:21 -0700 Subject: [PATCH 19/25] Add boolean index array guidance --- spec/API_specification/indexing.md | 15 +++++++++++++++ spec/API_specification/searching_functions.md | 2 ++ 2 files changed, 17 insertions(+) diff --git a/spec/API_specification/indexing.md b/spec/API_specification/indexing.md index cb8706799..a6121cff6 100644 --- a/spec/API_specification/indexing.md +++ b/spec/API_specification/indexing.md @@ -128,3 +128,18 @@ Multi-dimensional arrays must extend the concept of single-axis indexing to mult ## Boolean Array Indexing +An array must support indexing via a **single** `M`-dimensional boolean array `B` with shape `S1 = (s1, ..., sM)` according to the following rules. Let `A` be an `N`-dimensional array with shape `S2 = (s1, ..., sM, ..., sN)`. + +- If `N >= M`, then `A[B]` must replace the first `M` dimensions of `A` with a single dimension having a size equal to the number of `True` elements in `B`. + + .. note:: + + For example, if `N == M == 2`, indexing `A` via a boolean array `B` will return a one-dimensional array whose size is equal to the number of `True` elements in `B`. + +- If `N < M`, then an `IndexError` exception must be raised. + +- The size of each dimension in `B` must equal the size of the corresponding dimension in `A` or be `0`, beginning with the first dimension in `A`. If a dimension size does not equal the size of the corresponding dimension in `A` and is not `0`, then an `IndexError` exception must be raised. + +- The elements of a boolean index array must be iterated in row-major, C-style order, with the exception of zero-dimensional boolean arrays. + +- A zero-dimensional boolean index array (equivalent to `True` or `False`) follows the same axis replacement rules stated above. Namely, a zero-dimensional boolean index array removes zero dimensions and adds a single dimension of length `1` if the index array's value is `True` and of length `0` if the index array's value is `False`. Accordingly, for a zero-dimensional boolean index array `B`, the result of `A[B]` has shape `S = (1, s1, ..., sN)` if the index array's value is `True` and has shape `S = (0, s1, ..., sN)` if the index array's value is `False`. \ No newline at end of file diff --git a/spec/API_specification/searching_functions.md b/spec/API_specification/searching_functions.md index 5e70e993d..70b3a84b1 100644 --- a/spec/API_specification/searching_functions.md +++ b/spec/API_specification/searching_functions.md @@ -1,3 +1,5 @@ +.. _searching-functions: + # Searching Functions > Array API specification for functions for searching arrays. From b764e4b14d8004839a8cb6dfc684145fd8b4b344 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sun, 20 Sep 2020 18:04:16 -0700 Subject: [PATCH 20/25] Update copy --- spec/API_specification/indexing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/API_specification/indexing.md b/spec/API_specification/indexing.md index a6121cff6..a3f78fc2f 100644 --- a/spec/API_specification/indexing.md +++ b/spec/API_specification/indexing.md @@ -142,4 +142,4 @@ An array must support indexing via a **single** `M`-dimensional boolean array `B - The elements of a boolean index array must be iterated in row-major, C-style order, with the exception of zero-dimensional boolean arrays. -- A zero-dimensional boolean index array (equivalent to `True` or `False`) follows the same axis replacement rules stated above. Namely, a zero-dimensional boolean index array removes zero dimensions and adds a single dimension of length `1` if the index array's value is `True` and of length `0` if the index array's value is `False`. Accordingly, for a zero-dimensional boolean index array `B`, the result of `A[B]` has shape `S = (1, s1, ..., sN)` if the index array's value is `True` and has shape `S = (0, s1, ..., sN)` if the index array's value is `False`. \ No newline at end of file +- A zero-dimensional boolean index array (equivalent to `True` or `False`) must follow the same axis replacement rules stated above. Namely, a zero-dimensional boolean index array removes zero dimensions and adds a single dimension of length `1` if the index array's value is `True` and of length `0` if the index array's value is `False`. Accordingly, for a zero-dimensional boolean index array `B`, the result of `A[B]` has shape `S = (1, s1, ..., sN)` if the index array's value is `True` and has shape `S = (0, s1, ..., sN)` if the index array's value is `False`. \ No newline at end of file From b5ee472ea10edf4f2a471b5001df0c5b4c1303bc Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Mon, 21 Sep 2020 01:04:58 -0700 Subject: [PATCH 21/25] Update copy --- spec/API_specification/indexing.md | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/spec/API_specification/indexing.md b/spec/API_specification/indexing.md index a3f78fc2f..0caa1af85 100644 --- a/spec/API_specification/indexing.md +++ b/spec/API_specification/indexing.md @@ -34,7 +34,7 @@ To index a single array axis, an array must support standard Python indexing rul - A negative index `j` is related to a zero-based nonnegative index `i` via `i = n+j`. -- Colons `:` must be used for [slices](https://docs.python.org/3/library/functions.html?highlight=slice#slice): `start:stop:step`, where `start` is inclusive and `stop` is exclusive. +- Colons `:` must be used for [slices](https://docs.python.org/3/library/functions.html#slice): `start:stop:step`, where `start` is inclusive and `stop` is exclusive. ### Slice Syntax @@ -58,7 +58,7 @@ A[i:j:k] .. note:: - Slice syntax can be equivalently achieved using the Python built-in [`slice()`](https://docs.python.org/3/library/functions.html?highlight=slice#slice) API. From the perspective from `A`, the behavior of `A[i:j:k]` and `A[slice(i, j, k)]` are indistinguishable (i.e., both retrieve the same set of items from `__getitem__`). + Slice syntax can be equivalently achieved using the Python built-in [`slice()`](https://docs.python.org/3/library/functions.html#slice) API. From the perspective from `A`, the behavior of `A[i:j:k]` and `A[slice(i, j, k)]` must be indistinguishable (i.e., both must retrieve the same set of items from `__getitem__`). Using a slice to index a single array axis must select `m` elements with index values @@ -86,7 +86,7 @@ j > i + (m-1)k .. note:: - For `i < j`, **valid** integer index `i`, and positive step `k`, a starting index `i` is **always** included, while the stopping index `j` is **always** excluded. This preserves `x[:i]+x[i:]` always being equal to `x`. + For `i` on the interval `[0, n)` (where `n` is the axis size), `j` on the interval `(0, n]`, `i` less than `j`, and positive step `k`, a starting index `i` is **always** included, while the stopping index `j` is **always** excluded. This preserves `x[:i]+x[i:]` always being equal to `x`. .. note:: @@ -95,12 +95,20 @@ j > i + (m-1)k Slice syntax must have the following defaults. Let `n` be the axis (dimension) size. - If `k` is not provided (e.g., `0:10`), `k` must equal `1`. -- If `k > 0` and `i` is not provided (e.g., `:10:2`), `i` must equal `0`. -- If `k > 0` and `j` is not provided (e.g., `0::2`), `j` must equal `n`. -- If `k < 0` and `i` is not provided (e.g., `:10:-2`), `i` must equal `n-1`. -- If `k < 0` and `j` is not provided (e.g., `0::-2`), `j` must equal `-n-1`. +- If `k` is greater than `0` and `i` is not provided (e.g., `:10:2`), `i` must equal `0`. +- If `k` is greater than `0` and `j` is not provided (e.g., `0::2`), `j` must equal `n`. +- If `k` is less than `0` and `i` is not provided (e.g., `:10:-2`), `i` must equal `n-1`. +- If `k` is less than `0` and `j` is not provided (e.g., `0::-2`), `j` must equal `-n-1`. -Indexing via `:` and `::` must be equivalent and have defaults derived from the rules above. Both `:` and `::` indicate to select all elements along a single axis (dimension). +Using a slice to index a single array axis must adhere to the following rules. Let `n` be the axis (dimension) size. + +- If `i` equals `j`, a slice must return an empty array, whose axis (dimension) size along the indexed axis is `0`. + +- If `i` and `j` resolve to starting and stopping indices, respectively, which are out-of-bounds (i.e., a starting index less than `0` and/or a stopping index greater than `n`), then the respective index is clipped to the array axis bounds. For a starting index, the bound is `0`. For a stopping index, the bound is `n`. + +- Indexing a single array axis with an out-of-bounds slice (i.e., a slice which does not select any array axis elements) must return an empty array, whose axis (dimension) size along the indexed axis is `0`. + +- Indexing via `:` and `::` must be equivalent and have defaults derived from the rules above. Both `:` and `::` indicate to select all elements along a single axis (dimension). ## Multi-axis Indexing @@ -120,11 +128,13 @@ Multi-dimensional arrays must extend the concept of single-axis indexing to mult - Providing a slice must retain array dimensions (i.e., the array rank must remain the same; `rank(A) == rank(A[:])`). +- For each slice which attempts to select elements along a particular axis, but whose starting index is out-of-bounds, the axis (dimension) size of the result array must be `0`. + - If the number of provided single-axis indexing expressions is less than `N`, then `:` must be assumed for the remaining dimensions (e.g., if `A` has rank `2`, `A[2:10] == A[2:10, :]`). - An `IndexError` exception must be raised if the number of provided single-axis indexing expressions is greater than `N`. -- Providing [ellipsis](https://docs.python.org/3/library/constants.html#Ellipsis) must apply `:` to each dimension necessary to index all dimensions (e.g., if `A` has rank `4`, `A[1:, ..., 2:5] == A[1:, :, :, 2:5]`). Only a single ellipsis must be allowed. An `IndexError` exception must be raised if more than one ellipsis is provided. +- Providing [ellipsis](https://docs.python.org/3/library/constants.html#Ellipsis) must apply `:` to each dimension necessary to index all dimensions (e.g., if `A` has rank `4`, `A[1:, ..., 2:5] == A[1:, :, :, 2:5]`). Only a single ellipsis must be allowed. An `IndexError` exception must be raised if more than one ellipsis is provided. ## Boolean Array Indexing From 3522698388399c83149d3060a8ce45816b3873c1 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Mon, 21 Sep 2020 01:14:04 -0700 Subject: [PATCH 22/25] Update copy --- spec/API_specification/indexing.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/spec/API_specification/indexing.md b/spec/API_specification/indexing.md index 0caa1af85..fb68cd86c 100644 --- a/spec/API_specification/indexing.md +++ b/spec/API_specification/indexing.md @@ -136,6 +136,8 @@ Multi-dimensional arrays must extend the concept of single-axis indexing to mult - Providing [ellipsis](https://docs.python.org/3/library/constants.html#Ellipsis) must apply `:` to each dimension necessary to index all dimensions (e.g., if `A` has rank `4`, `A[1:, ..., 2:5] == A[1:, :, :, 2:5]`). Only a single ellipsis must be allowed. An `IndexError` exception must be raised if more than one ellipsis is provided. +- The result of multi-axis indexing must be an array of the same data type as the indexed array. + ## Boolean Array Indexing An array must support indexing via a **single** `M`-dimensional boolean array `B` with shape `S1 = (s1, ..., sM)` according to the following rules. Let `A` be an `N`-dimensional array with shape `S2 = (s1, ..., sM, ..., sN)`. @@ -152,4 +154,6 @@ An array must support indexing via a **single** `M`-dimensional boolean array `B - The elements of a boolean index array must be iterated in row-major, C-style order, with the exception of zero-dimensional boolean arrays. -- A zero-dimensional boolean index array (equivalent to `True` or `False`) must follow the same axis replacement rules stated above. Namely, a zero-dimensional boolean index array removes zero dimensions and adds a single dimension of length `1` if the index array's value is `True` and of length `0` if the index array's value is `False`. Accordingly, for a zero-dimensional boolean index array `B`, the result of `A[B]` has shape `S = (1, s1, ..., sN)` if the index array's value is `True` and has shape `S = (0, s1, ..., sN)` if the index array's value is `False`. \ No newline at end of file +- A zero-dimensional boolean index array (equivalent to `True` or `False`) must follow the same axis replacement rules stated above. Namely, a zero-dimensional boolean index array removes zero dimensions and adds a single dimension of length `1` if the index array's value is `True` and of length `0` if the index array's value is `False`. Accordingly, for a zero-dimensional boolean index array `B`, the result of `A[B]` has shape `S = (1, s1, ..., sN)` if the index array's value is `True` and has shape `S = (0, s1, ..., sN)` if the index array's value is `False`. + +- The result of indexing into an array via a boolean index array must be an array of the same data type as the indexed array. From 1c19139a39c813f729abbe8a79ab4fb3622c39e9 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Mon, 19 Oct 2020 02:44:47 -0700 Subject: [PATCH 23/25] Reword copy --- spec/API_specification/indexing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/API_specification/indexing.md b/spec/API_specification/indexing.md index fb68cd86c..846d92f37 100644 --- a/spec/API_specification/indexing.md +++ b/spec/API_specification/indexing.md @@ -58,7 +58,7 @@ A[i:j:k] .. note:: - Slice syntax can be equivalently achieved using the Python built-in [`slice()`](https://docs.python.org/3/library/functions.html#slice) API. From the perspective from `A`, the behavior of `A[i:j:k]` and `A[slice(i, j, k)]` must be indistinguishable (i.e., both must retrieve the same set of items from `__getitem__`). + Slice syntax can be equivalently achieved using the Python built-in [`slice()`](https://docs.python.org/3/library/functions.html#slice) API. From the perspective from `A`, the behavior of `A[i:j:k]` and `A[slice(i, j, k)]` is indistinguishable (i.e., both retrieve the same set of items from `__getitem__`). Using a slice to index a single array axis must select `m` elements with index values From e114e9c3d8c6b3c417fc6a059215a1d7ec407524 Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Tue, 3 Nov 2020 21:14:53 +0000 Subject: [PATCH 24/25] Address one review comment on boolean array indexing (result order) --- spec/API_specification/indexing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/API_specification/indexing.md b/spec/API_specification/indexing.md index 846d92f37..63bcc0846 100644 --- a/spec/API_specification/indexing.md +++ b/spec/API_specification/indexing.md @@ -142,7 +142,7 @@ Multi-dimensional arrays must extend the concept of single-axis indexing to mult An array must support indexing via a **single** `M`-dimensional boolean array `B` with shape `S1 = (s1, ..., sM)` according to the following rules. Let `A` be an `N`-dimensional array with shape `S2 = (s1, ..., sM, ..., sN)`. -- If `N >= M`, then `A[B]` must replace the first `M` dimensions of `A` with a single dimension having a size equal to the number of `True` elements in `B`. +- If `N >= M`, then `A[B]` must replace the first `M` dimensions of `A` with a single dimension having a size equal to the number of `True` elements in `B`. The values in the resulting array must be in row-major (C-style order); this is equivalent to `A[nonzero(B)]`. .. note:: From 2831ceb5eef9fcf2f6694daaa9f6036fee97d893 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sun, 8 Nov 2020 08:33:32 -0600 Subject: [PATCH 25/25] Remove bounds checking requirements --- spec/API_specification/indexing.md | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/spec/API_specification/indexing.md b/spec/API_specification/indexing.md index 63bcc0846..792896e06 100644 --- a/spec/API_specification/indexing.md +++ b/spec/API_specification/indexing.md @@ -18,7 +18,7 @@ To index a single array axis, an array must support standard Python indexing rul .. note:: - This specification does not explicitly require bounds checking. The behavior for out-of-bounds integer indices is left unspecified. + This specification does not require bounds checking. The behavior for out-of-bounds integer indices is left unspecified. - Negative indices must count backward from the last array index, starting from `-1` (i.e., negative-one-based indexing, where `-1` refers to the last array index). @@ -30,7 +30,7 @@ To index a single array axis, an array must support standard Python indexing rul .. note:: - This specification does not explicitly require bounds checking. The behavior for out-of-bounds integer indices is left unspecified. + This specification does not require bounds checking. The behavior for out-of-bounds integer indices is left unspecified. - A negative index `j` is related to a zero-based nonnegative index `i` via `i = n+j`. @@ -104,11 +104,19 @@ Using a slice to index a single array axis must adhere to the following rules. L - If `i` equals `j`, a slice must return an empty array, whose axis (dimension) size along the indexed axis is `0`. -- If `i` and `j` resolve to starting and stopping indices, respectively, which are out-of-bounds (i.e., a starting index less than `0` and/or a stopping index greater than `n`), then the respective index is clipped to the array axis bounds. For a starting index, the bound is `0`. For a stopping index, the bound is `n`. +- Indexing via `:` and `::` must be equivalent and have defaults derived from the rules above. Both `:` and `::` indicate to select all elements along a single axis (dimension). + +.. note:: -- Indexing a single array axis with an out-of-bounds slice (i.e., a slice which does not select any array axis elements) must return an empty array, whose axis (dimension) size along the indexed axis is `0`. + This specification does not require "clipping" out-of-bounds indices (i.e., requiring the starting and stopping indices `i` and `j` be bound by `0` and `n`, respectively). -- Indexing via `:` and `::` must be equivalent and have defaults derived from the rules above. Both `:` and `::` indicate to select all elements along a single axis (dimension). + _Rationale: this is consistent with bounds checking for integer indexing; the behavior of out-of-bounds indices is left unspecified. Implementations may choose to clip, raise an exception, return junk values, or some other behavior depending on device requirements and performance considerations._ + +.. note:: + + This specification leaves unspecified the behavior of indexing a single array axis with an out-of-bounds slice (i.e., a slice which does not select any array axis elements). + + _Rationale: this is consistent with bounds checking for integer indexing; the behavior of out-of-bounds indices is left unspecified. Implementations may choose to return an empty array (whose axis (dimension) size along the indexed axis is `0`), raise an exception, or some other behavior depending on device requirements and performance considerations._ ## Multi-axis Indexing @@ -128,8 +136,6 @@ Multi-dimensional arrays must extend the concept of single-axis indexing to mult - Providing a slice must retain array dimensions (i.e., the array rank must remain the same; `rank(A) == rank(A[:])`). -- For each slice which attempts to select elements along a particular axis, but whose starting index is out-of-bounds, the axis (dimension) size of the result array must be `0`. - - If the number of provided single-axis indexing expressions is less than `N`, then `:` must be assumed for the remaining dimensions (e.g., if `A` has rank `2`, `A[2:10] == A[2:10, :]`). - An `IndexError` exception must be raised if the number of provided single-axis indexing expressions is greater than `N`. @@ -138,6 +144,12 @@ Multi-dimensional arrays must extend the concept of single-axis indexing to mult - The result of multi-axis indexing must be an array of the same data type as the indexed array. +.. note:: + + This specification leaves unspecified the behavior of providing a slice which attempts to select elements along a particular axis, but whose starting index is out-of-bounds. + + _Rationale: this is consistent with bounds-checking for single-axis indexing. An implementation may choose to set the axis (dimension) size of the result array to `0`, raise an exception, return junk values, or some other behavior depending on device requirements and performance considerations._ + ## Boolean Array Indexing An array must support indexing via a **single** `M`-dimensional boolean array `B` with shape `S1 = (s1, ..., sM)` according to the following rules. Let `A` be an `N`-dimensional array with shape `S2 = (s1, ..., sM, ..., sN)`.